diff options
Diffstat (limited to 'src/pdclib')
229 files changed, 22197 insertions, 0 deletions
diff --git a/src/pdclib/.gitignore b/src/pdclib/.gitignore new file mode 100644 index 0000000..d4ef6a2 --- /dev/null +++ b/src/pdclib/.gitignore @@ -0,0 +1,61 @@ +# Prerequisites +*.d + +# Object files +*.o +*.ko +*.obj +*.elf + +# Linker output +*.ilk +*.map +*.exp + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +*.a +*.la +*.lo + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex + +# Debug files +*.dSYM/ +*.su +*.idb +*.pdb + +# Kernel Module Compile Results +*.mod* +*.cmd +.tmp_versions/ +modules.order +Module.symvers +Mkfile.old +dkms.conf + +# PDCLib test drivers +*_t + +# PDCLib regression test drivers +*_r + +# Auxiliary Targets +get-uctypes diff --git a/src/pdclib/COPYING.CC0 b/src/pdclib/COPYING.CC0 new file mode 100644 index 0000000..0e259d4 --- /dev/null +++ b/src/pdclib/COPYING.CC0 @@ -0,0 +1,121 @@ +Creative Commons Legal Code + +CC0 1.0 Universal + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS + PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM + THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED + HEREUNDER. + +Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer +exclusive Copyright and Related Rights (defined below) upon the creator +and subsequent owner(s) (each and all, an "owner") of an original work of +authorship and/or a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for +the purpose of contributing to a commons of creative, cultural and +scientific works ("Commons") that the public can reliably and without fear +of later claims of infringement build upon, modify, incorporate in other +works, reuse and redistribute as freely as possible in any form whatsoever +and for any purposes, including without limitation commercial purposes. +These owners may contribute to the Commons to promote the ideal of a free +culture and the further production of creative, cultural and scientific +works, or to gain reputation or greater distribution for their Work in +part through the use and efforts of others. + +For these and/or other purposes and motivations, and without any +expectation of additional consideration or compensation, the person +associating CC0 with a Work (the "Affirmer"), to the extent that he or she +is an owner of Copyright and Related Rights in the Work, voluntarily +elects to apply CC0 to the Work and publicly distribute the Work under its +terms, with knowledge of his or her Copyright and Related Rights in the +Work and the meaning and intended legal effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be +protected by copyright and related or neighboring rights ("Copyright and +Related Rights"). Copyright and Related Rights include, but are not +limited to, the following: + + i. the right to reproduce, adapt, distribute, perform, display, + communicate, and translate a Work; + ii. moral rights retained by the original author(s) and/or performer(s); +iii. publicity and privacy rights pertaining to a person's image or + likeness depicted in a Work; + iv. rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(a), below; + v. rights protecting the extraction, dissemination, use and reuse of data + in a Work; + vi. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation + thereof, including any amended or successor version of such + directive); and +vii. other similar, equivalent or corresponding rights throughout the + world based on applicable law or treaty, and any national + implementations thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention +of, applicable law, Affirmer hereby overtly, fully, permanently, +irrevocably and unconditionally waives, abandons, and surrenders all of +Affirmer's Copyright and Related Rights and associated claims and causes +of action, whether now known or unknown (including existing as well as +future claims and causes of action), in the Work (i) in all territories +worldwide, (ii) for the maximum duration provided by applicable law or +treaty (including future time extensions), (iii) in any current or future +medium and for any number of copies, and (iv) for any purpose whatsoever, +including without limitation commercial, advertising or promotional +purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each +member of the public at large and to the detriment of Affirmer's heirs and +successors, fully intending that such Waiver shall not be subject to +revocation, rescission, cancellation, termination, or any other legal or +equitable action to disrupt the quiet enjoyment of the Work by the public +as contemplated by Affirmer's express Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason +be judged legally invalid or ineffective under applicable law, then the +Waiver shall be preserved to the maximum extent permitted taking into +account Affirmer's express Statement of Purpose. In addition, to the +extent the Waiver is so judged Affirmer hereby grants to each affected +person a royalty-free, non transferable, non sublicensable, non exclusive, +irrevocable and unconditional license to exercise Affirmer's Copyright and +Related Rights in the Work (i) in all territories worldwide, (ii) for the +maximum duration provided by applicable law or treaty (including future +time extensions), (iii) in any current or future medium and for any number +of copies, and (iv) for any purpose whatsoever, including without +limitation commercial, advertising or promotional purposes (the +"License"). The License shall be deemed effective as of the date CC0 was +applied by Affirmer to the Work. Should any part of the License for any +reason be judged legally invalid or ineffective under applicable law, such +partial invalidity or ineffectiveness shall not invalidate the remainder +of the License, and in such case Affirmer hereby affirms that he or she +will not (i) exercise any of his or her remaining Copyright and Related +Rights in the Work or (ii) assert any associated claims and causes of +action with respect to the Work, in either case contrary to Affirmer's +express Statement of Purpose. + +4. Limitations and Disclaimers. + + a. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + b. Affirmer offers the Work as-is and makes no representations or + warranties of any kind concerning the Work, express, implied, + statutory or otherwise, including without limitation warranties of + title, merchantability, fitness for a particular purpose, non + infringement, or the absence of latent or other defects, accuracy, or + the present or absence of errors, whether or not discoverable, all to + the greatest extent permissible under applicable law. + c. Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without + limitation any person's Copyright and Related Rights in the Work. + Further, Affirmer disclaims responsibility for obtaining any necessary + consents, permissions or other rights required for any use of the + Work. + d. Affirmer understands and acknowledges that Creative Commons is not a + party to this document and has no duty or obligation with respect to + this CC0 or use of the Work. diff --git a/src/pdclib/Internals.txt b/src/pdclib/Internals.txt new file mode 100644 index 0000000..f069e4a --- /dev/null +++ b/src/pdclib/Internals.txt @@ -0,0 +1,65 @@ +Internals +========= + +Large parts of PDCLib (or any standard library, really) work well in isolation, +and have minimal dependencies. The implementation of <string.h>, for example, +is really just a collection of stand-alone functions. + +Other parts, however, depend on each other, and on "background" functionality +that all involved parts need to be aware of and agree upon. + +This text file is intended to give a rough overview of what those parts are, +and how PDCLib goes about implementing them. + +Numeric conversion functions -- strto*() +---------------------------------------- + +The numeric conversion functions -- strtol(), strtoul(), strtoll(), strtoull() +from <stdlib.h> and strtoimax(), strtoumax() from <inttypes.h> -- all use the +same two internal functions, _PDCLIB_strtox_prelim() and _PDCLIB_strtox_main(). +The former does skip leading whitespace, determines the sign (if any), and the +base prefix (0 for octal, 0x for hexadecimal, none for decimal). The latter is +working on type uintmax_t, and gets the limiting values (to determine when to +set ERANGE) from the caller. + +Numeric conversion functions -- ato*() +-------------------------------------- + +The non-checking conversion functions atoi(), atol() and atoll() use the simpler +backend function _PDCLIB_atomax(). + +Formatted input / output functions -- *printf(), *scanf() +--------------------------------------------------------- + +The rather complex formatting logic used by the functions of the *printf() and +*scanf() family is provided by _PDCLIB_print() and _PDCLIB_scan(), with the +individual implementations in functions/stdio/ being rather simple wrappers +around those two backend functions. + +There is some ugliness arising from the fact that the backend functions have to +work with both file I/O and string I/O. Both backend functions are designed to +work purely stack-based; there is no dependency on malloc(), which allows to use +especially the print variety very early in the boot process with only minimal +adjustments. + +File I/O +-------- + +The actual handling of stream buffers and I/O is handled by four functions: +_PDCLIB_prepread() and _PDCLIB_prepwrite() handle the I/O direction of a stream, +while _PDCLIB_fillbuffer() and _PDCLIB_flushbuffer() are responsible for moving +data between stream buffers and their associated files. + +Localization +------------ + +PDCLib does not yet have proper support for different locales. At the point of +this writing, only the "C" locale is supported. Some of the infrastructure that +will be required in the future is already in place though. + +<locale.h> holds the definition of struct lconv (the return value of the +localeconv() function, holding all the numerical and monetary formatting +options). There are also references to _PDCLIB_lc_* structures holding +the other types of locale-dependent information. The definition of the +structures is in _PDCLIB_int.h, with initialization (for the "C" locale) +in _PDCLIB_stdinit.c. diff --git a/src/pdclib/Makefile b/src/pdclib/Makefile new file mode 100644 index 0000000..ebb0ad4 --- /dev/null +++ b/src/pdclib/Makefile @@ -0,0 +1,126 @@ +# This is a list of all non-source files that are part of the distribution. +AUXFILES := Makefile Readme.txt + +# Directories belonging to the project +PROJDIRS := functions include platform/stmos +# Directory where binaries should be written +BUILDDIR := . +# All source files of the project +SRCFILES := $(shell find -L $(PROJDIRS) -type f -name "*.c") +# All header files of the project +HDRFILES := $(shell find -L $(PROJDIRS) -type f -name "*.h") +# All object files in the library +OBJFILES := $(patsubst %.c,$(BUILDDIR)/%.o,$(SRCFILES)) +# All test drivers (.t) +TSTFILES := $(patsubst %.c,$(BUILDDIR)/%_t,$(SRCFILES)) +# All regression test drivers (.r) +REGFILES := $(patsubst %.c,$(BUILDDIR)/%_r,$(SRCFILES)) +# All library dependency files (.d) +DEPFILES := $(patsubst %.c,$(BUILDDIR)/%.d,$(SRCFILES)) +# All test driver dependency files (_t.d) +TSTDEPFILES := $(patsubst %,$(BUILDDIR)/%.d,$(TSTFILES)) +# All regression test driver dependency files (_r.d) +REGDEPFILES := $(patsubst %,$(BUILDDIR)/%.d,$(REGFILES)) +# All files belonging to the source distribution +ALLFILES := $(SRCFILES) $(HDRFILES) $(AUXFILES) + +WARNINGS := -Wall -Wextra -pedantic -Wno-unused-parameter -Wshadow -Wpointer-arith -Wcast-align -Wwrite-strings -Wmissing-prototypes -Wmissing-declarations -Wredundant-decls -Wnested-externs -Winline -Wno-long-long -Wuninitialized -Wstrict-prototypes -Wdeclaration-after-statement +CFLAGS := -fno-builtin -g -std=c99 -I./testing -I../user -I./platform/stmos/include $(WARNINGS) $(USERFLAGS) + +.PHONY: all clean srcdist tests testdrivers regtests regtestdrivers todos fixmes help + +all: $(BUILDDIR)/pdclib.a #testdrivers regtestdrivers + #@echo + #@echo "========================" + #@echo "Executing library tests:" + #@echo "========================" + #@echo + #@$(MAKE) tests | grep -v "^ TST" | grep -v "^Failed" + #@echo + #@echo "===========================" + #@echo "Executing regression tests:" + #@echo "===========================" + #@echo + #@$(MAKE) regtests | grep -v "^ RTST" | grep -v "^Failed" + #@echo + #@echo "========" + #@echo "FIXME's:" + #@echo "========" + #@echo + #@$(MAKE) fixmes + #@echo + #@echo "=======" + #@echo "TODO's:" + #@echo "=======" + #@echo + #@$(MAKE) todos | head + #@echo "..." + +$(BUILDDIR)/pdclib.a: $(OBJFILES) + @echo " AR $@" + @ar rc $(BUILDDIR)/pdclib.a $? + @echo + +tests: testdrivers + -@rc=0; count=0; failed=""; for file in $(TSTFILES); do echo " TST $$file"; $$file; test=$$?; if [ $$test != 0 ]; then rc=`expr $$rc + $$test`; failed="$$failed $$file"; fi; count=`expr $$count + 1`; done; echo; echo "Tests executed (linking PDCLib): $$count Tests failed: $$rc"; echo; for file in $$failed; do echo "Failed: $$file"; done; echo + +testdrivers: $(TSTFILES) + @echo + +regtests: regtestdrivers + -@rc=0; count=0; failed=""; for file in $(REGFILES); do echo " RTST $$file"; $$file; test=$$?; if [ $$test != 0 ]; then rc=`expr $$rc + $$test`; failed="$$failed $$file"; fi; count=`expr $$count + 1`; done; echo; echo "Tests executed (linking system libc): $$count Tests failed: $$rc"; echo; for file in $$failed; do echo "Failed: $$file"; done; echo + +regtestdrivers: $(REGFILES) + @echo + +-include $(DEPFILES) $(TSTDEPFILES) $(REGDEPFILES) + +clean: + -@$(RM) $(wildcard $(OBJFILES) $(DEPFILES) $(TSTFILES) $(TSTDEPFILES) $(REGFILES) $(REGDEPFILES) $(BUILDDIR)/pdclib.a pdclib.tgz scanf_testdata_*) + +srcdist: + @tar czf pdclib.tgz $(ALLFILES) + +todos: + -@for file in $(ALLFILES:Makefile=); do grep -H TODO $$file; done; true + +fixmes: + -@for file in $(ALLFILES:Makefile=); do grep -H FIXME $$file; done; true + +help: + @echo "Available make targets:" + @echo + @echo "all - build pdclib.a" + @echo "clean - remove all object files, dependency files and test drivers" + @echo "srcdist - build pdclib.tgz (source tarball)" + @echo "tests - build and run test drivers (link pdclib.a)" + @echo " testdrivers - build but do not run test drivers" + @echo "regtests - build and run regression test drivers (link system clib)" + @echo " regtestdrivers - build but do not run regression test drivers" + @echo "todos - list all TODO comments in the sources" + @echo "fixmes - list all FIXME comments in the sources" + @echo "%.o - build an individual object file" + @echo "%.t - build an individual test driver" + @echo "%.r - build an individual regression test driver" + @echo "help - print this list" + @echo + @echo "Any additional compiler flags you want to use can be passed as USERFLAGS" + @echo "(Usage: USERFLAGS=\"flags\" make [...])." + @echo + @echo "If you want to build out-of-source, you can specify BUILDDIR" + @echo "(Usage: make [...] BUILDDIR=/path/to/binaries/)." + +$(BUILDDIR)/%.o: %.c Makefile + @echo " CC $(patsubst functions/%,%,$@)" + @mkdir -p $(dir $@) + @$(CC) $(CFLAGS) -MMD -MP -I./include -c $< -o $@ + +$(BUILDDIR)/%_t: %.c Makefile $(BUILDDIR)/pdclib.a + @echo " CC $(patsubst functions/%,%,$@)" + @mkdir -p $(dir $@) + @$(CC) $(CFLAGS) -MMD -MP -DTEST -I./include $< $(BUILDDIR)/pdclib.a -o $@ + +$(BUILDDIR)/%_r: %.c Makefile + @echo " CC $(patsubst functions/%,%,$@)" + @mkdir -p $(dir $@) + @$(CC) $(CFLAGS) -Wno-deprecated-declarations -Wno-format -MMD -MP -DTEST -DREGTEST $< -o $@ diff --git a/src/pdclib/Notes.txt b/src/pdclib/Notes.txt new file mode 100644 index 0000000..b4efb8b --- /dev/null +++ b/src/pdclib/Notes.txt @@ -0,0 +1,104 @@ +Credits +======= + +The vast majority of PDCLib is original work by me. I felt it was the only way +to ensure that the code was indeed free of third-party rights, and thus free to +be released into the Public Domain. + +Another issue was that of coding style, quality and stability of the code, and +the urge to really understand every miniscule part of the code as to be able to +maintain it well once v1.0 has been released. + +That is not to say there are no credits to be given. To the contrary: + +Paul Edwards (author of the PDPCLIB), for inspirational code fragments, thanks. + +P.J. Plauger (author of "The Standard C Library"), for a book without which I +would not have been able to create PDCLib at this quality, thanks. + +Paul Bourke (author of mathlib), for allowing me access to a complete math +library under public domain terms so I could use it as a reference, thanks. + +Peter ("Candy") Bindels (netizen of osdev.org), who located a copy of Cody +& Waite's "Software Manual for the Elementary Functions" for me and saved me +serious cash in the process, thanks. + +Michael Moody, who contributed the generic implementation for <stdarg.h> to +the Public Domain which can now be found in <_PDCLIB_config.h>, thanks. + +Rod Pemberton, for pointing out several flaws in early versions of PDCLib and +giving other valuable hints, thanks. + +Brian Damgaard, for a very friendly exchange over the fine details of the +Quicksort algorithm and its implementation in PDCLib, thanks. + +Rink Springer, for very precise bug reports including patches, a heads-up on +the capabilities of PDCLib when I most needed it, and for pushing me back in +the driver's seat, thanks. + +Everyone involved in the first, "public" attempt at PDCLib, for bearing with me +when I restarted from scratch, thanks. + +Everyone bearing with me during the "stdio block", a period of many years in +which PDCLib received not a single update because I was stuck and could not +find the time and energy to work it out. + +Lennart Frid�n and Sammy Nordstr�m, who have been great pals even after I sunk +some other project that had eaten countless hours of work between the three of +us, thanks. + +My wife, daughter, and son for sharing husband and daddy with this strange +machine, thanks. + + +Style +===== + +I followed a set of guidelines in creating PDCLib. If you find some piece that +does not adhere to them, that's a bug worth reporting. I mean it. I am a bit +obsessive when it comes to coding style. ;-) + +- All the stuff that is not part of the standard specification is "hidden" in + the _PDCLIB_* namespace - functions, variables, macros, files, directories. + This is to make it easier to distinguish between what the standard dictates + and what I added to make PDCLib work. + +- I always try to minimize the use of local variables. Wherever possible I used + parameters passed by-value directly, and deferred declaration of locals to the + innermost block of statements, in hopes that it might reduce memory footprint + when the library is compiled with a compiler that is not that great at + optimization. + +- Every function, every static data item that could possibly be shared, got its + own implementation file. This means the library itself is probably larger than + strictly necessary, and might take a couple of clock cycles longer to link, + but it reduces size of object files and executables. + +- Where possible, I tried to share functionality between similar functions (as + can be seen in the atoi() and strtol() function families). This means one or + two additional function calls, but again reduces memory footprint and eases + maintenance of the library. + +- Function arguments are named exactly as in the standard document. + +- The standard is taken quite literally in places. For example, the default + implementations of memcpy() really copies char-wise. This runs contrary to + earlier claims of performance, but is consistent with the *letter* of the + standard, and you will probably use your compiler builtins (through a platform + overlay) anyhow. + +- PDCLib code has no bias towards POSIX; indeed the absence of POSIX tidbits is + one of its hallmarks. However, PDCLib also has no bias *against* POSIX, and + when one platform abstraction is as good as another, I chose the POSIX one for + sheer familiarity. (This is mainly referring to naming and parameter lists of + OS "glue" functions.) + +- Identifiers are tersely named, but not cryptically abbreviated, and should be + intuitive enough to allow easy understanding of PDCLib inner workings. + +- I disagree with the notion that good code needs no comments. Code tells you + *how*, but not the *why*, and you have to figure out the *what* yourself. So + I added comments to every nontrivial piece of code explaining my motives and + hopefully keeping overly ambitious editors from repeating my mistakes. The + header files especially should be self-documenting to the point of being a + suitable replacement for any library reference book you might be using. diff --git a/src/pdclib/Readme.txt b/src/pdclib/Readme.txt new file mode 100644 index 0000000..9a1b335 --- /dev/null +++ b/src/pdclib/Readme.txt @@ -0,0 +1,183 @@ +PDCLib - Public Domain C Library +================================ + +License +------- + +PDCLib is distributed unter the Creative Commons CC0 License. You +should have received a copy of the full legal text of this license +as part of this distribution (COPYING.CC0). It is also available at + +https://creativecommons.org/publicdomain/zero/1.0/legalcode + +The following is a human-readable summary of that license. + + No Copyright + +The person who associated a work with this deed has dedicated the +work to the public domain by waiving all of his or her rights to +the work worldwide under copyright law, including all related and +neighboring rights, to the extent allowed by law. + +You can copy, modify, distribute and perform the work, even for +commercial purposes, all without asking permission. See Other +Information below. + + Other Information + +In no way are the patent or trademark rights of any person affected +by CC0, nor are the rights that other persons may have in the work +or in how the work is used, such as publicity or privacy rights. + +Unless expressly stated otherwise, the person who associated a work +with this deed makes no warranties about the work, and disclaims +liability for all uses of the work, to the fullest extent permitted +by applicable law. + +When using or citing the work, you should not imply endorsement by +the author or the affirmer. + +What is it +---------- + +This is a C Standard Library. Nothing more, nothing less. No POSIX +or other extensions, just what's defined in ISO/IEC 9899. + +(Well, this is what it will be when the 1.0 release comes out. See +the "Development Status" section to see what's implemented so far.) + +Internals +--------- + +As a namespace convention, everything (files, typedefs, functions, +macros) not defined in ISO/IEC 9899 is prefixed with _PDCLIB. +The standard defines any identifiers starting with '_' and a capital +letter as reserved for the implementation, and since the chances of +your compiler using an identifier in the _PDCLIB range are slim, +any strictly conforming application should work with this library. + +PDCLib consists of several parts: + +1) standard headers; +2) implementation files for standard functions; +3) internal header files keeping complex stuff out of the standard + headers; +4) the central, platform-specific file _PDCLIB_config.h; +5) platform-specific implementation files; +6) platform-specific, optimized "overlay" implementations (optional). + +The standard headers (in ./include/) only contain what they are +defined to contain. Where additional logic or macro magic is +necessary, that is deferred to the internal files. This has been done +so that the headers are actually educational as to what they provide +(as opposed to how the library does it). + +There is a seperate implementation file (in ./function/{header}/) for +every function defined by the standard, named {function}.c. Not only +does this avoid linking in huge amounts of unused code when you use +but a single function, it also allows the optimization overlay to work +(see below). + +(The directory ./functions/_PDCLIB/ contains internal and helper +functions that are not part of the standard.) + +Then there are internal header files (in ./include/pdclib/), which +contain all the "black magic" and "code fu" that was kept out of the +standard headers. You should not have to touch them if you want to +adapt PDCLib to a new platform. Note that, if you *do* have to touch +them, I would consider it a serious design flaw, and would be happy +to fix it in the next PDCLib release. Any adaption work should be +covered by the steps detailed below. + +For adapting PDCLib to a new platform (the trinity of CPU, operating +system, and compiler), make a copy of ./platform/example/ named +./platform/{your_platform}/, and modify the files of your copy to suit +the constraints of your platform. When you are done, copy the contents +of your platform directory over the source directory structure +of PDCLib (or link them into the appropriate places). That should be +all that is actually required to make PDCLib work for your platform. + +Of course, your platform might provide more efficient replacements +for the generic implementations offered by PDCLib. The math functions +are an especially "juicy" target for optimization - while PDCLib does +provide generic implementations for each of them, there are usually +FPU opcodes that do the same job, only orders of magnitude faster. For +this, you might want to create an "optimization overlay" for PDCLib. + +Optimization Overlay +-------------------- + +The basic idea of PDCLib is to provide a generic implementation that +is useable even on platforms I have never heard of - for example, the +OS and/or compiler *you* just wrote and now need a C library for. That +is actually what PDCLib was written for: To provide a C library for +compiler and OS builders that do not want the usual baggage of POSIX +and GNU extensions, licensing considerations etc. etc. + +Thus, PDCLib provides generic implementations. They do work, and do +so correctly, but they are not very efficient when compared to hand- +crafted assembler or compiler build-ins. So I wanted to provide a +means to modify PDCLib to run more efficiently on a given platform, +without cluttering the main branch with tons of #ifdef statements and +"featureset #defines" that grow stale quickly. + +The solution is the "optimization overlay". Every function has its +own implementation file, which makes it possible to replace them +piecemeal by copying a platform-specific overlay over the main PDCLib +branch to create a PDCLib adapted / optimized for the platform in +question. That overlay could be part of the PDCLib source tree (for +established platforms where maintainers won't bother with PDCLib), or +part of that platform's source tree (for under-development platforms +PDCLib maintainers won't bother with). + +So, to use PDCLib on your given platform, you unpack PDCLib (as you +obviously have done already since you are reading this), and copy +the overlay for your platform over the PDCLib source tree structure. + +Development Status +------------------ + +Note that pre-v1.0 "releases" are internal milestones only, and that +you are strongly encouraged to use the latest source snapshot at all +times. + +v0.1 - 2004-12-12 +Freestanding-only C99 implementation without any overlay, and missing +the INTN_C() / UINTN_C() macros. <float.h> still has the enquire.c +values hardcoded into it; not sure whether to include enquire.c in the +package, to leave <float.h> to the overlay, or devise some parameterized +macro magic as for <limits.h> / <stdint.h>. Not thoroughly tested, but +I had to make the 0.1 release sometime so why not now. + +v0.2 - 2005-01-12 +Adds implementations for <string.h> (excluding strerror()), INTN_C() / +UINTN_C() macros, and some improvements in the internal headers. +Test drivers still missing, but added warnings about that. + +v0.3 - 2005-11-21 +Adds test drivers, fixes some bugs in <string.h>. + +v0.4 - 2005-02-06 +Implementations for parts of <stdlib.h>. Still missing are the floating +point conversions, and the wide-/multibyte-character functions. + +v0.4.1 - 2006-11-16 +With v0.5 (<stdio.h>) taking longer than expected, v0.4.1 was set up as +a backport of bugfixes in the current development code. +- #1 realloc( NULL, size ) fails (fixed) +- #2 stdlib.h - insufficient documentation (fixed) +- #4 Misspelled name in credits (fixed) +- #5 malloc() splits off too-small nodes (fixed) +- #6 qsort() stack overflow (fixed) +- #7 malloc() bug in list handling (fixed) +- #8 strncmp() does not terminate at '\0' (fixed) +- #9 stdint.h dysfunctional (fixed) +- #10 NULL redefinition warnings (fixed) + +v0.5 - 2010-12-22 +Implementations for <inttypes.h>, <errno.h>, most parts of <stdio.h>, +and strerror() from <string.h>. +Still no locale / wide-char support. Enabled all GCC compiler warnings I +could find, and fixed everything that threw a warning. (You see this, +maintainers of Open Source software? No warnings whatsoever. Stop telling +me it cannot be done.) Fixed all known bugs in the v0.4 release. diff --git a/src/pdclib/auxiliary/uctype/Makefile b/src/pdclib/auxiliary/uctype/Makefile new file mode 100644 index 0000000..0d34b98 --- /dev/null +++ b/src/pdclib/auxiliary/uctype/Makefile @@ -0,0 +1,48 @@ +TARGET := get-uctypes +# All source files of the project +SRCFILES := $(wildcard *.c) +# All header files of the project +HDRFILES := $(wildcard *.h) +# All object files in the project +OBJFILES := $(patsubst %.c,%.o,$(SRCFILES)) +# All test drivers (_t) +TSTFILES := $(patsubst %.c,%_t,$(SRCFILES)) +# All dependency files (.d) +DEPFILES := $(patsubst %.c,%.d,$(SRCFILES)) +# All test driver dependency files (_t.d) +TSTDEPFILES := $(patsubst %,%.d,$(TSTFILES)) +# All test driver dependency files (_t.d) + +WARNINGS := -Wall -Wextra -pedantic -Wno-unused-parameter -Wshadow -Wpointer-arith -Wcast-align -Wwrite-strings -Wmissing-prototypes -Wmissing-declarations -Wredundant-decls -Wnested-externs -Winline -Wno-long-long -Wuninitialized -Wstrict-prototypes -Wdeclaration-after-statement +CFLAGS := -g -std=c99 $(WARNINGS) $(USERFLAGS) -I. + +.PHONY: all clean tests + +all: $(TARGET) + +$(TARGET): $(OBJFILES) + @echo " CC $@" + @$(CC) $^ -o $@ + @echo + +tests: testdrivers + -@rc=0; count=0; failed=""; for file in $(TSTFILES); do echo " TST $$file"; ./$$file; test=$$?; if [ $$test != 0 ]; then rc=`expr $$rc + $$test`; failed="$$failed $$file"; fi; count=`expr $$count + 1`; done; echo; echo "Tests executed: $$count Tests failed: $$rc"; echo; for file in $$failed; do echo "Failed: $$file"; done; echo + +testdrivers: $(TSTFILES) + @echo + +-include $(DEPFILES) $(TSTDEPFILES) + +clean: + -@$(RM) $(wildcard $(OBJFILES) $(DEPFILES) $(TSTFILES) $(TSTDEPFILES) $(TARGET) aux.a) + +%.o: %.c Makefile + @echo " CC $@" + @$(CC) $(CFLAGS) -MMD -MP -c $< -o $@ + +%_t: %.c Makefile aux.a + @echo " CC $@" + @$(CC) $(CFLAGS) -MMD -MP -DTEST $< aux.a -o $@ + +aux.a: $(OBJFILES) + @ar rc $@ $^ diff --git a/src/pdclib/auxiliary/uctype/derived_properties.c b/src/pdclib/auxiliary/uctype/derived_properties.c new file mode 100644 index 0000000..c024efe --- /dev/null +++ b/src/pdclib/auxiliary/uctype/derived_properties.c @@ -0,0 +1,300 @@ +/* derived properties + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "text_utilities.h" + +#include "derived_properties.h" + +#define LINE_BUFFER_SIZE 500u + +struct derived_properties_t * read_derived_properties( const char * filename ) +{ + FILE * fh; + char buffer[ LINE_BUFFER_SIZE ]; + struct derived_properties_t * dp = NULL; + size_t code_points = 0; + size_t properties = 0; + const char * code_point_count = "# Total code points: "; + + if ( ( fh = fopen( filename, "r" ) ) == NULL ) + { + fprintf( stderr, "Could not open '%s' for reading.\n", filename ); + return NULL; + } + + if ( ( check_file( fh, LINE_BUFFER_SIZE, ';', sizeof( derived_properties_fields ) / sizeof( int ), derived_properties_fields ) ) != (size_t)-1 ) + { + while ( fgets( buffer, LINE_BUFFER_SIZE, fh ) ) + { + if ( strstr( buffer, code_point_count ) != NULL ) + { + size_t count = strtoul( buffer + strlen( code_point_count ), NULL, 10 ); + + if ( ( SIZE_MAX - count ) < code_points ) + { + fprintf( stderr, "Summing up total code points in '%s' would overflow.\n", filename ); + fclose( fh ); + return NULL; + } + + code_points += count; + ++properties; + } + } + + rewind( fh ); + + if ( ( dp = malloc( sizeof( struct derived_properties_t ) ) ) ) + { + dp->count = properties; + + if ( ( dp->name = calloc( properties, sizeof( char * ) ) ) ) + { + if ( ( dp->begin = calloc( properties, sizeof( size_t ) ) ) ) + { + if ( ( dp->end = calloc( properties, sizeof( size_t ) ) ) ) + { + if ( ( dp->code_points = malloc( code_points * sizeof( size_t ) ) ) ) + { + char * p; + char * range; + properties = 0; /* Re-using the variable */ + code_points = 0; /* Re-using the variable */ + + while ( fgets( buffer, LINE_BUFFER_SIZE, fh ) ) + { + /* Remove comments */ + if ( ( p = strchr( buffer, '#' ) ) != NULL ) + { + *p = '\0'; + } + + /* > 0 because of newline */ + if ( strlen( buffer ) > 1 ) + { + size_t first; + size_t last; + + range = next_token( buffer, ';' ); + p = next_token( NULL, ';' ); + + if ( ! range || ! p ) + { + size_t i; + + fprintf( stderr, "Parse error, malformed input.\n" ); + + for ( i = 0; i < properties; ++i ) + { + free( dp->name[ i ] ); + } + + free( dp->name ); + free( dp->begin ); + free( dp->end ); + free( dp->code_points ); + free( dp ); + return NULL; + } + + /* If we got to a new property (except the first) */ + if ( dp->name[ properties ] && strcmp( p, dp->name[ properties ] ) ) + { + /* Index into ->code_points where the previous property ends */ + dp->end[ properties ] = code_points; + ++properties; + } + + /* If we got to a new property, even the first */ + if ( dp->name[ properties ] == NULL ) + { + dp->name[ properties ] = malloc( strlen( p ) + 1 ); + strcpy( dp->name[ properties ], p ); + + /* Index into ->code_points where this property begins */ + dp->begin[ properties ] = code_points; + } + + /* Re-using p, as we have done everything related to the property + name at this point. + */ + first = strtoul( range, &p, 16 ); + + if ( *p == '\0' ) + { + last = first; + } + else + { + while ( *p && ! isxdigit( *p ) ) + { + ++p; + } + + last = strtoul( p, NULL, 16 ); + + if ( last <= first ) + { + size_t i; + + fprintf( stderr, "Parse error, malformed input.\n" ); + + for ( i = 0; i < properties; ++i ) + { + free( dp->name[ i ] ); + } + + free( dp->name ); + free( dp->begin ); + free( dp->end ); + free( dp->code_points ); + free( dp ); + return NULL; + } + } + + for ( ; first <= last; ++first ) + { + dp->code_points[ code_points++ ] = first; + } + } + } + + /* Have to end the last property as well */ + dp->end[ properties ] = code_points; + } + else + { + fprintf( stderr, "Memory allocation failure.\n" ); + free( dp->name ); + free( dp->begin ); + free( dp->end ); + free( dp ); + dp = NULL; + } + } + else + { + fprintf( stderr, "Memory allocation failure.\n" ); + free( dp->name ); + free( dp->begin ); + free( dp ); + dp = NULL; + } + } + else + { + fprintf( stderr, "Memory allocation failure.\n" ); + free( dp->name ); + free( dp ); + dp = NULL; + } + } + else + { + fprintf( stderr, "Memory allocation failure.\n" ); + free( dp ); + dp = NULL; + } + } + else + { + fprintf( stderr, "Memory allocation failure.\n" ); + } + } + + fclose( fh ); + return dp; +} + +static int comp( const void * l, const void * r ) +{ + const size_t * lhs = l; + const size_t * rhs = r; + + return ( *lhs < *rhs ) ? -1 : ( *lhs > *rhs ) ? 1 : 0; +} + +int lookup_property( struct derived_properties_t * dp, const char * property, size_t codepoint ) +{ + size_t i; + + for ( i = 0; i < dp->count; ++i ) + { + /* Look for the requested property */ + if ( strcmp( dp->name[ i ], property ) == 0 ) + { + size_t cp = dp->begin[ i ]; + + return bsearch( &codepoint, dp->code_points + cp, dp->end[ i ] - cp, sizeof( size_t ), comp ) != NULL; + } + } + + return 0; +} + +void release_derived_properties( struct derived_properties_t * dp ) +{ + size_t i; + + for ( i = 0; i < dp->count; ++i ) + { + free( dp->name[ i ] ); + } + + free( dp->name ); + free( dp->begin ); + free( dp->end ); + free( dp->code_points ); + free( dp ); +} + +#ifdef TEST + +#include "test.h" + +int main( void ) +{ + FILE * fh = fopen( "test.txt", "wb+" ); + struct derived_properties_t * dp; + + TESTCASE( fh != NULL ); + TESTCASE( fprintf( fh, "0000..0006 ; Test1 \n" ) == 20 ); + TESTCASE( fprintf( fh, "# Total code points: 7\n" ) == 23 ); + TESTCASE( fprintf( fh, "0001;Test2\n" ) == 11 ); + TESTCASE( fprintf( fh, "# Total code points: 1\n" ) == 23 ); + + fclose( fh ); + dp = read_derived_properties( "test.txt" ); + + TESTCASE( dp != NULL ); + TESTCASE( dp->count == 2 ); + TESTCASE( ! strcmp( dp->name[0], "Test1" ) ); + TESTCASE( ! strcmp( dp->name[1], "Test2" ) ); + + TESTCASE( lookup_property( dp, "Test1", 0 ) ); + TESTCASE( lookup_property( dp, "Test1", 6 ) ); + TESTCASE( ! lookup_property( dp, "Test1", 7 ) ); + + TESTCASE( ! lookup_property( dp, "Test2", 0 ) ); + TESTCASE( lookup_property( dp, "Test2", 1 ) ); + TESTCASE( ! lookup_property( dp, "Test2", 2 ) ); + + TESTCASE( ! lookup_property( dp, "Test", 0 ) ); + TESTCASE( ! lookup_property( dp, "Test3", 0 ) ); + + release_derived_properties( dp ); + remove( "test.txt" ); + + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/auxiliary/uctype/derived_properties.h b/src/pdclib/auxiliary/uctype/derived_properties.h new file mode 100644 index 0000000..d06ac84 --- /dev/null +++ b/src/pdclib/auxiliary/uctype/derived_properties.h @@ -0,0 +1,34 @@ +/* derived properties + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#ifndef DERIVED_PROPERTIES +#define DERIVED_PROPERTIES DERIVED_PROPERTIES + +#include <stddef.h> + +/* https://www.unicode.org/reports/tr44/#DerivedCoreProperties.txt */ + +struct derived_properties_t +{ + size_t count; + char * * name; + size_t * begin; + size_t * end; + size_t * code_points; +}; + +static const int derived_properties_fields[] = { + -1, /* code point or code point range */ + -1 /* property name */ +}; + +struct derived_properties_t * read_derived_properties( const char * filename ); + +int lookup_property( struct derived_properties_t * dp, const char * property, size_t codepoint ); + +void release_derived_properties( struct derived_properties_t * dp ); + +#endif diff --git a/src/pdclib/auxiliary/uctype/main.c b/src/pdclib/auxiliary/uctype/main.c new file mode 100644 index 0000000..ef60bb4 --- /dev/null +++ b/src/pdclib/auxiliary/uctype/main.c @@ -0,0 +1,300 @@ +/* main + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <locale.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#ifdef TEST +#include <wctype.h> +#endif + +#include "uctype.h" + +/* RLE Compressed Output + + <wctype.h> requires *11* flags: + iswupper, iswlower, iswalpha, iswdigit, iswblank, iswspace, + iswcntrl, iswxdigit, iswgraph, iswprint. + iswalnum (the 12th classification function) is *defined* as + iswalpha || iswdigit. And iswdigit and iswxdigit are defined + in a rather restrictive way that can be expressed by simple + ranges instead of lookup tables. And isgraph is defined as + isprint && ! isspace (which is trivial to check that it holds + true for all the records provided by get-unicode-ctype, at + least up to Unicode 11.0). + So we have only 8 flags we actually need in a lookup... nicely + reducing the storage requirement to an unsigned char. + + Another trick is to express toupper / tolower as offsets + instead of absolute values, which will allow run-time-length + compression of the data. +*/ + +struct output_record_t +{ + size_t codepoint; + int toupper_diff; + int tolower_diff; + unsigned char flags; +}; + +#ifdef TEST +static void print_codepoint_age( size_t codepoint, struct derived_properties_t * age ) +{ + size_t index = age->count; + + while ( index ) + { + --index; + + if ( lookup_property( age, age->name[ index ], codepoint ) ) + { + printf( "%s", age->name[ index ] ); + return; + } + } +} + +static void print_additional_codepoint_info( size_t codepoint, struct unicode_record_t * ur ) +{ + printf( " - %s", ur->name ); + printf( " - %s", ur->general_category ); + printf( " - %d", ur->canonical_combining_class ); + printf( " - %s", ur->bidi_class ); + printf( " - %s", ( ur->decomposition ? ur->decomposition : "NULL" ) ); + printf( " - %d", ur->numeric_type ); + printf( " - %d", ur->numeric_digit ); + printf( " - %s", ( ur->numeric_value ? ur->numeric_value : "NULL" ) ); + printf( " - %c", ur->bidi_mirrored ); + printf( " - U+%06zx", ur->simple_uppercase_mapping ); + printf( " - U+%06zx", ur->simple_lowercase_mapping ); + printf( " - U+%06zx", ur->simple_titlecase_mapping ); + printf( " - " ); + + /* Implementations are at liberty to return non-zero values other + than 1 for "true". + */ + printf( "%d", ( iswupper( codepoint ) ) ? 1 : 0 ); + printf( "%d", ( iswlower( codepoint ) ) ? 1 : 0 ); + printf( "%d", ( iswalpha( codepoint ) ) ? 1 : 0 ); + printf( "%d", ( iswdigit( codepoint ) ) ? 1 : 0 ); + printf( "%d", ( iswblank( codepoint ) ) ? 1 : 0 ); + printf( "%d", ( iswspace( codepoint ) ) ? 1 : 0 ); + printf( "%d", ( iswcntrl( codepoint ) ) ? 1 : 0 ); + printf( "%d", ( iswxdigit( codepoint ) ) ? 1 : 0 ); + printf( "%d", ( iswgraph( codepoint ) ) ? 1 : 0 ); + printf( "%d", ( iswprint( codepoint ) ) ? 1 : 0 ); + printf( "%d", ( iswpunct( codepoint ) ) ? 1 : 0 ); +} + +static void print_codepoint_info( size_t codepoint, struct unicode_record_t * ur, struct derived_properties_t * core, struct derived_properties_t * age ) +{ + int rc; + int equal = 1; + + if ( codepoint % 20 == 0 ) + { + printf( " cp up low UlA0_WCXGP.\n" ); + } + + printf( "U+%06zX ", codepoint ); + rc = get_towupper( codepoint, ur ); equal &= ( (unsigned)rc == towupper( codepoint ) ); printf( "U+%06X ", rc ); + rc = get_towlower( codepoint, ur ); equal &= ( (unsigned)rc == towlower( codepoint ) ); printf( "U+%06X ", rc ); + rc = get_iswupper( codepoint, ur, core ); equal &= ( iswupper( codepoint ) ? 1 : 0 == rc ); printf( "%d", rc ? 1 : 0 ); + rc = get_iswlower( codepoint, ur, core ); equal &= ( iswlower( codepoint ) ? 1 : 0 == rc ); printf( "%d", rc ? 1 : 0 ); + rc = get_iswalpha( codepoint, ur, core ); equal &= ( iswalpha( codepoint ) ? 1 : 0 == rc ); printf( "%d", rc ? 1 : 0 ); + rc = get_iswdigit( codepoint ); equal &= ( iswdigit( codepoint ) ? 1 : 0 == rc ); printf( "%d", rc ? 1 : 0 ); + rc = get_iswblank( codepoint, ur ); equal &= ( iswblank( codepoint ) ? 1 : 0 == rc ); printf( "%d", rc ? 1 : 0 ); + rc = get_iswspace( codepoint, ur ); equal &= ( iswspace( codepoint ) ? 1 : 0 == rc ); printf( "%d", rc ? 1 : 0 ); + rc = get_iswcntrl( codepoint, ur ); equal &= ( iswcntrl( codepoint ) ? 1 : 0 == rc ); printf( "%d", rc ? 1 : 0 ); + rc = get_iswxdigit( codepoint ); equal &= ( iswxdigit( codepoint ) ? 1 : 0 == rc ); printf( "%d", rc ? 1 : 0 ); + rc = get_iswgraph( codepoint, ur ); equal &= ( iswgraph( codepoint ) ? 1 : 0 == rc ); printf( "%d", rc ? 1 : 0 ); + rc = get_iswprint( codepoint, ur ); equal &= ( iswprint( codepoint ) ? 1 : 0 == rc ); printf( "%d", rc ? 1 : 0 ); + rc = get_iswpunct( codepoint, ur, core ); equal &= ( iswpunct( codepoint ) ? 1 : 0 == rc ); printf( "%d", rc ? 1 : 0 ); + + if ( codepoint != ur->code_point ) + { + /* These two may only differ for codepoint "ranges", which are + signified by "..., First>" / "..., Last>" pairs in UnicodeData. + If they differ and it's NOT a range, that is an error of some + kind. + */ + if ( ! strstr( ur->name, ", Last>" ) || codepoint < ( ur - 1 )->code_point ) + { + printf( " ERROR: U+%06zX != U+%06zX outside of First, Last codepoint range. ", codepoint, ur->code_point ); + } + } + + if ( ! equal ) + { + printf( " ERROR: Deviation from SysLib: " ); + print_codepoint_age( codepoint, age ); + print_additional_codepoint_info( codepoint, ur ); + } + + printf( "\n" ); +} +#else +static struct output_record_t get_output_record( size_t codepoint, struct unicode_record_t * ur, struct derived_properties_t * core ) +{ + struct output_record_t rc; + char buffer[ 9 ]; + + rc.codepoint = codepoint; + rc.toupper_diff = get_towupper( codepoint, ur ) - codepoint; + rc.tolower_diff = get_towlower( codepoint, ur ) - codepoint; + + sprintf( buffer, "%zu%zu%zu%zu%zu%zu%zu%zu", + get_iswupper( codepoint, ur, core ), + get_iswlower( codepoint, ur, core ), + get_iswalpha( codepoint, ur, core ), + get_iswblank( codepoint, ur ), + get_iswspace( codepoint, ur ), + get_iswcntrl( codepoint, ur ), + get_iswprint( codepoint, ur ), + get_iswpunct( codepoint, ur, core ) ); + + rc.flags = strtoul( buffer, NULL, 2 ); + + return rc; +} +#endif + +int main( int argc, char * argv[] ) +{ + struct unicode_data_t * ud; + struct derived_properties_t * core; +#ifdef TEST + struct derived_properties_t * age; +#endif + + char * locale = setlocale( LC_CTYPE, "" ); + + if ( ! strstr( locale, "UTF-8" ) || strstr( locale, "TR" ) || strstr( locale, "tr" ) ) + { + fprintf( stderr, "Need non-turkish locale to work correctly.\n'%s' will not do.\n", locale ); + return EXIT_FAILURE; + } + + if ( argc != 4 ) + { + printf( "\n" + "Usage: get-uctypes <UnicodeData.txt> <DerivedCoreProperties.txt>" +#ifdef TEST + " <DerivedAge.txt>" +#endif + "\n\n" + "Generates lookup tables for <wctype.h> from files available from\n" + "the Unicode Consortium.\n" + "\n" + "The required files can be retrieved from the following URL:\n" + "\n" + "http://www.unicode.org/Public/UCD/latest/ucd/\n" + "\n" ); + return EXIT_FAILURE; + } + + if ( ( ud = read_unicode_data( argv[ 1 ] ) ) != NULL ) + { + if ( ( core = read_derived_properties( argv[ 2 ] ) ) != NULL ) + { +#ifndef TEST + /* Print (to file) RLE compressed data */ + FILE * fh = fopen( "ctype.dat", "wb" ); + + if ( fh ) + { + size_t codepoint = 0; + size_t i = 0; + struct unicode_record_t * ur = &(ud->records[i]); + /* Name substring indicating a code point _range_ */ + const char * last = ", Last>"; + + struct output_record_t previous = get_output_record( codepoint, ur, core ); + + fprintf( fh, "%zx ", previous.codepoint ); + + for ( codepoint = 1; codepoint < 0x10fffe; ++codepoint ) + { + struct output_record_t current; + + while ( codepoint > ur->code_point ) + { + ur = &(ud->records[++i]); + } + + if ( codepoint != ur->code_point && ( ur->name && ( strstr( ur->name, last ) != ( ur->name + strlen( ur->name ) - strlen( last ) ) ) ) ) + { + /* Unregistered Code Point */ + continue; + } + + current = get_output_record( codepoint, ur, core ); + + /* RLE */ + if ( current.codepoint != previous.codepoint + 1 || + current.toupper_diff != previous.toupper_diff || + current.tolower_diff != previous.tolower_diff || + current.flags != previous.flags ) + { + fprintf( fh, "%zx %d %d %hhx\n", previous.codepoint, previous.toupper_diff, previous.tolower_diff, previous.flags ); + fprintf( fh, "%zx ", current.codepoint ); + } + + previous = current; + } + + fprintf( fh, "%zx %d %d %hhx\n", previous.codepoint, previous.toupper_diff, previous.tolower_diff, previous.flags ); + fclose( fh ); + } + else + { + fprintf( stderr, "Could not open 'ctype.dat' for writing.\n" ); + } +#else + if ( ( age = read_derived_properties( argv[ 3 ] ) ) != NULL ) + { + /* Print (to screen) raw data comparing our results + to the system library. + Differences are often because the system library + uses older data, which is why we add the age to + the output. + */ + size_t codepoint = 0; + size_t i = 0; + struct unicode_record_t * ur = &(ud->records[i]); + /* Name substring indicating a code point _range_ */ + const char * last = ", Last>"; + + for ( codepoint = 0; codepoint < 0x10fffe; ++codepoint ) + { + while ( codepoint > ur->code_point ) + { + ur = &(ud->records[++i]); + } + + if ( codepoint != ur->code_point && ! name_ends_with( ur, last ) ) + { + /* Unregistered Code Point */ + continue; + } + + print_codepoint_info( codepoint, ur, core, age ); + } + + release_derived_properties( age ); + } +#endif + + release_derived_properties( core ); + } + + release_unicode_data( ud ); + } + + return EXIT_SUCCESS; +} diff --git a/src/pdclib/auxiliary/uctype/test.h b/src/pdclib/auxiliary/uctype/test.h new file mode 100644 index 0000000..3cd33a8 --- /dev/null +++ b/src/pdclib/auxiliary/uctype/test.h @@ -0,0 +1,19 @@ +/* test + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#ifndef TEST_H +#define TEST_H TEST_H + +#include <stdio.h> + +#define NO_TESTDRIVER 0 + +static int TEST_RESULTS = 0; + +#define TESTCASE( x ) if ( x ) {} \ + else { TEST_RESULTS += 1; printf( "FAILED: " __FILE__ ", line %d - %s\n", __LINE__, #x ); } + +#endif diff --git a/src/pdclib/auxiliary/uctype/text_utilities.c b/src/pdclib/auxiliary/uctype/text_utilities.c new file mode 100644 index 0000000..20973d9 --- /dev/null +++ b/src/pdclib/auxiliary/uctype/text_utilities.c @@ -0,0 +1,206 @@ +/* text utilities + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include "text_utilities.h" + +#include <ctype.h> +#include <stdlib.h> +#include <string.h> + +char * trim( char * s ) +{ + char * p; + + /* Skip over leading whitespace */ + while ( *s && isspace( *s ) ) + { + ++s; + } + + /* Trim trailing whitespace */ + p = s; + + while ( *p ) + { + ++p; + } + + while ( isspace( *(--p) ) ) + { + *p = '\0'; + } + + return s; +} + +char * next_token( char * s, char delim ) +{ + static char * p = NULL; + char * rc; + + if ( s != NULL ) + { + /* Re-init the to-be-tokenized string */ + p = s; + } + + /* Remembering the start of the next token */ + rc = p; + + /* In case the function has not been initialized, or the previous + string been exhaused, do nothing. + */ + if ( p ) + { + /* Re-using s here */ + if ( ( s = strchr( p, delim ) ) ) + { + /* Null the delimiter */ + *s = '\0'; + /* Make the internal, static pointer point to the next token */ + p = s + 1; + } + else + { + /* Delimiter not found, end-of-string reached. */ + p = NULL; + } + + /* Trim the result */ + rc = trim( rc ); + } + + return rc; +} + +size_t check_file( FILE * fh, size_t buffer_size, char delim, size_t fields, int const * widths ) +{ + /* Dynamically allocated buffer */ + char * buffer = malloc( buffer_size ); + size_t lines = 0; + + rewind( fh ); + + while ( fgets( buffer, buffer_size, fh ) ) + { + size_t i; + char * p; + + ++lines; + + /* Check line for complete read */ + if ( buffer[ strlen( buffer ) - 1 ] != '\n' ) + { + fprintf( stderr, "Line %zu will not fit into a %zu-character buffer.\n", lines, buffer_size ); + rewind( fh ); + free( buffer ); + return -1; + } + + /* Remove comments */ + if ( ( p = strchr( buffer, '#' ) ) != NULL ) + { + *p = '\0'; + } + + /* > 1 because of newline */ + if ( strlen( buffer ) > 1 ) + { + /* Check field count and field widths */ + p = next_token( buffer, delim ); + + for ( i = 0; i < fields; ++i ) + { + if ( ! p ) + { + fprintf( stderr, "Line %zu contains less than %zu fields.\n", lines, fields ); + rewind( fh ); + free( buffer ); + return -1; + } + + if ( widths[ i ] >= 0 && strlen( p ) >= (unsigned)widths[ i ] ) + { + fprintf( stderr, "Line %zu: Field %zu '%s' will not fit in a %d character string.\n", lines, i + 1, p, widths[ i ] ); + rewind( fh ); + free( buffer ); + return -1; + } + + p = next_token( NULL, delim ); + } + + if ( p ) + { + fprintf( stderr, "Line %zu contains more than %zu fields.\n", lines, fields ); + rewind( fh ); + free( buffer ); + return -1; + } + } + } + + /* Rewind, free the buffer, and report the number of lines */ + rewind( fh ); + free( buffer ); + return lines; +} + +#ifdef TEST + +#include "test.h" + +int main( void ) +{ + FILE * fh = fopen( "test.txt", "wb+" ); + int widths[] = { 4, 4, 4 }; + char buffer[ 500 ]; + + /* check_file() (and as dependency, next_token() */ + + /* All ok */ + TESTCASE( fprintf( fh, "%s;%s;%s\n", "1", "123", "12" ) == 9 ); + TESTCASE( fprintf( fh, ";;\n" ) == 3 ); + TESTCASE( check_file( fh, 10, ';', 3, widths ) == 2 ); + /* Field 1 too long */ + TESTCASE( fprintf( fh, "%s;%s;%s\n", "", "1234", "1" ) == 8 ); + TESTCASE( check_file( fh, 10, ';', 3, widths ) == (size_t)-1 ); + /* Too few fields */ + TESTCASE( fprintf( fh, "%s;%s\n", "123", "123" ) == 8 ); + TESTCASE( check_file( fh, 10, ';', 3, widths )== (size_t)-1 ); + /* Too many fields */ + TESTCASE( fprintf( fh, "%s;%s;%s;%s\n", "1", "1", "1", "1" ) == 8 ); + TESTCASE( check_file( fh, 10, ';', 3, widths )== (size_t)-1 ); + /* Line too long */ + TESTCASE( fprintf( fh, "%s;%s;%s\n", "12", "123", "12" ) == 10 ); + TESTCASE( check_file( fh, 10, ';', 3, widths )== (size_t)-1 ); + + fclose( fh ); + remove( "test.txt" ); + + /* trim() */ + + strcpy( buffer, " xyz" ); + TESTCASE( ! strcmp( trim( buffer ), "xyz" ) ); + strcpy( buffer, "xyz " ); + TESTCASE( ! strcmp( trim( buffer ), "xyz" ) ); + strcpy( buffer, " xyz " ); + TESTCASE( ! strcmp( trim( buffer ), "xyz" ) ); + strcpy( buffer, " x" ); + TESTCASE( ! strcmp( trim( buffer ), "x" ) ); + strcpy( buffer, "x " ); + TESTCASE( ! strcmp( trim( buffer ), "x" ) ); + strcpy( buffer, " " ); + TESTCASE( ! strcmp( trim( buffer ), "" ) ); + strcpy( buffer, " " ); + TESTCASE( ! strcmp( trim( buffer ), "" ) ); + strcpy( buffer, "" ); + TESTCASE( ! strcmp( trim( buffer ), "" ) ); + + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/auxiliary/uctype/text_utilities.h b/src/pdclib/auxiliary/uctype/text_utilities.h new file mode 100644 index 0000000..f961e6b --- /dev/null +++ b/src/pdclib/auxiliary/uctype/text_utilities.h @@ -0,0 +1,59 @@ +/* text utilities + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#ifndef TEXT_UTILITIES_H +#define TEXT_UTILITIES_H TEXT_UTILITIES_H + +#include <inttypes.h> +#include <stdio.h> + +/* Trim leading and trailing whitespace from a given string. + Will return a pointer beyond leading whitespace, and overwrite trailing + whitespace with null bytes. +*/ +char * trim( char * s ); + +/* A function similar to strtok(), that returns the next token in a string, + up to the next separator character (which is replaced with a null byte) + or up to end-of-string. + As opposed to strtok(), which treats consecutive separators as one, this + function will work "correctly" for those as well, returning a (pointer + to an) empty string in those cases. + Pass the string as first parameter IN THE FIRST CALL ONLY, and NULL in + subsequent calls. The function holds an internal, static pointer to the + string being processed. This, of course, means the function is not thread- + safe. +*/ +char * next_token( char * s, char delim ); + +/* When processing a file with delimited-values, there are a couple of things + you want to be sure about before parsing it: + - the number of lines (data records) in the file; + - that all lines of the file will fit the intended line buffer size; + - that all records in the file indeed have the expected number of fields; + - that none of the fields for which you are assuming a given size exceeds + that size. + (For line buffer size, consider that the buffer must be large enough for + the line contents, the newline (to check that the line was actually read + in full), and the null terminator.) + This function does all that for you in a single pass. The parameters are: + - FILE handle to the file (function will rewind the file before checking, + and rewind again when it is done); + - the intended line buffer size; + - the field delimiter; + - the expected number of fields; + - a pointer to an array holding the expected maximum width for each field, + with a negative value indicating that this field's width need not be + checked. + The function will return the number of lines in the file, or (size_t)-1 + if one of the checks failed. The reason for the failed check will be + written to stderr. (The file will not be rewound in this case.) + This requires reading and tokenizing the file twice, but removes lots of + error checking from the actual parsing, making for cleaner code. +*/ +size_t check_file( FILE * fh, size_t max_line_length, char delim, size_t fields, int const * widths ); + +#endif diff --git a/src/pdclib/auxiliary/uctype/uctype.c b/src/pdclib/auxiliary/uctype/uctype.c new file mode 100644 index 0000000..ce8d8ef --- /dev/null +++ b/src/pdclib/auxiliary/uctype/uctype.c @@ -0,0 +1,85 @@ +/* uctype + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include "uctype.h" + +size_t get_towupper( size_t codepoint, struct unicode_record_t * ur ) +{ + return towupper_differs( ur, codepoint ) ? ur->simple_uppercase_mapping : codepoint; +} + +size_t get_towlower( size_t codepoint, struct unicode_record_t * ur ) +{ + return towlower_differs( ur, codepoint ) ? ur->simple_lowercase_mapping : codepoint; +} + +size_t get_iswupper( size_t codepoint, struct unicode_record_t * ur, struct derived_properties_t * core ) +{ + return towlower_differs( ur, codepoint ) || lookup_property( core, "Uppercase", codepoint ); +} + +size_t get_iswlower( size_t codepoint, struct unicode_record_t * ur, struct derived_properties_t * core ) +{ + return towupper_differs( ur, codepoint ) || lookup_property( core, "Lowercase", codepoint ); +} + +size_t get_iswalpha( size_t codepoint, struct unicode_record_t * ur, struct derived_properties_t * core ) +{ + return lookup_property( core, "Alphabetic", codepoint ) || ( is_general_category( ur, "Nd" ) && ! get_iswdigit( codepoint ) ); +} + +size_t get_iswdigit( size_t codepoint ) +{ + return codepoint >= 0x0030 && codepoint <= 0x0039; +} + +size_t get_iswxdigit( size_t codepoint ) +{ + return get_iswdigit( codepoint ) || ( codepoint >= 0x0041 && codepoint <= 0x0046 ) || ( codepoint >= 0x0061 && codepoint <= 0x0066 ); +} + +size_t get_iswblank( size_t codepoint, struct unicode_record_t * ur ) +{ + return ( codepoint == 0x0009 ) || ( is_general_category( ur, "Zs" ) && ! decomposition_contains( ur, "<noBreak>" ) ); +} + +size_t get_iswspace( size_t codepoint, struct unicode_record_t * ur ) +{ + return is_general_category( ur, "Zl" ) || is_general_category( ur, "Zp" ) || ( is_general_category( ur, "Zs" ) && ! decomposition_contains( ur, "<noBreak>" ) ) || ( codepoint == 0x0020 ) || ( codepoint >= 0x0009 && codepoint <= 0x000D ); +} + +size_t get_iswcntrl( size_t codepoint, struct unicode_record_t * ur ) +{ + return is_general_category( ur, "Zl" ) || is_general_category( ur, "Zp" ) || has_name( ur, "<control>" ); +} + +size_t get_iswgraph( size_t codepoint, struct unicode_record_t * ur ) +{ + return ! is_general_category( ur, "Cs" ) && ! has_name( ur, "<control>" ) && ! get_iswspace( codepoint, ur ); +} + +size_t get_iswprint( size_t codepoint, struct unicode_record_t * ur ) +{ + return ! is_general_category( ur, "Zp" ) && ! is_general_category( ur, "Zl" ) && ! is_general_category( ur, "Cs" ) && ! has_name( ur, "<control>" ); +} + +size_t get_iswpunct( size_t codepoint, struct unicode_record_t * ur, struct derived_properties_t * core ) +{ + return ! get_iswalpha( codepoint, ur, core ) && ! get_iswdigit( codepoint ) && ( ! has_name( ur, "<control>" ) && ! get_iswspace( codepoint, ur ) ) && ! is_general_category( ur, "Cs" ); +} + +#ifdef TEST + +#include "test.h" + +int main( void ) +{ + TESTCASE( NO_TESTDRIVER ); + + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/auxiliary/uctype/uctype.h b/src/pdclib/auxiliary/uctype/uctype.h new file mode 100644 index 0000000..8cdda43 --- /dev/null +++ b/src/pdclib/auxiliary/uctype/uctype.h @@ -0,0 +1,29 @@ +/* uctype data + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#ifndef UCTYPE +#define UCTYPE + +#include "derived_properties.h" +#include "unicode_data.h" + +size_t get_towupper( size_t codepoint, struct unicode_record_t * ur ); +size_t get_towlower( size_t codepoint, struct unicode_record_t * ur ); +size_t get_iswupper( size_t codepoint, struct unicode_record_t * ur, struct derived_properties_t * core ); +size_t get_iswlower( size_t codepoint, struct unicode_record_t * ur, struct derived_properties_t * core ); +size_t get_iswalpha( size_t codepoint, struct unicode_record_t * ur, struct derived_properties_t * core ); +size_t get_iswdigit( size_t codepoint ); +size_t get_iswxdigit( size_t codepoint ); +size_t get_iswblank( size_t codepoint, struct unicode_record_t * ur ); +size_t get_iswspace( size_t codepoint, struct unicode_record_t * ur ); +size_t get_iswcntrl( size_t codepoint, struct unicode_record_t * ur ); +size_t get_iswgraph( size_t codepoint, struct unicode_record_t * ur ); +size_t get_iswprint( size_t codepoint, struct unicode_record_t * ur ); +size_t get_iswpunct( size_t codepoint, struct unicode_record_t * ur, struct derived_properties_t * core ); + + +#endif + diff --git a/src/pdclib/auxiliary/uctype/unicode_data.c b/src/pdclib/auxiliary/uctype/unicode_data.c new file mode 100644 index 0000000..5d92fda --- /dev/null +++ b/src/pdclib/auxiliary/uctype/unicode_data.c @@ -0,0 +1,224 @@ +/* unicode data + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "text_utilities.h" + +#include "unicode_data.h" + +#define LINE_BUFFER_SIZE 500u + +struct unicode_data_t * read_unicode_data( const char * filename ) +{ + FILE * fh; + char buffer[ LINE_BUFFER_SIZE ]; + struct unicode_data_t * ud = NULL; + size_t lines; + + if ( ( fh = fopen( filename, "r" ) ) == NULL ) + { + fprintf( stderr, "Could not open '%s' for reading.\n", filename ); + return NULL; + } + + if ( ( lines = check_file( fh, LINE_BUFFER_SIZE, ';', sizeof( unicode_record_fields ) / sizeof( int ), unicode_record_fields ) ) != (size_t)-1 ) + { + if ( ( ud = malloc( sizeof( struct unicode_data_t ) ) ) ) + { + ud->size = lines; + + if ( ( ud->records = calloc( lines, sizeof( struct unicode_record_t ) ) ) ) + { + size_t i; + + for ( i = 0; i < lines; ++i ) + { + char * p; + + fgets( buffer, LINE_BUFFER_SIZE, fh ); + + ud->records[ i ].code_point = strtoul( next_token( buffer, ';' ), NULL, 16 ); + + p = next_token( NULL, ';' ); + if ( *p ) + { + ud->records[ i ].name = malloc( strlen( p ) + 1 ); + strcpy( ud->records[ i ].name, p ); + } + + strcpy( ud->records[ i ].general_category, next_token( NULL, ';' ) ); + + p = next_token( NULL, ';' ); + ud->records[ i ].canonical_combining_class = ( *p ) ? strtol( p, NULL, 10 ) : -1l; + + strcpy( ud->records[ i ].bidi_class, next_token( NULL, ';' ) ); + + p = next_token( NULL, ';' ); + if ( *p ) + { + ud->records[ i ].decomposition = malloc( strlen( p ) + 1 ); + strcpy( ud->records[ i ].decomposition, p ); + } + + p = next_token( NULL, ';' ); + ud->records[ i ].numeric_type = ( *p ) ? strtol( p, NULL, 10 ) : -1l; + + p = next_token( NULL, ';' ); + ud->records[ i ].numeric_digit = ( *p ) ? strtol( p, NULL, 10 ) : -1l; + + p = next_token( NULL, ';' ); + if ( *p ) + { + ud->records[ i ].numeric_value = malloc( strlen( p ) + 1 ); + strcpy( ud->records[ i ].numeric_value, p ); + } + + p = next_token( NULL, ';' ); + ud->records[ i ].bidi_mirrored = ( *p ) ? *p : '\0'; + + next_token( NULL, ';' ); /* Unicode_1_Name */ + next_token( NULL, ';' ); /* ISO_Comment */ + + ud->records[ i ].simple_uppercase_mapping = strtoul( next_token( NULL, ';' ), NULL, 16 ); + ud->records[ i ].simple_lowercase_mapping = strtoul( next_token( NULL, ';' ), NULL, 16 ); + ud->records[ i ].simple_titlecase_mapping = strtoul( next_token( NULL, ';' ), NULL, 16 ); + } + } + else + { + fprintf( stderr, "Memory allocation failure.\n" ); + free( ud ); + ud = NULL; + } + } + else + { + fprintf( stderr, "Memory allocation failure.\n" ); + } + } + + fclose( fh ); + return ud; +} + +int has_name( struct unicode_record_t * ur, const char * name ) +{ + return strcmp( ur->name, name ) == 0; +} + +int name_ends_with( struct unicode_record_t * ur, const char * name ) +{ + return strstr( ur->name, name ) == ( ur->name + ( strlen( ur->name ) - strlen( name ) ) ); +} + +int is_general_category( struct unicode_record_t * ur, const char * category ) +{ + return strcmp( ur->general_category, category ) == 0; +} + +int decomposition_contains( struct unicode_record_t * ur, const char * substring ) +{ + return ur->decomposition && strstr( ur->decomposition, substring ) != NULL; +} + +int towupper_differs( struct unicode_record_t * ur, size_t codepoint ) +{ + return ur->simple_uppercase_mapping && ( ur->simple_uppercase_mapping != codepoint ); +} + +int towlower_differs( struct unicode_record_t * ur, size_t codepoint ) +{ + return ur->simple_lowercase_mapping && ( ur->simple_lowercase_mapping != codepoint ); +} + +void release_unicode_data( struct unicode_data_t * ud ) +{ + size_t i; + + for ( i = 0; i < ud->size; ++i ) + { + free( ud->records[i].name ); + free( ud->records[i].decomposition ); + free( ud->records[i].numeric_value ); + } + + free( ud->records ); + free( ud ); +} + +#ifdef TEST + +#include "test.h" + +#include <inttypes.h> + +int main( void ) +{ + FILE * fh = fopen( "test.txt", "w" ); + struct unicode_data_t * ud; + int rc; + + TESTCASE( fh != NULL ); + TESTCASE( fprintf( fh, "%04x;%s;%s;%d;%s;;;;;%c;%s;;;;\n", 0, "<control>", "Cc", 0, "BN", 'N', "NULL" ) == 38 ); + TESTCASE( ( rc = fprintf( fh, "%04x;%s;%s;%d;%s;%s;;;%s;%c;;;%04x;;%04x\n", 0x2170, "SMALL ROMAN NUMERAL ONE", "Nl", 0, "L", "<compat> 0069", "1", 'N', 0x2160, 0x2160 ) ) == 69 ); + + fclose( fh ); + ud = read_unicode_data( "test.txt" ); + remove( "test.txt" ); + + TESTCASE( ud != NULL ); + TESTCASE( ud->size == 2 ); + + TESTCASE( ud->records[0].code_point == 0 ); + TESTCASE( strcmp( ud->records[0].name, "<control>" ) == 0 ); + TESTCASE( strcmp( ud->records[0].general_category, "Cc" ) == 0 ); + TESTCASE( ud->records[0].canonical_combining_class == 0 ); + TESTCASE( strcmp( ud->records[0].bidi_class, "BN" ) == 0 ); + TESTCASE( ud->records[0].decomposition == NULL ); + TESTCASE( ud->records[0].numeric_type == -1 ); + TESTCASE( ud->records[0].numeric_digit == -1 ); + TESTCASE( ud->records[0].numeric_value == NULL ); + TESTCASE( ud->records[0].bidi_mirrored == 'N' ); + TESTCASE( ud->records[0].simple_uppercase_mapping == 0 ); + TESTCASE( ud->records[0].simple_lowercase_mapping == 0 ); + TESTCASE( ud->records[0].simple_titlecase_mapping == 0 ); + + TESTCASE( ud->records[1].code_point == 0x2170 ); + TESTCASE( strcmp( ud->records[1].name, "SMALL ROMAN NUMERAL ONE" ) == 0 ); + TESTCASE( strcmp( ud->records[1].general_category, "Nl" ) == 0 ); + TESTCASE( ud->records[1].canonical_combining_class == 0 ); + TESTCASE( strcmp( ud->records[1].bidi_class, "L" ) == 0 ); + TESTCASE( strcmp( ud->records[1].decomposition, "<compat> 0069" ) == 0 ); + TESTCASE( ud->records[1].numeric_type == -1 ); + TESTCASE( ud->records[1].numeric_digit == -1 ); + TESTCASE( strcmp( ud->records[1].numeric_value, "1" ) == 0 ); + TESTCASE( ud->records[1].bidi_mirrored == 'N' ); + TESTCASE( ud->records[1].simple_uppercase_mapping == 0x2160 ); + TESTCASE( ud->records[1].simple_lowercase_mapping == 0 ); + TESTCASE( ud->records[1].simple_titlecase_mapping == 0x2160 ); + + TESTCASE( is_general_category( &(ud->records[0]), "Cc" ) ); + TESTCASE( ! is_general_category( &(ud->records[0]), "" ) ); + TESTCASE( is_general_category( &(ud->records[1]), "Nl" ) ); + TESTCASE( ! is_general_category( &(ud->records[1]), "Foo" ) ); + + TESTCASE( decomposition_contains( &(ud->records[1]), "<compat>" ) ); + TESTCASE( ! decomposition_contains( &(ud->records[1]), "Foo" ) ); + + TESTCASE( ! towupper_differs( &(ud->records[0]), 0 ) ); + TESTCASE( ! towlower_differs( &(ud->records[0]), 0 ) ); + TESTCASE( towupper_differs( &(ud->records[1]), 0x2170 ) ); + TESTCASE( ! towlower_differs( &(ud->records[1]), 0x2170 ) ); + + release_unicode_data( ud ); + + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/auxiliary/uctype/unicode_data.h b/src/pdclib/auxiliary/uctype/unicode_data.h new file mode 100644 index 0000000..8cd4832 --- /dev/null +++ b/src/pdclib/auxiliary/uctype/unicode_data.h @@ -0,0 +1,77 @@ +/* unicode data + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#ifndef UNICODE_DATA +#define UNICODE_DATA UNICODE_DATA + +#include <stddef.h> + +/* https://www.unicode.org/reports/tr44/#UnicodeData.txt */ + +/* We do not need all these fields at this point, but we read them anyway + so we do not need to change much should the need arise later. +*/ +struct unicode_record_t +{ + size_t code_point; + char * name; + char general_category[ 3 ]; + int canonical_combining_class; + char bidi_class[ 4 ]; + char * decomposition; + int numeric_type; + int numeric_digit; + char * numeric_value; + char bidi_mirrored; + /*char * unicode_1_name;*/ /* Obsolete as of 6.2.0 */ + /*char * iso_comment;*/ /* Obsoöete as of 5.2.0 */ + size_t simple_uppercase_mapping; + size_t simple_lowercase_mapping; + size_t simple_titlecase_mapping; +}; + +struct unicode_data_t +{ + size_t size; + struct unicode_record_t * records; +}; + +/* The assumed field widths, for use with check_file(). */ +static const int unicode_record_fields[] = { + -1, /* code_point */ + -1, /* name */ + 3, /* general_category */ + -1, /* canonical_combining_class */ + 4, /* bidi_class */ + -1, /* decomposition */ + -1, /* numeric_type */ + -1, /* numeric_digit */ + -1, /* numeric_value */ + 2, /* bidi_mirrored */ + -1, /* unicode_1_name */ + -1, /* iso_comment */ + -1, /* simple_uppercase_mapping */ + -1, /* simple_lowercase_mapping */ + -1 /* simple_titlecase_mapping */ +}; + +struct unicode_data_t * read_unicode_data( const char * filename ); + +int has_name( struct unicode_record_t * ur, const char * name ); + +int name_ends_with( struct unicode_record_t * ur, const char * name ); + +int is_general_category( struct unicode_record_t * ur, const char * category ); + +int decomposition_contains( struct unicode_record_t * ur, const char * substring ); + +int towupper_differs( struct unicode_record_t * ur, size_t codepoint ); + +int towlower_differs( struct unicode_record_t * ur, size_t codepoint ); + +void release_unicode_data( struct unicode_data_t * ud ); + +#endif diff --git a/src/pdclib/functions/_PDCLIB/Readme.txt b/src/pdclib/functions/_PDCLIB/Readme.txt new file mode 100644 index 0000000..13ad05c --- /dev/null +++ b/src/pdclib/functions/_PDCLIB/Readme.txt @@ -0,0 +1,10 @@ +This directory holds various "internals" of PDCLib: + +- definitions of helper functions not specified by the standard (hidden in the + _PDCLIB_* namespace); + +- definitions of data objects, both internal (like _PDCLIB_digits) and specified by + the standard (_PDCLIB_errno); + +- test drivers for functionality that does not have its own implementation + file to put the test driver in (stdarg). diff --git a/src/pdclib/functions/_PDCLIB/_PDCLIB_atomax.c b/src/pdclib/functions/_PDCLIB/_PDCLIB_atomax.c new file mode 100644 index 0000000..eaf7ced --- /dev/null +++ b/src/pdclib/functions/_PDCLIB/_PDCLIB_atomax.c @@ -0,0 +1,46 @@ +/* _PDCLIB_atomax( const char * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <string.h> +#include <ctype.h> + +#ifndef REGTEST + +_PDCLIB_intmax_t _PDCLIB_atomax( const char * s ) +{ + _PDCLIB_intmax_t rc = 0; + char sign = '+'; + const char * x; + /* TODO: In other than "C" locale, additional patterns may be defined */ + while ( isspace( *s ) ) ++s; + if ( *s == '+' ) ++s; + else if ( *s == '-' ) sign = *(s++); + /* TODO: Earlier version was missing tolower() but was not caught by tests */ + while ( ( x = memchr( _PDCLIB_digits, tolower(*(s++)), 10 ) ) != NULL ) + { + rc = rc * 10 + ( x - _PDCLIB_digits ); + } + return ( sign == '+' ) ? rc : -rc; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ +#ifndef REGTEST + /* basic functionality */ + TESTCASE( _PDCLIB_atomax( "123" ) == 123 ); + /* testing skipping of leading whitespace and trailing garbage */ + TESTCASE( _PDCLIB_atomax( " \n\v\t\f123xyz" ) == 123 ); +#endif + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/_PDCLIB/_PDCLIB_closeall.c b/src/pdclib/functions/_PDCLIB/_PDCLIB_closeall.c new file mode 100644 index 0000000..3c928e7 --- /dev/null +++ b/src/pdclib/functions/_PDCLIB/_PDCLIB_closeall.c @@ -0,0 +1,37 @@ +/* _PDCLIB_closeall( void ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdio.h> + +#ifndef REGTEST + +extern struct _PDCLIB_file_t * _PDCLIB_filelist; + +void _PDCLIB_closeall( void ) +{ + struct _PDCLIB_file_t * stream = _PDCLIB_filelist; + struct _PDCLIB_file_t * next; + while ( stream != NULL ) + { + next = stream->next; + fclose( stream ); + stream = next; + } +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + /* No testdriver */ + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/_PDCLIB/_PDCLIB_digits.c b/src/pdclib/functions/_PDCLIB/_PDCLIB_digits.c new file mode 100644 index 0000000..69c4f2b --- /dev/null +++ b/src/pdclib/functions/_PDCLIB/_PDCLIB_digits.c @@ -0,0 +1,33 @@ +/* _PDCLIB_digits + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#ifndef REGTEST + +#include "pdclib/_PDCLIB_int.h" + +const char _PDCLIB_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz"; + +/* For _PDCLIB/print.c only; obsolete with ctype.h */ +const char _PDCLIB_Xdigits[] = "0123456789ABCDEF"; + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +#include <string.h> + +int main( void ) +{ +#ifndef REGTEST + TESTCASE( strcmp( _PDCLIB_digits, "0123456789abcdefghijklmnopqrstuvwxyz" ) == 0 ); + TESTCASE( strcmp( _PDCLIB_Xdigits, "0123456789ABCDEF" ) == 0 ); +#endif + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/_PDCLIB/_PDCLIB_filemode.c b/src/pdclib/functions/_PDCLIB/_PDCLIB_filemode.c new file mode 100644 index 0000000..2555a00 --- /dev/null +++ b/src/pdclib/functions/_PDCLIB/_PDCLIB_filemode.c @@ -0,0 +1,90 @@ +/* _PDCLIB_filemode( const char * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stddef.h> + +#ifndef REGTEST + +/* Helper function that parses the C-style mode string passed to fopen() into + the PDCLib flags FREAD, FWRITE, FAPPEND, FRW (read-write) and FBIN (binary + mode). +*/ +unsigned int _PDCLIB_filemode( const char * const mode ) +{ + unsigned rc = 0; + size_t i; + switch ( mode[0] ) + { + case 'r': + rc |= _PDCLIB_FREAD; + break; + case 'w': + rc |= _PDCLIB_FWRITE; + break; + case 'a': + rc |= _PDCLIB_FAPPEND | _PDCLIB_FWRITE; + break; + default: + /* Other than read, write, or append - invalid */ + return 0; + } + for ( i = 1; i < 4; ++i ) + { + switch ( mode[i] ) + { + case '+': + if ( rc & _PDCLIB_FRW ) return 0; /* Duplicates are invalid */ + rc |= _PDCLIB_FRW; + break; + case 'b': + if ( rc & _PDCLIB_FBIN ) return 0; /* Duplicates are invalid */ + rc |= _PDCLIB_FBIN; + break; + case '\0': + /* End of mode */ + return rc; + default: + /* Other than read/write or binary - invalid. */ + return 0; + } + } + /* Longer than three chars - invalid. */ + return 0; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ +#ifndef REGTEST + TESTCASE( _PDCLIB_filemode( "r" ) == _PDCLIB_FREAD ); + TESTCASE( _PDCLIB_filemode( "w" ) == _PDCLIB_FWRITE ); + TESTCASE( _PDCLIB_filemode( "a" ) == ( _PDCLIB_FAPPEND | _PDCLIB_FWRITE ) ); + TESTCASE( _PDCLIB_filemode( "r+" ) == ( _PDCLIB_FREAD | _PDCLIB_FRW ) ); + TESTCASE( _PDCLIB_filemode( "w+" ) == ( _PDCLIB_FWRITE | _PDCLIB_FRW ) ); + TESTCASE( _PDCLIB_filemode( "a+" ) == ( _PDCLIB_FAPPEND | _PDCLIB_FWRITE | _PDCLIB_FRW ) ); + TESTCASE( _PDCLIB_filemode( "rb" ) == ( _PDCLIB_FREAD | _PDCLIB_FBIN ) ); + TESTCASE( _PDCLIB_filemode( "wb" ) == ( _PDCLIB_FWRITE | _PDCLIB_FBIN ) ); + TESTCASE( _PDCLIB_filemode( "ab" ) == ( _PDCLIB_FAPPEND | _PDCLIB_FWRITE | _PDCLIB_FBIN ) ); + TESTCASE( _PDCLIB_filemode( "r+b" ) == ( _PDCLIB_FREAD | _PDCLIB_FRW | _PDCLIB_FBIN ) ); + TESTCASE( _PDCLIB_filemode( "w+b" ) == ( _PDCLIB_FWRITE | _PDCLIB_FRW | _PDCLIB_FBIN ) ); + TESTCASE( _PDCLIB_filemode( "a+b" ) == ( _PDCLIB_FAPPEND | _PDCLIB_FWRITE | _PDCLIB_FRW | _PDCLIB_FBIN ) ); + TESTCASE( _PDCLIB_filemode( "rb+" ) == ( _PDCLIB_FREAD | _PDCLIB_FRW | _PDCLIB_FBIN ) ); + TESTCASE( _PDCLIB_filemode( "wb+" ) == ( _PDCLIB_FWRITE | _PDCLIB_FRW | _PDCLIB_FBIN ) ); + TESTCASE( _PDCLIB_filemode( "ab+" ) == ( _PDCLIB_FAPPEND | _PDCLIB_FWRITE | _PDCLIB_FRW | _PDCLIB_FBIN ) ); + TESTCASE( _PDCLIB_filemode( "x" ) == 0 ); + TESTCASE( _PDCLIB_filemode( "r++" ) == 0 ); + TESTCASE( _PDCLIB_filemode( "wbb" ) == 0 ); + TESTCASE( _PDCLIB_filemode( "a+bx" ) == 0 ); +#endif + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/_PDCLIB/_PDCLIB_is_leap.c b/src/pdclib/functions/_PDCLIB/_PDCLIB_is_leap.c new file mode 100644 index 0000000..2407337 --- /dev/null +++ b/src/pdclib/functions/_PDCLIB/_PDCLIB_is_leap.c @@ -0,0 +1,39 @@ +/* _PDCLIB_is_leap( int ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#ifndef REGTEST + +#include "pdclib/_PDCLIB_int.h" + +int _PDCLIB_is_leap( int year_offset ) +{ + /* year given as offset from 1900, matching tm.tm_year in <time.h> */ + long long year = year_offset + 1900ll; + return ( ( year % 4 ) == 0 && ( ( year % 25 ) != 0 || ( year % 400 ) == 0 ) ); +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ +#ifndef REGTEST + /* 1901 not leap */ + TESTCASE( ! _PDCLIB_is_leap( 1 ) ); + /* 1904 leap */ + TESTCASE( _PDCLIB_is_leap( 4 ) ); + /* 1900 not leap */ + TESTCASE( ! _PDCLIB_is_leap( 0 ) ); + /* 2000 leap */ + TESTCASE( _PDCLIB_is_leap( 100 ) ); +#endif + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/_PDCLIB/_PDCLIB_load_lc_collate.c b/src/pdclib/functions/_PDCLIB/_PDCLIB_load_lc_collate.c new file mode 100644 index 0000000..d66b996 --- /dev/null +++ b/src/pdclib/functions/_PDCLIB/_PDCLIB_load_lc_collate.c @@ -0,0 +1,63 @@ +/* _PDCLIB_load_lc_collate( const char *, const char * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#ifndef REGTEST + +#include <locale.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "pdclib/_PDCLIB_int.h" + +struct _PDCLIB_lc_collate_t * _PDCLIB_load_lc_collate( const char * path, const char * locale ) +{ + struct _PDCLIB_lc_collate_t * rc = NULL; + const char * extension = "_collate.dat"; + char * file = malloc( strlen( path ) + strlen( locale ) + strlen( extension ) + 1 ); + + if ( file ) + { + FILE * fh; + + strcpy( file, path ); + strcat( file, locale ); + strcat( file, extension ); + + if ( ( fh = fopen( file, "rb" ) ) != NULL ) + { + if ( ( rc = malloc( sizeof( struct _PDCLIB_lc_collate_t ) ) ) != NULL ) + { + /* TODO: Collation data */ + + rc->alloced = 1; + } + + fclose( fh ); + } + + free( file ); + } + + return rc; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ +#ifndef REGTEST + TESTCASE( NO_TESTDRIVER ); +#endif + + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/_PDCLIB/_PDCLIB_load_lc_ctype.c b/src/pdclib/functions/_PDCLIB/_PDCLIB_load_lc_ctype.c new file mode 100644 index 0000000..81fb18f --- /dev/null +++ b/src/pdclib/functions/_PDCLIB/_PDCLIB_load_lc_ctype.c @@ -0,0 +1,365 @@ +/* _PDCLIB_load_lc_ctype( const char *, const char * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#ifndef REGTEST + +#include <inttypes.h> +#include <limits.h> +#include <locale.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "pdclib/_PDCLIB_int.h" + +struct _PDCLIB_lc_ctype_t * _PDCLIB_load_lc_ctype( const char * path, const char * locale ) +{ + struct _PDCLIB_lc_ctype_t * rc = NULL; + const char * extension = "_ctype.dat"; + char * file = malloc( strlen( path ) + strlen( locale ) + strlen( extension ) + 1 ); + + if ( file ) + { + FILE * fh; + + strcpy( file, path ); + strcat( file, locale ); + strcat( file, extension ); + + if ( ( fh = fopen( file, "rb" ) ) != NULL ) + { + if ( ( rc = malloc( sizeof( struct _PDCLIB_lc_ctype_t ) ) ) != NULL ) + { + struct _PDCLIB_lc_ctype_entry_t * entry; + + if ( ( entry = malloc( sizeof( struct _PDCLIB_lc_ctype_entry_t ) * _PDCLIB_CHARSET_SIZE + 1 ) ) != NULL ) + { + rc->entry = entry + 1; + rc->entry[ -1 ].flags = rc->entry[ -1 ].upper = rc->entry[ -1 ].lower = 0; + + if ( fscanf( fh, "%x %x %x %x %x %x", &rc->digits_low, &_PDCLIB_lc_ctype.digits_high, &_PDCLIB_lc_ctype.Xdigits_low, &_PDCLIB_lc_ctype.Xdigits_high, &_PDCLIB_lc_ctype.xdigits_low, &_PDCLIB_lc_ctype.xdigits_high ) == 6 ) + { + size_t i; + + for ( i = 0; i < _PDCLIB_CHARSET_SIZE; ++i ) + { + if ( fscanf( fh, "%x %hhx %hhx", &rc->entry[ i ].flags, &rc->entry[ i ].upper, &rc->entry[ i ].lower ) != 3 ) + { + fclose( fh ); + free( file ); + free( rc->entry - 1 ); + free( rc ); + return NULL; + } + } + } + + rc->alloced = 1; + } + else + { + free( rc ); + } + } + + fclose( fh ); + } + + free( file ); + } + + return rc; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +#include <ctype.h> + +int main( void ) +{ +#ifndef REGTEST + FILE * fh = fopen( "test_ctype.dat", "wb" ); + TESTCASE( fh != NULL ); + /* For test purposes, let's set up a charset that only has the hex digits */ + /* 0x00..0x09 - digits */ + /* 0x11..0x16 - Xdigits */ + /* 0x21..0x26 - xdigits */ + TESTCASE( fprintf( fh, "%x %x\n", 0x00, 0x09 ) ); + TESTCASE( fprintf( fh, "%x %x %x %x\n", 0x11, 0x16, 0x21, 0x26 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", _PDCLIB_CTYPE_GRAPH, 0x00, 0x00 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", _PDCLIB_CTYPE_GRAPH, 0x01, 0x01 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", _PDCLIB_CTYPE_GRAPH, 0x02, 0x02 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", _PDCLIB_CTYPE_GRAPH, 0x03, 0x03 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", _PDCLIB_CTYPE_GRAPH, 0x04, 0x04 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", _PDCLIB_CTYPE_GRAPH, 0x05, 0x05 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", _PDCLIB_CTYPE_GRAPH, 0x06, 0x06 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", _PDCLIB_CTYPE_GRAPH, 0x07, 0x07 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", _PDCLIB_CTYPE_GRAPH, 0x08, 0x08 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", _PDCLIB_CTYPE_GRAPH, 0x09, 0x09 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x0A, 0x0A ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x0B, 0x0B ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x0C, 0x0C ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x0D, 0x0D ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x0E, 0x0E ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x0F, 0x0F ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x10, 0x10 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x11, 0x11 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x12, 0x12 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x13, 0x13 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x14, 0x14 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x15, 0x15 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x16, 0x16 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x17, 0x17 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x18, 0x18 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x19, 0x19 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x1A, 0x1A ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x1B, 0x1B ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x1C, 0x1C ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x1D, 0x1D ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x1E, 0x1E ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x1F, 0x1F ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x20, 0x20 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x21, 0x21 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x22, 0x22 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x23, 0x23 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x24, 0x24 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x25, 0x25 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x26, 0x26 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x27, 0x27 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x28, 0x28 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x29, 0x29 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x2A, 0x2A ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x2B, 0x2B ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x2C, 0x2C ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x2D, 0x2D ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x2E, 0x2E ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x2F, 0x2F ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x30, 0x30 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x31, 0x31 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x32, 0x32 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x33, 0x33 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x34, 0x34 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x35, 0x35 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x36, 0x36 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x37, 0x37 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x38, 0x38 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x39, 0x39 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x3A, 0x3A ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x3B, 0x3B ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x3C, 0x3C ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x3D, 0x3D ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x3E, 0x3E ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x3F, 0x3F ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x40, 0x40 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x41, 0x41 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x42, 0x42 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x43, 0x43 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x44, 0x44 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x45, 0x45 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x46, 0x46 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x47, 0x47 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x48, 0x48 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x49, 0x49 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x4A, 0x4A ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x4B, 0x4B ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x4C, 0x4C ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x4D, 0x4D ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x4E, 0x4E ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x4F, 0x4F ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x50, 0x50 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x51, 0x51 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x52, 0x52 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x53, 0x53 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x54, 0x54 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x55, 0x55 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x56, 0x56 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x57, 0x57 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x58, 0x58 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x59, 0x59 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x5A, 0x5A ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x5B, 0x5B ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x5C, 0x5C ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x5D, 0x5D ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x5E, 0x5E ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x5F, 0x5F ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x60, 0x60 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x61, 0x61 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x62, 0x62 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x63, 0x63 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x64, 0x64 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x65, 0x65 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x66, 0x66 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x67, 0x67 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x68, 0x68 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x69, 0x69 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x6A, 0x6A ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x6B, 0x6B ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x6C, 0x6C ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x6D, 0x6D ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x6E, 0x6E ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x6F, 0x6F ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x70, 0x70 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x71, 0x71 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x72, 0x72 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x73, 0x73 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x74, 0x74 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x75, 0x75 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x76, 0x76 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x77, 0x77 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x78, 0x78 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x79, 0x79 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x7A, 0x7A ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x7B, 0x7B ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x7C, 0x7C ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x7D, 0x7D ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x7E, 0x7E ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x7F, 0x7F ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x80, 0x80 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x81, 0x81 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x82, 0x82 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x83, 0x83 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x84, 0x84 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x85, 0x85 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x86, 0x86 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x87, 0x87 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x88, 0x88 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x89, 0x89 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x8A, 0x8A ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x8B, 0x8B ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x8C, 0x8C ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x8D, 0x8D ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x8E, 0x8E ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x8F, 0x8F ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x90, 0x90 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x91, 0x91 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x92, 0x92 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x93, 0x93 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x94, 0x94 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x95, 0x95 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x96, 0x96 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x97, 0x97 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x98, 0x98 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x99, 0x99 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x9A, 0x9A ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x9B, 0x9B ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x9C, 0x9C ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x9D, 0x9D ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x9E, 0x9E ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x9F, 0x9F ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xA0, 0xA0 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xA1, 0xA1 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xA2, 0xA2 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xA3, 0xA3 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xA4, 0xA4 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xA5, 0xA5 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xA6, 0xA6 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xA7, 0xA7 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xA8, 0xA8 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xA9, 0xA9 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xAA, 0xAA ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xAB, 0xAB ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xAC, 0xAC ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xAD, 0xAD ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xAE, 0xAE ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xAF, 0xAF ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xB0, 0xB0 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xB1, 0xB1 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xB2, 0xB2 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xB3, 0xB3 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xB4, 0xB4 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xB5, 0xB5 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xB6, 0xB6 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xB7, 0xB7 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xB8, 0xB8 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xB9, 0xB9 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xBA, 0xBA ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xBB, 0xBB ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xBC, 0xBC ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xBD, 0xBD ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xBE, 0xBE ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xBF, 0xBF ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xC0, 0xC0 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xC1, 0xC1 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xC2, 0xC2 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xC3, 0xC3 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xC4, 0xC4 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xC5, 0xC5 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xC6, 0xC6 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xC7, 0xC7 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xC8, 0xC8 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xC9, 0xC9 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xCA, 0xCA ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xCB, 0xCB ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xCC, 0xCC ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xCD, 0xCD ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xCE, 0xCE ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xCF, 0xCF ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xD0, 0xD0 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xD1, 0xD1 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xD2, 0xD2 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xD3, 0xD3 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xD4, 0xD4 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xD5, 0xD5 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xD6, 0xD6 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xD7, 0xD7 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xD8, 0xD8 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xD9, 0xD9 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xDA, 0xDA ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xDB, 0xDB ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xDC, 0xDC ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xDD, 0xDD ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xDE, 0xDE ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xDF, 0xDF ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xE0, 0xE0 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xE1, 0xE1 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xE2, 0xE2 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xE3, 0xE3 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xE4, 0xE4 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xE5, 0xE5 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xE6, 0xE6 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xE7, 0xE7 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xE8, 0xE8 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xE9, 0xE9 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xEA, 0xEA ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xEB, 0xEB ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xEC, 0xEC ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xED, 0xED ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xEE, 0xEE ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xEF, 0xEF ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xF0, 0xF0 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xF1, 0xF1 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xF2, 0xF2 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xF3, 0xF3 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xF4, 0xF4 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xF5, 0xF5 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xF6, 0xF6 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xF7, 0xF7 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xF8, 0xF8 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xF9, 0xF9 ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xFA, 0xFA ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xFB, 0xFB ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xFC, 0xFC ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xFD, 0xFD ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xFE, 0xFE ) ); + TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xFF, 0xFF) ); + fclose( fh ); + TESTCASE( _PDCLIB_load_lc_ctype( "./", "test" ) != NULL ); + remove( "test_ctype.dat" ); + /* + TESTCASE( isdigit( 0x00 ) && ! isxdigit( 0x00 ) && ! isalpha( 0x00 ) ); + TESTCASE( ! isdigit( 0x11 ) && isxdigit( 0x11 ) && isalpha( 0x11 ) && isupper( 0x11 ) && ! islower( 0x11 ) ); + TESTCASE( ! isdigit( 0x21 ) && isxdigit( 0x21 ) && isalpha( 0x21 ) && ! isupper( 0x11 ) && islower( 0x11 ) ); + */ +#endif + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/_PDCLIB/_PDCLIB_load_lc_messages.c b/src/pdclib/functions/_PDCLIB/_PDCLIB_load_lc_messages.c new file mode 100644 index 0000000..6ff2a50 --- /dev/null +++ b/src/pdclib/functions/_PDCLIB/_PDCLIB_load_lc_messages.c @@ -0,0 +1,88 @@ +/* _PDCLIB_load_lc_messages( const char *, const char * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#ifndef REGTEST + +#include <locale.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "pdclib/_PDCLIB_int.h" + +struct _PDCLIB_lc_messages_t * _PDCLIB_load_lc_messages( const char * path, const char * locale ) +{ + struct _PDCLIB_lc_messages_t * rc = NULL; + const char * extension = "_messages.dat"; + char * file = malloc( strlen( path ) + strlen( locale ) + strlen( extension ) + 1 ); + + if ( file ) + { + FILE * fh; + + strcpy( file, path ); + strcat( file, locale ); + strcat( file, extension ); + + if ( ( fh = fopen( file, "rb" ) ) != NULL ) + { + if ( ( rc = malloc( sizeof( struct _PDCLIB_lc_messages_t ) ) ) != NULL ) + { + char * data = _PDCLIB_load_lines( fh, _PDCLIB_ERRNO_MAX ); + + if ( data != NULL ) + { + size_t i; + + for ( i = 0; i < _PDCLIB_ERRNO_MAX; ++i ) + { + rc->errno_texts[ i ] = data; + data += strlen( data ) + 1; + } + + rc->alloced = 1; + } + else + { + free( rc ); + rc = NULL; + } + } + + fclose( fh ); + } + + free( file ); + } + + return rc; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ +#ifndef REGTEST + FILE * fh = fopen( "test_numeric.dat", "wb" ); + struct _PDCLIB_lc_lconv_numeric_t * lc; + TESTCASE( fh != NULL ); + TESTCASE( fputs( ",\n.\n\n", fh ) != EOF ); + fclose( fh ); + TESTCASE( ( lc = _PDCLIB_load_lc_numeric( "./", "test" ) ) ); + remove( "test_numeric.dat" ); + TESTCASE( strcmp( lc->decimal_point, "," ) == 0 ); + TESTCASE( strcmp( lc->thousands_sep, "." ) == 0 ); + TESTCASE( strcmp( lc->grouping, "" ) == 0 ); +#endif + + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/_PDCLIB/_PDCLIB_load_lc_monetary.c b/src/pdclib/functions/_PDCLIB/_PDCLIB_load_lc_monetary.c new file mode 100644 index 0000000..e2dcbb4 --- /dev/null +++ b/src/pdclib/functions/_PDCLIB/_PDCLIB_load_lc_monetary.c @@ -0,0 +1,158 @@ +/* _PDCLIB_load_lc_monetary( const char *, const char * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#ifndef REGTEST + +#include <locale.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "pdclib/_PDCLIB_int.h" + +struct _PDCLIB_lc_lconv_monetary_t * _PDCLIB_load_lc_monetary( const char * path, const char * locale ) +{ + struct _PDCLIB_lc_lconv_monetary_t * rc = NULL; + const char * extension = "_monetary.dat"; + char * file = malloc( strlen( path ) + strlen( locale ) + strlen( extension ) + 1 ); + + if ( file ) + { + FILE * fh; + + strcpy( file, path ); + strcat( file, locale ); + strcat( file, extension ); + + if ( ( fh = fopen( file, "rb" ) ) != NULL ) + { + if ( ( rc = malloc( sizeof( struct _PDCLIB_lc_lconv_monetary_t ) ) ) != NULL ) + { + char buffer[ 14 ]; + char * data = _PDCLIB_load_lines( fh, 7 ); + + if ( data != NULL ) + { + if ( fread( buffer, 1, 14, fh ) == 14 ) + { + rc->mon_decimal_point = data; + data += strlen( data ) + 1; + rc->mon_thousands_sep = data; + data += strlen( data ) + 1; + rc->mon_grouping = data; + data += strlen( data ) + 1; + rc->positive_sign = data; + data += strlen( data ) + 1; + rc->negative_sign = data; + data += strlen( data ) + 1; + rc->currency_symbol = data; + data += strlen( data ) + 1; + rc->int_curr_symbol = data; + + rc->frac_digits = buffer[ 0 ]; + rc->p_cs_precedes = buffer[ 1 ]; + rc->n_cs_precedes = buffer[ 2 ]; + rc->p_sep_by_space = buffer[ 3 ]; + rc->n_sep_by_space = buffer[ 4 ]; + rc->p_sign_posn = buffer[ 5 ]; + rc->n_sign_posn = buffer[ 6 ]; + rc->int_frac_digits = buffer[ 7 ]; + rc->int_p_cs_precedes = buffer[ 8 ]; + rc->int_n_cs_precedes = buffer[ 9 ]; + rc->int_p_sep_by_space = buffer[ 10 ]; + rc->int_n_sep_by_space = buffer[ 11 ]; + rc->int_p_sign_posn = buffer[ 12 ]; + rc->int_n_sign_posn= buffer[ 13 ]; + } + else + { + free( data ); + free( rc ); + rc = NULL; + } + } + else + { + free( rc ); + rc = NULL; + } + } + + fclose( fh ); + } + + free( file ); + } + + return rc; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ +#ifndef REGTEST + FILE * fh = fopen( "test_monetary.dat", "wb" ); + struct _PDCLIB_lc_lconv_monetary_t * lc; + TESTCASE( fh != NULL ); + fprintf( fh, "%s\n", "," ); /* mon_decimal_point */ + fprintf( fh, "%s\n", "." ); /* mon_thousands_sep */ + fprintf( fh, "%s\n", "3" ); /* mon_grouping */ + fprintf( fh, "%s\n", "" ); /* positive_sign */ + fprintf( fh, "%s\n", "-" ); /* negative_sign */ + fprintf( fh, "%s\n", "\xa4" ); /* currency_symbol */ + fprintf( fh, "%s\n", "EUR" ); /* int_curr_symbol */ + fputc( 2, fh ); /* frac_digits */ + fputc( 0, fh ); /* p_cs_precedes */ + fputc( 0, fh ); /* n_cs_precedes */ + fputc( 1, fh ); /* p_sep_by_space */ + fputc( 1, fh ); /* n_sep_by_space */ + fputc( 1, fh ); /* p_sign_posn */ + fputc( 1, fh ); /* n_sign_posn */ + fputc( 2, fh ); /* int_frac_digits */ + fputc( 0, fh ); /* int_p_cs_precedes */ + fputc( 0, fh ); /* int_n_cs_precedes */ + fputc( 1, fh ); /* int_p_sep_by_space */ + fputc( 1, fh ); /* int_n_sep_by_space */ + fputc( 1, fh ); /* int_p_sign_posn */ + fputc( 1, fh ); /* int_n_sign_posn */ + fprintf( fh, "\n" ); + fclose( fh ); + TESTCASE( ( lc = _PDCLIB_load_lc_monetary( "./", "test" ) ) ); + remove( "test_monetary.dat" ); + TESTCASE( strcmp( lc->mon_decimal_point, "," ) == 0 ); + TESTCASE( strcmp( lc->mon_thousands_sep, "." ) == 0 ); + TESTCASE( strcmp( lc->mon_grouping, "3" ) == 0 ); + TESTCASE( strcmp( lc->positive_sign, "" ) == 0 ); + TESTCASE( strcmp( lc->negative_sign, "-" ) == 0 ); + TESTCASE( strcmp( lc->currency_symbol, "\xa4" ) == 0 ); + TESTCASE( strcmp( lc->int_curr_symbol, "EUR" ) == 0 ); + + TESTCASE( lc->frac_digits == 2 ); + TESTCASE( lc->p_cs_precedes == 0 ); + TESTCASE( lc->n_cs_precedes == 0 ); + TESTCASE( lc->p_sep_by_space == 1 ); + TESTCASE( lc->n_sep_by_space == 1 ); + TESTCASE( lc->p_sign_posn == 1 ); + TESTCASE( lc->n_sign_posn == 1 ); + TESTCASE( lc->int_frac_digits == 2 ); + TESTCASE( lc->int_p_cs_precedes == 0 ); + TESTCASE( lc->int_n_cs_precedes == 0 ); + TESTCASE( lc->int_p_sep_by_space == 1 ); + TESTCASE( lc->int_n_sep_by_space == 1 ); + TESTCASE( lc->int_p_sign_posn == 1 ); + TESTCASE( lc->int_n_sign_posn == 1 ); +#endif + + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/_PDCLIB/_PDCLIB_load_lc_numeric.c b/src/pdclib/functions/_PDCLIB/_PDCLIB_load_lc_numeric.c new file mode 100644 index 0000000..de42bbd --- /dev/null +++ b/src/pdclib/functions/_PDCLIB/_PDCLIB_load_lc_numeric.c @@ -0,0 +1,84 @@ +/* _PDCLIB_load_lc_numeric( const char *, const char * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#ifndef REGTEST + +#include <locale.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "pdclib/_PDCLIB_int.h" + +struct _PDCLIB_lc_lconv_numeric_t * _PDCLIB_load_lc_numeric( const char * path, const char * locale ) +{ + struct _PDCLIB_lc_lconv_numeric_t * rc = NULL; + const char * extension = "_numeric.dat"; + char * file = malloc( strlen( path ) + strlen( locale ) + strlen( extension ) + 1 ); + + if ( file ) + { + FILE * fh; + + strcpy( file, path ); + strcat( file, locale ); + strcat( file, extension ); + + if ( ( fh = fopen( file, "rb" ) ) != NULL ) + { + if ( ( rc = malloc( sizeof( struct _PDCLIB_lc_lconv_numeric_t ) ) ) != NULL ) + { + char * data = _PDCLIB_load_lines( fh, 3 ); + + if ( data != NULL ) + { + rc->decimal_point = data; + data += strlen( data ) + 1; + rc->thousands_sep = data; + data += strlen( data ) + 1; + rc->grouping = data; + } + else + { + free( rc ); + rc = NULL; + } + } + + fclose( fh ); + } + + free( file ); + } + + return rc; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ +#ifndef REGTEST + FILE * fh = fopen( "test_numeric.dat", "wb" ); + struct _PDCLIB_lc_lconv_numeric_t * lc; + TESTCASE( fh != NULL ); + TESTCASE( fputs( ",\n.\n\n", fh ) != EOF ); + fclose( fh ); + TESTCASE( ( lc = _PDCLIB_load_lc_numeric( "./", "test" ) ) ); + remove( "test_numeric.dat" ); + TESTCASE( strcmp( lc->decimal_point, "," ) == 0 ); + TESTCASE( strcmp( lc->thousands_sep, "." ) == 0 ); + TESTCASE( strcmp( lc->grouping, "" ) == 0 ); +#endif + + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/_PDCLIB/_PDCLIB_load_lc_time.c b/src/pdclib/functions/_PDCLIB/_PDCLIB_load_lc_time.c new file mode 100644 index 0000000..733e5c7 --- /dev/null +++ b/src/pdclib/functions/_PDCLIB/_PDCLIB_load_lc_time.c @@ -0,0 +1,165 @@ +/* _PDCLIB_load_lc_time( const char *, const char * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#ifndef REGTEST + +#include <locale.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "pdclib/_PDCLIB_int.h" + +struct _PDCLIB_lc_time_t * _PDCLIB_load_lc_time( const char * path, const char * locale ) +{ + struct _PDCLIB_lc_time_t * rc = NULL; + const char * extension = "_time.dat"; + char * file = malloc( strlen( path ) + strlen( locale ) + strlen( extension ) + 1 ); + + if ( file ) + { + FILE * fh; + + strcpy( file, path ); + strcat( file, locale ); + strcat( file, extension ); + + if ( ( fh = fopen( file, "rb" ) ) != NULL ) + { + if ( ( rc = malloc( sizeof( struct _PDCLIB_lc_time_t ) ) ) != NULL ) + { + char * data = _PDCLIB_load_lines( fh, 44 ); + + if ( data != NULL ) + { + size_t i; + + for ( i = 0; i < 12; ++i ) + { + rc->month_name_abbr[ i ] = data; + data += strlen( data ) + 1; + } + + for ( i = 0; i < 12; ++i ) + { + rc->month_name_full[ i ] = data; + data += strlen( data ) + 1; + } + + for ( i = 0; i < 7; ++i ) + { + rc->day_name_abbr[ i ] = data; + data += strlen( data ) + 1; + } + + for ( i = 0; i < 7; ++i ) + { + rc->day_name_full[ i ] = data; + data += strlen( data ) + 1; + } + + rc->alloced = 1; + } + else + { + free( rc ); + rc = NULL; + } + } + + fclose( fh ); + } + + free( file ); + } + + return rc; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ +#ifndef REGTEST + FILE * fh = fopen( "test_time.dat", "wb" ); + struct _PDCLIB_lc_time_t * lc; + + TESTCASE( fh != NULL ); + + /* month name abbreviation */ + TESTCASE( fprintf( fh, "%s\n", "Jan" ) == 4 ); + TESTCASE( fprintf( fh, "%s\n", "Feb" ) == 4 ); + TESTCASE( fprintf( fh, "%s\n", "M\xe4r" ) == 4 ); + TESTCASE( fprintf( fh, "%s\n", "Apr" ) == 4 ); + TESTCASE( fprintf( fh, "%s\n", "Mai" ) == 4 ); + TESTCASE( fprintf( fh, "%s\n", "Jun" ) == 4 ); + TESTCASE( fprintf( fh, "%s\n", "Jul" ) == 4 ); + TESTCASE( fprintf( fh, "%s\n", "Aug" ) == 4 ); + TESTCASE( fprintf( fh, "%s\n", "Sep" ) == 4 ); + TESTCASE( fprintf( fh, "%s\n", "Okt" ) == 4 ); + TESTCASE( fprintf( fh, "%s\n", "Nov" ) == 4 ); + TESTCASE( fprintf( fh, "%s\n", "Dez" ) == 4 ); + /* month name full */ + TESTCASE( fprintf( fh, "%s\n", "Januar" ) == 7 ); + TESTCASE( fprintf( fh, "%s\n", "Februar" ) == 8 ); + TESTCASE( fprintf( fh, "%s\n", "M\xe4rz" ) == 5 ); + TESTCASE( fprintf( fh, "%s\n", "April" ) == 6 ); + TESTCASE( fprintf( fh, "%s\n", "Mai" ) == 4 ); + TESTCASE( fprintf( fh, "%s\n", "Juni" ) == 5 ); + TESTCASE( fprintf( fh, "%s\n", "Juli" ) == 5 ); + TESTCASE( fprintf( fh, "%s\n", "August" ) == 7 ); + TESTCASE( fprintf( fh, "%s\n", "September" ) == 10 ); + TESTCASE( fprintf( fh, "%s\n", "Oktober" ) == 8 ); + TESTCASE( fprintf( fh, "%s\n", "November" ) == 9 ); + TESTCASE( fprintf( fh, "%s\n", "Dezember" ) == 9 ); + /* day name abbreviation */ + TESTCASE( fprintf( fh, "%s\n", "So" ) == 3 ); + TESTCASE( fprintf( fh, "%s\n", "Mo" ) == 3 ); + TESTCASE( fprintf( fh, "%s\n", "Di" ) == 3 ); + TESTCASE( fprintf( fh, "%s\n", "Mi" ) == 3 ); + TESTCASE( fprintf( fh, "%s\n", "Do" ) == 3 ); + TESTCASE( fprintf( fh, "%s\n", "Fr" ) == 3 ); + TESTCASE( fprintf( fh, "%s\n", "Sa" ) == 3 ); + /* day name full */ + TESTCASE( fprintf( fh, "%s\n", "Sonntag" ) == 8 ); + TESTCASE( fprintf( fh, "%s\n", "Montag" ) == 7 ); + TESTCASE( fprintf( fh, "%s\n", "Dienstag" ) == 9 ); + TESTCASE( fprintf( fh, "%s\n", "Mittwoch" ) == 9 ); + TESTCASE( fprintf( fh, "%s\n", "Donnerstag" ) == 11 ); + TESTCASE( fprintf( fh, "%s\n", "Freitag" ) == 8 ); + TESTCASE( fprintf( fh, "%s\n", "Samstag" ) == 8 ); + + TESTCASE( fprintf( fh, "%s\n", "%a %d %b %Y %T %Z" ) == 18 ); /* date time format (%c) */ + TESTCASE( fprintf( fh, "%s\n", "%I:%M:%S" ) == 9 ); /* 12-hour time format (%r) */ + TESTCASE( fprintf( fh, "%s\n", "%d.%m.%Y" ) == 9 ); /* date format (%x) */ + TESTCASE( fprintf( fh, "%s\n", "%H:%M:%S" ) == 9 ); /* time format (%X) */ + + TESTCASE( fprintf( fh, "%s\n", "" ) == 1 ); /* AM */ + TESTCASE( fprintf( fh, "%s\n", "" ) == 1 ); /* PM */ + fclose( fh ); + TESTCASE( ( lc = _PDCLIB_load_lc_time( "./", "test" ) ) ); + remove( "test_time.dat" ); + + TESTCASE( strcmp( lc->month_name_abbr[ 0 ], "Jan" ) == 0 ); + TESTCASE( strcmp( lc->month_name_abbr[ 11 ], "Dez" ) == 0 ); + TESTCASE( strcmp( lc->month_name_full[ 0 ], "Januar" ) == 0 ); + TESTCASE( strcmp( lc->month_name_full[ 11 ], "Dezember" ) == 0 ); + TESTCASE( strcmp( lc->day_name_abbr[ 0 ], "So" ) == 0 ); + TESTCASE( strcmp( lc->day_name_abbr[ 6 ], "Sa" ) == 0 ); + TESTCASE( strcmp( lc->day_name_full[ 0 ], "Sonntag" ) == 0 ); + TESTCASE( strcmp( lc->day_name_full[ 6 ], "Samstag" ) == 0 ); + +#endif + + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/_PDCLIB/_PDCLIB_load_lines.c b/src/pdclib/functions/_PDCLIB/_PDCLIB_load_lines.c new file mode 100644 index 0000000..aaaa743 --- /dev/null +++ b/src/pdclib/functions/_PDCLIB/_PDCLIB_load_lines.c @@ -0,0 +1,81 @@ +/* _PDCLIB_load_lines( FILE *, size_t ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdio.h> +#include <stdlib.h> + +#ifndef REGTEST + +char * _PDCLIB_load_lines( FILE * fh, size_t lines ) +{ + size_t required = 0; + long pos = ftell( fh ); + char * rc = NULL; + int c; + + /* Count the number of characters */ + while ( lines && ( c = fgetc( fh ) ) != EOF ) + { + if ( c == '\n' ) + { + --lines; + } + + ++required; + } + + if ( ! feof( fh ) ) + { + if ( ( rc = malloc( required ) ) != NULL ) + { + size_t i; + + fseek( fh, pos, SEEK_SET ); + fread( rc, 1, required, fh ); + + for ( i = 0; i < required; ++i ) + { + if ( rc[ i ] == '\n' ) + { + rc[ i ] = '\0'; + } + } + } + } + + return rc; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ +#ifndef REGTEST + FILE * fh = fopen( "test_lines.txt", "w+" ); + char * rc; + + TESTCASE( fh != NULL ); + TESTCASE( fputs( "Foo\n\nBar\n", fh ) != EOF ); + + rewind( fh ); + rc = _PDCLIB_load_lines( fh, 3 ); + fclose( fh ); + remove( "test_lines.txt" ); + + TESTCASE( rc != NULL ); + TESTCASE( strcmp( rc, "Foo" ) == 0 ); + TESTCASE( strcmp( rc + 4, "" ) == 0 ); + TESTCASE( strcmp( rc + 5, "Bar" ) == 0 ); + +#endif + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/_PDCLIB/_PDCLIB_prepread.c b/src/pdclib/functions/_PDCLIB/_PDCLIB_prepread.c new file mode 100644 index 0000000..1d60642 --- /dev/null +++ b/src/pdclib/functions/_PDCLIB/_PDCLIB_prepread.c @@ -0,0 +1,50 @@ +/* _PDCLIB_prepread( struct _PDCLIB_file_t * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdio.h> + +#ifndef REGTEST + +#include "pdclib/_PDCLIB_glue.h" + +int _PDCLIB_prepread( struct _PDCLIB_file_t * stream ) +{ + if ( ( stream->bufidx > stream->bufend ) || + ( stream->status & ( _PDCLIB_FWRITE | _PDCLIB_FAPPEND | _PDCLIB_ERRORFLAG | _PDCLIB_WIDESTREAM | _PDCLIB_EOFFLAG ) ) || + ! ( stream->status & ( _PDCLIB_FREAD | _PDCLIB_FRW ) ) ) + { + /* Function called on illegal (e.g. output) stream. + See comments on implementation-defined errno values in + <_PDCLIB_config.h>. + */ + _PDCLIB_errno = _PDCLIB_ERROR; + stream->status |= _PDCLIB_ERRORFLAG; + return EOF; + } + stream->status |= _PDCLIB_FREAD | _PDCLIB_BYTESTREAM; + if ( ( stream->bufidx == stream->bufend ) && ( stream->ungetidx == 0 ) ) + { + return _PDCLIB_fillbuffer( stream ); + } + else + { + return 0; + } +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + /* Testing covered by ftell.c */ + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/_PDCLIB/_PDCLIB_prepwrite.c b/src/pdclib/functions/_PDCLIB/_PDCLIB_prepwrite.c new file mode 100644 index 0000000..dcdc970 --- /dev/null +++ b/src/pdclib/functions/_PDCLIB/_PDCLIB_prepwrite.c @@ -0,0 +1,41 @@ +/* _PDCLIB_prepwrite( struct _PDCLIB_file_t * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdio.h> + +#ifndef REGTEST + +int _PDCLIB_prepwrite( struct _PDCLIB_file_t * stream ) +{ + if ( ( stream->bufidx < stream->bufend ) || ( stream->ungetidx > 0 ) || + ( stream->status & ( _PDCLIB_FREAD | _PDCLIB_ERRORFLAG | _PDCLIB_WIDESTREAM | _PDCLIB_EOFFLAG ) ) || + ! ( stream->status & ( _PDCLIB_FWRITE | _PDCLIB_FAPPEND | _PDCLIB_FRW ) ) ) + { + /* Function called on illegal (e.g. input) stream. + See the comments on implementation-defined errno values in + <_PDCLIB_config.h>. + */ + _PDCLIB_errno = _PDCLIB_ERROR; + stream->status |= _PDCLIB_ERRORFLAG; + return EOF; + } + stream->status |= _PDCLIB_FWRITE | _PDCLIB_BYTESTREAM; + return 0; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + /* Testing covered by ftell.c */ + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/_PDCLIB/_PDCLIB_print.c b/src/pdclib/functions/_PDCLIB/_PDCLIB_print.c new file mode 100644 index 0000000..3c13da2 --- /dev/null +++ b/src/pdclib/functions/_PDCLIB/_PDCLIB_print.c @@ -0,0 +1,625 @@ +/* _PDCLIB_print( const char *, struct _PDCLIB_status_t * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdio.h> +#include <stdint.h> +#include <stdarg.h> +#include <stdlib.h> +#include <stddef.h> +#include <string.h> + +#ifndef REGTEST + +/* Using an integer's bits as flags for both the conversion flags and length + modifiers. +*/ +/* FIXME: one too many flags to work on a 16-bit machine, join some (e.g. the + width flags) into a combined field. +*/ +#define E_minus (1<<0) +#define E_plus (1<<1) +#define E_alt (1<<2) +#define E_space (1<<3) +#define E_zero (1<<4) +#define E_done (1<<5) + +#define E_char (1<<6) +#define E_short (1<<7) +#define E_long (1<<8) +#define E_llong (1<<9) +#define E_intmax (1<<10) +#define E_size (1<<11) +#define E_ptrdiff (1<<12) +#define E_pointer (1<<13) + +#define E_ldouble (1<<14) + +#define E_lower (1<<15) +#define E_unsigned (1<<16) + +/* This macro delivers a given character to either a memory buffer or a stream, + depending on the contents of 'status' (struct _PDCLIB_status_t). + x - the character to be delivered + i - pointer to number of characters already delivered in this call + n - pointer to maximum number of characters to be delivered in this call + s - the buffer into which the character shall be delivered +*/ +#define PUT( x ) \ +do { \ + int character = x; \ + if ( status->i < status->n ) { \ + if ( status->stream != NULL ) \ + putc( character, status->stream ); \ + else \ + status->s[status->i] = character; \ + } \ + ++(status->i); \ +} while ( 0 ) + + +static void intformat( intmax_t value, struct _PDCLIB_status_t * status ) +{ + /* At worst, we need two prefix characters (hex prefix). */ + char preface[3] = "\0"; + size_t preidx = 0; + if ( status->prec < 0 ) + { + status->prec = 1; + } + if ( ( status->flags & E_alt ) && ( status->base == 16 || status->base == 8 ) && ( value != 0 ) ) + { + /* Octal / hexadecimal prefix for "%#" conversions */ + preface[ preidx++ ] = '0'; + if ( status->base == 16 ) + { + preface[ preidx++ ] = ( status->flags & E_lower ) ? 'x' : 'X'; + } + } + if ( value < 0 ) + { + /* Negative sign for negative values - at all times. */ + preface[ preidx++ ] = '-'; + } + else if ( ! ( status->flags & E_unsigned ) ) + { + /* plus sign / extra space are only for unsigned conversions */ + if ( status->flags & E_plus ) + { + preface[ preidx++ ] = '+'; + } + else if ( status->flags & E_space ) + { + preface[ preidx++ ] = ' '; + } + } + { + /* At this point, status->current has the number of digits queued up. + Determine if we have a precision requirement to pad those. + */ + size_t prec_pads = ( (_PDCLIB_size_t)status->prec > status->current ) ? ( (_PDCLIB_size_t)status->prec - status->current ) : 0; + if ( ! ( status->flags & ( E_minus | E_zero ) ) ) + { + /* Space padding is only done if no zero padding or left alignment + is requested. Calculate the number of characters that WILL be + printed, including any prefixes determined above. + */ + /* The number of characters to be printed, plus prefixes if any. */ + /* This line contained probably the most stupid, time-wasting bug + I've ever perpetrated. Greetings to Samface, DevL, and all + sceners at Breakpoint 2006. + */ + size_t characters = preidx + ( ( status->current > (_PDCLIB_size_t)status->prec ) ? status->current : (_PDCLIB_size_t)status->prec ); + if ( status->width > characters ) + { + size_t i; + for ( i = 0; i < status->width - characters; ++i ) + { + PUT( ' ' ); + ++(status->current); + } + } + } + /* Now we did the padding, do the prefixes (if any). */ + preidx = 0; + while ( preface[ preidx ] != '\0' ) + { + PUT( preface[ preidx++ ] ); + ++(status->current); + } + /* Do the precision padding if necessary. */ + while ( prec_pads-- > 0 ) + { + PUT( '0' ); + ++(status->current); + } + if ( ( ! ( status->flags & E_minus ) ) && ( status->flags & E_zero ) ) + { + /* If field is not left aligned, and zero padding is requested, do + so. + */ + while ( status->current < status->width ) + { + PUT( '0' ); + ++(status->current); + } + } + } +} + + +/* This function recursively converts a given integer value to a character + stream. The conversion is done under the control of a given status struct + and written either to a character string or a stream, depending on that + same status struct. The status struct also keeps the function from exceeding + snprintf() limits, and enables any necessary padding / prefixing of the + output once the number of characters to be printed is known, which happens + at the lowermost recursion level. +*/ +#define INT2BASE() \ +do \ +{ \ + /* Special case: zero value, zero precision -- no output (but padding) */ \ + if ( status->current == 0 && value == 0 && status->prec == 0 ) \ + { \ + intformat( value, status ); \ + } \ + else \ + { \ + /* Registering the character being printed at the end of the function here \ + already so it will be taken into account when the deepestmost recursion \ + does the prefix / padding stuff. \ + */ \ + ++(status->current); \ + if ( ( value / status->base ) != 0 ) \ + { \ + /* More digits to be done - recurse deeper */ \ + int2base( value / status->base, status ); \ + } \ + else \ + { \ + /* We reached the last digit, the deepest point of our recursion, and \ + only now know how long the number to be printed actually is. Now we \ + have to do the sign, prefix, width, and precision padding stuff \ + before printing the numbers while we resurface from the recursion. \ + */ \ + intformat( value, status ); \ + } \ + /* Recursion tail - print the current digit. */ \ + { \ + int digit = value % status->base; \ + if ( digit < 0 ) \ + { \ + digit *= -1; \ + } \ + if ( status->flags & E_lower ) \ + { \ + /* Lowercase letters. Same array used for strto...(). */ \ + PUT( _PDCLIB_digits[ digit ] ); \ + } \ + else \ + { \ + /* Uppercase letters. Array only used here, only 0-F. */ \ + PUT( _PDCLIB_Xdigits[ digit ] ); \ + } \ + } \ + } \ +} while ( 0 ) + + +static void int2base( intmax_t value, struct _PDCLIB_status_t * status ) +{ + INT2BASE(); +} + + +static void stringformat( const char * s, struct _PDCLIB_status_t * status ) +{ + if ( status->flags & E_char ) + { + status->prec = 1; + } + else + { + if ( status->prec < 0 ) + { + status->prec = strlen( s ); + } + else + { + int i; + for ( i = 0; i < status->prec; ++i ) + { + if ( s[i] == 0 ) + { + status->prec = i; + break; + } + } + } + } + if ( ! ( status->flags & E_minus ) && ( status->width > (_PDCLIB_size_t)status->prec ) ) + { + while ( status->current < ( status->width - status->prec ) ) + { + PUT( ' ' ); + ++(status->current); + } + } + while ( status->prec > 0 ) + { + PUT( *(s++) ); + --(status->prec); + ++(status->current); + } + if ( status->flags & E_minus ) + { + while ( status->width > status->current ) + { + PUT( ' ' ); + ++(status->current); + } + } +} + + +const char * _PDCLIB_print( const char * spec, struct _PDCLIB_status_t * status ) +{ + const char * orig_spec = spec; + if ( *(++spec) == '%' ) + { + /* %% -> print single '%' */ + PUT( *spec ); + return ++spec; + } + /* Initializing status structure */ + status->flags = 0; + status->base = 0; + status->current = 0; + status->width = 0; + status->prec = EOF; + + /* First come 0..n flags */ + do + { + switch ( *spec ) + { + case '-': + /* left-aligned output */ + status->flags |= E_minus; + ++spec; + break; + case '+': + /* positive numbers prefixed with '+' */ + status->flags |= E_plus; + ++spec; + break; + case '#': + /* alternative format (leading 0x for hex, 0 for octal) */ + status->flags |= E_alt; + ++spec; + break; + case ' ': + /* positive numbers prefixed with ' ' */ + status->flags |= E_space; + ++spec; + break; + case '0': + /* right-aligned padding done with '0' instead of ' ' */ + status->flags |= E_zero; + ++spec; + break; + default: + /* not a flag, exit flag parsing */ + status->flags |= E_done; + break; + } + } while ( ! ( status->flags & E_done ) ); + + /* Optional field width */ + if ( *spec == '*' ) + { + /* Retrieve width value from argument stack */ + int width = va_arg( status->arg, int ); + if ( width < 0 ) + { + status->flags |= E_minus; + status->width = abs( width ); + } + else + { + status->width = width; + } + ++spec; + } + else + { + /* If a width is given, strtol() will return its value. If not given, + strtol() will return zero. In both cases, endptr will point to the + rest of the conversion specifier - just what we need. + */ + status->width = (int)strtol( spec, (char**)&spec, 10 ); + } + + /* Optional precision */ + if ( *spec == '.' ) + { + ++spec; + if ( *spec == '*' ) + { + /* Retrieve precision value from argument stack. A negative value + is as if no precision is given - as precision is initalized to + EOF (negative), there is no need for testing for negative here. + */ + status->prec = va_arg( status->arg, int ); + ++spec; + } + else + { + char * endptr; + status->prec = (int)strtol( spec, &endptr, 10 ); + if ( spec == endptr ) + { + /* Decimal point but no number - equals zero */ + status->prec = 0; + } + spec = endptr; + } + /* Having a precision cancels out any zero flag. */ + status->flags &= ~E_zero; + } + + /* Optional length modifier + We step one character ahead in any case, and step back only if we find + there has been no length modifier (or step ahead another character if it + has been "hh" or "ll"). + */ + switch ( *(spec++) ) + { + case 'h': + if ( *spec == 'h' ) + { + /* hh -> char */ + status->flags |= E_char; + ++spec; + } + else + { + /* h -> short */ + status->flags |= E_short; + } + break; + case 'l': + if ( *spec == 'l' ) + { + /* ll -> long long */ + status->flags |= E_llong; + ++spec; + } + else + { + /* k -> long */ + status->flags |= E_long; + } + break; + case 'j': + /* j -> intmax_t, which might or might not be long long */ + status->flags |= E_intmax; + break; + case 'z': + /* z -> size_t, which might or might not be unsigned int */ + status->flags |= E_size; + break; + case 't': + /* t -> ptrdiff_t, which might or might not be long */ + status->flags |= E_ptrdiff; + break; + case 'L': + /* L -> long double */ + status->flags |= E_ldouble; + break; + default: + --spec; + break; + } + + /* Conversion specifier */ + switch ( *spec ) + { + case 'd': + /* FALLTHROUGH */ + case 'i': + status->base = 10; + break; + case 'o': + status->base = 8; + status->flags |= E_unsigned; + break; + case 'u': + status->base = 10; + status->flags |= E_unsigned; + break; + case 'x': + status->base = 16; + status->flags |= ( E_lower | E_unsigned ); + break; + case 'X': + status->base = 16; + status->flags |= E_unsigned; + break; + case 'f': + case 'F': + case 'e': + case 'E': + case 'g': + case 'G': + break; + case 'a': + case 'A': + break; + case 'c': + /* TODO: wide chars. */ + { + char c[1]; + c[0] = (char)va_arg( status->arg, int ); + status->flags |= E_char; + stringformat( c, status ); + return ++spec; + } + case 's': + /* TODO: wide chars. */ + stringformat( va_arg( status->arg, char * ), status ); + return ++spec; + case 'p': + status->base = 16; + status->flags |= ( E_lower | E_unsigned | E_alt | E_pointer ); + break; + case 'n': + { + int * val = va_arg( status->arg, int * ); + *val = status->i; + return ++spec; + } + default: + /* No conversion specifier. Bad conversion. */ + return orig_spec; + } + + /* Do the actual output based on our findings */ + if ( status->base != 0 ) + { + /* Integer conversions */ + /* TODO: Check for invalid flag combinations. */ + if ( status->flags & E_unsigned ) + { + uintmax_t value; + switch ( status->flags & ( E_char | E_short | E_long | E_llong | E_size | E_pointer | E_intmax ) ) + { + case E_char: + value = (uintmax_t)(unsigned char)va_arg( status->arg, int ); + break; + case E_short: + value = (uintmax_t)(unsigned short)va_arg( status->arg, int ); + break; + case 0: + value = (uintmax_t)va_arg( status->arg, unsigned int ); + break; + case E_long: + value = (uintmax_t)va_arg( status->arg, unsigned long ); + break; + case E_llong: + value = (uintmax_t)va_arg( status->arg, unsigned long long ); + break; + case E_size: + value = (uintmax_t)va_arg( status->arg, size_t ); + break; + case E_pointer: + value = (uintmax_t)(uintptr_t)va_arg( status->arg, void * ); + break; + case E_intmax: + value = va_arg( status->arg, uintmax_t ); + break; + default: + puts( "UNSUPPORTED PRINTF FLAG COMBINATION" ); + return NULL; + } + INT2BASE(); + } + else + { + intmax_t value; + switch ( status->flags & ( E_char | E_short | E_long | E_llong | E_intmax ) ) + { + case E_char: + value = (intmax_t)(char)va_arg( status->arg, int ); + break; + case E_short: + value = (intmax_t)(short)va_arg( status->arg, int ); + break; + case 0: + value = (intmax_t)va_arg( status->arg, int ); + break; + case E_long: + value = (intmax_t)va_arg( status->arg, long ); + break; + case E_llong: + value = (intmax_t)va_arg( status->arg, long long ); + break; + case E_ptrdiff: + value = (intmax_t)va_arg( status->arg, ptrdiff_t ); + break; + case E_intmax: + value = va_arg( status->arg, intmax_t ); + break; + default: + puts( "UNSUPPORTED PRINTF FLAG COMBINATION" ); + return NULL; + } + INT2BASE(); + } + if ( status->flags & E_minus ) + { + while ( status->current < status->width ) + { + PUT( ' ' ); + ++(status->current); + } + } + if ( status->i >= status->n && status->n > 0 ) + { + status->s[status->n - 1] = '\0'; + } + } + return ++spec; +} + +#endif + +#ifdef TEST +#define _PDCLIB_FILEID "_PDCLIB/print.c" +#define _PDCLIB_STRINGIO + +#include "_PDCLIB_test.h" + +#ifndef REGTEST + +static int testprintf( char * buffer, const char * format, ... ) +{ + /* Members: base, flags, n, i, current, s, width, prec, stream, arg */ + struct _PDCLIB_status_t status; + status.base = 0; + status.flags = 0; + status.n = 100; + status.i = 0; + status.current = 0; + status.s = buffer; + status.width = 0; + status.prec = EOF; + status.stream = NULL; + va_start( status.arg, format ); + memset( buffer, '\0', 100 ); + if ( *(_PDCLIB_print( format, &status )) != '\0' ) + { + printf( "_PDCLIB_print() did not return end-of-specifier on '%s'.\n", format ); + ++TEST_RESULTS; + } + va_end( status.arg ); + return status.i; +} + +#endif + +#define TEST_CONVERSION_ONLY + +int main( void ) +{ +#ifndef REGTEST + char target[100]; +#include "printf_testcases.h" +#endif + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/_PDCLIB/_PDCLIB_scan.c b/src/pdclib/functions/_PDCLIB/_PDCLIB_scan.c new file mode 100644 index 0000000..1f8fd71 --- /dev/null +++ b/src/pdclib/functions/_PDCLIB/_PDCLIB_scan.c @@ -0,0 +1,639 @@ +/* _PDCLIB_scan( const char *, struct _PDCLIB_status_t * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <stdint.h> +#include <ctype.h> +#include <string.h> +#include <stddef.h> +#include <limits.h> + +#ifndef REGTEST + +/* Using an integer's bits as flags for both the conversion flags and length + modifiers. +*/ +#define E_suppressed 1<<0 +#define E_char 1<<6 +#define E_short 1<<7 +#define E_long 1<<8 +#define E_llong 1<<9 +#define E_intmax 1<<10 +#define E_size 1<<11 +#define E_ptrdiff 1<<12 +#define E_pointer 1<<13 +#define E_ldouble 1<<14 +#define E_unsigned 1<<16 + + +/* Helper function to get a character from the string or stream, whatever is + used for input. When reading from a string, returns EOF on end-of-string + so that handling of the return value can be uniform for both streams and + strings. +*/ +static int GET( struct _PDCLIB_status_t * status ) +{ + int rc = EOF; + if ( status->stream != NULL ) + { + rc = getc( status->stream ); + } + else + { + rc = ( *status->s == '\0' ) ? EOF : (unsigned char)*((status->s)++); + } + if ( rc != EOF ) + { + ++(status->i); + ++(status->current); + } + return rc; +} + + +/* Helper function to put a read character back into the string or stream, + whatever is used for input. +*/ +static void UNGET( int c, struct _PDCLIB_status_t * status ) +{ + if ( status->stream != NULL ) + { + ungetc( c, status->stream ); /* TODO: Error? */ + } + else + { + --(status->s); + } + --(status->i); + --(status->current); +} + + +/* Helper function to check if a character is part of a given scanset */ +static int IN_SCANSET( const char * scanlist, const char * end_scanlist, int rc ) +{ + /* SOLAR */ + int previous = -1; + while ( scanlist != end_scanlist ) + { + if ( ( *scanlist == '-' ) && ( previous != -1 ) ) + { + /* possible scangroup ("a-z") */ + if ( ++scanlist == end_scanlist ) + { + /* '-' at end of scanlist does not describe a scangroup */ + return rc == '-'; + } + while ( ++previous <= (unsigned char)*scanlist ) + { + if ( previous == rc ) + { + return 1; + } + } + previous = -1; + } + else + { + /* not a scangroup, check verbatim */ + if ( rc == (unsigned char)*scanlist ) + { + return 1; + } + previous = (unsigned char)(*scanlist++); + } + } + return 0; +} + + +const char * _PDCLIB_scan( const char * spec, struct _PDCLIB_status_t * status ) +{ + /* generic input character */ + int rc; + const char * prev_spec; + const char * orig_spec = spec; + int value_parsed; + if ( *(++spec) == '%' ) + { + /* %% -> match single '%' */ + rc = GET( status ); + switch ( rc ) + { + case EOF: + /* input error */ + if ( status->n == 0 ) + { + status->n = -1; + } + return NULL; + case '%': + return ++spec; + default: + UNGET( rc, status ); + break; + } + } + /* Initializing status structure */ + status->flags = 0; + status->base = -1; + status->current = 0; + status->width = 0; + status->prec = 0; + + /* '*' suppresses assigning parsed value to variable */ + if ( *spec == '*' ) + { + status->flags |= E_suppressed; + ++spec; + } + + /* If a width is given, strtol() will return its value. If not given, + strtol() will return zero. In both cases, endptr will point to the + rest of the conversion specifier - just what we need. + */ + prev_spec = spec; + status->width = (int)strtol( spec, (char**)&spec, 10 ); + if ( spec == prev_spec ) + { + status->width = SIZE_MAX; + } + + /* Optional length modifier + We step one character ahead in any case, and step back only if we find + there has been no length modifier (or step ahead another character if it + has been "hh" or "ll"). + */ + switch ( *(spec++) ) + { + case 'h': + if ( *spec == 'h' ) + { + /* hh -> char */ + status->flags |= E_char; + ++spec; + } + else + { + /* h -> short */ + status->flags |= E_short; + } + break; + case 'l': + if ( *spec == 'l' ) + { + /* ll -> long long */ + status->flags |= E_llong; + ++spec; + } + else + { + /* l -> long */ + status->flags |= E_long; + } + break; + case 'j': + /* j -> intmax_t, which might or might not be long long */ + status->flags |= E_intmax; + break; + case 'z': + /* z -> size_t, which might or might not be unsigned int */ + status->flags |= E_size; + break; + case 't': + /* t -> ptrdiff_t, which might or might not be long */ + status->flags |= E_ptrdiff; + break; + case 'L': + /* L -> long double */ + status->flags |= E_ldouble; + break; + default: + --spec; + break; + } + + /* Conversion specifier */ + + /* whether valid input had been parsed */ + value_parsed = 0; + + switch ( *spec ) + { + case 'd': + status->base = 10; + break; + case 'i': + status->base = 0; + break; + case 'o': + status->base = 8; + status->flags |= E_unsigned; + break; + case 'u': + status->base = 10; + status->flags |= E_unsigned; + break; + case 'x': + status->base = 16; + status->flags |= E_unsigned; + break; + case 'f': + case 'F': + case 'e': + case 'E': + case 'g': + case 'G': + case 'a': + case 'A': + break; + case 'c': + { + char * c = va_arg( status->arg, char * ); + /* for %c, default width is one */ + if ( status->width == SIZE_MAX ) + { + status->width = 1; + } + /* reading until width reached or input exhausted */ + while ( ( status->current < status->width ) && + ( ( rc = GET( status ) ) != EOF ) ) + { + *(c++) = rc; + value_parsed = 1; + } + /* width or input exhausted */ + if ( value_parsed ) + { + ++status->n; + return ++spec; + } + else + { + /* input error, no character read */ + if ( status->n == 0 ) + { + status->n = -1; + } + return NULL; + } + } + case 's': + { + char * c = va_arg( status->arg, char * ); + while ( ( status->current < status->width ) && + ( ( rc = GET( status ) ) != EOF ) ) + { + if ( isspace( rc ) ) + { + UNGET( rc, status ); + if ( value_parsed ) + { + /* matching sequence terminated by whitespace */ + *c = '\0'; + ++status->n; + return ++spec; + } + else + { + /* matching error */ + return NULL; + } + } + else + { + /* match */ + value_parsed = 1; + *(c++) = rc; + } + } + /* width or input exhausted */ + if ( value_parsed ) + { + *c = '\0'; + ++status->n; + return ++spec; + } + else + { + /* input error, no character read */ + if ( status->n == 0 ) + { + status->n = -1; + } + return NULL; + } + } + case '[': + { + const char * endspec = spec; + int negative_scanlist = 0; + char * c; + if ( *(++endspec) == '^' ) + { + negative_scanlist = 1; + ++endspec; + } + spec = endspec; + do + { + /* TODO: This can run beyond a malformed format string */ + ++endspec; + } while ( *endspec != ']' ); + /* read according to scanlist, equiv. to %s above */ + c = va_arg( status->arg, char * ); + while ( ( status->current < status->width ) && + ( ( rc = GET( status ) ) != EOF ) ) + { + if ( negative_scanlist ) + { + if ( IN_SCANSET( spec, endspec, rc ) ) + { + UNGET( rc, status ); + break; + } + } + else + { + if ( ! IN_SCANSET( spec, endspec, rc ) ) + { + UNGET( rc, status ); + break; + } + } + value_parsed = 1; + *(c++) = rc; + } + if ( value_parsed ) + { + *c = '\0'; + ++status->n; + return ++endspec; + } + else + { + if ( rc == EOF ) + { + status->n = -1; + } + return NULL; + } + } + case 'p': + status->base = 16; + status->flags |= E_pointer; + break; + case 'n': + { + int * val = va_arg( status->arg, int * ); + *val = status->i; + return ++spec; + } + default: + /* No conversion specifier. Bad conversion. */ + return orig_spec; + } + + if ( status->base != -1 ) + { + /* integer conversion */ + uintmax_t value = 0; /* absolute value read */ + int prefix_parsed = 0; + int sign = 0; + while ( ( status->current < status->width ) && + ( ( rc = GET( status ) ) != EOF ) ) + { + if ( isspace( rc ) ) + { + if ( sign ) + { + /* matching sequence terminated by whitespace */ + UNGET( rc, status ); + break; + } + else + { + /* leading whitespace not counted against width */ + status->current--; + } + } + else if ( ! sign ) + { + /* no sign parsed yet */ + switch ( rc ) + { + case '-': + sign = -1; + break; + case '+': + sign = 1; + break; + default: + /* not a sign; put back character */ + sign = 1; + UNGET( rc, status ); + break; + } + } + else if ( ! prefix_parsed ) + { + /* no prefix (0x... for hex, 0... for octal) parsed yet */ + prefix_parsed = 1; + if ( rc != '0' ) + { + /* not a prefix; if base not yet set, set to decimal */ + if ( status->base == 0 ) + { + status->base = 10; + } + UNGET( rc, status ); + } + else + { + /* starts with zero, so it might be a prefix. */ + /* check what follows next (might be 0x...) */ + if ( ( status->current < status->width ) && + ( ( rc = GET( status ) ) != EOF ) ) + { + if ( tolower( rc ) == 'x' ) + { + /* 0x... would be prefix for hex base... */ + if ( ( status->base == 0 ) || + ( status->base == 16 ) ) + { + status->base = 16; + } + else + { + /* ...unless already set to other value */ + UNGET( rc, status ); + value_parsed = 1; + } + } + else + { + /* 0... but not 0x.... would be octal prefix */ + UNGET( rc, status ); + if ( status->base == 0 ) + { + status->base = 8; + } + /* in any case we have read a zero */ + value_parsed = 1; + } + } + else + { + /* failed to read beyond the initial zero */ + value_parsed = 1; + break; + } + } + } + else + { + char * digitptr = memchr( _PDCLIB_digits, tolower( rc ), status->base ); + if ( digitptr == NULL ) + { + /* end of input item */ + UNGET( rc, status ); + break; + } + value *= status->base; + value += digitptr - _PDCLIB_digits; + value_parsed = 1; + } + } + /* width or input exhausted, or non-matching character */ + if ( ! value_parsed ) + { + /* out of input before anything could be parsed - input error */ + /* FIXME: if first character does not match, value_parsed is not set - but it is NOT an input error */ + if ( ( status->n == 0 ) && ( rc == EOF ) ) + { + status->n = -1; + } + return NULL; + } + /* convert value to target type and assign to parameter */ + if ( ! ( status->flags & E_suppressed ) ) + { + switch ( status->flags & ( E_char | E_short | E_long | E_llong | + E_intmax | E_size | E_ptrdiff | E_pointer | + E_unsigned ) ) + { + case E_char: + *( va_arg( status->arg, char * ) ) = (char)( value * sign ); + break; + case E_char | E_unsigned: + *( va_arg( status->arg, unsigned char * ) ) = (unsigned char)( value * sign ); + break; + + case E_short: + *( va_arg( status->arg, short * ) ) = (short)( value * sign ); + break; + case E_short | E_unsigned: + *( va_arg( status->arg, unsigned short * ) ) = (unsigned short)( value * sign ); + break; + + case 0: + *( va_arg( status->arg, int * ) ) = (int)( value * sign ); + break; + case E_unsigned: + *( va_arg( status->arg, unsigned int * ) ) = (unsigned int)( value * sign ); + break; + + case E_long: + *( va_arg( status->arg, long * ) ) = (long)( value * sign ); + break; + case E_long | E_unsigned: + *( va_arg( status->arg, unsigned long * ) ) = (unsigned long)( value * sign ); + break; + + case E_llong: + *( va_arg( status->arg, long long * ) ) = (long long)( value * sign ); + break; + case E_llong | E_unsigned: + *( va_arg( status->arg, unsigned long long * ) ) = (unsigned long long)( value * sign ); + break; + + case E_intmax: + *( va_arg( status->arg, intmax_t * ) ) = (intmax_t)( value * sign ); + break; + case E_intmax | E_unsigned: + *( va_arg( status->arg, uintmax_t * ) ) = (uintmax_t)( value * sign ); + break; + + case E_size: + /* E_size always implies unsigned */ + *( va_arg( status->arg, size_t * ) ) = (size_t)( value * sign ); + break; + + case E_ptrdiff: + /* E_ptrdiff always implies signed */ + *( va_arg( status->arg, ptrdiff_t * ) ) = (ptrdiff_t)( value * sign ); + break; + + case E_pointer: + /* E_pointer always implies unsigned */ + *( uintptr_t* )( va_arg( status->arg, void * ) ) = (uintptr_t)( value * sign ); + break; + + default: + puts( "UNSUPPORTED SCANF FLAG COMBINATION" ); + return NULL; /* behaviour unspecified */ + } + ++(status->n); + } + return ++spec; + } + /* TODO: Floats. */ + return NULL; +} + +#endif + +#ifdef TEST +#define _PDCLIB_FILEID "_PDCLIB/scan.c" +#define _PDCLIB_STRINGIO + +#include "_PDCLIB_test.h" + +#ifndef REGTEST + +static int testscanf( const char * s, const char * format, ... ) +{ + struct _PDCLIB_status_t status; + status.n = 0; + status.i = 0; + status.s = (char *)s; + status.stream = NULL; + va_start( status.arg, format ); + if ( *(_PDCLIB_scan( format, &status )) != '\0' ) + { + printf( "_PDCLIB_scan() did not return end-of-specifier on '%s'.\n", format ); + ++TEST_RESULTS; + } + va_end( status.arg ); + return status.n; +} + +#endif + +#define TEST_CONVERSION_ONLY + +int main( void ) +{ +#ifndef REGTEST + char source[100]; +#include "scanf_testcases.h" +#endif + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/_PDCLIB/_PDCLIB_seed.c b/src/pdclib/functions/_PDCLIB/_PDCLIB_seed.c new file mode 100644 index 0000000..ce7c31c --- /dev/null +++ b/src/pdclib/functions/_PDCLIB/_PDCLIB_seed.c @@ -0,0 +1,19 @@ +/* _PDCLIB_seed + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +unsigned long int _PDCLIB_seed = 1; + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + /* no tests for raw data */ + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/_PDCLIB/_PDCLIB_strtox_main.c b/src/pdclib/functions/_PDCLIB/_PDCLIB_strtox_main.c new file mode 100644 index 0000000..4808952 --- /dev/null +++ b/src/pdclib/functions/_PDCLIB/_PDCLIB_strtox_main.c @@ -0,0 +1,88 @@ +/* _PDCLIB_strtox_main( const char * *, int, _PDCLIB_uintmax_t, _PDCLIB_uintmax_t, int ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <ctype.h> +#include <errno.h> +#include <string.h> +#include <stdint.h> + +#ifndef REGTEST + +_PDCLIB_uintmax_t _PDCLIB_strtox_main( const char ** p, unsigned int base, uintmax_t error, uintmax_t limval, int limdigit, char * sign ) +{ + _PDCLIB_uintmax_t rc = 0; + int digit = -1; + const char * x; + while ( ( x = memchr( _PDCLIB_digits, tolower(**p), base ) ) != NULL ) + { + digit = x - _PDCLIB_digits; + if ( ( rc < limval ) || ( ( rc == limval ) && ( digit <= limdigit ) ) ) + { + rc = rc * base + (unsigned)digit; + ++(*p); + } + else + { + errno = ERANGE; + /* TODO: Only if endptr != NULL - but do we really want *another* parameter? */ + /* TODO: Earlier version was missing tolower() here but was not caught by tests */ + while ( memchr( _PDCLIB_digits, tolower(**p), base ) != NULL ) ++(*p); + /* TODO: This is ugly, but keeps caller from negating the error value */ + *sign = '+'; + return error; + } + } + if ( digit == -1 ) + { + *p = NULL; + return 0; + } + return rc; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +#include <errno.h> + +int main( void ) +{ +#ifndef REGTEST + const char * p; + char test[] = "123_"; + char fail[] = "xxx"; + char sign = '-'; + /* basic functionality */ + p = test; + errno = 0; + TESTCASE( _PDCLIB_strtox_main( &p, 10u, (uintmax_t)999, (uintmax_t)12, 3, &sign ) == 123 ); + TESTCASE( errno == 0 ); + TESTCASE( p == &test[3] ); + /* proper functioning to smaller base */ + p = test; + TESTCASE( _PDCLIB_strtox_main( &p, 8u, (uintmax_t)999, (uintmax_t)12, 3, &sign ) == 0123 ); + TESTCASE( errno == 0 ); + TESTCASE( p == &test[3] ); + /* overflowing subject sequence must still return proper endptr */ + p = test; + TESTCASE( _PDCLIB_strtox_main( &p, 4u, (uintmax_t)999, (uintmax_t)1, 2, &sign ) == 999 ); + TESTCASE( errno == ERANGE ); + TESTCASE( p == &test[3] ); + TESTCASE( sign == '+' ); + /* testing conversion failure */ + errno = 0; + p = fail; + sign = '-'; + TESTCASE( _PDCLIB_strtox_main( &p, 10u, (uintmax_t)999, (uintmax_t)99, 8, &sign ) == 0 ); + TESTCASE( p == NULL ); +#endif + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/_PDCLIB/_PDCLIB_strtox_prelim.c b/src/pdclib/functions/_PDCLIB/_PDCLIB_strtox_prelim.c new file mode 100644 index 0000000..6e16b35 --- /dev/null +++ b/src/pdclib/functions/_PDCLIB/_PDCLIB_strtox_prelim.c @@ -0,0 +1,94 @@ +/* _PDCLIB_strtox_prelim( const char *, char *, int * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <ctype.h> +#include <stddef.h> +#include <string.h> + +#ifndef REGTEST + +const char * _PDCLIB_strtox_prelim( const char * p, char * sign, int * base ) +{ + /* skipping leading whitespace */ + while ( isspace( *p ) ) ++p; + /* determining / skipping sign */ + if ( *p != '+' && *p != '-' ) *sign = '+'; + else *sign = *(p++); + /* determining base */ + if ( *p == '0' ) + { + ++p; + if ( ( *base == 0 || *base == 16 ) && ( *p == 'x' || *p == 'X' ) ) + { + *base = 16; + ++p; + /* catching a border case here: "0x" followed by a non-digit should + be parsed as the unprefixed zero. + We have to "rewind" the parsing; having the base set to 16 if it + was zero previously does not hurt, as the result is zero anyway. + */ + if ( memchr( _PDCLIB_digits, tolower(*p), *base ) == NULL ) + { + p -= 2; + } + } + else if ( *base == 0 ) + { + *base = 8; + } + else + { + --p; + } + } + else if ( ! *base ) + { + *base = 10; + } + return ( ( *base >= 2 ) && ( *base <= 36 ) ) ? p : NULL; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ +#ifndef REGTEST + int base = 0; + char sign = '\0'; + char test1[] = " 123"; + char test2[] = "\t+0123"; + char test3[] = "\v-0x123"; + TESTCASE( _PDCLIB_strtox_prelim( test1, &sign, &base ) == &test1[2] ); + TESTCASE( sign == '+' ); + TESTCASE( base == 10 ); + base = 0; + sign = '\0'; + TESTCASE( _PDCLIB_strtox_prelim( test2, &sign, &base ) == &test2[3] ); + TESTCASE( sign == '+' ); + TESTCASE( base == 8 ); + base = 0; + sign = '\0'; + TESTCASE( _PDCLIB_strtox_prelim( test3, &sign, &base ) == &test3[4] ); + TESTCASE( sign == '-' ); + TESTCASE( base == 16 ); + base = 10; + sign = '\0'; + TESTCASE( _PDCLIB_strtox_prelim( test3, &sign, &base ) == &test3[2] ); + TESTCASE( sign == '-' ); + TESTCASE( base == 10 ); + base = 1; + TESTCASE( _PDCLIB_strtox_prelim( test3, &sign, &base ) == NULL ); + base = 37; + TESTCASE( _PDCLIB_strtox_prelim( test3, &sign, &base ) == NULL ); +#endif + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/_PDCLIB/assert.c b/src/pdclib/functions/_PDCLIB/assert.c new file mode 100644 index 0000000..f84265f --- /dev/null +++ b/src/pdclib/functions/_PDCLIB/assert.c @@ -0,0 +1,71 @@ +/* _PDCLIB_assert( const char * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> + +#ifndef REGTEST + +#include "pdclib/_PDCLIB_aux.h" + +void _PDCLIB_assert99( const char * const message1, const char * const function, const char * const message2 ) +{ + fputs( message1, stderr ); + fputs( function, stderr ); + fputs( message2, stderr ); + abort(); +} + +void _PDCLIB_assert89( const char * const message ) +{ + fputs( message, stderr ); + abort(); +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +#include <signal.h> + +static int EXPECTED_ABORT = 0; +static int UNEXPECTED_ABORT = 1; + +static void aborthandler( int sig ) +{ + TESTCASE( ! EXPECTED_ABORT ); + exit( (signed int)TEST_RESULTS ); +} + +#define NDEBUG + +#include <assert.h> + +static int disabled_test( void ) +{ + int i = 0; + assert( i == 0 ); /* NDEBUG set, condition met */ + assert( i == 1 ); /* NDEBUG set, condition fails */ + return i; +} + +#undef NDEBUG + +#include <assert.h> + +int main( void ) +{ + TESTCASE( signal( SIGABRT, &aborthandler ) != SIG_ERR ); + TESTCASE( disabled_test() == 0 ); + assert( UNEXPECTED_ABORT ); /* NDEBUG not set, condition met */ + assert( EXPECTED_ABORT ); /* NDEBUG not set, condition fails - should abort */ + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/_PDCLIB/errno.c b/src/pdclib/functions/_PDCLIB/errno.c new file mode 100644 index 0000000..13270fc --- /dev/null +++ b/src/pdclib/functions/_PDCLIB/errno.c @@ -0,0 +1,37 @@ +/* _PDCLIB_errno + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#ifndef REGTEST + +#include "pdclib/_PDCLIB_int.h" + +int _PDCLIB_errno = 0; + +int * _PDCLIB_errno_func() +{ + return &_PDCLIB_errno; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +#include <errno.h> + +int main( void ) +{ + errno = 0; + TESTCASE( errno == 0 ); + errno = EDOM; + TESTCASE( errno == EDOM ); + errno = ERANGE; + TESTCASE( errno == ERANGE ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/_PDCLIB/stdarg.c b/src/pdclib/functions/_PDCLIB/stdarg.c new file mode 100644 index 0000000..7ad1087 --- /dev/null +++ b/src/pdclib/functions/_PDCLIB/stdarg.c @@ -0,0 +1,115 @@ +/* stdarg + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdarg.h> +#include <limits.h> +#include <float.h> + +#ifdef TEST + +#include "_PDCLIB_test.h" + +typedef int (*intfunc_t)( void ); + +enum tag_t +{ + TAG_END, + TAG_INT, + TAG_LONG, + TAG_LLONG, + TAG_DBL, + TAG_LDBL, + TAG_INTPTR, + TAG_LDBLPTR, + TAG_FUNCPTR +}; + +static int dummy( void ) +{ + return INT_MAX; +} + +static int test( enum tag_t s, ... ) +{ + enum tag_t tag = s; + va_list ap; + va_start( ap, s ); + for (;;) + { + switch ( tag ) + { + case TAG_INT: + { + TESTCASE( va_arg( ap, int ) == INT_MAX ); + tag = va_arg( ap, enum tag_t ); + break; + } + case TAG_LONG: + { + TESTCASE( va_arg( ap, long ) == LONG_MAX ); + tag = va_arg( ap, enum tag_t ); + break; + } + case TAG_LLONG: + { + TESTCASE( va_arg( ap, long long ) == LLONG_MAX ); + tag = va_arg( ap, enum tag_t ); + break; + } + case TAG_DBL: + { + TESTCASE( va_arg( ap, double ) == DBL_MAX ); + tag = va_arg( ap, enum tag_t ); + break; + } + case TAG_LDBL: + { + TESTCASE( va_arg( ap, long double ) == LDBL_MAX ); + tag = va_arg( ap, enum tag_t ); + break; + } + case TAG_INTPTR: + { + TESTCASE( *( va_arg( ap, int * ) ) == INT_MAX ); + tag = va_arg( ap, enum tag_t ); + break; + } + case TAG_LDBLPTR: + { + TESTCASE( *( va_arg( ap, long double * ) ) == LDBL_MAX ); + tag = va_arg( ap, enum tag_t ); + break; + } + case TAG_FUNCPTR: + { + intfunc_t function; + TESTCASE( ( function = va_arg( ap, intfunc_t ) ) == dummy ); + TESTCASE( function() == INT_MAX ); + tag = va_arg( ap, enum tag_t ); + break; + } + case TAG_END: + { + va_end( ap ); + return 0; + } + } + } +} + +int main( void ) +{ + int x = INT_MAX; + long double d = LDBL_MAX; + test( TAG_END ); + test( TAG_INT, INT_MAX, TAG_END ); + test( TAG_LONG, LONG_MAX, TAG_LLONG, LLONG_MAX, TAG_END ); + test( TAG_DBL, DBL_MAX, TAG_LDBL, LDBL_MAX, TAG_END ); + test( TAG_INTPTR, &x, TAG_LDBLPTR, &d, TAG_FUNCPTR, dummy, TAG_END ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/ctype/isalnum.c b/src/pdclib/functions/ctype/isalnum.c new file mode 100644 index 0000000..d3ef7c9 --- /dev/null +++ b/src/pdclib/functions/ctype/isalnum.c @@ -0,0 +1,38 @@ +/* isalnum( int ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <ctype.h> + +#ifndef REGTEST + +#include <locale.h> + +int isalnum( int c ) +{ + return ( isdigit( c ) || isalpha( c ) ); +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + TESTCASE( isalnum( 'a' ) ); + TESTCASE( isalnum( 'z' ) ); + TESTCASE( isalnum( 'A' ) ); + TESTCASE( isalnum( 'Z' ) ); + TESTCASE( isalnum( '0' ) ); + TESTCASE( isalnum( '9' ) ); + TESTCASE( ! isalnum( ' ' ) ); + TESTCASE( ! isalnum( '\n' ) ); + TESTCASE( ! isalnum( '@' ) ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/ctype/isalpha.c b/src/pdclib/functions/ctype/isalpha.c new file mode 100644 index 0000000..b3fa513 --- /dev/null +++ b/src/pdclib/functions/ctype/isalpha.c @@ -0,0 +1,34 @@ +/* isalpha( int ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <ctype.h> + +#ifndef REGTEST + +#include <locale.h> + +int isalpha( int c ) +{ + return ( _PDCLIB_lc_ctype.entry[c].flags & _PDCLIB_CTYPE_ALPHA ); +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + TESTCASE( isalpha( 'a' ) ); + TESTCASE( isalpha( 'z' ) ); + TESTCASE( ! isalpha( ' ' ) ); + TESTCASE( ! isalpha( '1' ) ); + TESTCASE( ! isalpha( '@' ) ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/ctype/isblank.c b/src/pdclib/functions/ctype/isblank.c new file mode 100644 index 0000000..dd6af44 --- /dev/null +++ b/src/pdclib/functions/ctype/isblank.c @@ -0,0 +1,35 @@ +/* isblank( int ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <ctype.h> + +#ifndef REGTEST + +#include <locale.h> + +int isblank( int c ) +{ + return ( _PDCLIB_lc_ctype.entry[c].flags & _PDCLIB_CTYPE_BLANK ); +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + TESTCASE( isblank( ' ' ) ); + TESTCASE( isblank( '\t' ) ); + TESTCASE( ! isblank( '\v' ) ); + TESTCASE( ! isblank( '\r' ) ); + TESTCASE( ! isblank( 'x' ) ); + TESTCASE( ! isblank( '@' ) ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/ctype/iscntrl.c b/src/pdclib/functions/ctype/iscntrl.c new file mode 100644 index 0000000..14d50e5 --- /dev/null +++ b/src/pdclib/functions/ctype/iscntrl.c @@ -0,0 +1,33 @@ +/* iscntrl( int ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <ctype.h> + +#ifndef REGTEST + +#include <locale.h> + +int iscntrl( int c ) +{ + return ( _PDCLIB_lc_ctype.entry[c].flags & _PDCLIB_CTYPE_CNTRL ); +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + TESTCASE( iscntrl( '\a' ) ); + TESTCASE( iscntrl( '\b' ) ); + TESTCASE( iscntrl( '\n' ) ); + TESTCASE( ! iscntrl( ' ' ) ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/ctype/isdigit.c b/src/pdclib/functions/ctype/isdigit.c new file mode 100644 index 0000000..00d6bcf --- /dev/null +++ b/src/pdclib/functions/ctype/isdigit.c @@ -0,0 +1,34 @@ +/* isdigit( int ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <ctype.h> + +#ifndef REGTEST + +#include <locale.h> + +int isdigit( int c ) +{ + return ( c >= _PDCLIB_lc_ctype.digits_low && c <= _PDCLIB_lc_ctype.digits_high ); +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + TESTCASE( isdigit( '0' ) ); + TESTCASE( isdigit( '9' ) ); + TESTCASE( ! isdigit( ' ' ) ); + TESTCASE( ! isdigit( 'a' ) ); + TESTCASE( ! isdigit( '@' ) ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/ctype/isgraph.c b/src/pdclib/functions/ctype/isgraph.c new file mode 100644 index 0000000..fdc5819 --- /dev/null +++ b/src/pdclib/functions/ctype/isgraph.c @@ -0,0 +1,37 @@ +/* isgraph( int ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <ctype.h> + +#ifndef REGTEST + +#include <locale.h> + +int isgraph( int c ) +{ + return ( _PDCLIB_lc_ctype.entry[c].flags & _PDCLIB_CTYPE_GRAPH ); +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + TESTCASE( isgraph( 'a' ) ); + TESTCASE( isgraph( 'z' ) ); + TESTCASE( isgraph( 'A' ) ); + TESTCASE( isgraph( 'Z' ) ); + TESTCASE( isgraph( '@' ) ); + TESTCASE( ! isgraph( '\t' ) ); + TESTCASE( ! isgraph( '\0' ) ); + TESTCASE( ! isgraph( ' ' ) ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/ctype/islower.c b/src/pdclib/functions/ctype/islower.c new file mode 100644 index 0000000..5d225db --- /dev/null +++ b/src/pdclib/functions/ctype/islower.c @@ -0,0 +1,35 @@ +/* islower( int ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <ctype.h> + +#ifndef REGTEST + +#include <locale.h> + +int islower( int c ) +{ + return ( _PDCLIB_lc_ctype.entry[c].flags & _PDCLIB_CTYPE_LOWER ); +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + TESTCASE( islower( 'a' ) ); + TESTCASE( islower( 'z' ) ); + TESTCASE( ! islower( 'A' ) ); + TESTCASE( ! islower( 'Z' ) ); + TESTCASE( ! islower( ' ' ) ); + TESTCASE( ! islower( '@' ) ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/ctype/isprint.c b/src/pdclib/functions/ctype/isprint.c new file mode 100644 index 0000000..d3f1489 --- /dev/null +++ b/src/pdclib/functions/ctype/isprint.c @@ -0,0 +1,38 @@ +/* isprint( int ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <ctype.h> + +#ifndef REGTEST + +#include <locale.h> + +int isprint( int c ) +{ + /* FIXME: Space as of current locale charset, not source charset. */ + return ( _PDCLIB_lc_ctype.entry[c].flags & _PDCLIB_CTYPE_GRAPH ) || ( c == ' ' ); +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + TESTCASE( isprint( 'a' ) ); + TESTCASE( isprint( 'z' ) ); + TESTCASE( isprint( 'A' ) ); + TESTCASE( isprint( 'Z' ) ); + TESTCASE( isprint( '@' ) ); + TESTCASE( ! isprint( '\t' ) ); + TESTCASE( ! isprint( '\0' ) ); + TESTCASE( isprint( ' ' ) ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/ctype/ispunct.c b/src/pdclib/functions/ctype/ispunct.c new file mode 100644 index 0000000..2afdb0c --- /dev/null +++ b/src/pdclib/functions/ctype/ispunct.c @@ -0,0 +1,38 @@ +/* ispunct( int ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <ctype.h> + +#ifndef REGTEST + +#include <locale.h> + +int ispunct( int c ) +{ + return ( _PDCLIB_lc_ctype.entry[c].flags & _PDCLIB_CTYPE_PUNCT ); +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + TESTCASE( ! ispunct( 'a' ) ); + TESTCASE( ! ispunct( 'z' ) ); + TESTCASE( ! ispunct( 'A' ) ); + TESTCASE( ! ispunct( 'Z' ) ); + TESTCASE( ispunct( '@' ) ); + TESTCASE( ispunct( '.' ) ); + TESTCASE( ! ispunct( '\t' ) ); + TESTCASE( ! ispunct( '\0' ) ); + TESTCASE( ! ispunct( ' ' ) ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/ctype/isspace.c b/src/pdclib/functions/ctype/isspace.c new file mode 100644 index 0000000..a724de6 --- /dev/null +++ b/src/pdclib/functions/ctype/isspace.c @@ -0,0 +1,36 @@ +/* isspace( int ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <ctype.h> + +#ifndef REGTEST + +#include <locale.h> + +int isspace( int c ) +{ + return ( _PDCLIB_lc_ctype.entry[c].flags & _PDCLIB_CTYPE_SPACE ); +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + TESTCASE( isspace( ' ' ) ); + TESTCASE( isspace( '\f' ) ); + TESTCASE( isspace( '\n' ) ); + TESTCASE( isspace( '\r' ) ); + TESTCASE( isspace( '\t' ) ); + TESTCASE( isspace( '\v' ) ); + TESTCASE( ! isspace( 'a' ) ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/ctype/isupper.c b/src/pdclib/functions/ctype/isupper.c new file mode 100644 index 0000000..79b55a3 --- /dev/null +++ b/src/pdclib/functions/ctype/isupper.c @@ -0,0 +1,35 @@ +/* isupper( int ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <ctype.h> + +#ifndef REGTEST + +#include <locale.h> + +int isupper( int c ) +{ + return ( _PDCLIB_lc_ctype.entry[c].flags & _PDCLIB_CTYPE_UPPER ); +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + TESTCASE( isupper( 'A' ) ); + TESTCASE( isupper( 'Z' ) ); + TESTCASE( ! isupper( 'a' ) ); + TESTCASE( ! isupper( 'z' ) ); + TESTCASE( ! isupper( ' ' ) ); + TESTCASE( ! isupper( '@' ) ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/ctype/isxdigit.c b/src/pdclib/functions/ctype/isxdigit.c new file mode 100644 index 0000000..30839c0 --- /dev/null +++ b/src/pdclib/functions/ctype/isxdigit.c @@ -0,0 +1,41 @@ +/* isxdigit( int ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <ctype.h> + +#ifndef REGTEST + +#include <locale.h> + +int isxdigit( int c ) +{ + return ( isdigit( c ) + || ( c >= _PDCLIB_lc_ctype.Xdigits_low && c <= _PDCLIB_lc_ctype.Xdigits_high ) + || ( c >= _PDCLIB_lc_ctype.xdigits_low && c <= _PDCLIB_lc_ctype.xdigits_high ) ); +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + TESTCASE( isxdigit( '0' ) ); + TESTCASE( isxdigit( '9' ) ); + TESTCASE( isxdigit( 'a' ) ); + TESTCASE( isxdigit( 'f' ) ); + TESTCASE( ! isxdigit( 'g' ) ); + TESTCASE( isxdigit( 'A' ) ); + TESTCASE( isxdigit( 'F' ) ); + TESTCASE( ! isxdigit( 'G' ) ); + TESTCASE( ! isxdigit( '@' ) ); + TESTCASE( ! isxdigit( ' ' ) ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/ctype/tolower.c b/src/pdclib/functions/ctype/tolower.c new file mode 100644 index 0000000..bbb76d1 --- /dev/null +++ b/src/pdclib/functions/ctype/tolower.c @@ -0,0 +1,35 @@ +/* tolower( int ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <ctype.h> + +#ifndef REGTEST + +#include <locale.h> + +int tolower( int c ) +{ + return _PDCLIB_lc_ctype.entry[c].lower; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + TESTCASE( tolower( 'A' ) == 'a' ); + TESTCASE( tolower( 'Z' ) == 'z' ); + TESTCASE( tolower( 'a' ) == 'a' ); + TESTCASE( tolower( 'z' ) == 'z' ); + TESTCASE( tolower( '@' ) == '@' ); + TESTCASE( tolower( '[' ) == '[' ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/ctype/toupper.c b/src/pdclib/functions/ctype/toupper.c new file mode 100644 index 0000000..79e6e2b --- /dev/null +++ b/src/pdclib/functions/ctype/toupper.c @@ -0,0 +1,35 @@ +/* toupper( int ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <ctype.h> + +#ifndef REGTEST + +#include <locale.h> + +int toupper( int c ) +{ + return _PDCLIB_lc_ctype.entry[c].upper; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + TESTCASE( toupper( 'a' ) == 'A' ); + TESTCASE( toupper( 'z' ) == 'Z' ); + TESTCASE( toupper( 'A' ) == 'A' ); + TESTCASE( toupper( 'Z' ) == 'Z' ); + TESTCASE( toupper( '@' ) == '@' ); + TESTCASE( toupper( '[' ) == '[' ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/inttypes/imaxabs.c b/src/pdclib/functions/inttypes/imaxabs.c new file mode 100644 index 0000000..06d029e --- /dev/null +++ b/src/pdclib/functions/inttypes/imaxabs.c @@ -0,0 +1,32 @@ +/* imaxabs( intmax_t ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <inttypes.h> + +#ifndef REGTEST + +intmax_t imaxabs( intmax_t j ) +{ + return ( j >= 0 ) ? j : -j; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +#include <limits.h> + +int main( void ) +{ + TESTCASE( imaxabs( (intmax_t)0 ) == 0 ); + TESTCASE( imaxabs( INTMAX_MAX ) == INTMAX_MAX ); + TESTCASE( imaxabs( INTMAX_MIN + 1 ) == -( INTMAX_MIN + 1 ) ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/inttypes/imaxdiv.c b/src/pdclib/functions/inttypes/imaxdiv.c new file mode 100644 index 0000000..7143c3d --- /dev/null +++ b/src/pdclib/functions/inttypes/imaxdiv.c @@ -0,0 +1,39 @@ +/* lldiv( long long int, long long int ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <inttypes.h> + +#ifndef REGTEST + +imaxdiv_t imaxdiv( intmax_t numer, intmax_t denom ) +{ + imaxdiv_t rc; + rc.quot = numer / denom; + rc.rem = numer % denom; + return rc; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + imaxdiv_t result; + result = imaxdiv( (intmax_t)5, (intmax_t)2 ); + TESTCASE( result.quot == 2 && result.rem == 1 ); + result = imaxdiv( (intmax_t)-5, (intmax_t)2 ); + TESTCASE( result.quot == -2 && result.rem == -1 ); + result = imaxdiv( (intmax_t)5, (intmax_t)-2 ); + TESTCASE( result.quot == -2 && result.rem == 1 ); + TESTCASE( sizeof( result.quot ) == sizeof( intmax_t ) ); + TESTCASE( sizeof( result.rem ) == sizeof( intmax_t ) ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/inttypes/strtoimax.c b/src/pdclib/functions/inttypes/strtoimax.c new file mode 100644 index 0000000..29a3c92 --- /dev/null +++ b/src/pdclib/functions/inttypes/strtoimax.c @@ -0,0 +1,147 @@ +/* strtoimax( const char *, char * *, int ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <limits.h> +#include <inttypes.h> + +#ifndef REGTEST + +#include <stddef.h> + +intmax_t strtoimax( const char * _PDCLIB_restrict nptr, char ** _PDCLIB_restrict endptr, int base ) +{ + intmax_t rc; + char sign = '+'; + const char * p = _PDCLIB_strtox_prelim( nptr, &sign, &base ); + if ( base < 2 || base > 36 ) return 0; + if ( sign == '+' ) + { + rc = (intmax_t)_PDCLIB_strtox_main( &p, (unsigned)base, (uintmax_t)INTMAX_MAX, (uintmax_t)( INTMAX_MAX / base ), (int)( INTMAX_MAX % base ), &sign ); + } + else + { + rc = (intmax_t)_PDCLIB_strtox_main( &p, (unsigned)base, (uintmax_t)INTMAX_MIN, (uintmax_t)( INTMAX_MIN / -base ), (int)( -( INTMAX_MIN % base ) ), &sign ); + } + if ( endptr != NULL ) *endptr = ( p != NULL ) ? (char *) p : (char *) nptr; + return ( sign == '+' ) ? rc : -rc; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +#include <errno.h> + +int main( void ) +{ + char * endptr; + /* this, to base 36, overflows even a 256 bit integer */ + char overflow[] = "-ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ_"; + /* tricky border case */ + char tricky[] = "+0xz"; + errno = 0; + /* basic functionality */ + TESTCASE( strtoimax( "123", NULL, 10 ) == 123 ); + /* proper detecting of default base 10 */ + TESTCASE( strtoimax( "456", NULL, 0 ) == 456 ); + /* proper functioning to smaller base */ + TESTCASE( strtoimax( "14", NULL, 8 ) == 12 ); + /* proper autodetecting of octal */ + TESTCASE( strtoimax( "016", NULL, 0 ) == 14 ); + /* proper autodetecting of hexadecimal, lowercase 'x' */ + TESTCASE( strtoimax( "0xFF", NULL, 0 ) == 255 ); + /* proper autodetecting of hexadecimal, uppercase 'X' */ + TESTCASE( strtoimax( "0Xa1", NULL, 0 ) == 161 ); + /* proper handling of border case: 0x followed by non-hexdigit */ + TESTCASE( strtoimax( tricky, &endptr, 0 ) == 0 ); + TESTCASE( endptr == tricky + 2 ); + /* proper handling of border case: 0 followed by non-octdigit */ + TESTCASE( strtoimax( tricky, &endptr, 8 ) == 0 ); + TESTCASE( endptr == tricky + 2 ); + /* errno should still be 0 */ + TESTCASE( errno == 0 ); + /* overflowing subject sequence must still return proper endptr */ + TESTCASE( strtoimax( overflow, &endptr, 36 ) == INTMAX_MIN ); + TESTCASE( errno == ERANGE ); + TESTCASE( ( endptr - overflow ) == 53 ); + /* same for positive */ + errno = 0; + TESTCASE( strtoimax( overflow + 1, &endptr, 36 ) == INTMAX_MAX ); + TESTCASE( errno == ERANGE ); + TESTCASE( ( endptr - overflow ) == 53 ); + /* testing skipping of leading whitespace */ + TESTCASE( strtoimax( " \n\v\t\f789", NULL, 0 ) == 789 ); + /* testing conversion failure */ + TESTCASE( strtoimax( overflow, &endptr, 10 ) == 0 ); + TESTCASE( endptr == overflow ); + endptr = NULL; + TESTCASE( strtoimax( overflow, &endptr, 0 ) == 0 ); + TESTCASE( endptr == overflow ); + /* These tests assume two-complement, but conversion should work for */ + /* one-complement and signed magnitude just as well. Anyone having a */ + /* platform to test this on? */ + errno = 0; +#if INTMAX_MAX >> 62 == 1 + /* testing "odd" overflow, i.e. base is not a power of two */ + TESTCASE( strtoimax( "9223372036854775807", NULL, 0 ) == INTMAX_MAX ); + TESTCASE( errno == 0 ); + TESTCASE( strtoimax( "9223372036854775808", NULL, 0 ) == INTMAX_MAX ); + TESTCASE( errno == ERANGE ); + errno = 0; + TESTCASE( strtoimax( "-9223372036854775807", NULL, 0 ) == (INTMAX_MIN + 1) ); + TESTCASE( errno == 0 ); + TESTCASE( strtoimax( "-9223372036854775808", NULL, 0 ) == INTMAX_MIN ); + TESTCASE( errno == 0 ); + TESTCASE( strtoimax( "-9223372036854775809", NULL, 0 ) == INTMAX_MIN ); + TESTCASE( errno == ERANGE ); + /* testing "even" overflow, i.e. base is power of two */ + errno = 0; + TESTCASE( strtoimax( "0x7fffffffffffffff", NULL, 0 ) == INTMAX_MAX ); + TESTCASE( errno == 0 ); + TESTCASE( strtoimax( "0x8000000000000000", NULL, 0 ) == INTMAX_MAX ); + TESTCASE( errno == ERANGE ); + errno = 0; + TESTCASE( strtoimax( "-0x7fffffffffffffff", NULL, 0 ) == (INTMAX_MIN + 1) ); + TESTCASE( errno == 0 ); + TESTCASE( strtoimax( "-0x8000000000000000", NULL, 0 ) == INTMAX_MIN ); + TESTCASE( errno == 0 ); + TESTCASE( strtoimax( "-0x8000000000000001", NULL, 0 ) == INTMAX_MIN ); + TESTCASE( errno == ERANGE ); +#elif LLONG_MAX >> 126 == 1 + /* testing "odd" overflow, i.e. base is not a power of two */ + TESTCASE( strtoimax( "170141183460469231731687303715884105728", NULL, 0 ) == INTMAX_MAX ); + TESTCASE( errno == 0 ); + TESTCASE( strtoimax( "170141183460469231731687303715884105729", NULL, 0 ) == INTMAX_MAX ); + TESTCASE( errno == ERANGE ); + errno = 0; + TESTCASE( strtoimax( "-170141183460469231731687303715884105728", NULL, 0 ) == (INTMAX_MIN + 1) ); + TESTCASE( errno == 0 ); + TESTCASE( strtoimax( "-170141183460469231731687303715884105729", NULL, 0 ) == INTMAX_MIN ); + TESTCASE( errno == 0 ); + TESTCASE( strtoimax( "-170141183460469231731687303715884105730", NULL, 0 ) == INTMAX_MIN ); + TESTCASE( errno == ERANGE ); + /* testing "even" overflow, i.e. base is power of two */ + errno = 0; + TESTCASE( strtoimax( "0x7fffffffffffffffffffffffffffffff", NULL, 0 ) == INTMAX_MAX ); + TESTCASE( errno == 0 ); + TESTCASE( strtoimax( "0x80000000000000000000000000000000", NULL, 0 ) == INTMAX_MAX ); + TESTCASE( errno == ERANGE ); + errno = 0; + TESTCASE( strtoimax( "-0x7fffffffffffffffffffffffffffffff", NULL, 0 ) == (INTMAX_MIN + 1) ); + TESTCASE( errno == 0 ); + TESTCASE( strtoimax( "-0x80000000000000000000000000000000", NULL, 0 ) == INTMAX_MIN ); + TESTCASE( errno == 0 ); + TESTCASE( strtoimax( "-0x80000000000000000000000000000001", NULL, 0 ) == INTMAX_MIN ); + TESTCASE( errno == ERANGE ); +#else +#error Unsupported width of 'intmax_t' (neither 64 nor 128 bit). +#endif + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/inttypes/strtoumax.c b/src/pdclib/functions/inttypes/strtoumax.c new file mode 100644 index 0000000..9ed16c1 --- /dev/null +++ b/src/pdclib/functions/inttypes/strtoumax.c @@ -0,0 +1,111 @@ +/* strtoumax( const char *, char * *, int ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <limits.h> +#include <inttypes.h> + +#ifndef REGTEST + +#include <stddef.h> + +uintmax_t strtoumax( const char * _PDCLIB_restrict nptr, char ** _PDCLIB_restrict endptr, int base ) +{ + uintmax_t rc; + char sign = '+'; + const char * p = _PDCLIB_strtox_prelim( nptr, &sign, &base ); + if ( base < 2 || base > 36 ) return 0; + rc = _PDCLIB_strtox_main( &p, (unsigned)base, (uintmax_t)UINTMAX_MAX, (uintmax_t)( UINTMAX_MAX / base ), (int)( UINTMAX_MAX % base ), &sign ); + if ( endptr != NULL ) *endptr = ( p != NULL ) ? (char *) p : (char *) nptr; + return ( sign == '+' ) ? rc : -rc; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +#include <errno.h> + +int main( void ) +{ + char * endptr; + /* this, to base 36, overflows even a 256 bit integer */ + char overflow[] = "-ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ_"; + /* tricky border case */ + char tricky[] = "+0xz"; + errno = 0; + /* basic functionality */ + TESTCASE( strtoumax( "123", NULL, 10 ) == 123 ); + /* proper detecting of default base 10 */ + TESTCASE( strtoumax( "456", NULL, 0 ) == 456 ); + /* proper functioning to smaller base */ + TESTCASE( strtoumax( "14", NULL, 8 ) == 12 ); + /* proper autodetecting of octal */ + TESTCASE( strtoumax( "016", NULL, 0 ) == 14 ); + /* proper autodetecting of hexadecimal, lowercase 'x' */ + TESTCASE( strtoumax( "0xFF", NULL, 0 ) == 255 ); + /* proper autodetecting of hexadecimal, uppercase 'X' */ + TESTCASE( strtoumax( "0Xa1", NULL, 0 ) == 161 ); + /* proper handling of border case: 0x followed by non-hexdigit */ + TESTCASE( strtoumax( tricky, &endptr, 0 ) == 0 ); + TESTCASE( endptr == tricky + 2 ); + /* proper handling of border case: 0 followed by non-octdigit */ + TESTCASE( strtoumax( tricky, &endptr, 8 ) == 0 ); + TESTCASE( endptr == tricky + 2 ); + /* errno should still be 0 */ + TESTCASE( errno == 0 ); + /* overflowing subject sequence must still return proper endptr */ + TESTCASE( strtoumax( overflow, &endptr, 36 ) == UINTMAX_MAX ); + TESTCASE( errno == ERANGE ); + TESTCASE( ( endptr - overflow ) == 53 ); + /* same for positive */ + errno = 0; + TESTCASE( strtoumax( overflow + 1, &endptr, 36 ) == UINTMAX_MAX ); + TESTCASE( errno == ERANGE ); + TESTCASE( ( endptr - overflow ) == 53 ); + /* testing skipping of leading whitespace */ + TESTCASE( strtoumax( " \n\v\t\f789", NULL, 0 ) == 789 ); + /* testing conversion failure */ + TESTCASE( strtoumax( overflow, &endptr, 10 ) == 0 ); + TESTCASE( endptr == overflow ); + endptr = NULL; + TESTCASE( strtoumax( overflow, &endptr, 0 ) == 0 ); + TESTCASE( endptr == overflow ); + errno = 0; +/* uintmax_t -> long long -> 64 bit */ +#if UINTMAX_MAX >> 63 == 1 + /* testing "odd" overflow, i.e. base is not power of two */ + TESTCASE( strtoumax( "18446744073709551615", NULL, 0 ) == UINTMAX_MAX ); + TESTCASE( errno == 0 ); + TESTCASE( strtoumax( "18446744073709551616", NULL, 0 ) == UINTMAX_MAX ); + TESTCASE( errno == ERANGE ); + /* testing "even" overflow, i.e. base is power of two */ + errno = 0; + TESTCASE( strtoumax( "0xFFFFFFFFFFFFFFFF", NULL, 0 ) == UINTMAX_MAX ); + TESTCASE( errno == 0 ); + TESTCASE( strtoumax( "0x10000000000000000", NULL, 0 ) == UINTMAX_MAX ); + TESTCASE( errno == ERANGE ); +/* uintmax_t -> long long -> 128 bit */ +#elif UINTMAX_MAX >> 127 == 1 + /* testing "odd" overflow, i.e. base is not power of two */ + TESTCASE( strtoumax( "340282366920938463463374607431768211455", NULL, 0 ) == UINTMAX_MAX ); + TESTCASE( errno == 0 ); + TESTCASE( strtoumax( "340282366920938463463374607431768211456", NULL, 0 ) == UINTMAX_MAX ); + TESTCASE( errno == ERANGE ); + /* testing "even" everflow, i.e. base is power of two */ + errno = 0; + TESTCASE( strtoumax( "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", NULL, 0 ) == UINTMAX_MAX ); + TESTCASE( errno == 0 ); + TESTCASE( strtoumax( "0x100000000000000000000000000000000", NULL, 0 ) == UINTMAX_MAX ); + TESTCASE( errno == ERANGE ); +#else +#error Unsupported width of 'uintmax_t' (neither 64 nor 128 bit). +#endif + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/locale/localeconv.c b/src/pdclib/functions/locale/localeconv.c new file mode 100644 index 0000000..cdcb1b0 --- /dev/null +++ b/src/pdclib/functions/locale/localeconv.c @@ -0,0 +1,28 @@ +/* localeconv( void ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <locale.h> + +#ifndef REGTEST + +struct lconv * localeconv( void ) +{ + return _PDCLIB_lc_numeric_monetary.lconv; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + TESTCASE( NO_TESTDRIVER ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/locale/setlocale.c b/src/pdclib/functions/locale/setlocale.c new file mode 100644 index 0000000..585504a --- /dev/null +++ b/src/pdclib/functions/locale/setlocale.c @@ -0,0 +1,257 @@ +/* setlocale( int, const char * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <locale.h> +#include <stdlib.h> +#include <string.h> + +#ifndef REGTEST + +static const char * _PDCLIB_LC_category_name[ _PDCLIB_LC_COUNT ] = { NULL, "LC_COLLATE", "LC_CTYPE", "LC_MONETARY", "LC_NUMERIC", "LC_TIME", "LC_MESSAGES" }; + +static const char * _PDCLIB_default_locale( int category ) +{ + const char * s; + + if ( ( s = getenv( "LC_ALL" ) ) == NULL ) + { + if ( category == LC_ALL || ( s = getenv( _PDCLIB_LC_category_name[ category ] ) ) == NULL ) + { + if ( ( s = getenv( "LANG" ) ) == NULL ) + { + s = "C"; + } + } + } + + return s; +} + +char * setlocale( int category, const char * locale ) +{ + /* All below is very much work-in-progress, so we do a dumb-dummy + return here. + */ + if ( locale == NULL || ! strcmp( locale, "C" ) ) + { + return (char *)"C"; + } + else + { + return NULL; + } + +#if 0 + /* Path to locale data files - _PDCLIB_LOCALE_PATH unless overruled + by the environment variable whose name is defined by preprocessor + symbol _PDCLIB_LOCALE_PATH_ENV (defaulting to PDCLIB_I18N). + Both of these definitions are set in _PDCLIB_config.h. + */ + const char * path = _PDCLIB_LOCALE_PATH; + + struct _PDCLIB_lc_lconv_numeric_t * numeric = NULL; + struct _PDCLIB_lc_lconv_monetary_t * monetary = NULL; + struct _PDCLIB_lc_collate_t * collate = NULL; + struct _PDCLIB_lc_ctype_t * ctype = NULL; + struct _PDCLIB_lc_messages_t * messages = NULL; + struct _PDCLIB_lc_time_t * time = NULL; + + char * rc = (char *)locale; + + if ( category < 0 || category >= _PDCLIB_LC_COUNT ) + { + /* Bad category */ + return NULL; + } + + if ( locale == NULL ) + { + /* NULL - Return current locale settings */ + /* TODO */ + } + + if ( strlen( locale ) == 0 ) + { + /* "" - Use default locale */ + locale = _PDCLIB_default_locale( category ); + } + + if ( getenv( _PDCLIB_symbol2string( _PDCLIB_LOCALE_PATH_ENV ) ) != NULL ) + { + path = getenv( _PDCLIB_symbol2string( _PDCLIB_LOCALE_PATH_ENV ) ); + } + + /* We have to do this in two runs. As we might be facing LC_ALL, we + need to be certain all the loads are successful before we start + to overwrite the current locale settings, because there is no way + this function could report a _partial_ success. + */ + + /* Run One -- get all the data for the new locale setting */ + if ( category == LC_COLLATE || category == LC_ALL ) + { + if ( ! ( collate = _PDCLIB_load_lc_collate( path, locale ) ) ) + { + rc = NULL; + } + } + + if ( category == LC_CTYPE || category == LC_ALL ) + { + if ( ! ( ctype = _PDCLIB_load_lc_ctype( path, locale ) ) ) + { + rc = NULL; + } + } + + if ( category == LC_MONETARY || category == LC_ALL ) + { + if ( ! ( monetary = _PDCLIB_load_lc_monetary( path, locale ) ) ) + { + rc = NULL; + } + } + + if ( category == LC_NUMERIC || category == LC_ALL ) + { + if ( ! ( numeric = _PDCLIB_load_lc_numeric( path, locale ) ) ) + { + rc = NULL; + } + } + + if ( category == LC_TIME || category == LC_ALL ) + { + if ( ! ( time = _PDCLIB_load_lc_time( path, locale ) ) ) + { + rc = NULL; + } + } + + if ( category == LC_MESSAGES || category == LC_ALL ) + { + if ( ! ( messages = _PDCLIB_load_lc_messages( path, locale ) ) ) + { + rc = NULL; + } + } + + /* Run Two -- continue or release resources */ + if ( rc != NULL ) + { + if ( category == LC_COLLATE || category == LC_ALL ) + { + if ( _PDCLIB_lc_collate.alloced ) + { + /* free resources */ + } + + _PDCLIB_lc_collate = *collate; + free( collate ); + } + + if ( category == LC_CTYPE || category == LC_ALL ) + { + if ( _PDCLIB_lc_ctype.alloced ) + { + free( _PDCLIB_lc_ctype.entry - 1 ); + } + + _PDCLIB_lc_ctype = *ctype; + free( ctype ); + } + + if ( category == LC_MONETARY || category == LC_ALL ) + { + if ( _PDCLIB_lc_numeric_monetary.monetary_alloced ) + { + free( _PDCLIB_lc_numeric_monetary.lconv->mon_decimal_point ); + } + + _PDCLIB_lc_numeric_monetary.lconv->mon_decimal_point = monetary->mon_decimal_point; + _PDCLIB_lc_numeric_monetary.lconv->mon_thousands_sep = monetary->mon_thousands_sep; + _PDCLIB_lc_numeric_monetary.lconv->mon_grouping = monetary->mon_grouping; + _PDCLIB_lc_numeric_monetary.lconv->positive_sign = monetary->positive_sign; + _PDCLIB_lc_numeric_monetary.lconv->negative_sign = monetary->negative_sign; + _PDCLIB_lc_numeric_monetary.lconv->currency_symbol = monetary->currency_symbol; + _PDCLIB_lc_numeric_monetary.lconv->int_curr_symbol = monetary->int_curr_symbol; + _PDCLIB_lc_numeric_monetary.lconv->frac_digits = monetary->frac_digits; + _PDCLIB_lc_numeric_monetary.lconv->p_cs_precedes = monetary->p_cs_precedes; + _PDCLIB_lc_numeric_monetary.lconv->n_cs_precedes = monetary->n_cs_precedes; + _PDCLIB_lc_numeric_monetary.lconv->p_sep_by_space = monetary->p_sep_by_space; + _PDCLIB_lc_numeric_monetary.lconv->n_sep_by_space = monetary->n_sep_by_space; + _PDCLIB_lc_numeric_monetary.lconv->p_sign_posn = monetary->p_sign_posn; + _PDCLIB_lc_numeric_monetary.lconv->n_sign_posn = monetary->n_sign_posn; + _PDCLIB_lc_numeric_monetary.lconv->int_frac_digits = monetary->int_frac_digits; + _PDCLIB_lc_numeric_monetary.lconv->int_p_cs_precedes = monetary->int_p_cs_precedes; + _PDCLIB_lc_numeric_monetary.lconv->int_n_cs_precedes = monetary->int_n_cs_precedes; + _PDCLIB_lc_numeric_monetary.lconv->int_p_sep_by_space = monetary->int_p_sep_by_space; + _PDCLIB_lc_numeric_monetary.lconv->int_n_sep_by_space = monetary->int_n_sep_by_space; + _PDCLIB_lc_numeric_monetary.lconv->int_p_sign_posn = monetary->int_p_sign_posn; + _PDCLIB_lc_numeric_monetary.lconv->int_n_sign_posn = monetary->int_n_sign_posn; + + _PDCLIB_lc_numeric_monetary.monetary_alloced = 1; + + free( monetary ); + } + + if ( category == LC_NUMERIC || category == LC_ALL ) + { + if ( _PDCLIB_lc_numeric_monetary.numeric_alloced ) + { + free( _PDCLIB_lc_numeric_monetary.lconv->decimal_point ); + } + + _PDCLIB_lc_numeric_monetary.lconv->decimal_point = numeric->decimal_point; + _PDCLIB_lc_numeric_monetary.lconv->thousands_sep = numeric->thousands_sep; + _PDCLIB_lc_numeric_monetary.lconv->grouping = numeric->grouping; + + _PDCLIB_lc_numeric_monetary.numeric_alloced = 1; + + free( numeric ); + } + + if ( category == LC_TIME || category == LC_ALL ) + { + if ( _PDCLIB_lc_time.alloced ) + { + free( _PDCLIB_lc_time.month_name_abbr[ 0 ] ); + } + + _PDCLIB_lc_time = *time; + free( time ); + } + + if ( category == LC_MESSAGES || category == LC_ALL ) + { + if ( _PDCLIB_lc_messages.alloced ) + { + free( _PDCLIB_lc_messages.errno_texts[ 0 ] ); + } + + _PDCLIB_lc_messages = *messages; + free( messages ); + } + } + + return NULL; +#endif +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + setlocale(0,""); + TESTCASE( NO_TESTDRIVER ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdio/clearerr.c b/src/pdclib/functions/stdio/clearerr.c new file mode 100644 index 0000000..91cd00a --- /dev/null +++ b/src/pdclib/functions/stdio/clearerr.c @@ -0,0 +1,52 @@ +/* clearerr( FILE * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdio.h> + +#ifndef REGTEST + +void clearerr( struct _PDCLIB_file_t * stream ) +{ + stream->status &= ~( _PDCLIB_ERRORFLAG | _PDCLIB_EOFFLAG ); +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + FILE * fh; + TESTCASE( ( fh = tmpfile() ) != NULL ); + /* Flags should be clear */ + TESTCASE( ! ferror( fh ) ); + TESTCASE( ! feof( fh ) ); + /* Reading from empty stream - should provoke EOF */ + rewind( fh ); + TESTCASE( fgetc( fh ) == EOF ); + TESTCASE( ! ferror( fh ) ); + TESTCASE( feof( fh ) ); + /* clearerr() should clear flags */ + clearerr( fh ); + TESTCASE( ! ferror( fh ) ); + TESTCASE( ! feof( fh ) ); + /* reopen() the file write-only */ + TESTCASE( ( fh = freopen( NULL, "w", fh ) ) != NULL ); + /* Reading from write-only stream - should provoke error */ + TESTCASE( fgetc( fh ) == EOF ); + TESTCASE( ferror( fh ) ); + TESTCASE( ! feof( fh ) ); + /* clearerr() should clear flags */ + clearerr( fh ); + TESTCASE( ! ferror( fh ) ); + TESTCASE( ! feof( fh ) ); + TESTCASE( fclose( fh ) == 0 ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdio/fclose.c b/src/pdclib/functions/stdio/fclose.c new file mode 100644 index 0000000..9a1388d --- /dev/null +++ b/src/pdclib/functions/stdio/fclose.c @@ -0,0 +1,106 @@ +/* fclose( FILE * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdio.h> +#include <stdlib.h> + +#ifndef REGTEST + +#include "pdclib/_PDCLIB_glue.h" + +extern struct _PDCLIB_file_t * _PDCLIB_filelist; + +int fclose( struct _PDCLIB_file_t * stream ) +{ + struct _PDCLIB_file_t * current = _PDCLIB_filelist; + struct _PDCLIB_file_t * previous = NULL; + /* Checking that the FILE handle is actually one we had opened before. */ + while ( current != NULL ) + { + if ( stream == current ) + { + /* Flush buffer */ + if ( stream->status & _PDCLIB_FWRITE ) + { + if ( _PDCLIB_flushbuffer( stream ) == EOF ) + { + /* Flush failed, errno already set */ + return EOF; + } + } + /* Close handle */ + _PDCLIB_close( stream->handle ); + /* Remove stream from list */ + if ( previous != NULL ) + { + previous->next = stream->next; + } + else + { + _PDCLIB_filelist = stream->next; + } + /* Delete tmpfile() */ + if ( stream->status & _PDCLIB_DELONCLOSE ) + { + remove( stream->filename ); + } + /* Free user buffer (SetVBuf allocated) */ + if ( stream->status & _PDCLIB_FREEBUFFER ) + { + free( stream->buffer ); + } + /* Free stream */ + if ( ! ( stream->status & _PDCLIB_STATIC ) ) + { + free( stream ); + } + return 0; + } + previous = current; + current = current->next; + } + /* See the comments on implementation-defined errno values in + <_PDCLIB_config.h>. + */ + _PDCLIB_errno = _PDCLIB_ERROR; + return -1; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ +#ifndef REGTEST + struct _PDCLIB_file_t * file1; + struct _PDCLIB_file_t * file2; + remove( testfile1 ); + remove( testfile2 ); + TESTCASE( _PDCLIB_filelist == stdin ); + TESTCASE( ( file1 = fopen( testfile1, "w" ) ) != NULL ); + TESTCASE( _PDCLIB_filelist == file1 ); + TESTCASE( ( file2 = fopen( testfile2, "w" ) ) != NULL ); + TESTCASE( _PDCLIB_filelist == file2 ); + TESTCASE( fclose( file2 ) == 0 ); + TESTCASE( _PDCLIB_filelist == file1 ); + TESTCASE( ( file2 = fopen( testfile2, "w" ) ) != NULL ); + TESTCASE( _PDCLIB_filelist == file2 ); + TESTCASE( fclose( file1 ) == 0 ); + TESTCASE( _PDCLIB_filelist == file2 ); + TESTCASE( fclose( file2 ) == 0 ); + TESTCASE( _PDCLIB_filelist == stdin ); + TESTCASE( remove( testfile1 ) == 0 ); + TESTCASE( remove( testfile2 ) == 0 ); +#else + puts( " NOTEST fclose() test driver is PDCLib-specific." ); +#endif + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdio/feof.c b/src/pdclib/functions/stdio/feof.c new file mode 100644 index 0000000..a57071f --- /dev/null +++ b/src/pdclib/functions/stdio/feof.c @@ -0,0 +1,28 @@ +/* feof( FILE * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdio.h> + +#ifndef REGTEST + +int feof( struct _PDCLIB_file_t * stream ) +{ + return stream->status & _PDCLIB_EOFFLAG; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + /* Testing covered by clearerr(). */ + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdio/ferror.c b/src/pdclib/functions/stdio/ferror.c new file mode 100644 index 0000000..54f43f0 --- /dev/null +++ b/src/pdclib/functions/stdio/ferror.c @@ -0,0 +1,28 @@ +/* ferror( FILE * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdio.h> + +#ifndef REGTEST + +int ferror( struct _PDCLIB_file_t * stream ) +{ + return stream->status & _PDCLIB_ERRORFLAG; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + /* Testing covered by clearerr(). */ + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdio/fflush.c b/src/pdclib/functions/stdio/fflush.c new file mode 100644 index 0000000..3d0b297 --- /dev/null +++ b/src/pdclib/functions/stdio/fflush.c @@ -0,0 +1,53 @@ +/* fflush( FILE * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdio.h> + +#ifndef REGTEST + +#include "pdclib/_PDCLIB_glue.h" + +extern struct _PDCLIB_file_t * _PDCLIB_filelist; + +int fflush( struct _PDCLIB_file_t * stream ) +{ + if ( stream == NULL ) + { + int rc = 0; + stream = _PDCLIB_filelist; + /* TODO: Check what happens when fflush( NULL ) encounters write errors, in other libs */ + while ( stream != NULL ) + { + if ( stream->status & _PDCLIB_FWRITE ) + { + if ( _PDCLIB_flushbuffer( stream ) == EOF ) + { + rc = EOF; + } + } + stream = stream->next; + } + return rc; + } + else + { + return _PDCLIB_flushbuffer( stream ); + } +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + /* Testing covered by ftell.c */ + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdio/fgetc.c b/src/pdclib/functions/stdio/fgetc.c new file mode 100644 index 0000000..bdb233e --- /dev/null +++ b/src/pdclib/functions/stdio/fgetc.c @@ -0,0 +1,38 @@ +/* fgetc( FILE * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdio.h> + +#ifndef REGTEST + +#include "pdclib/_PDCLIB_glue.h" + +int fgetc( struct _PDCLIB_file_t * stream ) +{ + if ( _PDCLIB_prepread( stream ) == EOF ) + { + return EOF; + } + if ( stream->ungetidx > 0 ) + { + return (unsigned char)stream->ungetbuf[ --(stream->ungetidx) ]; + } + return (unsigned char)stream->buffer[stream->bufidx++]; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + /* Testing covered by ftell.c */ + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdio/fgetpos.c b/src/pdclib/functions/stdio/fgetpos.c new file mode 100644 index 0000000..db9be06 --- /dev/null +++ b/src/pdclib/functions/stdio/fgetpos.c @@ -0,0 +1,43 @@ +/* fgetpos( FILE * , fpos_t * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdio.h> + +#ifndef REGTEST + +int fgetpos( struct _PDCLIB_file_t * _PDCLIB_restrict stream, struct _PDCLIB_fpos_t * _PDCLIB_restrict pos ) +{ + pos->offset = stream->pos.offset + stream->bufidx - stream->ungetidx; + pos->status = stream->pos.status; + /* TODO: Add mbstate. */ + return 0; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +#include <string.h> + +int main( void ) +{ + FILE * fh; + fpos_t pos1, pos2; + TESTCASE( ( fh = tmpfile() ) != NULL ); + TESTCASE( fgetpos( fh, &pos1 ) == 0 ); + TESTCASE( fwrite( teststring, 1, strlen( teststring ), fh ) == strlen( teststring ) ); + TESTCASE( fgetpos( fh, &pos2 ) == 0 ); + TESTCASE( fsetpos( fh, &pos1 ) == 0 ); + TESTCASE( ftell( fh ) == 0 ); + TESTCASE( fsetpos( fh, &pos2 ) == 0 ); + TESTCASE( (size_t)ftell( fh ) == strlen( teststring ) ); + TESTCASE( fclose( fh ) == 0 ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdio/fgets.c b/src/pdclib/functions/stdio/fgets.c new file mode 100644 index 0000000..0499afd --- /dev/null +++ b/src/pdclib/functions/stdio/fgets.c @@ -0,0 +1,88 @@ +/* fgets( char *, int, FILE * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdio.h> + +#ifndef REGTEST + +#include "pdclib/_PDCLIB_glue.h" + +char * fgets( char * _PDCLIB_restrict s, int size, struct _PDCLIB_file_t * _PDCLIB_restrict stream ) +{ + char * dest = s; + if ( size == 0 ) + { + return NULL; + } + if ( size == 1 ) + { + *s = '\0'; + return s; + } + if ( _PDCLIB_prepread( stream ) == EOF ) + { + return NULL; + } + while ( ( ( *dest++ = stream->buffer[stream->bufidx++] ) != '\n' ) && --size > 0 ) + { + if ( stream->bufidx == stream->bufend ) + { + if ( _PDCLIB_fillbuffer( stream ) == EOF ) + { + /* In case of error / EOF before a character is read, this + will lead to a \0 be written anyway. Since the results + are "indeterminate" by definition, this does not hurt. + */ + break; + } + } + } + *dest = '\0'; + return ( dest == s ) ? NULL : s; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +#include <string.h> + +int main( void ) +{ + FILE * fh; + char buffer[10]; + const char * fgets_test = "foo\nbar\0baz\nweenie"; + TESTCASE( ( fh = fopen( testfile, "wb+" ) ) != NULL ); + TESTCASE( fwrite( fgets_test, 1, 18, fh ) == 18 ); + rewind( fh ); + TESTCASE( fgets( buffer, 10, fh ) == buffer ); + TESTCASE( strcmp( buffer, "foo\n" ) == 0 ); + TESTCASE( fgets( buffer, 10, fh ) == buffer ); + TESTCASE( memcmp( buffer, "bar\0baz\n", 8 ) == 0 ); + TESTCASE( fgets( buffer, 10, fh ) == buffer ); + TESTCASE( strcmp( buffer, "weenie" ) == 0 ); + TESTCASE( feof( fh ) ); + TESTCASE( fseek( fh, -1, SEEK_END ) == 0 ); + TESTCASE( fgets( buffer, 1, fh ) == buffer ); + TESTCASE( strcmp( buffer, "" ) == 0 ); + TESTCASE( fgets( buffer, 0, fh ) == NULL ); + TESTCASE( ! feof( fh ) ); + TESTCASE( fgets( buffer, 1, fh ) == buffer ); + TESTCASE( strcmp( buffer, "" ) == 0 ); + TESTCASE( ! feof( fh ) ); + TESTCASE( fgets( buffer, 2, fh ) == buffer ); + TESTCASE( strcmp( buffer, "e" ) == 0 ); + TESTCASE( fseek( fh, 0, SEEK_END ) == 0 ); + TESTCASE( fgets( buffer, 2, fh ) == NULL ); + TESTCASE( feof( fh ) ); + TESTCASE( fclose( fh ) == 0 ); + TESTCASE( remove( testfile ) == 0 ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdio/fopen.c b/src/pdclib/functions/stdio/fopen.c new file mode 100644 index 0000000..d5241a7 --- /dev/null +++ b/src/pdclib/functions/stdio/fopen.c @@ -0,0 +1,102 @@ +/* fopen( const char *, const char * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdio.h> +#include <stdlib.h> + +#ifndef REGTEST + +#include "pdclib/_PDCLIB_glue.h" + +#include <string.h> + +extern struct _PDCLIB_file_t * _PDCLIB_filelist; + +struct _PDCLIB_file_t * fopen( const char * _PDCLIB_restrict filename, const char * _PDCLIB_restrict mode ) +{ + struct _PDCLIB_file_t * rc; + size_t filename_len; + if ( mode == NULL || filename == NULL || filename[0] == '\0' ) + { + /* Mode or filename invalid */ + return NULL; + } + /* To reduce the number of malloc calls, all data fields are concatenated: + * the FILE structure itself, + * ungetc buffer, + * filename buffer, + * data buffer. + Data buffer comes last because it might change in size ( setvbuf() ). + */ + filename_len = strlen( filename ) + 1; + if ( ( rc = calloc( 1, sizeof( struct _PDCLIB_file_t ) + _PDCLIB_UNGETCBUFSIZE + filename_len + BUFSIZ ) ) == NULL ) + { + /* no memory */ + return NULL; + } + if ( ( rc->status = _PDCLIB_filemode( mode ) ) == 0 ) + { + /* invalid mode */ + free( rc ); + return NULL; + } + rc->handle = _PDCLIB_open( filename, rc->status ); + if ( rc->handle == _PDCLIB_NOHANDLE ) + { + /* OS open() failed */ + free( rc ); + return NULL; + } + /* Setting pointers into the memory block allocated above */ + rc->ungetbuf = (unsigned char *)rc + sizeof( struct _PDCLIB_file_t ); + rc->filename = (char *)rc->ungetbuf + _PDCLIB_UNGETCBUFSIZE; + rc->buffer = rc->filename + filename_len; + /* Copying filename to FILE structure */ + strcpy( rc->filename, filename ); + /* Initializing the rest of the structure */ + rc->bufsize = BUFSIZ; + rc->bufidx = 0; + rc->ungetidx = 0; + /* Setting buffer to _IOLBF because "when opened, a stream is fully + buffered if and only if it can be determined not to refer to an + interactive device." + */ + rc->status |= _IOLBF; + /* TODO: Setting mbstate */ + /* Adding to list of open files */ + rc->next = _PDCLIB_filelist; + _PDCLIB_filelist = rc; + return rc; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + /* Some of the tests are not executed for regression tests, as the libc on + my system is at once less forgiving (segfaults on mode NULL) and more + forgiving (accepts undefined modes). + */ + FILE * fh; + remove( testfile ); + TESTCASE_NOREG( fopen( NULL, NULL ) == NULL ); + TESTCASE( fopen( NULL, "w" ) == NULL ); + TESTCASE_NOREG( fopen( "", NULL ) == NULL ); + TESTCASE( fopen( "", "w" ) == NULL ); + TESTCASE( fopen( "foo", "" ) == NULL ); + TESTCASE_NOREG( fopen( testfile, "wq" ) == NULL ); /* Undefined mode */ + TESTCASE_NOREG( fopen( testfile, "wr" ) == NULL ); /* Undefined mode */ + TESTCASE( ( fh = fopen( testfile, "w" ) ) != NULL ); + TESTCASE( fclose( fh ) == 0 ); + TESTCASE( remove( testfile ) == 0 ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdio/fprintf.c b/src/pdclib/functions/stdio/fprintf.c new file mode 100644 index 0000000..e16adf8 --- /dev/null +++ b/src/pdclib/functions/stdio/fprintf.c @@ -0,0 +1,43 @@ +/* fprintf( FILE *, const char *, ... ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdio.h> +#include <stdarg.h> + +#ifndef REGTEST + +int fprintf( struct _PDCLIB_file_t * _PDCLIB_restrict stream, const char * _PDCLIB_restrict format, ... ) +{ + int rc; + va_list ap; + va_start( ap, format ); + rc = vfprintf( stream, format, ap ); + va_end( ap ); + return rc; +} + +#endif + +#ifdef TEST +#include <stdint.h> +#include <stddef.h> +#define _PDCLIB_FILEID "stdio/fprintf.c" +#define _PDCLIB_FILEIO + +#include "_PDCLIB_test.h" + +#define testprintf( stream, ... ) fprintf( stream, __VA_ARGS__ ) + +int main( void ) +{ + FILE * target; + TESTCASE( ( target = tmpfile() ) != NULL ); +#include "printf_testcases.h" + TESTCASE( fclose( target ) == 0 ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdio/fputc.c b/src/pdclib/functions/stdio/fputc.c new file mode 100644 index 0000000..05ac792 --- /dev/null +++ b/src/pdclib/functions/stdio/fputc.c @@ -0,0 +1,47 @@ +/* fputc( int, FILE * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdio.h> + +#ifndef REGTEST + +#include "pdclib/_PDCLIB_glue.h" + +/* Write the value c (cast to unsigned char) to the given stream. + Returns c if successful, EOF otherwise. + If a write error occurs, the error indicator of the stream is set. +*/ +int fputc( int c, struct _PDCLIB_file_t * stream ) +{ + if ( _PDCLIB_prepwrite( stream ) == EOF ) + { + return EOF; + } + stream->buffer[stream->bufidx++] = (char)c; + if ( ( stream->bufidx == stream->bufsize ) /* _IOFBF */ + || ( ( stream->status & _IOLBF ) && ( (char)c == '\n' ) ) /* _IOLBF */ + || ( stream->status & _IONBF ) /* _IONBF */ + ) + { + /* buffer filled, unbuffered stream, or end-of-line. */ + return ( _PDCLIB_flushbuffer( stream ) == 0 ) ? c : EOF; + } + return c; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + /* Testing covered by ftell.c */ + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdio/fputs.c b/src/pdclib/functions/stdio/fputs.c new file mode 100644 index 0000000..a5d7e56 --- /dev/null +++ b/src/pdclib/functions/stdio/fputs.c @@ -0,0 +1,69 @@ +/* fputs( const char *, FILE * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdio.h> + +#ifndef REGTEST + +#include "pdclib/_PDCLIB_glue.h" + +int fputs( const char * _PDCLIB_restrict s, struct _PDCLIB_file_t * _PDCLIB_restrict stream ) +{ + if ( _PDCLIB_prepwrite( stream ) == EOF ) + { + return EOF; + } + while ( *s != '\0' ) + { + /* Unbuffered and line buffered streams get flushed when fputs() does + write the terminating end-of-line. All streams get flushed if the + buffer runs full. + */ + stream->buffer[ stream->bufidx++ ] = *s; + if ( ( stream->bufidx == stream->bufsize ) || + ( ( stream->status & _IOLBF ) && *s == '\n' ) + ) + { + if ( _PDCLIB_flushbuffer( stream ) == EOF ) + { + return EOF; + } + } + ++s; + } + if ( stream->status & _IONBF ) + { + if ( _PDCLIB_flushbuffer( stream ) == EOF ) + { + return EOF; + } + } + return 0; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + const char * const message = "SUCCESS testing fputs()"; + FILE * fh; + size_t i; + TESTCASE( ( fh = tmpfile() ) != NULL ); + TESTCASE( fputs( message, fh ) >= 0 ); + rewind( fh ); + for ( i = 0; i < 23; ++i ) + { + TESTCASE( fgetc( fh ) == message[i] ); + } + TESTCASE( fclose( fh ) == 0 ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdio/fread.c b/src/pdclib/functions/stdio/fread.c new file mode 100644 index 0000000..319e9ba --- /dev/null +++ b/src/pdclib/functions/stdio/fread.c @@ -0,0 +1,81 @@ +/* fwrite( void *, size_t, size_t, FILE * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdio.h> +#include <string.h> + +#ifndef REGTEST + +#include "pdclib/_PDCLIB_glue.h" + +size_t fread( void * _PDCLIB_restrict ptr, size_t size, size_t nmemb, struct _PDCLIB_file_t * _PDCLIB_restrict stream ) +{ + char * dest = (char *)ptr; + size_t nmemb_i; + if ( _PDCLIB_prepread( stream ) == EOF ) + { + return 0; + } + for ( nmemb_i = 0; nmemb_i < nmemb; ++nmemb_i ) + { + size_t size_i; + for ( size_i = 0; size_i < size; ++size_i ) + { + if ( stream->bufidx == stream->bufend ) + { + if ( _PDCLIB_fillbuffer( stream ) == EOF ) + { + /* Could not read requested data */ + return nmemb_i; + } + } + dest[ nmemb_i * size + size_i ] = stream->buffer[ stream->bufidx++ ]; + } + } + return nmemb_i; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + FILE * fh; + const char * message = "Testing fwrite()...\n"; + char buffer[21]; + buffer[20] = 'x'; + TESTCASE( ( fh = tmpfile() ) != NULL ); + /* fwrite() / readback */ + TESTCASE( fwrite( message, 1, 20, fh ) == 20 ); + rewind( fh ); + TESTCASE( fread( buffer, 1, 20, fh ) == 20 ); + TESTCASE( memcmp( buffer, message, 20 ) == 0 ); + TESTCASE( buffer[20] == 'x' ); + /* same, different nmemb / size settings */ + rewind( fh ); + TESTCASE( memset( buffer, '\0', 20 ) == buffer ); + TESTCASE( fwrite( message, 5, 4, fh ) == 4 ); + rewind( fh ); + TESTCASE( fread( buffer, 5, 4, fh ) == 4 ); + TESTCASE( memcmp( buffer, message, 20 ) == 0 ); + TESTCASE( buffer[20] == 'x' ); + /* same... */ + rewind( fh ); + TESTCASE( memset( buffer, '\0', 20 ) == buffer ); + TESTCASE( fwrite( message, 20, 1, fh ) == 1 ); + rewind( fh ); + TESTCASE( fread( buffer, 20, 1, fh ) == 1 ); + TESTCASE( memcmp( buffer, message, 20 ) == 0 ); + TESTCASE( buffer[20] == 'x' ); + /* Done. */ + TESTCASE( fclose( fh ) == 0 ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdio/freopen.c b/src/pdclib/functions/stdio/freopen.c new file mode 100644 index 0000000..2cb774c --- /dev/null +++ b/src/pdclib/functions/stdio/freopen.c @@ -0,0 +1,104 @@ +/* freopen( const char *, const char *, FILE * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#ifndef REGTEST + +#include "pdclib/_PDCLIB_glue.h" + +struct _PDCLIB_file_t * freopen( const char * _PDCLIB_restrict filename, const char * _PDCLIB_restrict mode, struct _PDCLIB_file_t * _PDCLIB_restrict stream ) +{ + unsigned int status = stream->status & ( _IONBF | _IOLBF | _IOFBF | _PDCLIB_FREEBUFFER | _PDCLIB_DELONCLOSE ); + /* TODO: This function can change wide orientation of a stream */ + if ( stream->status & _PDCLIB_FWRITE ) + { + _PDCLIB_flushbuffer( stream ); + } + if ( ( filename == NULL ) && ( stream->filename == NULL ) ) + { + /* TODO: Special handling for mode changes on std-streams */ + return NULL; + } + _PDCLIB_close( stream->handle ); + /* TODO: It is not nice to do this on a stream we just closed. + It does not matter with the current implementation of clearerr(), + but it might start to matter if someone replaced that implementation. + */ + clearerr( stream ); + /* The new filename might not fit the old buffer */ + if ( filename == NULL ) + { + /* Use previous filename */ + filename = stream->filename; + } + else if ( ( stream->filename != NULL ) && ( strlen( stream->filename ) >= strlen( filename ) ) ) + { + /* Copy new filename into existing buffer */ + strcpy( stream->filename, filename ); + } + else + { + /* Allocate new buffer */ + if ( ( stream->filename = (char *)malloc( strlen( filename ) ) ) == NULL ) + { + return NULL; + } + strcpy( stream->filename, filename ); + } + if ( ( mode == NULL ) || ( filename[0] == '\0' ) ) + { + return NULL; + } + if ( ( stream->status = _PDCLIB_filemode( mode ) ) == 0 ) + { + return NULL; + } + /* Re-add the flags we saved above */ + stream->status |= status; + stream->bufidx = 0; + stream->bufend = 0; + stream->ungetidx = 0; + /* TODO: Setting mbstate */ + if ( ( stream->handle = _PDCLIB_open( filename, stream->status ) ) == _PDCLIB_NOHANDLE ) + { + return NULL; + } + return stream; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + FILE * fin; + FILE * fout; + TESTCASE( ( fin = fopen( testfile1, "wb+" ) ) != NULL ); + TESTCASE( fputc( 'x', fin ) == 'x' ); + TESTCASE( fclose( fin ) == 0 ); + TESTCASE( ( fin = freopen( testfile1, "rb", stdin ) ) != NULL ); + TESTCASE( getchar() == 'x' ); + + TESTCASE( ( fout = freopen( testfile2, "wb+", stdout ) ) != NULL ); + TESTCASE( putchar( 'x' ) == 'x' ); + rewind( fout ); + TESTCASE( fgetc( fout ) == 'x' ); + + TESTCASE( fclose( fin ) == 0 ); + TESTCASE( fclose( fout ) == 0 ); + TESTCASE( remove( testfile1 ) == 0 ); + TESTCASE( remove( testfile2 ) == 0 ); + + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdio/fscanf.c b/src/pdclib/functions/stdio/fscanf.c new file mode 100644 index 0000000..cc8c031 --- /dev/null +++ b/src/pdclib/functions/stdio/fscanf.c @@ -0,0 +1,41 @@ +/* fscanf( FILE *, const char *, ... ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdio.h> +#include <stdarg.h> + +#ifndef REGTEST + +int fscanf( FILE * _PDCLIB_restrict stream, const char * _PDCLIB_restrict format, ... ) +{ + int rc; + va_list ap; + va_start( ap, format ); + rc = vfscanf( stream, format, ap ); + va_end( ap ); + return rc; +} + +#endif + +#ifdef TEST +#define _PDCLIB_FILEID "stdio/fscanf.c" +#define _PDCLIB_FILEIO + +#include "_PDCLIB_test.h" + +#define testscanf( stream, format, ... ) fscanf( stream, format, __VA_ARGS__ ) + +int main( void ) +{ + FILE * source; + TESTCASE( ( source = tmpfile() ) != NULL ); +#include "scanf_testcases.h" + TESTCASE( fclose( source ) == 0 ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdio/fseek.c b/src/pdclib/functions/stdio/fseek.c new file mode 100644 index 0000000..54f4c4b --- /dev/null +++ b/src/pdclib/functions/stdio/fseek.c @@ -0,0 +1,85 @@ +/* fseek( FILE *, long, int ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdio.h> + +#ifndef REGTEST + +#include "pdclib/_PDCLIB_glue.h" + +int fseek( struct _PDCLIB_file_t * stream, long offset, int whence ) +{ + if ( stream->status & _PDCLIB_FWRITE ) + { + if ( _PDCLIB_flushbuffer( stream ) == EOF ) + { + return EOF; + } + } + stream->status &= ~ _PDCLIB_EOFFLAG; + if ( stream->status & _PDCLIB_FRW ) + { + stream->status &= ~ ( _PDCLIB_FREAD | _PDCLIB_FWRITE ); + } + return ( _PDCLIB_seek( stream, offset, whence ) != EOF ) ? 0 : EOF; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +#include <string.h> + +int main( void ) +{ + FILE * fh; + TESTCASE( ( fh = tmpfile() ) != NULL ); + TESTCASE( fwrite( teststring, 1, strlen( teststring ), fh ) == strlen( teststring ) ); + /* General functionality */ + TESTCASE( fseek( fh, -1, SEEK_END ) == 0 ); + TESTCASE( (size_t)ftell( fh ) == strlen( teststring ) - 1 ); + TESTCASE( fseek( fh, 0, SEEK_END ) == 0 ); + TESTCASE( (size_t)ftell( fh ) == strlen( teststring ) ); + TESTCASE( fseek( fh, 0, SEEK_SET ) == 0 ); + TESTCASE( ftell( fh ) == 0 ); + TESTCASE( fseek( fh, 5, SEEK_CUR ) == 0 ); + TESTCASE( ftell( fh ) == 5 ); + TESTCASE( fseek( fh, -3, SEEK_CUR ) == 0 ); + TESTCASE( ftell( fh ) == 2 ); + /* Checking behaviour around EOF */ + TESTCASE( fseek( fh, 0, SEEK_END ) == 0 ); + TESTCASE( ! feof( fh ) ); + TESTCASE( fgetc( fh ) == EOF ); + TESTCASE( feof( fh ) ); + TESTCASE( fseek( fh, 0, SEEK_END ) == 0 ); + TESTCASE( ! feof( fh ) ); + /* Checking undo of ungetc() */ + TESTCASE( fseek( fh, 0, SEEK_SET ) == 0 ); + TESTCASE( fgetc( fh ) == teststring[0] ); + TESTCASE( fgetc( fh ) == teststring[1] ); + TESTCASE( fgetc( fh ) == teststring[2] ); + TESTCASE( ftell( fh ) == 3 ); + TESTCASE( ungetc( teststring[2], fh ) == teststring[2] ); + TESTCASE( ftell( fh ) == 2 ); + TESTCASE( fgetc( fh ) == teststring[2] ); + TESTCASE( ftell( fh ) == 3 ); + TESTCASE( ungetc( 'x', fh ) == 'x' ); + TESTCASE( ftell( fh ) == 2 ); + TESTCASE( fgetc( fh ) == 'x' ); + TESTCASE( ungetc( 'x', fh ) == 'x' ); + TESTCASE( ftell( fh ) == 2 ); + TESTCASE( fseek( fh, 2, SEEK_SET ) == 0 ); + TESTCASE( fgetc( fh ) == teststring[2] ); + /* Checking error handling */ + TESTCASE( fseek( fh, -5, SEEK_SET ) == -1 ); + TESTCASE( fseek( fh, 0, SEEK_END ) == 0 ); + TESTCASE( fclose( fh ) == 0 ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdio/fsetpos.c b/src/pdclib/functions/stdio/fsetpos.c new file mode 100644 index 0000000..323aaae --- /dev/null +++ b/src/pdclib/functions/stdio/fsetpos.c @@ -0,0 +1,43 @@ +/* fsetpos( FILE *, const fpos_t * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdio.h> + +#ifndef REGTEST + +#include "pdclib/_PDCLIB_glue.h" + +int fsetpos( struct _PDCLIB_file_t * stream, const struct _PDCLIB_fpos_t * pos ) +{ + if ( stream->status & _PDCLIB_FWRITE ) + { + if ( _PDCLIB_flushbuffer( stream ) == EOF ) + { + return EOF; + } + } + if ( _PDCLIB_seek( stream, pos->offset, SEEK_SET ) == EOF ) + { + return EOF; + } + stream->pos.status = pos->status; + /* TODO: Add mbstate. */ + return 0; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + /* fsetpos() tested together with fsetpos(). */ + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdio/ftell.c b/src/pdclib/functions/stdio/ftell.c new file mode 100644 index 0000000..f4bd300 --- /dev/null +++ b/src/pdclib/functions/stdio/ftell.c @@ -0,0 +1,100 @@ +/* ftell( FILE * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdio.h> +#include <limits.h> + +#ifndef REGTEST + +long int ftell( struct _PDCLIB_file_t * stream ) +{ + /* ftell() must take into account: + - the actual *physical* offset of the file, i.e. the offset as recognized + by the operating system (and stored in stream->pos.offset); and + - any buffers held by PDCLib, which + - in case of unwritten buffers, count in *addition* to the offset; or + - in case of unprocessed pre-read buffers, count in *substraction* to + the offset. (Remember to count ungetidx into this number.) + Conveniently, the calculation ( ( bufend - bufidx ) + ungetidx ) results + in just the right number in both cases: + - in case of unwritten buffers, ( ( 0 - unwritten ) + 0 ) + i.e. unwritten bytes as negative number + - in case of unprocessed pre-read, ( ( preread - processed ) + unget ) + i.e. unprocessed bytes as positive number. + That is how the somewhat obscure return-value calculation works. + */ + /* If offset is too large for return type, report error instead of wrong + offset value. + */ + /* TODO: Check what happens when ungetc() is called on a stream at offset 0 */ + if ( ( stream->pos.offset - stream->bufend ) > ( LONG_MAX - ( stream->bufidx - stream->ungetidx ) ) ) + { + /* integer overflow */ + _PDCLIB_errno = _PDCLIB_ERANGE; + return -1; + } + return (long int)( stream->pos.offset - ( ( (int)stream->bufend - (int)stream->bufidx ) + stream->ungetidx ) ); +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +#include <stdlib.h> + +int main( void ) +{ + /* Testing all the basic I/O functions individually would result in lots + of duplicated code, so I took the liberty of lumping it all together + here. + */ + /* The following functions delegate their tests to here: + fgetc fflush rewind fputc ungetc fseek + flushbuffer seek fillbuffer prepread prepwrite + */ + char * buffer = (char*)malloc( 4 ); + FILE * fh; + TESTCASE( ( fh = tmpfile() ) != NULL ); + TESTCASE( setvbuf( fh, buffer, _IOLBF, 4 ) == 0 ); + /* Testing ungetc() at offset 0 */ + rewind( fh ); + TESTCASE( ungetc( 'x', fh ) == 'x' ); + TESTCASE( ftell( fh ) == -1l ); + rewind( fh ); + TESTCASE( ftell( fh ) == 0l ); + /* Commence "normal" tests */ + TESTCASE( fputc( '1', fh ) == '1' ); + TESTCASE( fputc( '2', fh ) == '2' ); + TESTCASE( fputc( '3', fh ) == '3' ); + /* Positions incrementing as expected? */ + TESTCASE( ftell( fh ) == 3l ); + TESTCASE_NOREG( fh->pos.offset == 0l ); + TESTCASE_NOREG( fh->bufidx == 3l ); + /* Buffer properly flushed when full? */ + TESTCASE( fputc( '4', fh ) == '4' ); + TESTCASE_NOREG( fh->pos.offset == 4l ); + TESTCASE_NOREG( fh->bufidx == 0 ); + /* fflush() resetting positions as expected? */ + TESTCASE( fputc( '5', fh ) == '5' ); + TESTCASE( fflush( fh ) == 0 ); + TESTCASE( ftell( fh ) == 5l ); + TESTCASE_NOREG( fh->pos.offset == 5l ); + TESTCASE_NOREG( fh->bufidx == 0l ); + /* rewind() resetting positions as expected? */ + rewind( fh ); + TESTCASE( ftell( fh ) == 0l ); + TESTCASE_NOREG( fh->pos.offset == 0 ); + TESTCASE_NOREG( fh->bufidx == 0 ); + /* Reading back first character after rewind for basic read check */ + TESTCASE( fgetc( fh ) == '1' ); + /* TODO: t.b.c. */ + TESTCASE( fclose( fh ) == 0 ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdio/fwrite.c b/src/pdclib/functions/stdio/fwrite.c new file mode 100644 index 0000000..7958a50 --- /dev/null +++ b/src/pdclib/functions/stdio/fwrite.c @@ -0,0 +1,93 @@ +/* fwrite( const void *, size_t, size_t, FILE * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdio.h> +#include <string.h> + +#ifndef REGTEST + +#include "pdclib/_PDCLIB_glue.h" + +size_t fwrite( const void * _PDCLIB_restrict ptr, size_t size, size_t nmemb, struct _PDCLIB_file_t * _PDCLIB_restrict stream ) +{ + _PDCLIB_size_t offset = 0; + /* TODO: lineend */ + /* int lineend = 0; */ + size_t nmemb_i; + if ( _PDCLIB_prepwrite( stream ) == EOF ) + { + return 0; + } + for ( nmemb_i = 0; nmemb_i < nmemb; ++nmemb_i ) + { + size_t size_i; + for ( size_i = 0; size_i < size; ++size_i ) + { + if ( ( stream->buffer[ stream->bufidx++ ] = ((char*)ptr)[ nmemb_i * size + size_i ] ) == '\n' ) + { + /* Remember last newline, in case we have to do a partial line-buffered flush */ + offset = stream->bufidx; + /* lineend = true; */ + } + if ( stream->bufidx == stream->bufsize ) + { + if ( _PDCLIB_flushbuffer( stream ) == EOF ) + { + /* Returning number of objects completely buffered */ + return nmemb_i; + } + /* lineend = false; */ + } + } + } + /* Fully-buffered streams are OK. Non-buffered streams must be flushed, + line-buffered streams only if there's a newline in the buffer. + */ + switch ( stream->status & ( _IONBF | _IOLBF ) ) + { + case _IONBF: + if ( _PDCLIB_flushbuffer( stream ) == EOF ) + { + /* We are in a pinch here. We have an error, which requires a + return value < nmemb. On the other hand, all objects have + been written to buffer, which means all the caller had to + do was removing the error cause, and re-flush the stream... + Catch 22. We'll return a value one short, to indicate the + error, and can't really do anything about the inconsistency. + */ + return nmemb_i - 1; + } + break; + case _IOLBF: + { + size_t bufidx = stream->bufidx; + stream->bufidx = offset; + if ( _PDCLIB_flushbuffer( stream ) == EOF ) + { + /* See comment above. */ + stream->bufidx = bufidx; + return nmemb_i - 1; + } + stream->bufidx = bufidx - offset; + memmove( stream->buffer, stream->buffer + offset, stream->bufidx ); + } + } + return nmemb_i; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + /* Testing covered by fread(). */ + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdio/getc.c b/src/pdclib/functions/stdio/getc.c new file mode 100644 index 0000000..3d082b3 --- /dev/null +++ b/src/pdclib/functions/stdio/getc.c @@ -0,0 +1,28 @@ +/* getc( FILE * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdio.h> + +#ifndef REGTEST + +int getc( struct _PDCLIB_file_t * stream ) +{ + return fgetc( stream ); +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + /* Testing covered by ftell.c */ + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdio/getchar.c b/src/pdclib/functions/stdio/getchar.c new file mode 100644 index 0000000..34ee545 --- /dev/null +++ b/src/pdclib/functions/stdio/getchar.c @@ -0,0 +1,28 @@ +/* getchar( void ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdio.h> + +#ifndef REGTEST + +int getchar( void ) +{ + return fgetc( stdin ); +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + /* Testing covered by ftell.c */ + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdio/perror.c b/src/pdclib/functions/stdio/perror.c new file mode 100644 index 0000000..dd6633c --- /dev/null +++ b/src/pdclib/functions/stdio/perror.c @@ -0,0 +1,58 @@ +/* perror( const char * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdio.h> +#include <errno.h> +#include <locale.h> + +#ifndef REGTEST + +/* TODO: Doing this via a static array is not the way to do it. */ +void perror( const char * s ) +{ + if ( ( s != NULL ) && ( s[0] != '\n' ) ) + { + fprintf( stderr, "%s: ", s ); + } + if ( errno >= _PDCLIB_ERRNO_MAX ) + { + fprintf( stderr, "Unknown error\n" ); + } + else + { + fprintf( stderr, "%s\n", _PDCLIB_lc_messages.errno_texts[errno] ); + } + return; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +#include <stdlib.h> +#include <string.h> +#include <limits.h> + +int main( void ) +{ + FILE * fh; + unsigned long long max = ULLONG_MAX; + char buffer[100]; + sprintf( buffer, "%llu", max ); + TESTCASE( ( fh = freopen( testfile, "wb+", stderr ) ) != NULL ); + TESTCASE( strtol( buffer, NULL, 10 ) == LONG_MAX ); + perror( "Test" ); + rewind( fh ); + TESTCASE( fread( buffer, 1, 7, fh ) == 7 ); + TESTCASE( memcmp( buffer, "Test: ", 6 ) == 0 ); + TESTCASE( fclose( fh ) == 0 ); + TESTCASE( remove( testfile ) == 0 ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdio/printf.c b/src/pdclib/functions/stdio/printf.c new file mode 100644 index 0000000..6d10113 --- /dev/null +++ b/src/pdclib/functions/stdio/printf.c @@ -0,0 +1,44 @@ +/* printf( const char *, ... ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdio.h> +#include <stdarg.h> + +#ifndef REGTEST + +int printf( const char * _PDCLIB_restrict format, ... ) +{ + int rc; + va_list ap; + va_start( ap, format ); + rc = vfprintf( stdout, format, ap ); + va_end( ap ); + return rc; +} + +#endif + +#ifdef TEST +#define _PDCLIB_FILEID "stdio/printf.c" +#define _PDCLIB_FILEIO +#include <stdint.h> +#include <stddef.h> + +#include "_PDCLIB_test.h" + +#define testprintf( stream, ... ) printf( __VA_ARGS__ ) + +int main( void ) +{ + FILE * target; + TESTCASE( ( target = freopen( testfile, "wb+", stdout ) ) != NULL ); +#include "printf_testcases.h" + TESTCASE( fclose( target ) == 0 ); + TESTCASE( remove( testfile ) == 0 ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdio/putc.c b/src/pdclib/functions/stdio/putc.c new file mode 100644 index 0000000..c1eb2b0 --- /dev/null +++ b/src/pdclib/functions/stdio/putc.c @@ -0,0 +1,28 @@ +/* putc( int, FILE * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdio.h> + +#ifndef REGTEST + +int putc( int c, struct _PDCLIB_file_t * stream ) +{ + return fputc( c, stream ); +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + /* Testing covered by ftell.c */ + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdio/putchar.c b/src/pdclib/functions/stdio/putchar.c new file mode 100644 index 0000000..15bf299 --- /dev/null +++ b/src/pdclib/functions/stdio/putchar.c @@ -0,0 +1,28 @@ +/* putchar( int ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdio.h> + +#ifndef REGTEST + +int putchar( int c ) +{ + return fputc( c, stdout ); +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + /* Testing covered by ftell.c */ + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdio/puts.c b/src/pdclib/functions/stdio/puts.c new file mode 100644 index 0000000..89240cb --- /dev/null +++ b/src/pdclib/functions/stdio/puts.c @@ -0,0 +1,67 @@ +/* puts( const char * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdio.h> + +#ifndef REGTEST + +#include "pdclib/_PDCLIB_glue.h" + +extern char * _PDCLIB_eol; + +int puts( const char * s ) +{ + if ( _PDCLIB_prepwrite( stdout ) == EOF ) + { + return EOF; + } + while ( *s != '\0' ) + { + stdout->buffer[ stdout->bufidx++ ] = *s++; + if ( stdout->bufidx == stdout->bufsize ) + { + if ( _PDCLIB_flushbuffer( stdout ) == EOF ) + { + return EOF; + } + } + } + stdout->buffer[ stdout->bufidx++ ] = '\n'; + if ( ( stdout->bufidx == stdout->bufsize ) || + ( stdout->status & ( _IOLBF | _IONBF ) ) ) + { + return _PDCLIB_flushbuffer( stdout ); + } + else + { + return 0; + } +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + FILE * fh; + const char * message = "SUCCESS testing puts()"; + char buffer[23]; + buffer[22] = 'x'; + TESTCASE( ( fh = freopen( testfile, "wb+", stdout ) ) != NULL ); + TESTCASE( puts( message ) >= 0 ); + rewind( fh ); + TESTCASE( fread( buffer, 1, 22, fh ) == 22 ); + TESTCASE( memcmp( buffer, message, 22 ) == 0 ); + TESTCASE( buffer[22] == 'x' ); + TESTCASE( fclose( fh ) == 0 ); + TESTCASE( remove( testfile ) == 0 ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdio/rename.c b/src/pdclib/functions/stdio/rename.c new file mode 100644 index 0000000..5d45f1f --- /dev/null +++ b/src/pdclib/functions/stdio/rename.c @@ -0,0 +1,84 @@ +/* rename( const char *, const char * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdio.h> + +#ifndef REGTEST + +#include "pdclib/_PDCLIB_glue.h" + +#include <string.h> + +extern struct _PDCLIB_file_t * _PDCLIB_filelist; + +int rename( const char * old, const char * new ) +{ + struct _PDCLIB_file_t * current = _PDCLIB_filelist; + while ( current != NULL ) + { + if ( ( current->filename != NULL ) && ( strcmp( current->filename, old ) == 0 ) ) + { + /* File of that name currently open. Do not rename. */ + return EOF; + } + current = current->next; + } + return _PDCLIB_rename( old, new ); +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +#include <stdlib.h> + +int main( void ) +{ + FILE * file; + remove( testfile1 ); + remove( testfile2 ); + /* make sure that neither file exists */ + TESTCASE( fopen( testfile1, "r" ) == NULL ); + TESTCASE( fopen( testfile2, "r" ) == NULL ); + /* rename file 1 to file 2 - expected to fail */ + TESTCASE( rename( testfile1, testfile2 ) == -1 ); + /* create file 1 */ + TESTCASE( ( file = fopen( testfile1, "w" ) ) != NULL ); + TESTCASE( fputs( "x", file ) != EOF ); + TESTCASE( fclose( file ) == 0 ); + /* check that file 1 exists */ + TESTCASE( ( file = fopen( testfile1, "r" ) ) != NULL ); + TESTCASE( fclose( file ) == 0 ); + /* rename file 1 to file 2 */ + TESTCASE( rename( testfile1, testfile2 ) == 0 ); + /* check that file 2 exists, file 1 does not */ + TESTCASE( fopen( testfile1, "r" ) == NULL ); + TESTCASE( ( file = fopen( testfile2, "r" ) ) != NULL ); + TESTCASE( fclose( file ) == 0 ); + /* create another file 1 */ + TESTCASE( ( file = fopen( testfile1, "w" ) ) != NULL ); + TESTCASE( fputs( "x", file ) != EOF ); + TESTCASE( fclose( file ) == 0 ); + /* check that file 1 exists */ + TESTCASE( ( file = fopen( testfile1, "r" ) ) != NULL ); + TESTCASE( fclose( file ) == 0 ); + /* rename file 1 to file 2 - expected to fail, see comment in + _PDCLIB_rename() itself. + */ + /* NOREG as glibc overwrites existing destination file. */ + TESTCASE_NOREG( rename( testfile1, testfile2 ) == -1 ); + /* remove both files */ + TESTCASE( remove( testfile1 ) == 0 ); + TESTCASE( remove( testfile2 ) == 0 ); + /* check that they're gone */ + TESTCASE( fopen( testfile1, "r" ) == NULL ); + TESTCASE( fopen( testfile2, "r" ) == NULL ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdio/rewind.c b/src/pdclib/functions/stdio/rewind.c new file mode 100644 index 0000000..a449b7d --- /dev/null +++ b/src/pdclib/functions/stdio/rewind.c @@ -0,0 +1,29 @@ +/* rewind( FILE * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdio.h> + +#ifndef REGTEST + +void rewind( struct _PDCLIB_file_t * stream ) +{ + stream->status &= ~ _PDCLIB_ERRORFLAG; + fseek( stream, 0L, SEEK_SET ); +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + /* Testing covered by ftell.c */ + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdio/scanf.c b/src/pdclib/functions/stdio/scanf.c new file mode 100644 index 0000000..b29b1d5 --- /dev/null +++ b/src/pdclib/functions/stdio/scanf.c @@ -0,0 +1,39 @@ +/* scanf( const char *, ... ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdio.h> +#include <stdarg.h> + +#ifndef REGTEST + +int scanf( const char * _PDCLIB_restrict format, ... ) +{ + va_list ap; + va_start( ap, format ); + return vfscanf( stdin, format, ap ); +} + +#endif + +#ifdef TEST +#define _PDCLIB_FILEID "stdio/scanf.c" +#define _PDCLIB_FILEIO + +#include "_PDCLIB_test.h" + +#define testscanf( stream, format, ... ) scanf( format, __VA_ARGS__ ) + +int main( void ) +{ + FILE * source; + TESTCASE( ( source = freopen( testfile, "wb+", stdin ) ) != NULL ); +#include "scanf_testcases.h" + TESTCASE( fclose( source ) == 0 ); + TESTCASE( remove( testfile ) == 0 ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdio/setbuf.c b/src/pdclib/functions/stdio/setbuf.c new file mode 100644 index 0000000..6c32072 --- /dev/null +++ b/src/pdclib/functions/stdio/setbuf.c @@ -0,0 +1,55 @@ +/* setbuf( FILE *, char * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdio.h> + +#ifndef REGTEST + +void setbuf( struct _PDCLIB_file_t * _PDCLIB_restrict stream, char * _PDCLIB_restrict buf ) +{ + if ( buf == NULL ) + { + setvbuf( stream, buf, _IONBF, BUFSIZ ); + } + else + { + setvbuf( stream, buf, _IOFBF, BUFSIZ ); + } +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +#include <stdlib.h> + +int main( void ) +{ + /* TODO: Extend testing once setvbuf() is finished. */ +#ifndef REGTEST + char buffer[ BUFSIZ + 1 ]; + FILE * fh; + /* full buffered */ + TESTCASE( ( fh = tmpfile() ) != NULL ); + setbuf( fh, buffer ); + TESTCASE( fh->buffer == buffer ); + TESTCASE( fh->bufsize == BUFSIZ ); + TESTCASE( ( fh->status & ( _IOFBF | _IONBF | _IOLBF ) ) == _IOFBF ); + TESTCASE( fclose( fh ) == 0 ); + /* not buffered */ + TESTCASE( ( fh = tmpfile() ) != NULL ); + setbuf( fh, NULL ); + TESTCASE( ( fh->status & ( _IOFBF | _IONBF | _IOLBF ) ) == _IONBF ); + TESTCASE( fclose( fh ) == 0 ); +#else + puts( " NOTEST setbuf() test driver is PDCLib-specific." ); +#endif + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdio/setvbuf.c b/src/pdclib/functions/stdio/setvbuf.c new file mode 100644 index 0000000..00592ff --- /dev/null +++ b/src/pdclib/functions/stdio/setvbuf.c @@ -0,0 +1,108 @@ +/* setvbuf( FILE *, char *, int, size_t ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <limits.h> + +#ifndef REGTEST + +int setvbuf( struct _PDCLIB_file_t * _PDCLIB_restrict stream, char * _PDCLIB_restrict buf, int mode, size_t size ) +{ + switch ( mode ) + { + case _IONBF: + /* When unbuffered I/O is requested, we keep the buffer anyway, as + we don't want to e.g. flush the stream for every character of a + stream being printed. + */ + break; + case _IOFBF: + case _IOLBF: + if ( size > INT_MAX || size == 0 ) + { + /* PDCLib only supports buffers up to INT_MAX in size. A size + of zero doesn't make sense. + */ + return -1; + } + if ( buf == NULL ) + { + /* User requested buffer size, but leaves it to library to + allocate the buffer. + */ + /* If current buffer is big enough for requested size, but not + over twice as big (and wasting memory space), we use the + current buffer (i.e., do nothing), to save the malloc() / + free() overhead. + */ + if ( ( stream->bufsize < size ) || ( stream->bufsize > ( size << 1 ) ) ) + { + /* Buffer too small, or much too large - allocate. */ + if ( ( buf = (char *) malloc( size ) ) == NULL ) + { + /* Out of memory error. */ + return -1; + } + /* This buffer must be free()d on fclose() */ + stream->status |= _PDCLIB_FREEBUFFER; + } + } + stream->buffer = buf; + stream->bufsize = size; + break; + default: + /* If mode is something else than _IOFBF, _IOLBF or _IONBF -> exit */ + return -1; + } + /* Deleting current buffer mode */ + stream->status &= ~( _IOFBF | _IOLBF | _IONBF ); + /* Set user-defined mode */ + stream->status |= mode; + return 0; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +#include <errno.h> + +#define BUFFERSIZE 500 + +int main( void ) +{ +#ifndef REGTEST + char buffer[ BUFFERSIZE ]; + FILE * fh; + /* full buffered, user-supplied buffer */ + TESTCASE( ( fh = tmpfile() ) != NULL ); + TESTCASE( setvbuf( fh, buffer, _IOFBF, BUFFERSIZE ) == 0 ); + TESTCASE( fh->buffer == buffer ); + TESTCASE( fh->bufsize == BUFFERSIZE ); + TESTCASE( ( fh->status & ( _IOFBF | _IONBF | _IOLBF ) ) == _IOFBF ); + TESTCASE( fclose( fh ) == 0 ); + /* line buffered, lib-supplied buffer */ + TESTCASE( ( fh = tmpfile() ) != NULL ); + TESTCASE( setvbuf( fh, NULL, _IOLBF, BUFFERSIZE ) == 0 ); + TESTCASE( fh->buffer != NULL ); + TESTCASE( fh->bufsize == BUFFERSIZE ); + TESTCASE( ( fh->status & ( _IOFBF | _IONBF | _IOLBF ) ) == _IOLBF ); + TESTCASE( fclose( fh ) == 0 ); + /* not buffered, user-supplied buffer */ + TESTCASE( ( fh = tmpfile() ) != NULL ); + TESTCASE( setvbuf( fh, buffer, _IONBF, BUFFERSIZE ) == 0 ); + TESTCASE( ( fh->status & ( _IOFBF | _IONBF | _IOLBF ) ) == _IONBF ); + TESTCASE( fclose( fh ) == 0 ); +#else + puts( " NOTEST setvbuf() test driver is PDCLib-specific." ); +#endif + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdio/snprintf.c b/src/pdclib/functions/stdio/snprintf.c new file mode 100644 index 0000000..f095b8c --- /dev/null +++ b/src/pdclib/functions/stdio/snprintf.c @@ -0,0 +1,43 @@ +/* snprintf( char *, size_t, const char *, ... ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdio.h> +#include <stdarg.h> + +#ifndef REGTEST + +int snprintf( char * _PDCLIB_restrict s, size_t n, const char * _PDCLIB_restrict format, ...) +{ + int rc; + va_list ap; + va_start( ap, format ); + rc = vsnprintf( s, n, format, ap ); + va_end( ap ); + return rc; +} + +#endif + +#ifdef TEST +#define _PDCLIB_FILEID "stdio/snprintf.c" +#define _PDCLIB_STRINGIO +#include <stdint.h> +#include <stddef.h> + +#include "_PDCLIB_test.h" + +#define testprintf( s, ... ) snprintf( s, 100, __VA_ARGS__ ) + +int main( void ) +{ + char target[100]; +#include "printf_testcases.h" + TESTCASE( snprintf( NULL, 0, "foo" ) == 3 ); + TESTCASE( snprintf( NULL, 0, "%d", 100 ) == 3 ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdio/sprintf.c b/src/pdclib/functions/stdio/sprintf.c new file mode 100644 index 0000000..ce3a7ff --- /dev/null +++ b/src/pdclib/functions/stdio/sprintf.c @@ -0,0 +1,41 @@ +/* sprintf( char *, const char *, ... ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdio.h> +#include <stdint.h> +#include <stdarg.h> + +#ifndef REGTEST + +int sprintf( char * _PDCLIB_restrict s, const char * _PDCLIB_restrict format, ...) +{ + int rc; + va_list ap; + va_start( ap, format ); + rc = vsnprintf( s, SIZE_MAX, format, ap ); /* TODO: replace with non-checking call */ + va_end( ap ); + return rc; +} + +#endif + +#ifdef TEST +#define _PDCLIB_FILEID "stdio/sprintf.c" +#define _PDCLIB_STRINGIO +#include <stddef.h> + +#include "_PDCLIB_test.h" + +#define testprintf( s, ... ) sprintf( s, __VA_ARGS__ ) + +int main( void ) +{ + char target[100]; +#include "printf_testcases.h" + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdio/sscanf.c b/src/pdclib/functions/stdio/sscanf.c new file mode 100644 index 0000000..9ba830d --- /dev/null +++ b/src/pdclib/functions/stdio/sscanf.c @@ -0,0 +1,39 @@ +/* sscanf( const char *, const char *, ... ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdio.h> +#include <stdarg.h> + +#ifndef REGTEST + +int sscanf( const char * _PDCLIB_restrict s, const char * _PDCLIB_restrict format, ... ) +{ + int rc; + va_list ap; + va_start( ap, format ); + rc = vsscanf( s, format, ap ); + va_end( ap ); + return rc; +} + +#endif + +#ifdef TEST +#define _PDCLIB_FILEID "stdio/sscanf.c" +#define _PDCLIB_STRINGIO + +#include "_PDCLIB_test.h" + +#define testscanf( s, format, ... ) sscanf( s, format, __VA_ARGS__ ) + +int main( void ) +{ + char source[100]; +#include "scanf_testcases.h" + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdio/testfile.txt b/src/pdclib/functions/stdio/testfile.txt Binary files differnew file mode 100644 index 0000000..f08c4d3 --- /dev/null +++ b/src/pdclib/functions/stdio/testfile.txt diff --git a/src/pdclib/functions/stdio/tmpnam.c b/src/pdclib/functions/stdio/tmpnam.c new file mode 100644 index 0000000..5909aff --- /dev/null +++ b/src/pdclib/functions/stdio/tmpnam.c @@ -0,0 +1,42 @@ +/* tmpnam( char * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdio.h> + +#ifndef REGTEST + +#include "pdclib/_PDCLIB_glue.h" + +#include <string.h> + +char * tmpnam( char * s ) +{ + static char filename[ L_tmpnam ]; + FILE * file = tmpfile(); + if ( s == NULL ) + { + s = filename; + } + strcpy( s, file->filename ); + fclose( file ); + return s; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +#include <string.h> + +int main( void ) +{ + TESTCASE( strlen( tmpnam( NULL ) ) < L_tmpnam ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdio/ungetc.c b/src/pdclib/functions/stdio/ungetc.c new file mode 100644 index 0000000..dc5260b --- /dev/null +++ b/src/pdclib/functions/stdio/ungetc.c @@ -0,0 +1,32 @@ +/* ungetc( int, FILE * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdio.h> + +#ifndef REGTEST + +int ungetc( int c, struct _PDCLIB_file_t * stream ) +{ + if ( c == EOF || stream->ungetidx == _PDCLIB_UNGETCBUFSIZE ) + { + return -1; + } + return stream->ungetbuf[stream->ungetidx++] = (unsigned char) c; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + /* Testing covered by ftell.c */ + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdio/vfprintf.c b/src/pdclib/functions/stdio/vfprintf.c new file mode 100644 index 0000000..6f31bbd --- /dev/null +++ b/src/pdclib/functions/stdio/vfprintf.c @@ -0,0 +1,74 @@ +/* vfprintf( FILE *, const char *, va_list ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdio.h> +#include <stdarg.h> +#include <stdint.h> + +#ifndef REGTEST + +int vfprintf( struct _PDCLIB_file_t * _PDCLIB_restrict stream, const char * _PDCLIB_restrict format, va_list arg ) +{ + /* TODO: This function should interpret format as multibyte characters. */ + struct _PDCLIB_status_t status; + status.base = 0; + status.flags = 0; + status.n = SIZE_MAX; + status.i = 0; + status.current = 0; + status.s = NULL; + status.width = 0; + status.prec = EOF; + status.stream = stream; + va_copy( status.arg, arg ); + + while ( *format != '\0' ) + { + const char * rc; + if ( ( *format != '%' ) || ( ( rc = _PDCLIB_print( format, &status ) ) == format ) ) + { + /* No conversion specifier, print verbatim */ + putc( *(format++), stream ); + status.i++; + } + else + { + /* Continue parsing after conversion specifier */ + format = rc; + } + } + va_end( status.arg ); + return status.i; +} + +#endif + +#ifdef TEST +#define _PDCLIB_FILEID "stdio/vfprintf.c" +#define _PDCLIB_FILEIO +#include <stddef.h> +#include "_PDCLIB_test.h" + +static int testprintf( FILE * stream, const char * format, ... ) +{ + int i; + va_list arg; + va_start( arg, format ); + i = vfprintf( stream, format, arg ); + va_end( arg ); + return i; +} + +int main( void ) +{ + FILE * target; + TESTCASE( ( target = tmpfile() ) != NULL ); +#include "printf_testcases.h" + TESTCASE( fclose( target ) == 0 ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdio/vfscanf.c b/src/pdclib/functions/stdio/vfscanf.c new file mode 100644 index 0000000..bb24456 --- /dev/null +++ b/src/pdclib/functions/stdio/vfscanf.c @@ -0,0 +1,113 @@ +/* vfscanf( FILE *, const char *, va_list ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdio.h> +#include <stdarg.h> +#include <ctype.h> + +#ifndef REGTEST + +int vfscanf( FILE * _PDCLIB_restrict stream, const char * _PDCLIB_restrict format, va_list arg ) +{ + /* TODO: This function should interpret format as multibyte characters. */ + struct _PDCLIB_status_t status; + status.base = 0; + status.flags = 0; + status.n = 0; + status.i = 0; + status.current = 0; + status.s = NULL; + status.width = 0; + status.prec = EOF; + status.stream = stream; + va_copy( status.arg, arg ); + + while ( *format != '\0' ) + { + const char * rc; + if ( ( *format != '%' ) || ( ( rc = _PDCLIB_scan( format, &status ) ) == format ) ) + { + int c; + /* No conversion specifier, match verbatim */ + if ( isspace( *format ) ) + { + /* Whitespace char in format string: Skip all whitespaces */ + /* No whitespaces in input does not result in matching error */ + while ( isspace( c = getc( stream ) ) ) + { + ++status.i; + } + if ( ! feof( stream ) ) + { + ungetc( c, stream ); + } + } + else + { + /* Non-whitespace char in format string: Match verbatim */ + if ( ( ( c = getc( stream ) ) != *format ) || feof( stream ) ) + { + /* Matching error */ + if ( ! feof( stream ) && ! ferror( stream ) ) + { + ungetc( c, stream ); + } + else if ( status.n == 0 ) + { + return EOF; + } + return status.n; + } + else + { + ++status.i; + } + } + ++format; + } + else + { + /* NULL return code indicates matching error */ + if ( rc == NULL ) + { + break; + } + /* Continue parsing after conversion specifier */ + format = rc; + } + } + va_end( status.arg ); + return status.n; +} + +#endif + +#ifdef TEST +#define _PDCLIB_FILEID "stdio/vfscanf.c" +#define _PDCLIB_FILEIO + +#include "_PDCLIB_test.h" + +static int testscanf( FILE * stream, const char * format, ... ) +{ + va_list ap; + int result; + va_start( ap, format ); + result = vfscanf( stream, format, ap ); + va_end( ap ); + return result; +} + +int main( void ) +{ + FILE * source; + TESTCASE( ( source = tmpfile() ) != NULL ); +#include "scanf_testcases.h" + TESTCASE( fclose( source ) == 0 ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdio/vprintf.c b/src/pdclib/functions/stdio/vprintf.c new file mode 100644 index 0000000..fe80152 --- /dev/null +++ b/src/pdclib/functions/stdio/vprintf.c @@ -0,0 +1,46 @@ +/* vprintf( const char *, va_list ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdio.h> +#include <stdarg.h> + +#ifndef REGTEST + +int vprintf( const char * _PDCLIB_restrict format, _PDCLIB_va_list arg ) +{ + return vfprintf( stdout, format, arg ); +} + +#endif + +#ifdef TEST +#define _PDCLIB_FILEID "stdio/vprintf.c" +#define _PDCLIB_FILEIO +#include <stdint.h> +#include <stddef.h> +#include "_PDCLIB_test.h" + +static int testprintf( FILE * stream, const char * format, ... ) +{ + int i; + va_list arg; + va_start( arg, format ); + i = vprintf( format, arg ); + va_end( arg ); + return i; +} + +int main( void ) +{ + FILE * target; + TESTCASE( ( target = freopen( testfile, "wb+", stdout ) ) != NULL ); +#include "printf_testcases.h" + TESTCASE( fclose( target ) == 0 ); + TESTCASE( remove( testfile ) == 0 ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdio/vscanf.c b/src/pdclib/functions/stdio/vscanf.c new file mode 100644 index 0000000..d5ae5b3 --- /dev/null +++ b/src/pdclib/functions/stdio/vscanf.c @@ -0,0 +1,45 @@ +/* vscanf( const char *, va_list ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdio.h> +#include <stdarg.h> + +#ifndef REGTEST + +int vscanf( const char * _PDCLIB_restrict format, _PDCLIB_va_list arg ) +{ + return vfscanf( stdin, format, arg ); +} + +#endif + +#ifdef TEST +#define _PDCLIB_FILEID "stdio/vscanf.c" +#define _PDCLIB_FILEIO + +#include "_PDCLIB_test.h" + +static int testscanf( FILE * stream, const char * format, ... ) +{ + int i; + va_list arg; + va_start( arg, format ); + i = vscanf( format, arg ); + va_end( arg ); + return i; +} + +int main( void ) +{ + FILE * source; + TESTCASE( ( source = freopen( testfile, "wb+", stdin ) ) != NULL ); +#include "scanf_testcases.h" + TESTCASE( fclose( source ) == 0 ); + TESTCASE( remove( testfile ) == 0 ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdio/vsnprintf.c b/src/pdclib/functions/stdio/vsnprintf.c new file mode 100644 index 0000000..e57e682 --- /dev/null +++ b/src/pdclib/functions/stdio/vsnprintf.c @@ -0,0 +1,80 @@ +/* vsnprintf( char *, size_t, const char *, va_list ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdio.h> +#include <stdarg.h> + +#ifndef REGTEST + +int vsnprintf( char * _PDCLIB_restrict s, size_t n, const char * _PDCLIB_restrict format, _PDCLIB_va_list arg ) +{ + /* TODO: This function should interpret format as multibyte characters. */ + struct _PDCLIB_status_t status; + status.base = 0; + status.flags = 0; + status.n = n; + status.i = 0; + status.current = 0; + status.s = s; + status.width = 0; + status.prec = EOF; + status.stream = NULL; + va_copy( status.arg, arg ); + + while ( *format != '\0' ) + { + const char * rc; + if ( ( *format != '%' ) || ( ( rc = _PDCLIB_print( format, &status ) ) == format ) ) + { + /* No conversion specifier, print verbatim */ + if ( status.i < n ) + { + s[ status.i ] = *format; + } + status.i++; + format++; + } + else + { + /* Continue parsing after conversion specifier */ + format = rc; + } + } + if ( status.i < n ) + { + s[ status.i ] = '\0'; + } + va_end( status.arg ); + return status.i; +} + +#endif + +#ifdef TEST +#define _PDCLIB_FILEID "stdio/vsnprintf.c" +#define _PDCLIB_STRINGIO +#include <stdint.h> +#include <stddef.h> +#include "_PDCLIB_test.h" + +static int testprintf( char * s, const char * format, ... ) +{ + int i; + va_list arg; + va_start( arg, format ); + i = vsnprintf( s, 100, format, arg ); + va_end( arg ); + return i; +} + +int main( void ) +{ + char target[100]; +#include "printf_testcases.h" + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdio/vsprintf.c b/src/pdclib/functions/stdio/vsprintf.c new file mode 100644 index 0000000..4ab2742 --- /dev/null +++ b/src/pdclib/functions/stdio/vsprintf.c @@ -0,0 +1,44 @@ +/* vsprintf( char *, const char *, va_list ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdio.h> +#include <stdint.h> +#include <stdarg.h> + +#ifndef REGTEST + +int vsprintf( char * _PDCLIB_restrict s, const char * _PDCLIB_restrict format, va_list arg ) +{ + return vsnprintf( s, SIZE_MAX, format, arg ); /* TODO: Replace with a non-checking call */ +} + +#endif + +#ifdef TEST +#define _PDCLIB_FILEID "stdio/vsprintf.c" +#define _PDCLIB_STRINGIO +#include <stdint.h> +#include <stddef.h> +#include "_PDCLIB_test.h" + +static int testprintf( char * s, const char * format, ... ) +{ + int i; + va_list arg; + va_start( arg, format ); + i = vsprintf( s, format, arg ); + va_end( arg ); + return i; +} + +int main( void ) +{ + char target[100]; +#include "printf_testcases.h" + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdio/vsscanf.c b/src/pdclib/functions/stdio/vsscanf.c new file mode 100644 index 0000000..e76e70e --- /dev/null +++ b/src/pdclib/functions/stdio/vsscanf.c @@ -0,0 +1,109 @@ +/* vsscanf( const char *, const char *, va_list ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdio.h> +#include <stdarg.h> +#include <ctype.h> + +#ifndef REGTEST + +int vsscanf( const char * _PDCLIB_restrict s, const char * _PDCLIB_restrict format, va_list arg ) +{ + /* TODO: This function should interpret format as multibyte characters. */ + struct _PDCLIB_status_t status; + status.base = 0; + status.flags = 0; + status.n = 0; + status.i = 0; + status.current = 0; + status.s = (char *) s; + status.width = 0; + status.prec = EOF; + status.stream = NULL; + va_copy( status.arg, arg ); + + while ( *format != '\0' ) + { + const char * rc; + if ( ( *format != '%' ) || ( ( rc = _PDCLIB_scan( format, &status ) ) == format ) ) + { + /* No conversion specifier, match verbatim */ + if ( isspace( *format ) ) + { + /* Whitespace char in format string: Skip all whitespaces */ + /* No whitespaces in input do not result in matching error */ + while ( isspace( *status.s ) ) + { + ++status.s; + ++status.i; + } + } + else + { + /* Non-whitespace char in format string: Match verbatim */ + if ( *status.s != *format ) + { + if ( *status.s == '\0' && status.n == 0 ) + { + /* Early input error */ + return EOF; + } + /* Matching error */ + return status.n; + } + else + { + ++status.s; + ++status.i; + } + } + ++format; + } + else + { + /* NULL return code indicates error */ + if ( rc == NULL ) + { + if ( ( *status.s == '\n' ) && ( status.n == 0 ) ) + { + status.n = EOF; + } + break; + } + /* Continue parsing after conversion specifier */ + format = rc; + } + } + va_end( status.arg ); + return status.n; +} + +#endif + +#ifdef TEST +#define _PDCLIB_FILEID "stdio/vsscanf.c" +#define _PDCLIB_STRINGIO + +#include "_PDCLIB_test.h" + +static int testscanf( const char * stream, const char * format, ... ) +{ + va_list ap; + int result; + va_start( ap, format ); + result = vsscanf( stream, format, ap ); + va_end( ap ); + return result; +} + +int main( void ) +{ + char source[100]; +#include "scanf_testcases.h" + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdlib/_Exit.c b/src/pdclib/functions/stdlib/_Exit.c new file mode 100644 index 0000000..de387db --- /dev/null +++ b/src/pdclib/functions/stdlib/_Exit.c @@ -0,0 +1,36 @@ +/* _Exit( int ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdlib.h> +#include <stdio.h> + +#ifndef REGTEST + +#include "pdclib/_PDCLIB_glue.h" + +void _Exit( int status ) +{ + /* TODO: Flush and close open streams. Remove tmpfile() files. Make this + called on process termination automatically. + */ + _PDCLIB_Exit( status ); +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + int UNEXPECTED_RETURN = 0; + _Exit( 0 ); + TESTCASE( UNEXPECTED_RETURN ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdlib/abort.c b/src/pdclib/functions/stdlib/abort.c new file mode 100644 index 0000000..69422f9 --- /dev/null +++ b/src/pdclib/functions/stdlib/abort.c @@ -0,0 +1,40 @@ +/* abort( void ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdlib.h> +#include <signal.h> + +#ifndef REGTEST + +void abort( void ) +{ + raise( SIGABRT ); + exit( EXIT_FAILURE ); +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +#include <stdio.h> + +static void aborthandler( int sig ) +{ + exit( 0 ); +} + +int main( void ) +{ + int UNEXPECTED_RETURN_FROM_ABORT = 0; + TESTCASE( signal( SIGABRT, &aborthandler ) != SIG_ERR ); + abort(); + TESTCASE( UNEXPECTED_RETURN_FROM_ABORT ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdlib/abs.c b/src/pdclib/functions/stdlib/abs.c new file mode 100644 index 0000000..7a634e3 --- /dev/null +++ b/src/pdclib/functions/stdlib/abs.c @@ -0,0 +1,32 @@ +/* abs( int ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdlib.h> + +#ifndef REGTEST + +int abs( int j ) +{ + return ( j >= 0 ) ? j : -j; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +#include <limits.h> + +int main( void ) +{ + TESTCASE( abs( 0 ) == 0 ); + TESTCASE( abs( INT_MAX ) == INT_MAX ); + TESTCASE( abs( INT_MIN + 1 ) == -( INT_MIN + 1 ) ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdlib/atexit.c b/src/pdclib/functions/stdlib/atexit.c new file mode 100644 index 0000000..489c3df --- /dev/null +++ b/src/pdclib/functions/stdlib/atexit.c @@ -0,0 +1,64 @@ +/* atexit( void (*)( void ) ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdlib.h> + +#ifndef REGTEST + +extern void (*_PDCLIB_exitstack[])( void ); +extern size_t _PDCLIB_exitptr; + +int atexit( void (*func)( void ) ) +{ + if ( _PDCLIB_exitptr == 0 ) + { + return -1; + } + else + { + _PDCLIB_exitstack[ --_PDCLIB_exitptr ] = func; + return 0; + } +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +#include <assert.h> + +static int flags[ 32 ]; + +static void counthandler( void ) +{ + static int count = 0; + flags[ count ] = count; + ++count; +} + +static void checkhandler( void ) +{ + int i; + for ( i = 0; i < 31; ++i ) + { + assert( flags[ i ] == i ); + } +} + +int main( void ) +{ + int i; + TESTCASE( atexit( &checkhandler ) == 0 ); + for ( i = 0; i < 31; ++i ) + { + TESTCASE( atexit( &counthandler ) == 0 ); + } + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdlib/atoi.c b/src/pdclib/functions/stdlib/atoi.c new file mode 100644 index 0000000..eaa9100 --- /dev/null +++ b/src/pdclib/functions/stdlib/atoi.c @@ -0,0 +1,28 @@ +/* atoi( const char * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdlib.h> + +#ifndef REGTEST + +int atoi( const char * s ) +{ + return (int) _PDCLIB_atomax( s ); +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + /* no tests for a simple wrapper */ + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdlib/atol.c b/src/pdclib/functions/stdlib/atol.c new file mode 100644 index 0000000..df17e83 --- /dev/null +++ b/src/pdclib/functions/stdlib/atol.c @@ -0,0 +1,28 @@ +/* atol( const char * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdlib.h> + +#ifndef REGTEST + +long int atol( const char * s ) +{ + return (long int) _PDCLIB_atomax( s ); +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + /* no tests for a simple wrapper */ + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdlib/atoll.c b/src/pdclib/functions/stdlib/atoll.c new file mode 100644 index 0000000..8b65b35 --- /dev/null +++ b/src/pdclib/functions/stdlib/atoll.c @@ -0,0 +1,28 @@ +/* atoll( const char * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdlib.h> + +#ifndef REGTEST + +long long int atoll( const char * s ) +{ + return (long long int) _PDCLIB_atomax( s ); +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + /* no tests for a simple wrapper */ + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdlib/bsearch.c b/src/pdclib/functions/stdlib/bsearch.c new file mode 100644 index 0000000..211c55c --- /dev/null +++ b/src/pdclib/functions/stdlib/bsearch.c @@ -0,0 +1,61 @@ +/* bsearch( const void *, const void *, size_t, size_t, int(*)( const void *, const void * ) ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdlib.h> + +#ifndef REGTEST + +void * bsearch( const void * key, const void * base, size_t nmemb, size_t size, int (*compar)( const void *, const void * ) ) +{ + const void * pivot; + int rc; + size_t corr; + while ( nmemb ) + { + /* algorithm needs -1 correction if remaining elements are an even number. */ + corr = nmemb % 2; + nmemb /= 2; + pivot = (const char *)base + (nmemb * size); + rc = compar( key, pivot ); + if ( rc > 0 ) + { + base = (const char *)pivot + size; + /* applying correction */ + nmemb -= ( 1 - corr ); + } + else if ( rc == 0 ) + { + return (void *)pivot; + } + } + return NULL; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +static int compare( const void * left, const void * right ) +{ + return *( (unsigned char *)left ) - *( (unsigned char *)right ); +} + +int main( void ) +{ + TESTCASE( bsearch( "e", abcde, 4, 1, compare ) == NULL ); + TESTCASE( bsearch( "e", abcde, 5, 1, compare ) == &abcde[4] ); + TESTCASE( bsearch( "a", abcde + 1, 4, 1, compare ) == NULL ); + TESTCASE( bsearch( "0", abcde, 1, 1, compare ) == NULL ); + TESTCASE( bsearch( "a", abcde, 1, 1, compare ) == &abcde[0] ); + TESTCASE( bsearch( "a", abcde, 0, 1, compare ) == NULL ); + TESTCASE( bsearch( "e", abcde, 3, 2, compare ) == &abcde[4] ); + TESTCASE( bsearch( "b", abcde, 3, 2, compare ) == NULL ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdlib/calloc.c b/src/pdclib/functions/stdlib/calloc.c new file mode 100644 index 0000000..d736065 --- /dev/null +++ b/src/pdclib/functions/stdlib/calloc.c @@ -0,0 +1,48 @@ +/* void * calloc( size_t, size_t ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdlib.h> +#include <string.h> + +#ifndef REGTEST + +void * calloc( size_t nmemb, size_t size ) +{ + /* assign memory for nmemb elements of given size */ + void * rc = malloc( nmemb * size ); + if ( rc != NULL ) + { + /* zero-initialize the memory */ + memset( rc, 0, nmemb * size ); + } + return rc; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + char * s; + TESTCASE( ( s = calloc( 3, 2 ) ) != NULL ); + TESTCASE( s[0] == '\0' ); + TESTCASE( s[5] == '\0' ); + free( s ); + TESTCASE( ( s = calloc( 6, 1 ) ) != NULL ); + TESTCASE( s[0] == '\0' ); + TESTCASE( s[5] == '\0' ); + free( s ); + TESTCASE( ( s = calloc( 1, 6 ) ) != NULL ); + TESTCASE( s[0] == '\0' ); + TESTCASE( s[5] == '\0' ); + free( s ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdlib/div.c b/src/pdclib/functions/stdlib/div.c new file mode 100644 index 0000000..5d502c8 --- /dev/null +++ b/src/pdclib/functions/stdlib/div.c @@ -0,0 +1,40 @@ +/* div( int, int ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdlib.h> + +#ifndef REGTEST + +div_t div( int numer, int denom ) +{ + div_t rc; + rc.quot = numer / denom; + rc.rem = numer % denom; + /* TODO: pre-C99 compilers might require modulus corrections */ + return rc; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + div_t result; + result = div( 5, 2 ); + TESTCASE( result.quot == 2 && result.rem == 1 ); + result = div( -5, 2 ); + TESTCASE( result.quot == -2 && result.rem == -1 ); + result = div( 5, -2 ); + TESTCASE( result.quot == -2 && result.rem == 1 ); + TESTCASE( sizeof( result.quot ) == sizeof( int ) ); + TESTCASE( sizeof( result.rem ) == sizeof( int ) ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdlib/exit.c b/src/pdclib/functions/stdlib/exit.c new file mode 100644 index 0000000..e636a32 --- /dev/null +++ b/src/pdclib/functions/stdlib/exit.c @@ -0,0 +1,44 @@ +/* exit( int ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdlib.h> + +#ifndef REGTEST + +/* TODO - "except that a function is called after any previously registered + functions that had already been called at the time it was registered. +*/ + +/* TODO: 32 is guaranteed. This should be dynamic but ATM gives problems + with my malloc. +*/ +#define NUMBER_OF_SLOTS 40 + +void (*_PDCLIB_exitstack[ NUMBER_OF_SLOTS ])( void ) = { _PDCLIB_closeall }; +size_t _PDCLIB_exitptr = NUMBER_OF_SLOTS; + +void exit( int status ) +{ + while ( _PDCLIB_exitptr < NUMBER_OF_SLOTS ) + { + _PDCLIB_exitstack[ _PDCLIB_exitptr++ ](); + } + _Exit( status ); +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + /* Unwinding of regstack tested in atexit(). */ + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdlib/free.c b/src/pdclib/functions/stdlib/free.c new file mode 100644 index 0000000..126a17b --- /dev/null +++ b/src/pdclib/functions/stdlib/free.c @@ -0,0 +1,52 @@ +/* void free( void * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdlib.h> + +#ifndef REGTEST + +#include "pdclib/_PDCLIB_int.h" + +/* TODO: Primitive placeholder. Much room for improvement. */ + +/* structure holding first and last element of free node list */ +extern struct _PDCLIB_headnode_t _PDCLIB_memlist; + +void free( void * ptr ) +{ + if ( ptr == NULL ) + { + return; + } + ptr = (void *)( (char *)ptr - sizeof( struct _PDCLIB_memnode_t ) ); + ( (struct _PDCLIB_memnode_t *)ptr )->next = NULL; + if ( _PDCLIB_memlist.last != NULL ) + { + _PDCLIB_memlist.last->next = ptr; + } + else + { + _PDCLIB_memlist.first = ptr; + } + _PDCLIB_memlist.last = ptr; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +#include <stdbool.h> + +int main( void ) +{ + free( NULL ); + TESTCASE( true ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdlib/labs.c b/src/pdclib/functions/stdlib/labs.c new file mode 100644 index 0000000..3653453 --- /dev/null +++ b/src/pdclib/functions/stdlib/labs.c @@ -0,0 +1,32 @@ +/* labs( long int ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdlib.h> + +#ifndef REGTEST + +long int labs( long int j ) +{ + return ( j >= 0 ) ? j : -j; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +#include <limits.h> + +int main( void ) +{ + TESTCASE( labs( 0 ) == 0 ); + TESTCASE( labs( LONG_MAX ) == LONG_MAX ); + TESTCASE( labs( LONG_MIN + 1 ) == -( LONG_MIN + 1 ) ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdlib/ldiv.c b/src/pdclib/functions/stdlib/ldiv.c new file mode 100644 index 0000000..0f51944 --- /dev/null +++ b/src/pdclib/functions/stdlib/ldiv.c @@ -0,0 +1,40 @@ +/* ldiv( long int, long int ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdlib.h> + +#ifndef REGTEST + +ldiv_t ldiv( long int numer, long int denom ) +{ + ldiv_t rc; + rc.quot = numer / denom; + rc.rem = numer % denom; + /* TODO: pre-C99 compilers might require modulus corrections */ + return rc; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + ldiv_t result; + result = ldiv( 5, 2 ); + TESTCASE( result.quot == 2 && result.rem == 1 ); + result = ldiv( -5, 2 ); + TESTCASE( result.quot == -2 && result.rem == -1 ); + result = ldiv( 5, -2 ); + TESTCASE( result.quot == -2 && result.rem == 1 ); + TESTCASE( sizeof( result.quot ) == sizeof( long ) ); + TESTCASE( sizeof( result.rem ) == sizeof( long ) ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdlib/llabs.c b/src/pdclib/functions/stdlib/llabs.c new file mode 100644 index 0000000..bc05bf3 --- /dev/null +++ b/src/pdclib/functions/stdlib/llabs.c @@ -0,0 +1,32 @@ +/* llabs( long int ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdlib.h> + +#ifndef REGTEST + +long long int llabs( long long int j ) +{ + return ( j >= 0 ) ? j : -j; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +#include <limits.h> + +int main( void ) +{ + TESTCASE( llabs( 0ll ) == 0 ); + TESTCASE( llabs( LLONG_MAX ) == LLONG_MAX ); + TESTCASE( llabs( LLONG_MIN + 1 ) == -( LLONG_MIN + 1 ) ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdlib/lldiv.c b/src/pdclib/functions/stdlib/lldiv.c new file mode 100644 index 0000000..4219e31 --- /dev/null +++ b/src/pdclib/functions/stdlib/lldiv.c @@ -0,0 +1,40 @@ +/* lldiv( long long int, long long int ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdlib.h> + +#ifndef REGTEST + +lldiv_t lldiv( long long int numer, long long int denom ) +{ + lldiv_t rc; + rc.quot = numer / denom; + rc.rem = numer % denom; + /* TODO: pre-C99 compilers might require modulus corrections */ + return rc; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + lldiv_t result; + result = lldiv( 5ll, 2ll ); + TESTCASE( result.quot == 2 && result.rem == 1 ); + result = lldiv( -5ll, 2ll ); + TESTCASE( result.quot == -2 && result.rem == -1 ); + result = lldiv( 5ll, -2ll ); + TESTCASE( result.quot == -2 && result.rem == 1 ); + TESTCASE( sizeof( result.quot ) == sizeof( long long ) ); + TESTCASE( sizeof( result.rem ) == sizeof( long long ) ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdlib/malloc.c b/src/pdclib/functions/stdlib/malloc.c new file mode 100644 index 0000000..ed57e9a --- /dev/null +++ b/src/pdclib/functions/stdlib/malloc.c @@ -0,0 +1,427 @@ +/* void * malloc( size_t ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdlib.h> +#include <stdint.h> + +#ifndef REGTEST + +#include "pdclib/_PDCLIB_glue.h" + +/* TODO: Primitive placeholder. Much room for improvement. */ + +/* Keeping pointers to the first and the last element of the free list. */ +struct _PDCLIB_headnode_t _PDCLIB_memlist = { NULL, NULL }; + +void * malloc( size_t size ) +{ + if ( size == 0 ) + { + return NULL; + } + if ( size < _PDCLIB_MINALLOC ) + { + size = _PDCLIB_MINALLOC; + } + { + struct _PDCLIB_memnode_t * current = _PDCLIB_memlist.first; + struct _PDCLIB_memnode_t * previous = NULL; + struct _PDCLIB_memnode_t * firstfit = NULL; + struct _PDCLIB_memnode_t * firstfit_previous = NULL; + /* Trying exact fit */ + while ( current != NULL ) + { + if ( current->size == size ) + { + /* Found exact fit, allocate node */ + if ( previous != NULL ) + { + /* Node in the middle of the list */ + previous->next = current->next; + } + else + { + /* Node is first in list */ + _PDCLIB_memlist.first = current->next; + } + if ( _PDCLIB_memlist.last == current ) + { + /* Node is last in list */ + _PDCLIB_memlist.last = previous; + } + return (char *)current + sizeof( struct _PDCLIB_memnode_t ); + } + else if ( current->size > size && ( firstfit == NULL || current->size < firstfit->size ) ) + { + /* Remember previous node in case we do not get an exact fit. + Note that this is the node *pointing to* the first fit, + as we need that for allocating (i.e., changing next pointer). + */ + firstfit_previous = previous; + firstfit = current; + } + /* Skip to next node */ + previous = current; + current = current->next; + } + /* No exact fit; go for first fit */ + if ( firstfit != NULL ) + { + int node_split = 0; + if ( ( firstfit->size - size ) > ( _PDCLIB_MINALLOC + sizeof( struct _PDCLIB_memnode_t ) ) ) + { + /* Oversized - split into two nodes */ + struct _PDCLIB_memnode_t * newnode = (struct _PDCLIB_memnode_t *)( (char *)firstfit + sizeof( struct _PDCLIB_memnode_t ) + size ); + newnode->size = firstfit->size - size - sizeof( struct _PDCLIB_memnode_t ); + newnode->next = firstfit->next; + firstfit->next = newnode; + firstfit->size = firstfit->size - newnode->size - sizeof( struct _PDCLIB_memnode_t ); + node_split = 1; + } + if ( firstfit_previous != NULL ) + { + /* Node in the middle of the list */ + firstfit_previous->next = firstfit->next; + } + else + { + /* Node is first in list */ + _PDCLIB_memlist.first = firstfit->next; + } + if ( _PDCLIB_memlist.last == firstfit ) + { + /* Node is last in list */ + if ( node_split ) + { + _PDCLIB_memlist.last = firstfit->next; + } + else + { + _PDCLIB_memlist.last = firstfit_previous; + } + } + return (char *)firstfit + sizeof( struct _PDCLIB_memnode_t ); + } + } + { + /* No fit possible; how many additional pages do we need? */ + size_t pages = ( ( size + sizeof( struct _PDCLIB_memnode_t ) - 1 ) / _PDCLIB_PAGESIZE ) + 1; + /* Allocate more pages */ + struct _PDCLIB_memnode_t * newnode = (struct _PDCLIB_memnode_t *)_PDCLIB_allocpages( (int)pages ); + if ( newnode != NULL ) + { + newnode->next = NULL; + newnode->size = pages * _PDCLIB_PAGESIZE - sizeof( struct _PDCLIB_memnode_t ); + if ( ( newnode->size - size ) > ( _PDCLIB_MINALLOC + sizeof( struct _PDCLIB_memnode_t ) ) ) + { + /* Oversized - split into two nodes */ + struct _PDCLIB_memnode_t * splitnode = (struct _PDCLIB_memnode_t *)( (char *)newnode + sizeof( struct _PDCLIB_memnode_t ) + size ); + splitnode->size = newnode->size - size - sizeof( struct _PDCLIB_memnode_t ); + newnode->size = size; + /* Add splitted node as last element to free node list */ + if ( _PDCLIB_memlist.last == NULL ) + { + _PDCLIB_memlist.first = splitnode; + } + else + { + _PDCLIB_memlist.last->next = splitnode; + } + splitnode->next = NULL; /* TODO: This is bug #7, uncovered by testdriver yet. */ + _PDCLIB_memlist.last = splitnode; + } + return (char *)newnode + sizeof( struct _PDCLIB_memnode_t ); + } + } + /* No fit, heap extension not possible - out of memory */ + return NULL; +} + +#endif + + +#ifdef TEST +#include "_PDCLIB_test.h" +#include <string.h> +#include <stdarg.h> +#include <stdio.h> + + +#ifndef REGTEST + +/* Effective page size, i.e. how many bytes can be allocated and still be on + one page of memory. +*/ +#define EFFECTIVE _PDCLIB_PAGESIZE - sizeof( struct _PDCLIB_memnode_t ) +#define MEMTEST( ptr, size ) ( ( ptr = malloc( size ) ) != NULL ) && ( memset( ptr, 0, size ) == ptr ) + +char * pages_start = 0; +int test_nodes( const char * const, int, ... ); +void PRINT( const char * const, ... ); + +/* This can be enabled to give a dump of node information */ +#if 0 +void PRINT( const char * const format, ... ) +{ + va_list( ap ); + va_start( ap, format ); + vprintf( format, ap ); +} +#else +void PRINT( const char * const format, ... ) +{ + /* EMPTY */ +} +#endif + +/* Helper function checking number of allocated memory pages and the nodes + in the free memory list against expectations. +*/ +int test_nodes( const char * const action, int expected_pages, ... ) +{ + static int count = 1; + int result = 1; + /* Determining the amount of allocated pages */ + int allocated_pages = ( (intptr_t)_PDCLIB_allocpages( 0 ) - (intptr_t)pages_start ) / _PDCLIB_PAGESIZE; + PRINT( action ); + PRINT( "Test #%2d, %d allocated pages", count++, allocated_pages ); + if ( allocated_pages != expected_pages ) + { + PRINT( " - MISMATCH, expected\n %d pages\n", expected_pages ); + result = 0; + } + else + { + PRINT( "\n" ); + } + { + /* Now moving through the free nodes list */ + va_list( ap ); + struct _PDCLIB_memnode_t * tracer = _PDCLIB_memlist.first; + int firstnode = 0; + int lastnode = 0; + va_start( ap, expected_pages ); + while ( tracer != NULL ) + { + /* Expected data */ + size_t expected_location = va_arg( ap, size_t ); + /* Data from node */ + size_t node_location = (char *)tracer - (char *)pages_start; + PRINT( " - node %.4p, size %#.4x", node_location, tracer->size ); + if ( expected_location == 0 ) + { + PRINT( " - UNEXPECTED NODE\n" ); + result = 0; + continue; + } + /* Memorizing first and last expected node for later comparison. */ + if ( firstnode == 0 ) + { + firstnode = expected_location; + } + lastnode = expected_location; + { + /* Comparing expected node against current node */ + size_t expected_size = va_arg( ap, size_t ); + if ( ( node_location != expected_location ) || ( tracer->size != expected_size ) ) + { + PRINT( " - MISMATCH, expected values\n %.4p %#.4p\n", expected_location, expected_size ); + result = 0; + } + else + { + PRINT( "\n" ); + } + } + tracer = tracer->next; + } + /* Comparing first and last node in memlist against expectations. */ + PRINT( " - memlist first: %#.4x - last: %#.4x", + ( _PDCLIB_memlist.first == NULL ) ? NULL : (char *)_PDCLIB_memlist.first - (char *)pages_start, + ( _PDCLIB_memlist.last == NULL ) ? NULL : (char *)_PDCLIB_memlist.last - (char *)pages_start ); + if ( ( firstnode != 0 ) && + ( ( ( (char *)_PDCLIB_memlist.first - (char *)pages_start ) != firstnode ) + || ( ( (char *)_PDCLIB_memlist.last - (char *)pages_start ) != lastnode ) ) ) + { + PRINT( " - MISMATCH, expected values\n %#.4x - last: %#.4x\n", firstnode, lastnode ); + result = 0; + } + else + { + PRINT( "\n" ); + } + } + PRINT( "\n" ); + return result; +} + +#endif + +/* Note that this test driver heavily tests *internals* of the implementation + above (and of free() and realloc(), too). That means that changes in the + implementation must be accompanied with appropriate changes of the test + driver. It does *not* make a good regression tester for the implementation, + I am afraid, and thus there is no REGTEST equivalent. +*/ + +int main( void ) +{ +#ifndef REGTEST + void * ptr1, * ptr2, * ptr3, * ptr4, * ptr5, * ptr6, * ptr7, * ptr8, * ptr9, * ptrA, * ptrB, * ptrC; + + pages_start = _PDCLIB_allocpages( 0 ); + PRINT( "\nEffective is: %#.4x\nsizeof( memnode ) is: %#.2x\n\n", EFFECTIVE, sizeof( struct _PDCLIB_memnode_t ) ); + + /* Allocating 10 bytes; expecting one page allocation and a node split */ + TESTCASE( MEMTEST( ptr1, 10 ) ); + TESTCASE( test_nodes( "Allocating 10 bytes.", 1, + sizeof( struct _PDCLIB_memnode_t ) + 10, EFFECTIVE - sizeof( struct _PDCLIB_memnode_t ) - 10, + 0 ) ); + + /* Allocating the rest of the page; expecting no page allocation and assignment of the remaining node */ + TESTCASE( MEMTEST( ptr2, EFFECTIVE - 10 - sizeof( struct _PDCLIB_memnode_t ) ) ); + TESTCASE( test_nodes( "Allocating the rest of the page.", 1, + 0 ) ); + + /* Allocating a full page; expecting one page allocation, no node split */ + TESTCASE( MEMTEST( ptr3, EFFECTIVE ) ); + TESTCASE( test_nodes( "Allocating a full page.", 2, + 0 ) ); + + /* Allocating *almost* a full page; expecting one page allocation, no node split */ + TESTCASE( MEMTEST( ptr4, EFFECTIVE - 4 ) ); + TESTCASE( test_nodes( "Allocating *almost* a full page.", 3, + 0 ) ); + + /* Freeing and re-allocating the "almost" full page; expecting no page allocation, no node split */ + free( ptr4 ); + TESTCASE( MEMTEST( ptr5, EFFECTIVE - 4 ) ); + TESTCASE( ptr4 == ptr5 ); + TESTCASE( test_nodes( "Freeing and re-allocating the \"almost\" full page.", 3 ) ); + + /* Freeing the full page from test #3; expecting a full-sized free node. */ + free( ptr3 ); + TESTCASE( test_nodes( "Freeing the full page from test #3.", 3, + _PDCLIB_PAGESIZE * 1, EFFECTIVE, + 0 ) ); + + /* Allocating two full pages; expecting two page allocations, no node split */ + TESTCASE( MEMTEST( ptr3, EFFECTIVE + _PDCLIB_PAGESIZE ) ); + TESTCASE( test_nodes( "Allocating two full pages.", 5, + _PDCLIB_PAGESIZE * 1, EFFECTIVE, + 0 ) ); + + /* Re-allocating to size of 10 bytes; expecting no page allocation, no node split */ + /* TODO: Shouldn't realloc() split the now much-too-large node? */ + TESTCASE( realloc( ptr3, 10 ) == ptr3 ); + TESTCASE( test_nodes( "Re-allocating to size of 10 bytes.", 5, + _PDCLIB_PAGESIZE * 1, EFFECTIVE, + 0 ) ); + + /* Re-allocating to size of two full pages; expecting no page allocation, no node split */ + TESTCASE( realloc( ptr3, EFFECTIVE + _PDCLIB_PAGESIZE ) == ptr3 ); + TESTCASE( test_nodes( "Re-allocating to size of two full pages.", 5, + _PDCLIB_PAGESIZE * 1, EFFECTIVE, + 0 ) ); + + /* Re-allocating to size of three full pages; expecting three page allocation, freeing of two-page node */ + TESTCASE( realloc( ptr3, EFFECTIVE + _PDCLIB_PAGESIZE * 2 ) != ptr3 ); + TESTCASE( test_nodes( "Re-allocating to size of three full pages.", 8, + _PDCLIB_PAGESIZE * 1, EFFECTIVE, + _PDCLIB_PAGESIZE * 3, EFFECTIVE + _PDCLIB_PAGESIZE, + 0 ) ); + + /* Allocating two full pages; expecting allocation of the available two-page node */ + TESTCASE( MEMTEST( ptr4, EFFECTIVE + _PDCLIB_PAGESIZE ) ); + TESTCASE( test_nodes( "Allocating two full pages.", 8, + _PDCLIB_PAGESIZE * 1, EFFECTIVE, + 0 ) ); + + /* Allocating zero bytes; expecting no change */ + TESTCASE( ! MEMTEST( ptr6, 0 ) ); + TESTCASE( test_nodes( "Allocating zero bytes.", 8, + _PDCLIB_PAGESIZE * 1, EFFECTIVE, + 0 ) ); + + /* Allocating 4 bytes; expecting upsizing of requestupsizing of size, node split */ + TESTCASE( MEMTEST( ptr7, 4 ) ); + TESTCASE( test_nodes( "Allocating 4 bytes.", 8, + _PDCLIB_PAGESIZE * 1 + _PDCLIB_MINALLOC + sizeof( struct _PDCLIB_memnode_t ), + EFFECTIVE - _PDCLIB_MINALLOC - sizeof( struct _PDCLIB_memnode_t ), + 0 ) ); + + /* Allocating the rest of the page; expecting no page allocation and assignment of the remaining node */ + TESTCASE( MEMTEST( ptr8, EFFECTIVE - _PDCLIB_MINALLOC - sizeof( struct _PDCLIB_memnode_t ) ) ); + TESTCASE( test_nodes( "Allocating the rest of the page.", 8, 0 ) ); + + /* Freeing the node from the previous test; expecting node to re-appear in free list */ + free( ptr8 ); + TESTCASE( test_nodes( "Freeing the node from the previous test.", 8, + _PDCLIB_PAGESIZE * 1 + _PDCLIB_MINALLOC + sizeof( struct _PDCLIB_memnode_t ), + EFFECTIVE - _PDCLIB_MINALLOC - sizeof( struct _PDCLIB_memnode_t ), + 0 ) ); + + /* Allocating one byte more than available in free node; expecting page allocation */ + TESTCASE( MEMTEST( ptr8, EFFECTIVE + 1 - _PDCLIB_MINALLOC - sizeof( struct _PDCLIB_memnode_t ) ) ); + TESTCASE( test_nodes( "Allocating one byte more than available in free node.", 9, + _PDCLIB_PAGESIZE * 1 + _PDCLIB_MINALLOC + sizeof( struct _PDCLIB_memnode_t ), + EFFECTIVE - _PDCLIB_MINALLOC - sizeof( struct _PDCLIB_memnode_t ), + 0 ) ); + + /* Re-allocating with NULL pointer; expecting no page allocation, no node split */ + ptr9 = realloc( NULL, EFFECTIVE - _PDCLIB_MINALLOC - sizeof( struct _PDCLIB_memnode_t ) ); + TESTCASE( ptr9 != NULL ); + TESTCASE( memset( ptr9, 0, EFFECTIVE - _PDCLIB_MINALLOC - sizeof( struct _PDCLIB_memnode_t ) ) == ptr9 ); + TESTCASE( test_nodes( "Re-allocating with NULL pointer.", 9, 0 ) ); + + /* Allocating a bit more than half a page; expecting page allocation, node split */ +#define TESTSIZE 3000 + TESTCASE( MEMTEST( ptrA, TESTSIZE ) ); + TESTCASE( test_nodes( "Allocating a bit more than half a page.", 10, + _PDCLIB_PAGESIZE * 9 + sizeof( struct _PDCLIB_memnode_t ) + TESTSIZE, + EFFECTIVE - sizeof( struct _PDCLIB_memnode_t ) - TESTSIZE, + 0 ) ); + + /* Allocating a bit more than half a page; expecting page allocation, node split */ + TESTCASE( MEMTEST( ptrB, TESTSIZE ) ); + TESTCASE( test_nodes( "Allocating a bit more than half a page.", 11, + _PDCLIB_PAGESIZE * 9 + sizeof( struct _PDCLIB_memnode_t ) + TESTSIZE, + EFFECTIVE - sizeof( struct _PDCLIB_memnode_t ) - TESTSIZE, + _PDCLIB_PAGESIZE * 10 + sizeof( struct _PDCLIB_memnode_t ) + TESTSIZE, + EFFECTIVE - sizeof( struct _PDCLIB_memnode_t ) - TESTSIZE, + 0 ) ); + + /* Allocating a bit more than half a page; expecting page allocation, node split */ + TESTCASE( MEMTEST( ptrC, TESTSIZE ) ); + TESTCASE( test_nodes( "Allocating a bit more than half a page.", 12, + _PDCLIB_PAGESIZE * 9 + sizeof( struct _PDCLIB_memnode_t ) + TESTSIZE, + EFFECTIVE - sizeof( struct _PDCLIB_memnode_t ) - TESTSIZE, + _PDCLIB_PAGESIZE * 10 + sizeof( struct _PDCLIB_memnode_t ) + TESTSIZE, + EFFECTIVE - sizeof( struct _PDCLIB_memnode_t ) - TESTSIZE, + _PDCLIB_PAGESIZE * 11 + sizeof( struct _PDCLIB_memnode_t ) + TESTSIZE, + EFFECTIVE - sizeof( struct _PDCLIB_memnode_t ) - TESTSIZE, + 0 ) ); + + /* Freeing the middle node */ + free( ptrB ); + TESTCASE( test_nodes( "Freeing the middle node.", 12, + _PDCLIB_PAGESIZE * 9 + sizeof( struct _PDCLIB_memnode_t ) + TESTSIZE, + EFFECTIVE - sizeof( struct _PDCLIB_memnode_t ) - TESTSIZE, + _PDCLIB_PAGESIZE * 10 + sizeof( struct _PDCLIB_memnode_t ) + TESTSIZE, + EFFECTIVE - sizeof( struct _PDCLIB_memnode_t ) - TESTSIZE, + _PDCLIB_PAGESIZE * 11 + sizeof( struct _PDCLIB_memnode_t ) + TESTSIZE, + EFFECTIVE - sizeof( struct _PDCLIB_memnode_t ) - TESTSIZE, + _PDCLIB_PAGESIZE * 10, + TESTSIZE, + 0 ) ); + +#else + puts( " NOTEST malloc() test driver is PDCLib-specific." ); +#endif + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdlib/qsort.c b/src/pdclib/functions/stdlib/qsort.c new file mode 100644 index 0000000..d28f74c --- /dev/null +++ b/src/pdclib/functions/stdlib/qsort.c @@ -0,0 +1,166 @@ +/* qsort( void *, size_t, size_t, int(*)( const void *, const void * ) ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdlib.h> + +#ifndef REGTEST + +/* This implementation is taken from Paul Edward's PDPCLIB. + + Original code is credited to Raymond Gardner, Englewood CO. + Minor mods are credited to Paul Edwards. + Some reformatting and simplification done by Martin Baute. + All code is still Public Domain. +*/ + +/* Wrapper for _PDCLIB_memswp protects against multiple argument evaluation. */ +static _PDCLIB_inline void memswp( char * i, char * j, size_t size ) +{ + _PDCLIB_memswp( i, j, size ); +} + +/* For small sets, insertion sort is faster than quicksort. + T is the threshold below which insertion sort will be used. + Must be 3 or larger. +*/ +#define T 7 + +/* Macros for handling the QSort stack */ +#define PREPARE_STACK char * stack[STACKSIZE]; char * * stackptr = stack +#define PUSH( base, limit ) stackptr[0] = base; stackptr[1] = limit; stackptr += 2 +#define POP( base, limit ) stackptr -= 2; base = stackptr[0]; limit = stackptr[1] +/* TODO: Stack usage is log2( nmemb ) (minus what T shaves off the worst case). + Worst-case nmemb is platform dependent and should probably be + configured through _PDCLIB_config.h. +*/ +#define STACKSIZE 64 + +void qsort( void * base, size_t nmemb, size_t size, int (*compar)( const void *, const void * ) ) +{ + char * i; + char * j; + _PDCLIB_size_t thresh = T * size; + char * base_ = (char *)base; + char * limit = base_ + nmemb * size; + PREPARE_STACK; + + for ( ;; ) + { + if ( (size_t)( limit - base_ ) > thresh ) /* QSort for more than T elements. */ + { + /* We work from second to last - first will be pivot element. */ + i = base_ + size; + j = limit - size; + /* We swap first with middle element, then sort that with second + and last element so that eventually first element is the median + of the three - avoiding pathological pivots. + TODO: Instead of middle element, chose one randomly. + */ + memswp( ( ( ( (size_t)( limit - base_ ) ) / size ) / 2 ) * size + base_, base_, size ); + if ( compar( i, j ) > 0 ) memswp( i, j, size ); + if ( compar( base_, j ) > 0 ) memswp( base_, j, size ); + if ( compar( i, base_ ) > 0 ) memswp( i, base_, size ); + /* Now we have the median for pivot element, entering main Quicksort. */ + for ( ;; ) + { + do + { + /* move i right until *i >= pivot */ + i += size; + } while ( compar( i, base_ ) < 0 ); + do + { + /* move j left until *j <= pivot */ + j -= size; + } while ( compar( j, base_ ) > 0 ); + if ( i > j ) + { + /* break loop if pointers crossed */ + break; + } + /* else swap elements, keep scanning */ + memswp( i, j, size ); + } + /* move pivot into correct place */ + memswp( base_, j, size ); + /* larger subfile base / limit to stack, sort smaller */ + if ( j - base_ > limit - i ) + { + /* left is larger */ + PUSH( base_, j ); + base_ = i; + } + else + { + /* right is larger */ + PUSH( i, limit ); + limit = j; + } + } + else /* insertion sort for less than T elements */ + { + for ( j = base_, i = j + size; i < limit; j = i, i += size ) + { + for ( ; compar( j, j + size ) > 0; j -= size ) + { + memswp( j, j + size, size ); + if ( j == base_ ) + { + break; + } + } + } + if ( stackptr != stack ) /* if any entries on stack */ + { + POP( base_, limit ); + } + else /* else stack empty, done */ + { + break; + } + } + } +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +#include <string.h> +#include <limits.h> + +static int compare( const void * left, const void * right ) +{ + return *( (unsigned char *)left ) - *( (unsigned char *)right ); +} + +int main( void ) +{ + char presort[] = { "shreicnyjqpvozxmbt" }; + char sorted1[] = { "bcehijmnopqrstvxyz" }; + char sorted2[] = { "bticjqnyozpvreshxm" }; + char s[19]; + strcpy( s, presort ); + qsort( s, 18, 1, compare ); + TESTCASE( strcmp( s, sorted1 ) == 0 ); + strcpy( s, presort ); + qsort( s, 9, 2, compare ); + TESTCASE( strcmp( s, sorted2 ) == 0 ); + strcpy( s, presort ); + qsort( s, 1, 1, compare ); + TESTCASE( strcmp( s, presort ) == 0 ); +#if defined( REGTEST ) && ( defined( __BSD_VISIBLE ) || defined( __APPLE__ ) ) + puts( "qsort.c: Skipping test #4 for BSD as it goes into endless loop here." ); +#else + qsort( s, 100, 0, compare ); + TESTCASE( strcmp( s, presort ) == 0 ); +#endif + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdlib/rand.c b/src/pdclib/functions/stdlib/rand.c new file mode 100644 index 0000000..779b3b2 --- /dev/null +++ b/src/pdclib/functions/stdlib/rand.c @@ -0,0 +1,34 @@ +/* rand( void ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdlib.h> + +#ifndef REGTEST + +int rand( void ) +{ + _PDCLIB_seed = _PDCLIB_seed * 1103515245 + 12345; + return (int)( _PDCLIB_seed / 65536 ) % 32768; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + int rnd1, rnd2; + TESTCASE( ( rnd1 = rand() ) < RAND_MAX ); + TESTCASE( ( rnd2 = rand() ) < RAND_MAX ); + srand( 1 ); + TESTCASE( rand() == rnd1 ); + TESTCASE( rand() == rnd2 ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdlib/realloc.c b/src/pdclib/functions/stdlib/realloc.c new file mode 100644 index 0000000..cbc01d4 --- /dev/null +++ b/src/pdclib/functions/stdlib/realloc.c @@ -0,0 +1,56 @@ +/* void * realloc( void *, size_t ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdlib.h> +#include <string.h> +#include <stddef.h> + +#ifndef REGTEST + +/* TODO: Primitive placeholder. Improve. */ + +void * realloc( void * ptr, size_t size ) +{ + void * newptr = NULL; + if ( ptr == NULL ) + { + return malloc( size ); + } + if ( size > 0 ) + { + struct _PDCLIB_memnode_t * baseptr = (struct _PDCLIB_memnode_t *)( (char *)ptr - sizeof( struct _PDCLIB_memnode_t ) ); + if ( baseptr->size >= size ) + { + /* Current memnode is large enough; nothing to do. */ + return ptr; + } + else + { + /* Get larger memnode and copy over contents. */ + if ( ( newptr = malloc( size ) ) == NULL ) + { + return NULL; + } + memcpy( newptr, ptr, baseptr->size ); + } + } + free( ptr ); + return newptr; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + /* tests covered in malloc test driver */ + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdlib/srand.c b/src/pdclib/functions/stdlib/srand.c new file mode 100644 index 0000000..39c37ec --- /dev/null +++ b/src/pdclib/functions/stdlib/srand.c @@ -0,0 +1,28 @@ +/* srand( unsigned int ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdlib.h> + +#ifndef REGTEST + +void srand( unsigned int seed ) +{ + _PDCLIB_seed = seed; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + /* tested in rand.c */ + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdlib/strtol.c b/src/pdclib/functions/stdlib/strtol.c new file mode 100644 index 0000000..d89a648 --- /dev/null +++ b/src/pdclib/functions/stdlib/strtol.c @@ -0,0 +1,129 @@ +/* strtol( const char *, char * *, int ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <limits.h> +#include <stdlib.h> + +#ifndef REGTEST + +#include <stdint.h> + +long int strtol( const char * s, char ** endptr, int base ) +{ + long int rc; + char sign = '+'; + const char * p = _PDCLIB_strtox_prelim( s, &sign, &base ); + if ( base < 2 || base > 36 ) return 0; + if ( sign == '+' ) + { + rc = (long int)_PDCLIB_strtox_main( &p, (unsigned)base, (uintmax_t)LONG_MAX, (uintmax_t)( LONG_MAX / base ), (int)( LONG_MAX % base ), &sign ); + } + else + { + rc = (long int)_PDCLIB_strtox_main( &p, (unsigned)base, (uintmax_t)LONG_MIN, (uintmax_t)( LONG_MIN / -base ), (int)( -( LONG_MIN % base ) ), &sign ); + } + if ( endptr != NULL ) *endptr = ( p != NULL ) ? (char *) p : (char *) s; + return ( sign == '+' ) ? rc : -rc; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +#include <errno.h> + +int main( void ) +{ + char * endptr; + /* this, to base 36, overflows even a 256 bit integer */ + char overflow[] = "-ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ_"; + /* tricky border case */ + char tricky[] = "+0xz"; + errno = 0; + /* basic functionality */ + TESTCASE( strtol( "123", NULL, 10 ) == 123 ); + /* proper detecting of default base 10 */ + TESTCASE( strtol( "456", NULL, 0 ) == 456 ); + /* proper functioning to smaller base */ + TESTCASE( strtol( "14", NULL, 8 ) == 12 ); + /* proper autodetecting of octal */ + TESTCASE( strtol( "016", NULL, 0 ) == 14 ); + /* proper autodetecting of hexadecimal, lowercase 'x' */ + TESTCASE( strtol( "0xFF", NULL, 0 ) == 255 ); + /* proper autodetecting of hexadecimal, uppercase 'X' */ + TESTCASE( strtol( "0Xa1", NULL, 0 ) == 161 ); + /* proper handling of border case: 0x followed by non-hexdigit */ + TESTCASE( strtol( tricky, &endptr, 0 ) == 0 ); + TESTCASE( endptr == tricky + 2 ); + /* proper handling of border case: 0 followed by non-octdigit */ + TESTCASE( strtol( tricky, &endptr, 8 ) == 0 ); + TESTCASE( endptr == tricky + 2 ); + /* errno should still be 0 */ + TESTCASE( errno == 0 ); + /* overflowing subject sequence must still return proper endptr */ + TESTCASE( strtol( overflow, &endptr, 36 ) == LONG_MIN ); + TESTCASE( errno == ERANGE ); + TESTCASE( ( endptr - overflow ) == 53 ); + /* same for positive */ + errno = 0; + TESTCASE( strtol( overflow + 1, &endptr, 36 ) == LONG_MAX ); + TESTCASE( errno == ERANGE ); + TESTCASE( ( endptr - overflow ) == 53 ); + /* testing skipping of leading whitespace */ + TESTCASE( strtol( " \n\v\t\f789", NULL, 0 ) == 789 ); + /* testing conversion failure */ + TESTCASE( strtol( overflow, &endptr, 10 ) == 0 ); + TESTCASE( endptr == overflow ); + endptr = NULL; + TESTCASE( strtol( overflow, &endptr, 0 ) == 0 ); + TESTCASE( endptr == overflow ); + /* TODO: These tests assume two-complement, but conversion should work */ + /* for one-complement and signed magnitude just as well. Anyone having */ + /* a platform to test this on? */ + errno = 0; +#if LONG_MAX >> 30 == 1 + /* testing "even" overflow, i.e. base is power of two */ + TESTCASE( strtol( "2147483647", NULL, 0 ) == 0x7fffffff ); + TESTCASE( errno == 0 ); + errno = 0; + TESTCASE( strtol( "2147483648", NULL, 0 ) == LONG_MAX ); + TESTCASE( errno == ERANGE ); + errno = 0; + TESTCASE( strtol( "-2147483647", NULL, 0 ) == (long)0x80000001 ); + TESTCASE( errno == 0 ); + errno = 0; + TESTCASE( strtol( "-2147483648", NULL, 0 ) == LONG_MIN ); + TESTCASE( errno == 0 ); + errno = 0; + TESTCASE( strtol( "-2147483649", NULL, 0 ) == LONG_MIN ); + TESTCASE( errno == ERANGE ); + /* TODO: test "odd" overflow, i.e. base is not power of two */ +#elif LONG_MAX >> 62 == 1 + /* testing "even" overflow, i.e. base is power of two */ + TESTCASE( strtol( "9223372036854775807", NULL, 0 ) == 0x7fffffffffffffff ); + TESTCASE( errno == 0 ); + errno = 0; + TESTCASE( strtol( "9223372036854775808", NULL, 0 ) == LONG_MAX ); + TESTCASE( errno == ERANGE ); + errno = 0; + TESTCASE( strtol( "-9223372036854775807", NULL, 0 ) == (long)0x8000000000000001 ); + TESTCASE( errno == 0 ); + errno = 0; + TESTCASE( strtol( "-9223372036854775808", NULL, 0 ) == LONG_MIN ); + TESTCASE( errno == 0 ); + errno = 0; + TESTCASE( strtol( "-9223372036854775809", NULL, 0 ) == LONG_MIN ); + TESTCASE( errno == ERANGE ); + /* TODO: test "odd" overflow, i.e. base is not power of two */ +#else +#error Unsupported width of 'long' (neither 32 nor 64 bit). +#endif + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdlib/strtoll.c b/src/pdclib/functions/stdlib/strtoll.c new file mode 100644 index 0000000..24c3e8e --- /dev/null +++ b/src/pdclib/functions/stdlib/strtoll.c @@ -0,0 +1,123 @@ +/* strtoll( const char *, char * *, int ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <limits.h> +#include <stdlib.h> + +#ifndef REGTEST + +#include <stdint.h> + +long long int strtoll( const char * s, char ** endptr, int base ) +{ + long long int rc; + char sign = '+'; + const char * p = _PDCLIB_strtox_prelim( s, &sign, &base ); + if ( base < 2 || base > 36 ) return 0; + if ( sign == '+' ) + { + rc = (long long int)_PDCLIB_strtox_main( &p, (unsigned)base, (uintmax_t)LLONG_MAX, (uintmax_t)( LLONG_MAX / base ), (int)( LLONG_MAX % base ), &sign ); + } + else + { + rc = (long long int)_PDCLIB_strtox_main( &p, (unsigned)base, (uintmax_t)LLONG_MIN, (uintmax_t)( LLONG_MIN / -base ), (int)( -( LLONG_MIN % base ) ), &sign ); + } + if ( endptr != NULL ) *endptr = ( p != NULL ) ? (char *) p : (char *) s; + return ( sign == '+' ) ? rc : -rc; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +#include <errno.h> + +int main( void ) +{ + char * endptr; + /* this, to base 36, overflows even a 256 bit integer */ + char overflow[] = "-ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ_"; + /* tricky border case */ + char tricky[] = "+0xz"; + errno = 0; + /* basic functionality */ + TESTCASE( strtoll( "123", NULL, 10 ) == 123 ); + /* proper detecting of default base 10 */ + TESTCASE( strtoll( "456", NULL, 0 ) == 456 ); + /* proper functioning to smaller base */ + TESTCASE( strtoll( "14", NULL, 8 ) == 12 ); + /* proper autodetecting of octal */ + TESTCASE( strtoll( "016", NULL, 0 ) == 14 ); + /* proper autodetecting of hexadecimal, lowercase 'x' */ + TESTCASE( strtoll( "0xFF", NULL, 0 ) == 255 ); + /* proper autodetecting of hexadecimal, uppercase 'X' */ + TESTCASE( strtoll( "0Xa1", NULL, 0 ) == 161 ); + /* proper handling of border case: 0x followed by non-hexdigit */ + TESTCASE( strtoll( tricky, &endptr, 0 ) == 0 ); + TESTCASE( endptr == tricky + 2 ); + /* proper handling of border case: 0 followed by non-octdigit */ + TESTCASE( strtoll( tricky, &endptr, 8 ) == 0 ); + TESTCASE( endptr == tricky + 2 ); + /* errno should still be 0 */ + TESTCASE( errno == 0 ); + /* overflowing subject sequence must still return proper endptr */ + TESTCASE( strtoll( overflow, &endptr, 36 ) == LLONG_MIN ); + TESTCASE( errno == ERANGE ); + TESTCASE( ( endptr - overflow ) == 53 ); + /* same for positive */ + errno = 0; + TESTCASE( strtoll( overflow + 1, &endptr, 36 ) == LLONG_MAX ); + TESTCASE( errno == ERANGE ); + TESTCASE( ( endptr - overflow ) == 53 ); + /* testing skipping of leading whitespace */ + TESTCASE( strtoll( " \n\v\t\f789", NULL, 0 ) == 789 ); + /* testing conversion failure */ + TESTCASE( strtoll( overflow, &endptr, 10 ) == 0 ); + TESTCASE( endptr == overflow ); + endptr = NULL; + TESTCASE( strtoll( overflow, &endptr, 0 ) == 0 ); + TESTCASE( endptr == overflow ); + /* TODO: These tests assume two-complement, but conversion should work */ + /* for one-complement and signed magnitude just as well. Anyone having */ + /* a platform to test this on? */ + errno = 0; +#if LLONG_MAX >> 62 == 1 + /* testing "even" overflow, i.e. base is power of two */ + TESTCASE( strtoll( "9223372036854775807", NULL, 0 ) == 0x7fffffffffffffff ); + TESTCASE( errno == 0 ); + TESTCASE( strtoll( "9223372036854775808", NULL, 0 ) == LLONG_MAX ); + TESTCASE( errno == ERANGE ); + errno = 0; + TESTCASE( strtoll( "-9223372036854775807", NULL, 0 ) == (long long)0x8000000000000001 ); + TESTCASE( errno == 0 ); + TESTCASE( strtoll( "-9223372036854775808", NULL, 0 ) == LLONG_MIN ); + TESTCASE( errno == 0 ); + TESTCASE( strtoll( "-9223372036854775809", NULL, 0 ) == LLONG_MIN ); + TESTCASE( errno == ERANGE ); + /* TODO: test "odd" overflow, i.e. base is not power of two */ +#elif LLONG_MAX >> 126 == 1 + /* testing "even" overflow, i.e. base is power of two */ + TESTCASE( strtoll( "170141183460469231731687303715884105728", NULL, 0 ) == 0x7fffffffffffffffffffffffffffffff ); + TESTCASE( errno == 0 ); + TESTCASE( strtoll( "170141183460469231731687303715884105729", NULL, 0 ) == LLONG_MAX ); + TESTCASE( errno == ERANGE ); + errno = 0; + TESTCASE( strtoll( "-170141183460469231731687303715884105728", NULL, 0 ) == -0x80000000000000000000000000000001 ); + TESTCASE( errno == 0 ); + TESTCASE( strtoll( "-170141183460469231731687303715884105729", NULL, 0 ) == LLONG_MIN ); + TESTCASE( errno == 0 ); + TESTCASE( strtoll( "-170141183460469231731687303715884105730", NULL, 0 ) == LLONG_MIN ); + TESTCASE( errno == ERANGE ); + /* TODO: test "odd" overflow, i.e. base is not power of two */ +#else +#error Unsupported width of 'long long' (neither 64 nor 128 bit). +#endif + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdlib/strtoul.c b/src/pdclib/functions/stdlib/strtoul.c new file mode 100644 index 0000000..1a93477 --- /dev/null +++ b/src/pdclib/functions/stdlib/strtoul.c @@ -0,0 +1,106 @@ +/* strtoul( const char *, char * *, int ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <limits.h> +#include <stdlib.h> + +#ifndef REGTEST + +#include <stdint.h> + +unsigned long int strtoul( const char * s, char ** endptr, int base ) +{ + unsigned long int rc; + char sign = '+'; + const char * p = _PDCLIB_strtox_prelim( s, &sign, &base ); + if ( base < 2 || base > 36 ) return 0; + rc = (unsigned long int)_PDCLIB_strtox_main( &p, (unsigned)base, (uintmax_t)ULONG_MAX, (uintmax_t)( ULONG_MAX / base ), (int)( ULONG_MAX % base ), &sign ); + if ( endptr != NULL ) *endptr = ( p != NULL ) ? (char *) p : (char *) s; + return ( sign == '+' ) ? rc : -rc; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +#include <errno.h> + +int main( void ) +{ + char * endptr; + /* this, to base 36, overflows even a 256 bit integer */ + char overflow[] = "-ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ_"; + /* tricky border case */ + char tricky[] = "+0xz"; + errno = 0; + /* basic functionality */ + TESTCASE( strtoul( "123", NULL, 10 ) == 123 ); + /* proper detecting of default base 10 */ + TESTCASE( strtoul( "456", NULL, 0 ) == 456 ); + /* proper functioning to smaller base */ + TESTCASE( strtoul( "14", NULL, 8 ) == 12 ); + /* proper autodetecting of octal */ + TESTCASE( strtoul( "016", NULL, 0 ) == 14 ); + /* proper autodetecting of hexadecimal, lowercase 'x' */ + TESTCASE( strtoul( "0xFF", NULL, 0 ) == 255 ); + /* proper autodetecting of hexadecimal, uppercase 'X' */ + TESTCASE( strtoul( "0Xa1", NULL, 0 ) == 161 ); + /* proper handling of border case: 0x followed by non-hexdigit */ + TESTCASE( strtoul( tricky, &endptr, 0 ) == 0 ); + TESTCASE( endptr == tricky + 2 ); + /* proper handling of border case: 0 followed by non-octdigit */ + TESTCASE( strtoul( tricky, &endptr, 8 ) == 0 ); + TESTCASE( endptr == tricky + 2 ); + /* errno should still be 0 */ + TESTCASE( errno == 0 ); + /* overflowing subject sequence must still return proper endptr */ + TESTCASE( strtoul( overflow, &endptr, 36 ) == ULONG_MAX ); + TESTCASE( errno == ERANGE ); + TESTCASE( ( endptr - overflow ) == 53 ); + /* same for positive */ + errno = 0; + TESTCASE( strtoul( overflow + 1, &endptr, 36 ) == ULONG_MAX ); + TESTCASE( errno == ERANGE ); + TESTCASE( ( endptr - overflow ) == 53 ); + /* testing skipping of leading whitespace */ + TESTCASE( strtoul( " \n\v\t\f789", NULL, 0 ) == 789 ); + /* testing conversion failure */ + TESTCASE( strtoul( overflow, &endptr, 10 ) == 0 ); + TESTCASE( endptr == overflow ); + endptr = NULL; + TESTCASE( strtoul( overflow, &endptr, 0 ) == 0 ); + TESTCASE( endptr == overflow ); + /* TODO: These tests assume two-complement, but conversion should work */ + /* for one-complement and signed magnitude just as well. Anyone having */ + /* a platform to test this on? */ + errno = 0; +/* long -> 32 bit */ +#if ULONG_MAX >> 31 == 1 + /* testing "even" overflow, i.e. base is power of two */ + TESTCASE( strtoul( "4294967295", NULL, 0 ) == ULONG_MAX ); + TESTCASE( errno == 0 ); + errno = 0; + TESTCASE( strtoul( "4294967296", NULL, 0 ) == ULONG_MAX ); + TESTCASE( errno == ERANGE ); + /* TODO: test "odd" overflow, i.e. base is not power of two */ +/* long -> 64 bit */ +#elif ULONG_MAX >> 63 == 1 + /* testing "even" overflow, i.e. base is power of two */ + TESTCASE( strtoul( "18446744073709551615", NULL, 0 ) == ULONG_MAX ); + TESTCASE( errno == 0 ); + errno = 0; + TESTCASE( strtoul( "18446744073709551616", NULL, 0 ) == ULONG_MAX ); + TESTCASE( errno == ERANGE ); + /* TODO: test "odd" overflow, i.e. base is not power of two */ +#else +#error Unsupported width of 'long' (neither 32 nor 64 bit). +#endif + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/stdlib/strtoull.c b/src/pdclib/functions/stdlib/strtoull.c new file mode 100644 index 0000000..e207110 --- /dev/null +++ b/src/pdclib/functions/stdlib/strtoull.c @@ -0,0 +1,101 @@ +/* strtoull( const char *, char * *, int ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <limits.h> +#include <stdlib.h> + +#ifndef REGTEST + +#include <stdint.h> + +unsigned long long int strtoull( const char * s, char ** endptr, int base ) +{ + unsigned long long int rc; + char sign = '+'; + const char * p = _PDCLIB_strtox_prelim( s, &sign, &base ); + if ( base < 2 || base > 36 ) return 0; + rc = _PDCLIB_strtox_main( &p, (unsigned)base, (uintmax_t)ULLONG_MAX, (uintmax_t)( ULLONG_MAX / base ), (int)( ULLONG_MAX % base ), &sign ); + if ( endptr != NULL ) *endptr = ( p != NULL ) ? (char *) p : (char *) s; + return ( sign == '+' ) ? rc : -rc; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +#include <errno.h> + +int main( void ) +{ + char * endptr; + /* this, to base 36, overflows even a 256 bit integer */ + char overflow[] = "-ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ_"; + /* tricky border case */ + char tricky[] = "+0xz"; + errno = 0; + /* basic functionality */ + TESTCASE( strtoull( "123", NULL, 10 ) == 123 ); + /* proper detecting of default base 10 */ + TESTCASE( strtoull( "456", NULL, 0 ) == 456 ); + /* proper functioning to smaller base */ + TESTCASE( strtoull( "14", NULL, 8 ) == 12 ); + /* proper autodetecting of octal */ + TESTCASE( strtoull( "016", NULL, 0 ) == 14 ); + /* proper autodetecting of hexadecimal, lowercase 'x' */ + TESTCASE( strtoull( "0xFF", NULL, 0 ) == 255 ); + /* proper autodetecting of hexadecimal, uppercase 'X' */ + TESTCASE( strtoull( "0Xa1", NULL, 0 ) == 161 ); + /* proper handling of border case: 0x followed by non-hexdigit */ + TESTCASE( strtoull( tricky, &endptr, 0 ) == 0 ); + TESTCASE( endptr == tricky + 2 ); + /* proper handling of border case: 0 followed by non-octdigit */ + TESTCASE( strtoull( tricky, &endptr, 8 ) == 0 ); + TESTCASE( endptr == tricky + 2 ); + /* errno should still be 0 */ + TESTCASE( errno == 0 ); + /* overflowing subject sequence must still return proper endptr */ + TESTCASE( strtoull( overflow, &endptr, 36 ) == ULLONG_MAX ); + TESTCASE( errno == ERANGE ); + TESTCASE( ( endptr - overflow ) == 53 ); + /* same for positive */ + errno = 0; + TESTCASE( strtoull( overflow + 1, &endptr, 36 ) == ULLONG_MAX ); + TESTCASE( errno == ERANGE ); + TESTCASE( ( endptr - overflow ) == 53 ); + /* testing skipping of leading whitespace */ + TESTCASE( strtoull( " \n\v\t\f789", NULL, 0 ) == 789 ); + /* testing conversion failure */ + TESTCASE( strtoull( overflow, &endptr, 10 ) == 0 ); + TESTCASE( endptr == overflow ); + endptr = NULL; + TESTCASE( strtoull( overflow, &endptr, 0 ) == 0 ); + TESTCASE( endptr == overflow ); + errno = 0; +/* long long -> 64 bit */ +#if ULLONG_MAX >> 63 == 1 + /* testing "even" overflow, i.e. base is power of two */ + TESTCASE( strtoull( "18446744073709551615", NULL, 0 ) == ULLONG_MAX ); + TESTCASE( errno == 0 ); + TESTCASE( strtoull( "18446744073709551616", NULL, 0 ) == ULLONG_MAX ); + TESTCASE( errno == ERANGE ); + /* TODO: test "odd" overflow, i.e. base is not power of two */ +/* long long -> 128 bit */ +#elif ULLONG_MAX >> 127 == 1 + /* testing "even" overflow, i.e. base is power of two */ + TESTCASE( strtoull( "340282366920938463463374607431768211455", NULL, 0 ) == ULLONG_MAX ); + TESTCASE( errno == 0 ); + TESTCASE( strtoull( "340282366920938463463374607431768211456", NULL, 0 ) == ULLONG_MAX ); + TESTCASE( errno == ERANGE ); + /* TODO: test "odd" overflow, i.e. base is not power of two */ +#else +#error Unsupported width of 'long long' (neither 64 nor 128 bit). +#endif + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/string/memchr.c b/src/pdclib/functions/string/memchr.c new file mode 100644 index 0000000..29598a7 --- /dev/null +++ b/src/pdclib/functions/string/memchr.c @@ -0,0 +1,41 @@ +/* memchr( const void *, int, size_t ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <string.h> + +#ifndef REGTEST + +void * memchr( const void * s, int c, size_t n ) +{ + const unsigned char * p = (const unsigned char *) s; + while ( n-- ) + { + if ( *p == (unsigned char) c ) + { + return (void *) p; + } + ++p; + } + return NULL; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + TESTCASE( memchr( abcde, 'c', 5 ) == &abcde[2] ); + TESTCASE( memchr( abcde, 'a', 1 ) == &abcde[0] ); + TESTCASE( memchr( abcde, 'a', 0 ) == NULL ); + TESTCASE( memchr( abcde, '\0', 5 ) == NULL ); + TESTCASE( memchr( abcde, '\0', 6 ) == &abcde[5] ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/string/memcmp.c b/src/pdclib/functions/string/memcmp.c new file mode 100644 index 0000000..709b941 --- /dev/null +++ b/src/pdclib/functions/string/memcmp.c @@ -0,0 +1,43 @@ +/* memcmp( const void *, const void *, size_t ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <string.h> + +#ifndef REGTEST + +int memcmp( const void * s1, const void * s2, size_t n ) +{ + const unsigned char * p1 = (const unsigned char *) s1; + const unsigned char * p2 = (const unsigned char *) s2; + while ( n-- ) + { + if ( *p1 != *p2 ) + { + return *p1 - *p2; + } + ++p1; + ++p2; + } + return 0; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + const char xxxxx[] = "xxxxx"; + TESTCASE( memcmp( abcde, abcdx, 5 ) < 0 ); + TESTCASE( memcmp( abcde, abcdx, 4 ) == 0 ); + TESTCASE( memcmp( abcde, xxxxx, 0 ) == 0 ); + TESTCASE( memcmp( xxxxx, abcde, 1 ) > 0 ); + return 0; +} + +#endif diff --git a/src/pdclib/functions/string/memcpy.c b/src/pdclib/functions/string/memcpy.c new file mode 100644 index 0000000..21ef10e --- /dev/null +++ b/src/pdclib/functions/string/memcpy.c @@ -0,0 +1,40 @@ +/* memcpy( void *, const void *, size_t ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <string.h> + +#ifndef REGTEST + +void * memcpy( void * _PDCLIB_restrict s1, const void * _PDCLIB_restrict s2, size_t n ) +{ + char * dest = (char *) s1; + const char * src = (const char *) s2; + while ( n-- ) + { + *dest++ = *src++; + } + return s1; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + char s[] = "xxxxxxxxxxx"; + TESTCASE( memcpy( s, abcde, 6 ) == s ); + TESTCASE( s[4] == 'e' ); + TESTCASE( s[5] == '\0' ); + TESTCASE( memcpy( s + 5, abcde, 5 ) == s + 5 ); + TESTCASE( s[9] == 'e' ); + TESTCASE( s[10] == 'x' ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/string/memmove.c b/src/pdclib/functions/string/memmove.c new file mode 100644 index 0000000..af89813 --- /dev/null +++ b/src/pdclib/functions/string/memmove.c @@ -0,0 +1,52 @@ +/* memmove( void *, const void *, size_t ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <string.h> + +#ifndef REGTEST + +void * memmove( void * s1, const void * s2, size_t n ) +{ + char * dest = (char *) s1; + const char * src = (const char *) s2; + if ( dest <= src ) + { + while ( n-- ) + { + *dest++ = *src++; + } + } + else + { + src += n; + dest += n; + while ( n-- ) + { + *--dest = *--src; + } + } + return s1; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + char s[] = "xxxxabcde"; + TESTCASE( memmove( s, s + 4, 5 ) == s ); + TESTCASE( s[0] == 'a' ); + TESTCASE( s[4] == 'e' ); + TESTCASE( s[5] == 'b' ); + TESTCASE( memmove( s + 4, s, 5 ) == s + 4 ); + TESTCASE( s[4] == 'a' ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/string/memset.c b/src/pdclib/functions/string/memset.c new file mode 100644 index 0000000..522ad77 --- /dev/null +++ b/src/pdclib/functions/string/memset.c @@ -0,0 +1,40 @@ +/* memset( void *, int, size_t ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <string.h> + +#ifndef REGTEST + +void * memset( void * s, int c, size_t n ) +{ + unsigned char * p = (unsigned char *) s; + while ( n-- ) + { + *p++ = (unsigned char) c; + } + return s; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + char s[] = "xxxxxxxxx"; + TESTCASE( memset( s, 'o', 10 ) == s ); + TESTCASE( s[9] == 'o' ); + TESTCASE( memset( s, '_', 0 ) == s ); + TESTCASE( s[0] == 'o' ); + TESTCASE( memset( s, '_', 1 ) == s ); + TESTCASE( s[0] == '_' ); + TESTCASE( s[1] == 'o' ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/string/strcat.c b/src/pdclib/functions/string/strcat.c new file mode 100644 index 0000000..18fd409 --- /dev/null +++ b/src/pdclib/functions/string/strcat.c @@ -0,0 +1,46 @@ +/* strcat( char *, const char * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <string.h> + +#ifndef REGTEST + +char * strcat( char * _PDCLIB_restrict s1, const char * _PDCLIB_restrict s2 ) +{ + char * rc = s1; + if ( *s1 ) + { + while ( *++s1 ); + } + while ( (*s1++ = *s2++) ); + return rc; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + char s[] = "xx\0xxxxxx"; + TESTCASE( strcat( s, abcde ) == s ); + TESTCASE( s[2] == 'a' ); + TESTCASE( s[6] == 'e' ); + TESTCASE( s[7] == '\0' ); + TESTCASE( s[8] == 'x' ); + s[0] = '\0'; + TESTCASE( strcat( s, abcdx ) == s ); + TESTCASE( s[4] == 'x' ); + TESTCASE( s[5] == '\0' ); + TESTCASE( strcat( s, "\0" ) == s ); + TESTCASE( s[5] == '\0' ); + TESTCASE( s[6] == 'e' ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/string/strchr.c b/src/pdclib/functions/string/strchr.c new file mode 100644 index 0000000..621100e --- /dev/null +++ b/src/pdclib/functions/string/strchr.c @@ -0,0 +1,40 @@ +/* strchr( const char *, int ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <string.h> + +#ifndef REGTEST + +char * strchr( const char * s, int c ) +{ + do + { + if ( *s == (char) c ) + { + return (char *) s; + } + } while ( *s++ ); + return NULL; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + char abccd[] = "abccd"; + TESTCASE( strchr( abccd, 'x' ) == NULL ); + TESTCASE( strchr( abccd, 'a' ) == &abccd[0] ); + TESTCASE( strchr( abccd, 'd' ) == &abccd[4] ); + TESTCASE( strchr( abccd, '\0' ) == &abccd[5] ); + TESTCASE( strchr( abccd, 'c' ) == &abccd[2] ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/string/strcmp.c b/src/pdclib/functions/string/strcmp.c new file mode 100644 index 0000000..639fc10 --- /dev/null +++ b/src/pdclib/functions/string/strcmp.c @@ -0,0 +1,41 @@ +/* strcmp( const char *, const char * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <string.h> + +#ifndef REGTEST + +int strcmp( const char * s1, const char * s2 ) +{ + while ( ( *s1 ) && ( *s1 == *s2 ) ) + { + ++s1; + ++s2; + } + return ( *(unsigned char *)s1 - *(unsigned char *)s2 ); +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + char cmpabcde[] = "abcde"; + char cmpabcd_[] = "abcd\xfc"; + char empty[] = ""; + TESTCASE( strcmp( abcde, cmpabcde ) == 0 ); + TESTCASE( strcmp( abcde, abcdx ) < 0 ); + TESTCASE( strcmp( abcdx, abcde ) > 0 ); + TESTCASE( strcmp( empty, abcde ) < 0 ); + TESTCASE( strcmp( abcde, empty ) > 0 ); + TESTCASE( strcmp( abcde, cmpabcd_ ) < 0 ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/string/strcoll.c b/src/pdclib/functions/string/strcoll.c new file mode 100644 index 0000000..41d466a --- /dev/null +++ b/src/pdclib/functions/string/strcoll.c @@ -0,0 +1,46 @@ +/* strcoll( const char *, const char * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <string.h> + +#ifndef REGTEST + +#include <locale.h> + +int strcoll( const char * s1, const char * s2 ) +{ + return strcmp( s1, s2 ); + + /* FIXME: This code became invalid when we started doing *real* locales... */ + /* + while ( ( *s1 ) && ( _PDCLIB_lc_ctype[(unsigned char)*s1].collation == _PDCLIB_lc_ctype[(unsigned char)*s2].collation ) ) + { + ++s1; + ++s2; + } + return ( _PDCLIB_lc_ctype[(unsigned char)*s1].collation == _PDCLIB_lc_ctype[(unsigned char)*s2].collation ); + */ +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + char cmpabcde[] = "abcde"; + char empty[] = ""; + TESTCASE( strcmp( abcde, cmpabcde ) == 0 ); + TESTCASE( strcmp( abcde, abcdx ) < 0 ); + TESTCASE( strcmp( abcdx, abcde ) > 0 ); + TESTCASE( strcmp( empty, abcde ) < 0 ); + TESTCASE( strcmp( abcde, empty ) > 0 ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/string/strcpy.c b/src/pdclib/functions/string/strcpy.c new file mode 100644 index 0000000..e0357c8 --- /dev/null +++ b/src/pdclib/functions/string/strcpy.c @@ -0,0 +1,37 @@ +/* strcpy( char *, const char * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <string.h> + +#ifndef REGTEST + +char * strcpy( char * _PDCLIB_restrict s1, const char * _PDCLIB_restrict s2 ) +{ + char * rc = s1; + while ( ( *s1++ = *s2++ ) ); + return rc; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + char s[] = "xxxxx"; + TESTCASE( strcpy( s, "" ) == s ); + TESTCASE( s[0] == '\0' ); + TESTCASE( s[1] == 'x' ); + TESTCASE( strcpy( s, abcde ) == s ); + TESTCASE( s[0] == 'a' ); + TESTCASE( s[4] == 'e' ); + TESTCASE( s[5] == '\0' ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/string/strcspn.c b/src/pdclib/functions/string/strcspn.c new file mode 100644 index 0000000..84f8af1 --- /dev/null +++ b/src/pdclib/functions/string/strcspn.c @@ -0,0 +1,50 @@ +/* strcspn( const char *, const char * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <string.h> + +#ifndef REGTEST + +size_t strcspn( const char * s1, const char * s2 ) +{ + size_t len = 0; + const char * p; + while ( s1[len] ) + { + p = s2; + while ( *p ) + { + if ( s1[len] == *p++ ) + { + return len; + } + } + ++len; + } + return len; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + TESTCASE( strcspn( abcde, "x" ) == 5 ); + TESTCASE( strcspn( abcde, "xyz" ) == 5 ); + TESTCASE( strcspn( abcde, "zyx" ) == 5 ); + TESTCASE( strcspn( abcdx, "x" ) == 4 ); + TESTCASE( strcspn( abcdx, "xyz" ) == 4 ); + TESTCASE( strcspn( abcdx, "zyx" ) == 4 ); + TESTCASE( strcspn( abcde, "a" ) == 0 ); + TESTCASE( strcspn( abcde, "abc" ) == 0 ); + TESTCASE( strcspn( abcde, "cba" ) == 0 ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/string/strerror.c b/src/pdclib/functions/string/strerror.c new file mode 100644 index 0000000..4506376 --- /dev/null +++ b/src/pdclib/functions/string/strerror.c @@ -0,0 +1,41 @@ +/* strerror( int ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <string.h> + +#ifndef REGTEST + +#include <locale.h> + +/* TODO: Doing this via a static array is not the way to do it. */ +char * strerror( int errnum ) +{ + if ( errnum >= _PDCLIB_ERRNO_MAX ) + { + return (char *)"Unknown error"; + } + else + { + return _PDCLIB_lc_messages.errno_texts[errnum]; + } +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +#include <stdio.h> +#include <errno.h> + +int main( void ) +{ + TESTCASE( strerror( ERANGE ) != strerror( EDOM ) ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/string/strlen.c b/src/pdclib/functions/string/strlen.c new file mode 100644 index 0000000..c1a620e --- /dev/null +++ b/src/pdclib/functions/string/strlen.c @@ -0,0 +1,34 @@ +/* strlen( const char * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <string.h> + +#ifndef REGTEST + +size_t strlen( const char * s ) +{ + size_t rc = 0; + while ( s[rc] ) + { + ++rc; + } + return rc; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + TESTCASE( strlen( abcde ) == 5 ); + TESTCASE( strlen( "" ) == 0 ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/string/strncat.c b/src/pdclib/functions/string/strncat.c new file mode 100644 index 0000000..ba20edc --- /dev/null +++ b/src/pdclib/functions/string/strncat.c @@ -0,0 +1,60 @@ +/* strncat( char *, const char *, size_t ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <string.h> + +#ifndef REGTEST + +char * strncat( char * _PDCLIB_restrict s1, const char * _PDCLIB_restrict s2, size_t n ) +{ + char * rc = s1; + while ( *s1 ) + { + ++s1; + } + while ( n && ( *s1++ = *s2++ ) ) + { + --n; + } + if ( n == 0 ) + { + *s1 = '\0'; + } + return rc; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + char s[] = "xx\0xxxxxx"; + TESTCASE( strncat( s, abcde, 10 ) == s ); + TESTCASE( s[2] == 'a' ); + TESTCASE( s[6] == 'e' ); + TESTCASE( s[7] == '\0' ); + TESTCASE( s[8] == 'x' ); + s[0] = '\0'; + TESTCASE( strncat( s, abcdx, 10 ) == s ); + TESTCASE( s[4] == 'x' ); + TESTCASE( s[5] == '\0' ); + TESTCASE( strncat( s, "\0", 10 ) == s ); + TESTCASE( s[5] == '\0' ); + TESTCASE( s[6] == 'e' ); + TESTCASE( strncat( s, abcde, 0 ) == s ); + TESTCASE( s[5] == '\0' ); + TESTCASE( s[6] == 'e' ); + TESTCASE( strncat( s, abcde, 3 ) == s ); + TESTCASE( s[5] == 'a' ); + TESTCASE( s[7] == 'c' ); + TESTCASE( s[8] == '\0' ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/string/strncmp.c b/src/pdclib/functions/string/strncmp.c new file mode 100644 index 0000000..4bb3592 --- /dev/null +++ b/src/pdclib/functions/string/strncmp.c @@ -0,0 +1,54 @@ +/* strncmp( const char *, const char *, size_t ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <string.h> + +#ifndef REGTEST + +int strncmp( const char * s1, const char * s2, size_t n ) +{ + while ( n && *s1 && ( *s1 == *s2 ) ) + { + ++s1; + ++s2; + --n; + } + if ( n == 0 ) + { + return 0; + } + else + { + return ( *(unsigned char *)s1 - *(unsigned char *)s2 ); + } +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + char cmpabcde[] = "abcde\0f"; + char cmpabcd_[] = "abcde\xfc"; + char empty[] = ""; + char x[] = "x"; + TESTCASE( strncmp( abcde, cmpabcde, 5 ) == 0 ); + TESTCASE( strncmp( abcde, cmpabcde, 10 ) == 0 ); + TESTCASE( strncmp( abcde, abcdx, 5 ) < 0 ); + TESTCASE( strncmp( abcdx, abcde, 5 ) > 0 ); + TESTCASE( strncmp( empty, abcde, 5 ) < 0 ); + TESTCASE( strncmp( abcde, empty, 5 ) > 0 ); + TESTCASE( strncmp( abcde, abcdx, 4 ) == 0 ); + TESTCASE( strncmp( abcde, x, 0 ) == 0 ); + TESTCASE( strncmp( abcde, x, 1 ) < 0 ); + TESTCASE( strncmp( abcde, cmpabcd_, 10 ) < 0 ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/string/strncpy.c b/src/pdclib/functions/string/strncpy.c new file mode 100644 index 0000000..0627c41 --- /dev/null +++ b/src/pdclib/functions/string/strncpy.c @@ -0,0 +1,56 @@ +/* strncpy( char *, const char *, size_t ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <string.h> + +#ifndef REGTEST + +char * strncpy( char * _PDCLIB_restrict s1, const char * _PDCLIB_restrict s2, size_t n ) +{ + char * rc = s1; + while ( n && ( *s1++ = *s2++ ) ) + { + /* Cannot do "n--" in the conditional as size_t is unsigned and we have + to check it again for >0 in the next loop below, so we must not risk + underflow. + */ + --n; + } + /* Checking against 1 as we missed the last --n in the loop above. */ + while ( n-- > 1 ) + { + *s1++ = '\0'; + } + return rc; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + char s[] = "xxxxxxx"; + TESTCASE( strncpy( s, "", 1 ) == s ); + TESTCASE( s[0] == '\0' ); + TESTCASE( s[1] == 'x' ); + TESTCASE( strncpy( s, abcde, 6 ) == s ); + TESTCASE( s[0] == 'a' ); + TESTCASE( s[4] == 'e' ); + TESTCASE( s[5] == '\0' ); + TESTCASE( s[6] == 'x' ); + TESTCASE( strncpy( s, abcde, 7 ) == s ); + TESTCASE( s[6] == '\0' ); + TESTCASE( strncpy( s, "xxxx", 3 ) == s ); + TESTCASE( s[0] == 'x' ); + TESTCASE( s[2] == 'x' ); + TESTCASE( s[3] == 'd' ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/string/strpbrk.c b/src/pdclib/functions/string/strpbrk.c new file mode 100644 index 0000000..e95f0c1 --- /dev/null +++ b/src/pdclib/functions/string/strpbrk.c @@ -0,0 +1,49 @@ +/* strpbrk( const char *, const char * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <string.h> + +#ifndef REGTEST + +char * strpbrk( const char * s1, const char * s2 ) +{ + const char * p1 = s1; + const char * p2; + while ( *p1 ) + { + p2 = s2; + while ( *p2 ) + { + if ( *p1 == *p2++ ) + { + return (char *) p1; + } + } + ++p1; + } + return NULL; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + TESTCASE( strpbrk( abcde, "x" ) == NULL ); + TESTCASE( strpbrk( abcde, "xyz" ) == NULL ); + TESTCASE( strpbrk( abcdx, "x" ) == &abcdx[4] ); + TESTCASE( strpbrk( abcdx, "xyz" ) == &abcdx[4] ); + TESTCASE( strpbrk( abcdx, "zyx" ) == &abcdx[4] ); + TESTCASE( strpbrk( abcde, "a" ) == &abcde[0] ); + TESTCASE( strpbrk( abcde, "abc" ) == &abcde[0] ); + TESTCASE( strpbrk( abcde, "cba" ) == &abcde[0] ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/string/strrchr.c b/src/pdclib/functions/string/strrchr.c new file mode 100644 index 0000000..c2369fa --- /dev/null +++ b/src/pdclib/functions/string/strrchr.c @@ -0,0 +1,41 @@ +/* strrchr( const char *, int ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <string.h> + +#ifndef REGTEST + +char * strrchr( const char * s, int c ) +{ + size_t i = 0; + while ( s[i++] ); + do + { + if ( s[--i] == (char) c ) + { + return (char *) s + i; + } + } while ( i ); + return NULL; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + char abccd[] = "abccd"; + TESTCASE( strrchr( abcde, '\0' ) == &abcde[5] ); + TESTCASE( strrchr( abcde, 'e' ) == &abcde[4] ); + TESTCASE( strrchr( abcde, 'a' ) == &abcde[0] ); + TESTCASE( strrchr( abccd, 'c' ) == &abccd[3] ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/string/strspn.c b/src/pdclib/functions/string/strspn.c new file mode 100644 index 0000000..7b55b08 --- /dev/null +++ b/src/pdclib/functions/string/strspn.c @@ -0,0 +1,49 @@ +/* strspn( const char *, const char * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <string.h> + +#ifndef REGTEST + +size_t strspn( const char * s1, const char * s2 ) +{ + size_t len = 0; + const char * p; + while ( s1[ len ] ) + { + p = s2; + while ( *p ) + { + if ( s1[len] == *p ) + { + break; + } + ++p; + } + if ( ! *p ) + { + return len; + } + ++len; + } + return len; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + TESTCASE( strspn( abcde, "abc" ) == 3 ); + TESTCASE( strspn( abcde, "b" ) == 0 ); + TESTCASE( strspn( abcde, abcde ) == 5 ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/string/strstr.c b/src/pdclib/functions/string/strstr.c new file mode 100644 index 0000000..aee282f --- /dev/null +++ b/src/pdclib/functions/string/strstr.c @@ -0,0 +1,51 @@ +/* strstr( const char *, const char * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <string.h> + +#ifndef REGTEST + +char * strstr( const char * s1, const char * s2 ) +{ + const char * p1 = s1; + const char * p2; + while ( *s1 ) + { + p2 = s2; + while ( *p2 && ( *p1 == *p2 ) ) + { + ++p1; + ++p2; + } + if ( ! *p2 ) + { + return (char *) s1; + } + ++s1; + p1 = s1; + } + return NULL; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + char s[] = "abcabcabcdabcde"; + TESTCASE( strstr( s, "x" ) == NULL ); + TESTCASE( strstr( s, "xyz" ) == NULL ); + TESTCASE( strstr( s, "a" ) == &s[0] ); + TESTCASE( strstr( s, "abc" ) == &s[0] ); + TESTCASE( strstr( s, "abcd" ) == &s[6] ); + TESTCASE( strstr( s, "abcde" ) == &s[10] ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/string/strtok.c b/src/pdclib/functions/string/strtok.c new file mode 100644 index 0000000..69c2d68 --- /dev/null +++ b/src/pdclib/functions/string/strtok.c @@ -0,0 +1,107 @@ +/* strtok( char *, const char * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <string.h> + +#ifndef REGTEST + +char * strtok( char * _PDCLIB_restrict s1, const char * _PDCLIB_restrict s2 ) +{ + static char * tmp = NULL; + const char * p = s2; + + if ( s1 != NULL ) + { + /* new string */ + tmp = s1; + } + else + { + /* old string continued */ + if ( tmp == NULL ) + { + /* No old string, no new string, nothing to do */ + return NULL; + } + s1 = tmp; + } + + /* skipping leading s2 characters */ + while ( *p && *s1 ) + { + if ( *s1 == *p ) + { + /* found seperator; skip and start over */ + ++s1; + p = s2; + continue; + } + ++p; + } + + if ( ! *s1 ) + { + /* no more to parse */ + return ( tmp = NULL ); + } + + /* skipping non-s2 characters */ + tmp = s1; + while ( *tmp ) + { + p = s2; + while ( *p ) + { + if ( *tmp == *p++ ) + { + /* found seperator; overwrite with '\0', position tmp, return */ + *tmp++ = '\0'; + return s1; + } + } + ++tmp; + } + + /* parsed to end of string */ + tmp = NULL; + return s1; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + char s[] = "_a_bc__d_"; + TESTCASE( strtok( s, "_" ) == &s[1] ); + TESTCASE( s[1] == 'a' ); + TESTCASE( s[2] == '\0' ); + TESTCASE( strtok( NULL, "_" ) == &s[3] ); + TESTCASE( s[3] == 'b' ); + TESTCASE( s[4] == 'c' ); + TESTCASE( s[5] == '\0' ); + TESTCASE( strtok( NULL, "_" ) == &s[7] ); + TESTCASE( s[6] == '_' ); + TESTCASE( s[7] == 'd' ); + TESTCASE( s[8] == '\0' ); + TESTCASE( strtok( NULL, "_" ) == NULL ); + strcpy( s, "ab_cd" ); + TESTCASE( strtok( s, "_" ) == &s[0] ); + TESTCASE( s[0] == 'a' ); + TESTCASE( s[1] == 'b' ); + TESTCASE( s[2] == '\0' ); + TESTCASE( strtok( NULL, "_" ) == &s[3] ); + TESTCASE( s[3] == 'c' ); + TESTCASE( s[4] == 'd' ); + TESTCASE( s[5] == '\0' ); + TESTCASE( strtok( NULL, "_" ) == NULL ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/string/strxfrm.c b/src/pdclib/functions/string/strxfrm.c new file mode 100644 index 0000000..e08dba2 --- /dev/null +++ b/src/pdclib/functions/string/strxfrm.c @@ -0,0 +1,50 @@ +/* strxfrm( char *, const char *, size_t ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <string.h> + +#ifndef REGTEST + +#include <locale.h> + +size_t strxfrm( char * _PDCLIB_restrict s1, const char * _PDCLIB_restrict s2, size_t n ) +{ + size_t len = strlen( s2 ); + if ( len < n ) + { + /* Cannot use strncpy() here as the filling of s1 with '\0' is not part + of the spec. + */ + /* FIXME: The code below became invalid when we started doing *real* locales... */ + /*while ( n-- && ( *s1++ = _PDCLIB_lc_collate[(unsigned char)*s2++].collation ) );*/ + while ( n-- && ( *s1++ = (unsigned char)*s2++ ) ); + } + return len; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + char s[] = "xxxxxxxxxxx"; + TESTCASE( strxfrm( NULL, "123456789012", 0 ) == 12 ); + TESTCASE( strxfrm( s, "123456789012", 12 ) == 12 ); + /* + The following test case is true in *this* implementation, but doesn't have to. + TESTCASE( s[0] == 'x' ); + */ + TESTCASE( strxfrm( s, "1234567890", 11 ) == 10 ); + TESTCASE( s[0] == '1' ); + TESTCASE( s[9] == '0' ); + TESTCASE( s[10] == '\0' ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/time/asctime.c b/src/pdclib/functions/time/asctime.c new file mode 100644 index 0000000..8c9db60 --- /dev/null +++ b/src/pdclib/functions/time/asctime.c @@ -0,0 +1,28 @@ +/* asctime( const struct tm * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <time.h> + +#ifndef REGTEST + +char * asctime( const struct tm * timeptr ) +{ + return NULL; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + TESTCASE( NO_TESTDRIVER ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/time/ctime.c b/src/pdclib/functions/time/ctime.c new file mode 100644 index 0000000..d021a7d --- /dev/null +++ b/src/pdclib/functions/time/ctime.c @@ -0,0 +1,28 @@ +/* ctime( const time_t * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <time.h> + +#ifndef REGTEST + +char * ctime( const time_t * timer ) +{ + return NULL; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + TESTCASE( NO_TESTDRIVER ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/time/difftime.c b/src/pdclib/functions/time/difftime.c new file mode 100644 index 0000000..a6d94f8 --- /dev/null +++ b/src/pdclib/functions/time/difftime.c @@ -0,0 +1,70 @@ +/* difftime( time_t, time_t ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <time.h> + +#ifndef REGTEST + +double difftime( time_t time1, time_t time0 ) +{ + /* If we want to avoid rounding errors and overflows, we need to be + careful with the exact type of time_t being unknown to us. + The code below is based on tzcode's difftime.c, which is in the + public domain, so clarified as of 1996-06-05 by Arthur David Olson. + */ + + /* If double is large enough, simply covert and substract + (assuming that the larger type has more precision). + */ + if ( sizeof( time_t ) < sizeof( double ) ) + { + return (double)time1 - (double)time0; + } + + /* The difference of two unsigned values cannot overflow if the + minuend is greater or equal to the subtrahend. + */ + if ( ! _PDCLIB_TYPE_SIGNED( time_t ) ) + { + return ( time1 >= time0 ) ? (double)( time1 - time0 ) : -(double)( time0 - time1 ); + } + + /* Use uintmax_t if wide enough. */ + if ( sizeof( time_t ) <= sizeof( _PDCLIB_uintmax_t ) ) + { + _PDCLIB_uintmax_t t1 = time1, t0 = time0; + return ( time1 >= time0 ) ? t1 - t0 : -(double)( t0 - t1 ); + } + + /* If both times have the same sign, their difference cannot overflow. */ + if ( ( time1 < 0 ) == ( time0 < 0 ) ) + { + return time1 - time0; + } + + /* The times have opposite signs, and uintmax_t is too narrow. + This suffers from double rounding; attempt to lessen that + by using long double temporaries. + */ + { + long double t1 = time1, t0 = time0; + return t1 - t0; + } +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + TESTCASE( NO_TESTDRIVER ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/time/gmtime.c b/src/pdclib/functions/time/gmtime.c new file mode 100644 index 0000000..3bd001c --- /dev/null +++ b/src/pdclib/functions/time/gmtime.c @@ -0,0 +1,28 @@ +/* gmtime( const time_t * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <time.h> + +#ifndef REGTEST + +struct tm * gmtime( const time_t * timer ) +{ + return NULL; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + TESTCASE( NO_TESTDRIVER ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/time/localtime.c b/src/pdclib/functions/time/localtime.c new file mode 100644 index 0000000..91c0618 --- /dev/null +++ b/src/pdclib/functions/time/localtime.c @@ -0,0 +1,28 @@ +/* localtime( const time_t * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <time.h> + +#ifndef REGTEST + +struct tm * localtime( const time_t * timer ) +{ + return NULL; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + TESTCASE( NO_TESTDRIVER ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/time/mktime.c b/src/pdclib/functions/time/mktime.c new file mode 100644 index 0000000..0b8596a --- /dev/null +++ b/src/pdclib/functions/time/mktime.c @@ -0,0 +1,28 @@ +/* mktime( struct tm * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <time.h> + +#ifndef REGTEST + +time_t mktime( struct tm * timeptr ) +{ + return -1; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + TESTCASE( NO_TESTDRIVER ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/functions/time/strftime.c b/src/pdclib/functions/time/strftime.c new file mode 100644 index 0000000..81ae13d --- /dev/null +++ b/src/pdclib/functions/time/strftime.c @@ -0,0 +1,1719 @@ +/* strftime( char * restrict, size_t, const char * restrict, const struct tm * restrict ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <time.h> +#include <stdlib.h> +#include <locale.h> +#include <string.h> +#include <assert.h> + +#ifndef REGTEST + +/* TODO: Alternative representations / numerals not supported. Multibyte support missing. */ + +/* This implementation's code is highly repetitive, but I did not really + care for putting it into a number of macros / helper functions. +*/ + +enum wstart_t +{ + E_SUNDAY = 0, + E_MONDAY = 1, + E_ISO_WEEK, + E_ISO_YEAR +}; + +#include <stdio.h> + +static int week_calc( const struct tm * timeptr, int wtype ) +{ + int wday; + int bias; + int week; + + if ( wtype <= E_MONDAY ) + { + /* Simple -- first week starting with E_SUNDAY / E_MONDAY, + days before that are week 0. + */ + div_t weeks = div( timeptr->tm_yday, 7 ); + wday = ( timeptr->tm_wday + 7 - wtype ) % 7; + if ( weeks.rem >= wday ) + { + ++weeks.quot; + } + return weeks.quot; + } + + /* calculating ISO week; relies on Sunday == 7 */ + wday = timeptr->tm_wday; + if ( wday == 0 ) + { + wday = 7; + } + /* https://en.wikipedia.org/wiki/ISO_week_date */ + week = ( timeptr->tm_yday - wday + 11 ) / 7; + if ( week == 53 ) + { + /* date *may* belong to the *next* year, if: + * it is 31.12. and Monday - Wednesday + * it is 30.12. and Monday - Tuesday + * it is 29.12. and Monday + We can safely assume December... + */ + if ( ( timeptr->tm_yday - wday - _PDCLIB_is_leap( timeptr->tm_year ) ) > 360 ) + { + week = 1; + } + } + else if ( week == 0 ) + { + /* date *does* belong to *previous* year, + i.e. has week 52 *unless*... + * current year started on a Friday, or + * previous year is leap and this year + started on a Saturday. + */ + int firstday = timeptr->tm_wday - ( timeptr->tm_yday % 7 ); + if ( firstday < 0 ) + { + firstday += 7; + } + if ( ( firstday == 5 ) || ( _PDCLIB_is_leap( timeptr->tm_year - 1 ) && firstday == 6 ) ) + { + week = 53; + } + else + { + week = 52; + } + } + if ( wtype == E_ISO_WEEK ) + { + return week; + } + + /* E_ISO_YEAR -- determine the "week-based year" */ + bias = 0; + if ( week >= 52 && timeptr->tm_mon == 0 ) + { + --bias; + } + else if ( week == 1 && timeptr->tm_mon == 11 ) + { + ++bias; + } + return timeptr->tm_year + 1900 + bias; +} + +/* Assuming presence of s, rc, maxsize. + Checks index for valid range, target buffer for sufficient remaining + capacity, and copies the locale-specific string (or "?" if index out + of range). Returns with zero if buffer capacity insufficient. +*/ +#define SPRINTSTR( array, index, max ) \ + { \ + int ind = (index); \ + const char * str = "?"; \ + size_t len; \ + if ( ind >= 0 && ind <= max ) \ + { \ + str = array[ ind ]; \ + } \ + len = strlen( str ); \ + if ( rc < ( maxsize - len ) ) \ + { \ + strcpy( s + rc, str ); \ + rc += len; \ + } \ + else \ + { \ + return 0; \ + } \ + } + +#define SPRINTREC( format ) \ + { \ + size_t count = strftime( s + rc, maxsize - rc, format, timeptr ); \ + if ( count == 0 ) \ + { \ + return 0; \ + } \ + else \ + { \ + rc += count; \ + } \ + } + +size_t strftime( char * _PDCLIB_restrict s, size_t maxsize, const char * _PDCLIB_restrict format, const struct tm * _PDCLIB_restrict timeptr ) +{ + size_t rc = 0; + + while ( rc < maxsize ) + { + if ( *format != '%' ) + { + if ( ( s[rc] = *format++ ) == '\0' ) + { + return rc; + } + else + { + ++rc; + } + } + else + { + /* char flag = 0; */ + switch ( *++format ) + { + case 'E': + case 'O': + /* flag = *format++; */ + break; + default: + /* EMPTY */ + break; + } + switch( *format++ ) + { + case 'a': + { + /* tm_wday abbreviated */ + SPRINTSTR( _PDCLIB_lc_time.day_name_abbr, timeptr->tm_wday, 6 ); + break; + } + case 'A': + { + /* tm_wday full */ + SPRINTSTR( _PDCLIB_lc_time.day_name_full, timeptr->tm_wday, 6 ); + break; + } + case 'b': + case 'h': + { + /* tm_mon abbreviated */ + SPRINTSTR( _PDCLIB_lc_time.month_name_abbr, timeptr->tm_mon, 11 ); + break; + } + case 'B': + { + /* tm_mon full */ + SPRINTSTR( _PDCLIB_lc_time.month_name_full, timeptr->tm_mon, 11 ); + break; + } + case 'c': + { + /* locale's date / time representation, %a %b %e %T %Y for C locale */ + /* 'E' for locale's alternative representation */ + SPRINTREC( _PDCLIB_lc_time.date_time_format ); + break; + } + case 'C': + { + /* tm_year divided by 100, truncated to decimal (00-99) */ + /* 'E' for base year (period) in locale's alternative representation */ + if ( rc < ( maxsize - 2 ) ) + { + div_t period = div( ( ( timeptr->tm_year + 1900 ) / 100 ), 10 ); + s[rc++] = '0' + period.quot; + s[rc++] = '0' + period.rem; + } + else + { + return 0; + } + break; + } + case 'd': + { + /* tm_mday as decimal (01-31) */ + /* 'O' for locale's alternative numeric symbols */ + if ( rc < ( maxsize - 2 ) ) + { + div_t day = div( timeptr->tm_mday, 10 ); + s[rc++] = '0' + day.quot; + s[rc++] = '0' + day.rem; + } + else + { + return 0; + } + break; + } + case 'D': + { + /* %m/%d/%y */ + SPRINTREC( "%m/%d/%y" ); + break; + } + case 'e': + { + /* tm_mday as decimal ( 1-31) */ + /* 'O' for locale's alternative numeric symbols */ + if ( rc < ( maxsize - 2 ) ) + { + div_t day = div( timeptr->tm_mday, 10 ); + s[rc++] = ( day.quot > 0 ) ? '0' + day.quot : ' '; + s[rc++] = '0' + day.rem; + } + else + { + return 0; + } + break; + } + case 'F': + { + /* %Y-%m-%d */ + SPRINTREC( "%Y-%m-%d" ); + break; + } + case 'g': + { + /* last 2 digits of the week-based year as decimal (00-99) */ + if ( rc < ( maxsize - 2 ) ) + { + div_t year = div( week_calc( timeptr, E_ISO_YEAR ) % 100, 10 ); + s[rc++] = '0' + year.quot; + s[rc++] = '0' + year.rem; + } + else + { + return 0; + } + break; + } + case 'G': + { + /* week-based year as decimal (e.g. 1997) */ + if ( rc < ( maxsize - 4 ) ) + { + int year = week_calc( timeptr, E_ISO_YEAR ); + int i; + for ( i = 3; i >= 0; --i ) + { + div_t digit = div( year, 10 ); + s[ rc + i ] = '0' + digit.rem; + year = digit.quot; + } + + rc += 4; + } + else + { + return 0; + } + break; + } + case 'H': + { + /* tm_hour as 24h decimal (00-23) */ + /* 'O' for locale's alternative numeric symbols */ + if ( rc < ( maxsize - 2 ) ) + { + div_t hour = div( timeptr->tm_hour, 10 ); + s[rc++] = '0' + hour.quot; + s[rc++] = '0' + hour.rem; + } + else + { + return 0; + } + break; + } + case 'I': + { + /* tm_hour as 12h decimal (01-12) */ + /* 'O' for locale's alternative numeric symbols */ + if ( rc < ( maxsize - 2 ) ) + { + div_t hour = div( ( timeptr->tm_hour + 11 ) % 12 + 1, 10 ); + s[rc++] = '0' + hour.quot; + s[rc++] = '0' + hour.rem; + } + else + { + return 0; + } + break; + } + case 'j': + { + /* tm_yday as decimal (001-366) */ + if ( rc < ( maxsize - 3 ) ) + { + div_t yday = div( timeptr->tm_yday + 1, 100 ); + s[rc++] = '0' + yday.quot; + s[rc++] = '0' + yday.rem / 10; + s[rc++] = '0' + yday.rem % 10; + } + else + { + return 0; + } + break; + } + case 'm': + { + /* tm_mon as decimal (01-12) */ + /* 'O' for locale's alternative numeric symbols */ + if ( rc < ( maxsize - 2 ) ) + { + div_t mon = div( timeptr->tm_mon + 1, 10 ); + s[rc++] = '0' + mon.quot; + s[rc++] = '0' + mon.rem; + } + else + { + return 0; + } + break; + } + case 'M': + { + /* tm_min as decimal (00-59) */ + /* 'O' for locale's alternative numeric symbols */ + if ( rc < ( maxsize - 2 ) ) + { + div_t min = div( timeptr->tm_min, 10 ); + s[rc++] = '0' + min.quot; + s[rc++] = '0' + min.rem; + } + else + { + return 0; + } + break; + } + case 'n': + { + /* newline */ + s[rc++] = '\n'; + break; + } + case 'p': + { + /* tm_hour locale's AM/PM designations */ + SPRINTSTR( _PDCLIB_lc_time.am_pm, timeptr->tm_hour > 11, 1 ); + break; + } + case 'r': + { + /* tm_hour / tm_min / tm_sec as locale's 12-hour clock time, %I:%M:%S %p for C locale */ + SPRINTREC( _PDCLIB_lc_time.time_format_12h ); + break; + } + case 'R': + { + /* %H:%M */ + SPRINTREC( "%H:%M" ); + break; + } + case 'S': + { + /* tm_sec as decimal (00-60) */ + /* 'O' for locale's alternative numeric symbols */ + if ( rc < ( maxsize - 2 ) ) + { + div_t sec = div( timeptr->tm_sec, 10 ); + s[rc++] = '0' + sec.quot; + s[rc++] = '0' + sec.rem; + } + else + { + return 0; + } + break; + } + case 't': + { + /* tabulator */ + s[rc++] = '\t'; + break; + } + case 'T': + { + /* %H:%M:%S */ + SPRINTREC( "%H:%M:%S" ); + break; + } + case 'u': + { + /* tm_wday as decimal (1-7) with Monday == 1 */ + /* 'O' for locale's alternative numeric symbols */ + s[rc++] = ( timeptr->tm_wday == 0 ) ? '7' : '0' + timeptr->tm_wday; + break; + } + case 'U': + { + /* week number of the year (first Sunday as the first day of week 1) as decimal (00-53) */ + /* 'O' for locale's alternative numeric symbols */ + if ( rc < ( maxsize - 2 ) ) + { + div_t week = div( week_calc( timeptr, E_SUNDAY ), 10 ); + s[rc++] = '0' + week.quot; + s[rc++] = '0' + week.rem; + } + else + { + return 0; + } + break; + } + case 'V': + { + /* ISO week number as decimal (01-53) */ + /* 'O' for locale's alternative numeric symbols */ + if ( rc < ( maxsize - 2 ) ) + { + div_t week = div( week_calc( timeptr, E_ISO_WEEK ), 10 ); + s[rc++] = '0' + week.quot; + s[rc++] = '0' + week.rem; + } + else + { + return 0; + } + break; + } + case 'w': + { + /* tm_wday as decimal number (0-6) with Sunday == 0 */ + /* 'O' for locale's alternative numeric symbols */ + s[rc++] = '0' + timeptr->tm_wday; + break; + } + case 'W': + { + /* week number of the year (first Monday as the first day of week 1) as decimal (00-53) */ + /* 'O' for locale's alternative numeric symbols */ + if ( rc < ( maxsize - 2 ) ) + { + div_t week = div( week_calc( timeptr, E_MONDAY ), 10 ); + s[rc++] = '0' + week.quot; + s[rc++] = '0' + week.rem; + } + else + { + return 0; + } + break; + } + case 'x': + { + /* locale's date representation, %m/%d/%y for C locale */ + /* 'E' for locale's alternative representation */ + SPRINTREC( _PDCLIB_lc_time.date_format ); + break; + } + case 'X': + { + /* locale's time representation, %T for C locale */ + /* 'E' for locale's alternative representation */ + SPRINTREC( _PDCLIB_lc_time.time_format ); + break; + } + case 'y': + { + /* last 2 digits of tm_year as decimal (00-99) */ + /* 'E' for offset from %EC (year only) in locale's alternative representation */ + /* 'O' for locale's alternative numeric symbols */ + if ( rc < ( maxsize - 2 ) ) + { + div_t year = div( ( timeptr->tm_year % 100 ), 10 ); + s[rc++] = '0' + year.quot; + s[rc++] = '0' + year.rem; + } + else + { + return 0; + } + break; + } + case 'Y': + { + /* tm_year as decimal (e.g. 1997) */ + /* 'E' for locale's alternative representation */ + if ( rc < ( maxsize - 4 ) ) + { + int year = timeptr->tm_year + 1900; + int i; + + for ( i = 3; i >= 0; --i ) + { + div_t digit = div( year, 10 ); + s[ rc + i ] = '0' + digit.rem; + year = digit.quot; + } + + rc += 4; + } + else + { + return 0; + } + break; + } + case 'z': + { + /* tm_isdst / UTC offset in ISO8601 format (e.g. -0430 meaning 4 hours 30 minutes behind Greenwich), or no characters */ + /* TODO: 'z' */ + break; + } + case 'Z': + { + /* tm_isdst / locale's time zone name or abbreviation, or no characters */ + /* TODO: 'Z' */ + break; + } + case '%': + { + /* '%' character */ + s[rc++] = '%'; + break; + } + } + } + } + + return 0; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +#define MKTIME( tm, sec, min, hour, day, month, year, wday, yday ) tm.tm_sec = sec; tm.tm_min = min; tm.tm_hour = hour; tm.tm_mday = day; tm.tm_mon = month; tm.tm_year = year; tm.tm_wday = wday; tm.tm_yday = yday; tm.tm_isdst = -1; + +/* Test data generated by reference mktime() / strftime(), listing: + * tm_year + * tm_wday + * tm_yday + * '%U' result + * '%V' result + * '%W' result +*/ +int data[1020][6] = +{ +{ 70, 4, 0, 0, 1, 0 }, +{ 70, 5, 1, 0, 1, 0 }, +{ 70, 6, 2, 0, 1, 0 }, +{ 70, 0, 3, 1, 1, 0 }, +{ 70, 1, 4, 1, 2, 1 }, +{ 70, 2, 5, 1, 2, 1 }, +{ 70, 3, 6, 1, 2, 1 }, +{ 70, 4, 357, 51, 52, 51 }, +{ 70, 5, 358, 51, 52, 51 }, +{ 70, 6, 359, 51, 52, 51 }, +{ 70, 0, 360, 52, 52, 51 }, +{ 70, 1, 361, 52, 53, 52 }, +{ 70, 2, 362, 52, 53, 52 }, +{ 70, 3, 363, 52, 53, 52 }, +{ 70, 4, 364, 52, 53, 52 }, +{ 71, 5, 0, 0, 53, 0 }, +{ 71, 6, 1, 0, 53, 0 }, +{ 71, 0, 2, 1, 53, 0 }, +{ 71, 1, 3, 1, 1, 1 }, +{ 71, 2, 4, 1, 1, 1 }, +{ 71, 3, 5, 1, 1, 1 }, +{ 71, 4, 6, 1, 1, 1 }, +{ 71, 5, 357, 51, 51, 51 }, +{ 71, 6, 358, 51, 51, 51 }, +{ 71, 0, 359, 52, 51, 51 }, +{ 71, 1, 360, 52, 52, 52 }, +{ 71, 2, 361, 52, 52, 52 }, +{ 71, 3, 362, 52, 52, 52 }, +{ 71, 4, 363, 52, 52, 52 }, +{ 71, 5, 364, 52, 52, 52 }, +{ 72, 6, 0, 0, 52, 0 }, +{ 72, 0, 1, 1, 52, 0 }, +{ 72, 1, 2, 1, 1, 1 }, +{ 72, 2, 3, 1, 1, 1 }, +{ 72, 3, 4, 1, 1, 1 }, +{ 72, 4, 5, 1, 1, 1 }, +{ 72, 5, 6, 1, 1, 1 }, +{ 72, 0, 358, 52, 51, 51 }, +{ 72, 1, 359, 52, 52, 52 }, +{ 72, 2, 360, 52, 52, 52 }, +{ 72, 3, 361, 52, 52, 52 }, +{ 72, 4, 362, 52, 52, 52 }, +{ 72, 5, 363, 52, 52, 52 }, +{ 72, 6, 364, 52, 52, 52 }, +{ 72, 0, 365, 53, 52, 52 }, +{ 73, 1, 0, 0, 1, 1 }, +{ 73, 2, 1, 0, 1, 1 }, +{ 73, 3, 2, 0, 1, 1 }, +{ 73, 4, 3, 0, 1, 1 }, +{ 73, 5, 4, 0, 1, 1 }, +{ 73, 6, 5, 0, 1, 1 }, +{ 73, 0, 6, 1, 1, 1 }, +{ 73, 1, 357, 51, 52, 52 }, +{ 73, 2, 358, 51, 52, 52 }, +{ 73, 3, 359, 51, 52, 52 }, +{ 73, 4, 360, 51, 52, 52 }, +{ 73, 5, 361, 51, 52, 52 }, +{ 73, 6, 362, 51, 52, 52 }, +{ 73, 0, 363, 52, 52, 52 }, +{ 73, 1, 364, 52, 1, 53 }, +{ 74, 2, 0, 0, 1, 0 }, +{ 74, 3, 1, 0, 1, 0 }, +{ 74, 4, 2, 0, 1, 0 }, +{ 74, 5, 3, 0, 1, 0 }, +{ 74, 6, 4, 0, 1, 0 }, +{ 74, 0, 5, 1, 1, 0 }, +{ 74, 1, 6, 1, 2, 1 }, +{ 74, 2, 357, 51, 52, 51 }, +{ 74, 3, 358, 51, 52, 51 }, +{ 74, 4, 359, 51, 52, 51 }, +{ 74, 5, 360, 51, 52, 51 }, +{ 74, 6, 361, 51, 52, 51 }, +{ 74, 0, 362, 52, 52, 51 }, +{ 74, 1, 363, 52, 1, 52 }, +{ 74, 2, 364, 52, 1, 52 }, +{ 75, 3, 0, 0, 1, 0 }, +{ 75, 4, 1, 0, 1, 0 }, +{ 75, 5, 2, 0, 1, 0 }, +{ 75, 6, 3, 0, 1, 0 }, +{ 75, 0, 4, 1, 1, 0 }, +{ 75, 1, 5, 1, 2, 1 }, +{ 75, 2, 6, 1, 2, 1 }, +{ 75, 3, 357, 51, 52, 51 }, +{ 75, 4, 358, 51, 52, 51 }, +{ 75, 5, 359, 51, 52, 51 }, +{ 75, 6, 360, 51, 52, 51 }, +{ 75, 0, 361, 52, 52, 51 }, +{ 75, 1, 362, 52, 1, 52 }, +{ 75, 2, 363, 52, 1, 52 }, +{ 75, 3, 364, 52, 1, 52 }, +{ 76, 4, 0, 0, 1, 0 }, +{ 76, 5, 1, 0, 1, 0 }, +{ 76, 6, 2, 0, 1, 0 }, +{ 76, 0, 3, 1, 1, 0 }, +{ 76, 1, 4, 1, 2, 1 }, +{ 76, 2, 5, 1, 2, 1 }, +{ 76, 3, 6, 1, 2, 1 }, +{ 76, 5, 358, 51, 52, 51 }, +{ 76, 6, 359, 51, 52, 51 }, +{ 76, 0, 360, 52, 52, 51 }, +{ 76, 1, 361, 52, 53, 52 }, +{ 76, 2, 362, 52, 53, 52 }, +{ 76, 3, 363, 52, 53, 52 }, +{ 76, 4, 364, 52, 53, 52 }, +{ 76, 5, 365, 52, 53, 52 }, +{ 77, 6, 0, 0, 53, 0 }, +{ 77, 0, 1, 1, 53, 0 }, +{ 77, 1, 2, 1, 1, 1 }, +{ 77, 2, 3, 1, 1, 1 }, +{ 77, 3, 4, 1, 1, 1 }, +{ 77, 4, 5, 1, 1, 1 }, +{ 77, 5, 6, 1, 1, 1 }, +{ 77, 6, 357, 51, 51, 51 }, +{ 77, 0, 358, 52, 51, 51 }, +{ 77, 1, 359, 52, 52, 52 }, +{ 77, 2, 360, 52, 52, 52 }, +{ 77, 3, 361, 52, 52, 52 }, +{ 77, 4, 362, 52, 52, 52 }, +{ 77, 5, 363, 52, 52, 52 }, +{ 77, 6, 364, 52, 52, 52 }, +{ 78, 0, 0, 1, 52, 0 }, +{ 78, 1, 1, 1, 1, 1 }, +{ 78, 2, 2, 1, 1, 1 }, +{ 78, 3, 3, 1, 1, 1 }, +{ 78, 4, 4, 1, 1, 1 }, +{ 78, 5, 5, 1, 1, 1 }, +{ 78, 6, 6, 1, 1, 1 }, +{ 78, 0, 357, 52, 51, 51 }, +{ 78, 1, 358, 52, 52, 52 }, +{ 78, 2, 359, 52, 52, 52 }, +{ 78, 3, 360, 52, 52, 52 }, +{ 78, 4, 361, 52, 52, 52 }, +{ 78, 5, 362, 52, 52, 52 }, +{ 78, 6, 363, 52, 52, 52 }, +{ 78, 0, 364, 53, 52, 52 }, +{ 79, 1, 0, 0, 1, 1 }, +{ 79, 2, 1, 0, 1, 1 }, +{ 79, 3, 2, 0, 1, 1 }, +{ 79, 4, 3, 0, 1, 1 }, +{ 79, 5, 4, 0, 1, 1 }, +{ 79, 6, 5, 0, 1, 1 }, +{ 79, 0, 6, 1, 1, 1 }, +{ 79, 1, 357, 51, 52, 52 }, +{ 79, 2, 358, 51, 52, 52 }, +{ 79, 3, 359, 51, 52, 52 }, +{ 79, 4, 360, 51, 52, 52 }, +{ 79, 5, 361, 51, 52, 52 }, +{ 79, 6, 362, 51, 52, 52 }, +{ 79, 0, 363, 52, 52, 52 }, +{ 79, 1, 364, 52, 1, 53 }, +{ 80, 2, 0, 0, 1, 0 }, +{ 80, 3, 1, 0, 1, 0 }, +{ 80, 4, 2, 0, 1, 0 }, +{ 80, 5, 3, 0, 1, 0 }, +{ 80, 6, 4, 0, 1, 0 }, +{ 80, 0, 5, 1, 1, 0 }, +{ 80, 1, 6, 1, 2, 1 }, +{ 80, 3, 358, 51, 52, 51 }, +{ 80, 4, 359, 51, 52, 51 }, +{ 80, 5, 360, 51, 52, 51 }, +{ 80, 6, 361, 51, 52, 51 }, +{ 80, 0, 362, 52, 52, 51 }, +{ 80, 1, 363, 52, 1, 52 }, +{ 80, 2, 364, 52, 1, 52 }, +{ 80, 3, 365, 52, 1, 52 }, +{ 81, 4, 0, 0, 1, 0 }, +{ 81, 5, 1, 0, 1, 0 }, +{ 81, 6, 2, 0, 1, 0 }, +{ 81, 0, 3, 1, 1, 0 }, +{ 81, 1, 4, 1, 2, 1 }, +{ 81, 2, 5, 1, 2, 1 }, +{ 81, 3, 6, 1, 2, 1 }, +{ 81, 4, 357, 51, 52, 51 }, +{ 81, 5, 358, 51, 52, 51 }, +{ 81, 6, 359, 51, 52, 51 }, +{ 81, 0, 360, 52, 52, 51 }, +{ 81, 1, 361, 52, 53, 52 }, +{ 81, 2, 362, 52, 53, 52 }, +{ 81, 3, 363, 52, 53, 52 }, +{ 81, 4, 364, 52, 53, 52 }, +{ 82, 5, 0, 0, 53, 0 }, +{ 82, 6, 1, 0, 53, 0 }, +{ 82, 0, 2, 1, 53, 0 }, +{ 82, 1, 3, 1, 1, 1 }, +{ 82, 2, 4, 1, 1, 1 }, +{ 82, 3, 5, 1, 1, 1 }, +{ 82, 4, 6, 1, 1, 1 }, +{ 82, 5, 357, 51, 51, 51 }, +{ 82, 6, 358, 51, 51, 51 }, +{ 82, 0, 359, 52, 51, 51 }, +{ 82, 1, 360, 52, 52, 52 }, +{ 82, 2, 361, 52, 52, 52 }, +{ 82, 3, 362, 52, 52, 52 }, +{ 82, 4, 363, 52, 52, 52 }, +{ 82, 5, 364, 52, 52, 52 }, +{ 83, 6, 0, 0, 52, 0 }, +{ 83, 0, 1, 1, 52, 0 }, +{ 83, 1, 2, 1, 1, 1 }, +{ 83, 2, 3, 1, 1, 1 }, +{ 83, 3, 4, 1, 1, 1 }, +{ 83, 4, 5, 1, 1, 1 }, +{ 83, 5, 6, 1, 1, 1 }, +{ 83, 6, 357, 51, 51, 51 }, +{ 83, 0, 358, 52, 51, 51 }, +{ 83, 1, 359, 52, 52, 52 }, +{ 83, 2, 360, 52, 52, 52 }, +{ 83, 3, 361, 52, 52, 52 }, +{ 83, 4, 362, 52, 52, 52 }, +{ 83, 5, 363, 52, 52, 52 }, +{ 83, 6, 364, 52, 52, 52 }, +{ 84, 0, 0, 1, 52, 0 }, +{ 84, 1, 1, 1, 1, 1 }, +{ 84, 2, 2, 1, 1, 1 }, +{ 84, 3, 3, 1, 1, 1 }, +{ 84, 4, 4, 1, 1, 1 }, +{ 84, 5, 5, 1, 1, 1 }, +{ 84, 6, 6, 1, 1, 1 }, +{ 84, 1, 358, 52, 52, 52 }, +{ 84, 2, 359, 52, 52, 52 }, +{ 84, 3, 360, 52, 52, 52 }, +{ 84, 4, 361, 52, 52, 52 }, +{ 84, 5, 362, 52, 52, 52 }, +{ 84, 6, 363, 52, 52, 52 }, +{ 84, 0, 364, 53, 52, 52 }, +{ 84, 1, 365, 53, 1, 53 }, +{ 85, 2, 0, 0, 1, 0 }, +{ 85, 3, 1, 0, 1, 0 }, +{ 85, 4, 2, 0, 1, 0 }, +{ 85, 5, 3, 0, 1, 0 }, +{ 85, 6, 4, 0, 1, 0 }, +{ 85, 0, 5, 1, 1, 0 }, +{ 85, 1, 6, 1, 2, 1 }, +{ 85, 2, 357, 51, 52, 51 }, +{ 85, 3, 358, 51, 52, 51 }, +{ 85, 4, 359, 51, 52, 51 }, +{ 85, 5, 360, 51, 52, 51 }, +{ 85, 6, 361, 51, 52, 51 }, +{ 85, 0, 362, 52, 52, 51 }, +{ 85, 1, 363, 52, 1, 52 }, +{ 85, 2, 364, 52, 1, 52 }, +{ 86, 3, 0, 0, 1, 0 }, +{ 86, 4, 1, 0, 1, 0 }, +{ 86, 5, 2, 0, 1, 0 }, +{ 86, 6, 3, 0, 1, 0 }, +{ 86, 0, 4, 1, 1, 0 }, +{ 86, 1, 5, 1, 2, 1 }, +{ 86, 2, 6, 1, 2, 1 }, +{ 86, 3, 357, 51, 52, 51 }, +{ 86, 4, 358, 51, 52, 51 }, +{ 86, 5, 359, 51, 52, 51 }, +{ 86, 6, 360, 51, 52, 51 }, +{ 86, 0, 361, 52, 52, 51 }, +{ 86, 1, 362, 52, 1, 52 }, +{ 86, 2, 363, 52, 1, 52 }, +{ 86, 3, 364, 52, 1, 52 }, +{ 87, 4, 0, 0, 1, 0 }, +{ 87, 5, 1, 0, 1, 0 }, +{ 87, 6, 2, 0, 1, 0 }, +{ 87, 0, 3, 1, 1, 0 }, +{ 87, 1, 4, 1, 2, 1 }, +{ 87, 2, 5, 1, 2, 1 }, +{ 87, 3, 6, 1, 2, 1 }, +{ 87, 4, 357, 51, 52, 51 }, +{ 87, 5, 358, 51, 52, 51 }, +{ 87, 6, 359, 51, 52, 51 }, +{ 87, 0, 360, 52, 52, 51 }, +{ 87, 1, 361, 52, 53, 52 }, +{ 87, 2, 362, 52, 53, 52 }, +{ 87, 3, 363, 52, 53, 52 }, +{ 87, 4, 364, 52, 53, 52 }, +{ 88, 5, 0, 0, 53, 0 }, +{ 88, 6, 1, 0, 53, 0 }, +{ 88, 0, 2, 1, 53, 0 }, +{ 88, 1, 3, 1, 1, 1 }, +{ 88, 2, 4, 1, 1, 1 }, +{ 88, 3, 5, 1, 1, 1 }, +{ 88, 4, 6, 1, 1, 1 }, +{ 88, 6, 358, 51, 51, 51 }, +{ 88, 0, 359, 52, 51, 51 }, +{ 88, 1, 360, 52, 52, 52 }, +{ 88, 2, 361, 52, 52, 52 }, +{ 88, 3, 362, 52, 52, 52 }, +{ 88, 4, 363, 52, 52, 52 }, +{ 88, 5, 364, 52, 52, 52 }, +{ 88, 6, 365, 52, 52, 52 }, +{ 89, 0, 0, 1, 52, 0 }, +{ 89, 1, 1, 1, 1, 1 }, +{ 89, 2, 2, 1, 1, 1 }, +{ 89, 3, 3, 1, 1, 1 }, +{ 89, 4, 4, 1, 1, 1 }, +{ 89, 5, 5, 1, 1, 1 }, +{ 89, 6, 6, 1, 1, 1 }, +{ 89, 0, 357, 52, 51, 51 }, +{ 89, 1, 358, 52, 52, 52 }, +{ 89, 2, 359, 52, 52, 52 }, +{ 89, 3, 360, 52, 52, 52 }, +{ 89, 4, 361, 52, 52, 52 }, +{ 89, 5, 362, 52, 52, 52 }, +{ 89, 6, 363, 52, 52, 52 }, +{ 89, 0, 364, 53, 52, 52 }, +{ 90, 1, 0, 0, 1, 1 }, +{ 90, 2, 1, 0, 1, 1 }, +{ 90, 3, 2, 0, 1, 1 }, +{ 90, 4, 3, 0, 1, 1 }, +{ 90, 5, 4, 0, 1, 1 }, +{ 90, 6, 5, 0, 1, 1 }, +{ 90, 0, 6, 1, 1, 1 }, +{ 90, 1, 357, 51, 52, 52 }, +{ 90, 2, 358, 51, 52, 52 }, +{ 90, 3, 359, 51, 52, 52 }, +{ 90, 4, 360, 51, 52, 52 }, +{ 90, 5, 361, 51, 52, 52 }, +{ 90, 6, 362, 51, 52, 52 }, +{ 90, 0, 363, 52, 52, 52 }, +{ 90, 1, 364, 52, 1, 53 }, +{ 91, 2, 0, 0, 1, 0 }, +{ 91, 3, 1, 0, 1, 0 }, +{ 91, 4, 2, 0, 1, 0 }, +{ 91, 5, 3, 0, 1, 0 }, +{ 91, 6, 4, 0, 1, 0 }, +{ 91, 0, 5, 1, 1, 0 }, +{ 91, 1, 6, 1, 2, 1 }, +{ 91, 2, 357, 51, 52, 51 }, +{ 91, 3, 358, 51, 52, 51 }, +{ 91, 4, 359, 51, 52, 51 }, +{ 91, 5, 360, 51, 52, 51 }, +{ 91, 6, 361, 51, 52, 51 }, +{ 91, 0, 362, 52, 52, 51 }, +{ 91, 1, 363, 52, 1, 52 }, +{ 91, 2, 364, 52, 1, 52 }, +{ 92, 3, 0, 0, 1, 0 }, +{ 92, 4, 1, 0, 1, 0 }, +{ 92, 5, 2, 0, 1, 0 }, +{ 92, 6, 3, 0, 1, 0 }, +{ 92, 0, 4, 1, 1, 0 }, +{ 92, 1, 5, 1, 2, 1 }, +{ 92, 2, 6, 1, 2, 1 }, +{ 92, 4, 358, 51, 52, 51 }, +{ 92, 5, 359, 51, 52, 51 }, +{ 92, 6, 360, 51, 52, 51 }, +{ 92, 0, 361, 52, 52, 51 }, +{ 92, 1, 362, 52, 53, 52 }, +{ 92, 2, 363, 52, 53, 52 }, +{ 92, 3, 364, 52, 53, 52 }, +{ 92, 4, 365, 52, 53, 52 }, +{ 93, 5, 0, 0, 53, 0 }, +{ 93, 6, 1, 0, 53, 0 }, +{ 93, 0, 2, 1, 53, 0 }, +{ 93, 1, 3, 1, 1, 1 }, +{ 93, 2, 4, 1, 1, 1 }, +{ 93, 3, 5, 1, 1, 1 }, +{ 93, 4, 6, 1, 1, 1 }, +{ 93, 5, 357, 51, 51, 51 }, +{ 93, 6, 358, 51, 51, 51 }, +{ 93, 0, 359, 52, 51, 51 }, +{ 93, 1, 360, 52, 52, 52 }, +{ 93, 2, 361, 52, 52, 52 }, +{ 93, 3, 362, 52, 52, 52 }, +{ 93, 4, 363, 52, 52, 52 }, +{ 93, 5, 364, 52, 52, 52 }, +{ 94, 6, 0, 0, 52, 0 }, +{ 94, 0, 1, 1, 52, 0 }, +{ 94, 1, 2, 1, 1, 1 }, +{ 94, 2, 3, 1, 1, 1 }, +{ 94, 3, 4, 1, 1, 1 }, +{ 94, 4, 5, 1, 1, 1 }, +{ 94, 5, 6, 1, 1, 1 }, +{ 94, 6, 357, 51, 51, 51 }, +{ 94, 0, 358, 52, 51, 51 }, +{ 94, 1, 359, 52, 52, 52 }, +{ 94, 2, 360, 52, 52, 52 }, +{ 94, 3, 361, 52, 52, 52 }, +{ 94, 4, 362, 52, 52, 52 }, +{ 94, 5, 363, 52, 52, 52 }, +{ 94, 6, 364, 52, 52, 52 }, +{ 95, 0, 0, 1, 52, 0 }, +{ 95, 1, 1, 1, 1, 1 }, +{ 95, 2, 2, 1, 1, 1 }, +{ 95, 3, 3, 1, 1, 1 }, +{ 95, 4, 4, 1, 1, 1 }, +{ 95, 5, 5, 1, 1, 1 }, +{ 95, 6, 6, 1, 1, 1 }, +{ 95, 0, 357, 52, 51, 51 }, +{ 95, 1, 358, 52, 52, 52 }, +{ 95, 2, 359, 52, 52, 52 }, +{ 95, 3, 360, 52, 52, 52 }, +{ 95, 4, 361, 52, 52, 52 }, +{ 95, 5, 362, 52, 52, 52 }, +{ 95, 6, 363, 52, 52, 52 }, +{ 95, 0, 364, 53, 52, 52 }, +{ 96, 1, 0, 0, 1, 1 }, +{ 96, 2, 1, 0, 1, 1 }, +{ 96, 3, 2, 0, 1, 1 }, +{ 96, 4, 3, 0, 1, 1 }, +{ 96, 5, 4, 0, 1, 1 }, +{ 96, 6, 5, 0, 1, 1 }, +{ 96, 0, 6, 1, 1, 1 }, +{ 96, 2, 358, 51, 52, 52 }, +{ 96, 3, 359, 51, 52, 52 }, +{ 96, 4, 360, 51, 52, 52 }, +{ 96, 5, 361, 51, 52, 52 }, +{ 96, 6, 362, 51, 52, 52 }, +{ 96, 0, 363, 52, 52, 52 }, +{ 96, 1, 364, 52, 1, 53 }, +{ 96, 2, 365, 52, 1, 53 }, +{ 97, 3, 0, 0, 1, 0 }, +{ 97, 4, 1, 0, 1, 0 }, +{ 97, 5, 2, 0, 1, 0 }, +{ 97, 6, 3, 0, 1, 0 }, +{ 97, 0, 4, 1, 1, 0 }, +{ 97, 1, 5, 1, 2, 1 }, +{ 97, 2, 6, 1, 2, 1 }, +{ 97, 3, 357, 51, 52, 51 }, +{ 97, 4, 358, 51, 52, 51 }, +{ 97, 5, 359, 51, 52, 51 }, +{ 97, 6, 360, 51, 52, 51 }, +{ 97, 0, 361, 52, 52, 51 }, +{ 97, 1, 362, 52, 1, 52 }, +{ 97, 2, 363, 52, 1, 52 }, +{ 97, 3, 364, 52, 1, 52 }, +{ 98, 4, 0, 0, 1, 0 }, +{ 98, 5, 1, 0, 1, 0 }, +{ 98, 6, 2, 0, 1, 0 }, +{ 98, 0, 3, 1, 1, 0 }, +{ 98, 1, 4, 1, 2, 1 }, +{ 98, 2, 5, 1, 2, 1 }, +{ 98, 3, 6, 1, 2, 1 }, +{ 98, 4, 357, 51, 52, 51 }, +{ 98, 5, 358, 51, 52, 51 }, +{ 98, 6, 359, 51, 52, 51 }, +{ 98, 0, 360, 52, 52, 51 }, +{ 98, 1, 361, 52, 53, 52 }, +{ 98, 2, 362, 52, 53, 52 }, +{ 98, 3, 363, 52, 53, 52 }, +{ 98, 4, 364, 52, 53, 52 }, +{ 99, 5, 0, 0, 53, 0 }, +{ 99, 6, 1, 0, 53, 0 }, +{ 99, 0, 2, 1, 53, 0 }, +{ 99, 1, 3, 1, 1, 1 }, +{ 99, 2, 4, 1, 1, 1 }, +{ 99, 3, 5, 1, 1, 1 }, +{ 99, 4, 6, 1, 1, 1 }, +{ 99, 5, 357, 51, 51, 51 }, +{ 99, 6, 358, 51, 51, 51 }, +{ 99, 0, 359, 52, 51, 51 }, +{ 99, 1, 360, 52, 52, 52 }, +{ 99, 2, 361, 52, 52, 52 }, +{ 99, 3, 362, 52, 52, 52 }, +{ 99, 4, 363, 52, 52, 52 }, +{ 99, 5, 364, 52, 52, 52 }, +{ 100, 6, 0, 0, 52, 0 }, +{ 100, 0, 1, 1, 52, 0 }, +{ 100, 1, 2, 1, 1, 1 }, +{ 100, 2, 3, 1, 1, 1 }, +{ 100, 3, 4, 1, 1, 1 }, +{ 100, 4, 5, 1, 1, 1 }, +{ 100, 5, 6, 1, 1, 1 }, +{ 100, 0, 358, 52, 51, 51 }, +{ 100, 1, 359, 52, 52, 52 }, +{ 100, 2, 360, 52, 52, 52 }, +{ 100, 3, 361, 52, 52, 52 }, +{ 100, 4, 362, 52, 52, 52 }, +{ 100, 5, 363, 52, 52, 52 }, +{ 100, 6, 364, 52, 52, 52 }, +{ 100, 0, 365, 53, 52, 52 }, +{ 101, 1, 0, 0, 1, 1 }, +{ 101, 2, 1, 0, 1, 1 }, +{ 101, 3, 2, 0, 1, 1 }, +{ 101, 4, 3, 0, 1, 1 }, +{ 101, 5, 4, 0, 1, 1 }, +{ 101, 6, 5, 0, 1, 1 }, +{ 101, 0, 6, 1, 1, 1 }, +{ 101, 1, 357, 51, 52, 52 }, +{ 101, 2, 358, 51, 52, 52 }, +{ 101, 3, 359, 51, 52, 52 }, +{ 101, 4, 360, 51, 52, 52 }, +{ 101, 5, 361, 51, 52, 52 }, +{ 101, 6, 362, 51, 52, 52 }, +{ 101, 0, 363, 52, 52, 52 }, +{ 101, 1, 364, 52, 1, 53 }, +{ 102, 2, 0, 0, 1, 0 }, +{ 102, 3, 1, 0, 1, 0 }, +{ 102, 4, 2, 0, 1, 0 }, +{ 102, 5, 3, 0, 1, 0 }, +{ 102, 6, 4, 0, 1, 0 }, +{ 102, 0, 5, 1, 1, 0 }, +{ 102, 1, 6, 1, 2, 1 }, +{ 102, 2, 357, 51, 52, 51 }, +{ 102, 3, 358, 51, 52, 51 }, +{ 102, 4, 359, 51, 52, 51 }, +{ 102, 5, 360, 51, 52, 51 }, +{ 102, 6, 361, 51, 52, 51 }, +{ 102, 0, 362, 52, 52, 51 }, +{ 102, 1, 363, 52, 1, 52 }, +{ 102, 2, 364, 52, 1, 52 }, +{ 103, 3, 0, 0, 1, 0 }, +{ 103, 4, 1, 0, 1, 0 }, +{ 103, 5, 2, 0, 1, 0 }, +{ 103, 6, 3, 0, 1, 0 }, +{ 103, 0, 4, 1, 1, 0 }, +{ 103, 1, 5, 1, 2, 1 }, +{ 103, 2, 6, 1, 2, 1 }, +{ 103, 3, 357, 51, 52, 51 }, +{ 103, 4, 358, 51, 52, 51 }, +{ 103, 5, 359, 51, 52, 51 }, +{ 103, 6, 360, 51, 52, 51 }, +{ 103, 0, 361, 52, 52, 51 }, +{ 103, 1, 362, 52, 1, 52 }, +{ 103, 2, 363, 52, 1, 52 }, +{ 103, 3, 364, 52, 1, 52 }, +{ 104, 4, 0, 0, 1, 0 }, +{ 104, 5, 1, 0, 1, 0 }, +{ 104, 6, 2, 0, 1, 0 }, +{ 104, 0, 3, 1, 1, 0 }, +{ 104, 1, 4, 1, 2, 1 }, +{ 104, 2, 5, 1, 2, 1 }, +{ 104, 3, 6, 1, 2, 1 }, +{ 104, 5, 358, 51, 52, 51 }, +{ 104, 6, 359, 51, 52, 51 }, +{ 104, 0, 360, 52, 52, 51 }, +{ 104, 1, 361, 52, 53, 52 }, +{ 104, 2, 362, 52, 53, 52 }, +{ 104, 3, 363, 52, 53, 52 }, +{ 104, 4, 364, 52, 53, 52 }, +{ 104, 5, 365, 52, 53, 52 }, +{ 105, 6, 0, 0, 53, 0 }, +{ 105, 0, 1, 1, 53, 0 }, +{ 105, 1, 2, 1, 1, 1 }, +{ 105, 2, 3, 1, 1, 1 }, +{ 105, 3, 4, 1, 1, 1 }, +{ 105, 4, 5, 1, 1, 1 }, +{ 105, 5, 6, 1, 1, 1 }, +{ 105, 6, 357, 51, 51, 51 }, +{ 105, 0, 358, 52, 51, 51 }, +{ 105, 1, 359, 52, 52, 52 }, +{ 105, 2, 360, 52, 52, 52 }, +{ 105, 3, 361, 52, 52, 52 }, +{ 105, 4, 362, 52, 52, 52 }, +{ 105, 5, 363, 52, 52, 52 }, +{ 105, 6, 364, 52, 52, 52 }, +{ 106, 0, 0, 1, 52, 0 }, +{ 106, 1, 1, 1, 1, 1 }, +{ 106, 2, 2, 1, 1, 1 }, +{ 106, 3, 3, 1, 1, 1 }, +{ 106, 4, 4, 1, 1, 1 }, +{ 106, 5, 5, 1, 1, 1 }, +{ 106, 6, 6, 1, 1, 1 }, +{ 106, 0, 357, 52, 51, 51 }, +{ 106, 1, 358, 52, 52, 52 }, +{ 106, 2, 359, 52, 52, 52 }, +{ 106, 3, 360, 52, 52, 52 }, +{ 106, 4, 361, 52, 52, 52 }, +{ 106, 5, 362, 52, 52, 52 }, +{ 106, 6, 363, 52, 52, 52 }, +{ 106, 0, 364, 53, 52, 52 }, +{ 107, 1, 0, 0, 1, 1 }, +{ 107, 2, 1, 0, 1, 1 }, +{ 107, 3, 2, 0, 1, 1 }, +{ 107, 4, 3, 0, 1, 1 }, +{ 107, 5, 4, 0, 1, 1 }, +{ 107, 6, 5, 0, 1, 1 }, +{ 107, 0, 6, 1, 1, 1 }, +{ 107, 1, 357, 51, 52, 52 }, +{ 107, 2, 358, 51, 52, 52 }, +{ 107, 3, 359, 51, 52, 52 }, +{ 107, 4, 360, 51, 52, 52 }, +{ 107, 5, 361, 51, 52, 52 }, +{ 107, 6, 362, 51, 52, 52 }, +{ 107, 0, 363, 52, 52, 52 }, +{ 107, 1, 364, 52, 1, 53 }, +{ 108, 2, 0, 0, 1, 0 }, +{ 108, 3, 1, 0, 1, 0 }, +{ 108, 4, 2, 0, 1, 0 }, +{ 108, 5, 3, 0, 1, 0 }, +{ 108, 6, 4, 0, 1, 0 }, +{ 108, 0, 5, 1, 1, 0 }, +{ 108, 1, 6, 1, 2, 1 }, +{ 108, 3, 358, 51, 52, 51 }, +{ 108, 4, 359, 51, 52, 51 }, +{ 108, 5, 360, 51, 52, 51 }, +{ 108, 6, 361, 51, 52, 51 }, +{ 108, 0, 362, 52, 52, 51 }, +{ 108, 1, 363, 52, 1, 52 }, +{ 108, 2, 364, 52, 1, 52 }, +{ 108, 3, 365, 52, 1, 52 }, +{ 109, 4, 0, 0, 1, 0 }, +{ 109, 5, 1, 0, 1, 0 }, +{ 109, 6, 2, 0, 1, 0 }, +{ 109, 0, 3, 1, 1, 0 }, +{ 109, 1, 4, 1, 2, 1 }, +{ 109, 2, 5, 1, 2, 1 }, +{ 109, 3, 6, 1, 2, 1 }, +{ 109, 4, 357, 51, 52, 51 }, +{ 109, 5, 358, 51, 52, 51 }, +{ 109, 6, 359, 51, 52, 51 }, +{ 109, 0, 360, 52, 52, 51 }, +{ 109, 1, 361, 52, 53, 52 }, +{ 109, 2, 362, 52, 53, 52 }, +{ 109, 3, 363, 52, 53, 52 }, +{ 109, 4, 364, 52, 53, 52 }, +{ 110, 5, 0, 0, 53, 0 }, +{ 110, 6, 1, 0, 53, 0 }, +{ 110, 0, 2, 1, 53, 0 }, +{ 110, 1, 3, 1, 1, 1 }, +{ 110, 2, 4, 1, 1, 1 }, +{ 110, 3, 5, 1, 1, 1 }, +{ 110, 4, 6, 1, 1, 1 }, +{ 110, 5, 357, 51, 51, 51 }, +{ 110, 6, 358, 51, 51, 51 }, +{ 110, 0, 359, 52, 51, 51 }, +{ 110, 1, 360, 52, 52, 52 }, +{ 110, 2, 361, 52, 52, 52 }, +{ 110, 3, 362, 52, 52, 52 }, +{ 110, 4, 363, 52, 52, 52 }, +{ 110, 5, 364, 52, 52, 52 }, +{ 111, 6, 0, 0, 52, 0 }, +{ 111, 0, 1, 1, 52, 0 }, +{ 111, 1, 2, 1, 1, 1 }, +{ 111, 2, 3, 1, 1, 1 }, +{ 111, 3, 4, 1, 1, 1 }, +{ 111, 4, 5, 1, 1, 1 }, +{ 111, 5, 6, 1, 1, 1 }, +{ 111, 6, 357, 51, 51, 51 }, +{ 111, 0, 358, 52, 51, 51 }, +{ 111, 1, 359, 52, 52, 52 }, +{ 111, 2, 360, 52, 52, 52 }, +{ 111, 3, 361, 52, 52, 52 }, +{ 111, 4, 362, 52, 52, 52 }, +{ 111, 5, 363, 52, 52, 52 }, +{ 111, 6, 364, 52, 52, 52 }, +{ 112, 0, 0, 1, 52, 0 }, +{ 112, 1, 1, 1, 1, 1 }, +{ 112, 2, 2, 1, 1, 1 }, +{ 112, 3, 3, 1, 1, 1 }, +{ 112, 4, 4, 1, 1, 1 }, +{ 112, 5, 5, 1, 1, 1 }, +{ 112, 6, 6, 1, 1, 1 }, +{ 112, 1, 358, 52, 52, 52 }, +{ 112, 2, 359, 52, 52, 52 }, +{ 112, 3, 360, 52, 52, 52 }, +{ 112, 4, 361, 52, 52, 52 }, +{ 112, 5, 362, 52, 52, 52 }, +{ 112, 6, 363, 52, 52, 52 }, +{ 112, 0, 364, 53, 52, 52 }, +{ 112, 1, 365, 53, 1, 53 }, +{ 113, 2, 0, 0, 1, 0 }, +{ 113, 3, 1, 0, 1, 0 }, +{ 113, 4, 2, 0, 1, 0 }, +{ 113, 5, 3, 0, 1, 0 }, +{ 113, 6, 4, 0, 1, 0 }, +{ 113, 0, 5, 1, 1, 0 }, +{ 113, 1, 6, 1, 2, 1 }, +{ 113, 2, 357, 51, 52, 51 }, +{ 113, 3, 358, 51, 52, 51 }, +{ 113, 4, 359, 51, 52, 51 }, +{ 113, 5, 360, 51, 52, 51 }, +{ 113, 6, 361, 51, 52, 51 }, +{ 113, 0, 362, 52, 52, 51 }, +{ 113, 1, 363, 52, 1, 52 }, +{ 113, 2, 364, 52, 1, 52 }, +{ 114, 3, 0, 0, 1, 0 }, +{ 114, 4, 1, 0, 1, 0 }, +{ 114, 5, 2, 0, 1, 0 }, +{ 114, 6, 3, 0, 1, 0 }, +{ 114, 0, 4, 1, 1, 0 }, +{ 114, 1, 5, 1, 2, 1 }, +{ 114, 2, 6, 1, 2, 1 }, +{ 114, 3, 357, 51, 52, 51 }, +{ 114, 4, 358, 51, 52, 51 }, +{ 114, 5, 359, 51, 52, 51 }, +{ 114, 6, 360, 51, 52, 51 }, +{ 114, 0, 361, 52, 52, 51 }, +{ 114, 1, 362, 52, 1, 52 }, +{ 114, 2, 363, 52, 1, 52 }, +{ 114, 3, 364, 52, 1, 52 }, +{ 115, 4, 0, 0, 1, 0 }, +{ 115, 5, 1, 0, 1, 0 }, +{ 115, 6, 2, 0, 1, 0 }, +{ 115, 0, 3, 1, 1, 0 }, +{ 115, 1, 4, 1, 2, 1 }, +{ 115, 2, 5, 1, 2, 1 }, +{ 115, 3, 6, 1, 2, 1 }, +{ 115, 4, 357, 51, 52, 51 }, +{ 115, 5, 358, 51, 52, 51 }, +{ 115, 6, 359, 51, 52, 51 }, +{ 115, 0, 360, 52, 52, 51 }, +{ 115, 1, 361, 52, 53, 52 }, +{ 115, 2, 362, 52, 53, 52 }, +{ 115, 3, 363, 52, 53, 52 }, +{ 115, 4, 364, 52, 53, 52 }, +{ 116, 5, 0, 0, 53, 0 }, +{ 116, 6, 1, 0, 53, 0 }, +{ 116, 0, 2, 1, 53, 0 }, +{ 116, 1, 3, 1, 1, 1 }, +{ 116, 2, 4, 1, 1, 1 }, +{ 116, 3, 5, 1, 1, 1 }, +{ 116, 4, 6, 1, 1, 1 }, +{ 116, 6, 358, 51, 51, 51 }, +{ 116, 0, 359, 52, 51, 51 }, +{ 116, 1, 360, 52, 52, 52 }, +{ 116, 2, 361, 52, 52, 52 }, +{ 116, 3, 362, 52, 52, 52 }, +{ 116, 4, 363, 52, 52, 52 }, +{ 116, 5, 364, 52, 52, 52 }, +{ 116, 6, 365, 52, 52, 52 }, +{ 117, 0, 0, 1, 52, 0 }, +{ 117, 1, 1, 1, 1, 1 }, +{ 117, 2, 2, 1, 1, 1 }, +{ 117, 3, 3, 1, 1, 1 }, +{ 117, 4, 4, 1, 1, 1 }, +{ 117, 5, 5, 1, 1, 1 }, +{ 117, 6, 6, 1, 1, 1 }, +{ 117, 0, 357, 52, 51, 51 }, +{ 117, 1, 358, 52, 52, 52 }, +{ 117, 2, 359, 52, 52, 52 }, +{ 117, 3, 360, 52, 52, 52 }, +{ 117, 4, 361, 52, 52, 52 }, +{ 117, 5, 362, 52, 52, 52 }, +{ 117, 6, 363, 52, 52, 52 }, +{ 117, 0, 364, 53, 52, 52 }, +{ 118, 1, 0, 0, 1, 1 }, +{ 118, 2, 1, 0, 1, 1 }, +{ 118, 3, 2, 0, 1, 1 }, +{ 118, 4, 3, 0, 1, 1 }, +{ 118, 5, 4, 0, 1, 1 }, +{ 118, 6, 5, 0, 1, 1 }, +{ 118, 0, 6, 1, 1, 1 }, +{ 118, 1, 357, 51, 52, 52 }, +{ 118, 2, 358, 51, 52, 52 }, +{ 118, 3, 359, 51, 52, 52 }, +{ 118, 4, 360, 51, 52, 52 }, +{ 118, 5, 361, 51, 52, 52 }, +{ 118, 6, 362, 51, 52, 52 }, +{ 118, 0, 363, 52, 52, 52 }, +{ 118, 1, 364, 52, 1, 53 }, +{ 119, 2, 0, 0, 1, 0 }, +{ 119, 3, 1, 0, 1, 0 }, +{ 119, 4, 2, 0, 1, 0 }, +{ 119, 5, 3, 0, 1, 0 }, +{ 119, 6, 4, 0, 1, 0 }, +{ 119, 0, 5, 1, 1, 0 }, +{ 119, 1, 6, 1, 2, 1 }, +{ 119, 2, 357, 51, 52, 51 }, +{ 119, 3, 358, 51, 52, 51 }, +{ 119, 4, 359, 51, 52, 51 }, +{ 119, 5, 360, 51, 52, 51 }, +{ 119, 6, 361, 51, 52, 51 }, +{ 119, 0, 362, 52, 52, 51 }, +{ 119, 1, 363, 52, 1, 52 }, +{ 119, 2, 364, 52, 1, 52 }, +{ 120, 3, 0, 0, 1, 0 }, +{ 120, 4, 1, 0, 1, 0 }, +{ 120, 5, 2, 0, 1, 0 }, +{ 120, 6, 3, 0, 1, 0 }, +{ 120, 0, 4, 1, 1, 0 }, +{ 120, 1, 5, 1, 2, 1 }, +{ 120, 2, 6, 1, 2, 1 }, +{ 120, 4, 358, 51, 52, 51 }, +{ 120, 5, 359, 51, 52, 51 }, +{ 120, 6, 360, 51, 52, 51 }, +{ 120, 0, 361, 52, 52, 51 }, +{ 120, 1, 362, 52, 53, 52 }, +{ 120, 2, 363, 52, 53, 52 }, +{ 120, 3, 364, 52, 53, 52 }, +{ 120, 4, 365, 52, 53, 52 }, +{ 121, 5, 0, 0, 53, 0 }, +{ 121, 6, 1, 0, 53, 0 }, +{ 121, 0, 2, 1, 53, 0 }, +{ 121, 1, 3, 1, 1, 1 }, +{ 121, 2, 4, 1, 1, 1 }, +{ 121, 3, 5, 1, 1, 1 }, +{ 121, 4, 6, 1, 1, 1 }, +{ 121, 5, 357, 51, 51, 51 }, +{ 121, 6, 358, 51, 51, 51 }, +{ 121, 0, 359, 52, 51, 51 }, +{ 121, 1, 360, 52, 52, 52 }, +{ 121, 2, 361, 52, 52, 52 }, +{ 121, 3, 362, 52, 52, 52 }, +{ 121, 4, 363, 52, 52, 52 }, +{ 121, 5, 364, 52, 52, 52 }, +{ 122, 6, 0, 0, 52, 0 }, +{ 122, 0, 1, 1, 52, 0 }, +{ 122, 1, 2, 1, 1, 1 }, +{ 122, 2, 3, 1, 1, 1 }, +{ 122, 3, 4, 1, 1, 1 }, +{ 122, 4, 5, 1, 1, 1 }, +{ 122, 5, 6, 1, 1, 1 }, +{ 122, 6, 357, 51, 51, 51 }, +{ 122, 0, 358, 52, 51, 51 }, +{ 122, 1, 359, 52, 52, 52 }, +{ 122, 2, 360, 52, 52, 52 }, +{ 122, 3, 361, 52, 52, 52 }, +{ 122, 4, 362, 52, 52, 52 }, +{ 122, 5, 363, 52, 52, 52 }, +{ 122, 6, 364, 52, 52, 52 }, +{ 123, 0, 0, 1, 52, 0 }, +{ 123, 1, 1, 1, 1, 1 }, +{ 123, 2, 2, 1, 1, 1 }, +{ 123, 3, 3, 1, 1, 1 }, +{ 123, 4, 4, 1, 1, 1 }, +{ 123, 5, 5, 1, 1, 1 }, +{ 123, 6, 6, 1, 1, 1 }, +{ 123, 0, 357, 52, 51, 51 }, +{ 123, 1, 358, 52, 52, 52 }, +{ 123, 2, 359, 52, 52, 52 }, +{ 123, 3, 360, 52, 52, 52 }, +{ 123, 4, 361, 52, 52, 52 }, +{ 123, 5, 362, 52, 52, 52 }, +{ 123, 6, 363, 52, 52, 52 }, +{ 123, 0, 364, 53, 52, 52 }, +{ 124, 1, 0, 0, 1, 1 }, +{ 124, 2, 1, 0, 1, 1 }, +{ 124, 3, 2, 0, 1, 1 }, +{ 124, 4, 3, 0, 1, 1 }, +{ 124, 5, 4, 0, 1, 1 }, +{ 124, 6, 5, 0, 1, 1 }, +{ 124, 0, 6, 1, 1, 1 }, +{ 124, 2, 358, 51, 52, 52 }, +{ 124, 3, 359, 51, 52, 52 }, +{ 124, 4, 360, 51, 52, 52 }, +{ 124, 5, 361, 51, 52, 52 }, +{ 124, 6, 362, 51, 52, 52 }, +{ 124, 0, 363, 52, 52, 52 }, +{ 124, 1, 364, 52, 1, 53 }, +{ 124, 2, 365, 52, 1, 53 }, +{ 125, 3, 0, 0, 1, 0 }, +{ 125, 4, 1, 0, 1, 0 }, +{ 125, 5, 2, 0, 1, 0 }, +{ 125, 6, 3, 0, 1, 0 }, +{ 125, 0, 4, 1, 1, 0 }, +{ 125, 1, 5, 1, 2, 1 }, +{ 125, 2, 6, 1, 2, 1 }, +{ 125, 3, 357, 51, 52, 51 }, +{ 125, 4, 358, 51, 52, 51 }, +{ 125, 5, 359, 51, 52, 51 }, +{ 125, 6, 360, 51, 52, 51 }, +{ 125, 0, 361, 52, 52, 51 }, +{ 125, 1, 362, 52, 1, 52 }, +{ 125, 2, 363, 52, 1, 52 }, +{ 125, 3, 364, 52, 1, 52 }, +{ 126, 4, 0, 0, 1, 0 }, +{ 126, 5, 1, 0, 1, 0 }, +{ 126, 6, 2, 0, 1, 0 }, +{ 126, 0, 3, 1, 1, 0 }, +{ 126, 1, 4, 1, 2, 1 }, +{ 126, 2, 5, 1, 2, 1 }, +{ 126, 3, 6, 1, 2, 1 }, +{ 126, 4, 357, 51, 52, 51 }, +{ 126, 5, 358, 51, 52, 51 }, +{ 126, 6, 359, 51, 52, 51 }, +{ 126, 0, 360, 52, 52, 51 }, +{ 126, 1, 361, 52, 53, 52 }, +{ 126, 2, 362, 52, 53, 52 }, +{ 126, 3, 363, 52, 53, 52 }, +{ 126, 4, 364, 52, 53, 52 }, +{ 127, 5, 0, 0, 53, 0 }, +{ 127, 6, 1, 0, 53, 0 }, +{ 127, 0, 2, 1, 53, 0 }, +{ 127, 1, 3, 1, 1, 1 }, +{ 127, 2, 4, 1, 1, 1 }, +{ 127, 3, 5, 1, 1, 1 }, +{ 127, 4, 6, 1, 1, 1 }, +{ 127, 5, 357, 51, 51, 51 }, +{ 127, 6, 358, 51, 51, 51 }, +{ 127, 0, 359, 52, 51, 51 }, +{ 127, 1, 360, 52, 52, 52 }, +{ 127, 2, 361, 52, 52, 52 }, +{ 127, 3, 362, 52, 52, 52 }, +{ 127, 4, 363, 52, 52, 52 }, +{ 127, 5, 364, 52, 52, 52 }, +{ 128, 6, 0, 0, 52, 0 }, +{ 128, 0, 1, 1, 52, 0 }, +{ 128, 1, 2, 1, 1, 1 }, +{ 128, 2, 3, 1, 1, 1 }, +{ 128, 3, 4, 1, 1, 1 }, +{ 128, 4, 5, 1, 1, 1 }, +{ 128, 5, 6, 1, 1, 1 }, +{ 128, 0, 358, 52, 51, 51 }, +{ 128, 1, 359, 52, 52, 52 }, +{ 128, 2, 360, 52, 52, 52 }, +{ 128, 3, 361, 52, 52, 52 }, +{ 128, 4, 362, 52, 52, 52 }, +{ 128, 5, 363, 52, 52, 52 }, +{ 128, 6, 364, 52, 52, 52 }, +{ 128, 0, 365, 53, 52, 52 }, +{ 129, 1, 0, 0, 1, 1 }, +{ 129, 2, 1, 0, 1, 1 }, +{ 129, 3, 2, 0, 1, 1 }, +{ 129, 4, 3, 0, 1, 1 }, +{ 129, 5, 4, 0, 1, 1 }, +{ 129, 6, 5, 0, 1, 1 }, +{ 129, 0, 6, 1, 1, 1 }, +{ 129, 1, 357, 51, 52, 52 }, +{ 129, 2, 358, 51, 52, 52 }, +{ 129, 3, 359, 51, 52, 52 }, +{ 129, 4, 360, 51, 52, 52 }, +{ 129, 5, 361, 51, 52, 52 }, +{ 129, 6, 362, 51, 52, 52 }, +{ 129, 0, 363, 52, 52, 52 }, +{ 129, 1, 364, 52, 1, 53 }, +{ 130, 2, 0, 0, 1, 0 }, +{ 130, 3, 1, 0, 1, 0 }, +{ 130, 4, 2, 0, 1, 0 }, +{ 130, 5, 3, 0, 1, 0 }, +{ 130, 6, 4, 0, 1, 0 }, +{ 130, 0, 5, 1, 1, 0 }, +{ 130, 1, 6, 1, 2, 1 }, +{ 130, 2, 357, 51, 52, 51 }, +{ 130, 3, 358, 51, 52, 51 }, +{ 130, 4, 359, 51, 52, 51 }, +{ 130, 5, 360, 51, 52, 51 }, +{ 130, 6, 361, 51, 52, 51 }, +{ 130, 0, 362, 52, 52, 51 }, +{ 130, 1, 363, 52, 1, 52 }, +{ 130, 2, 364, 52, 1, 52 }, +{ 131, 3, 0, 0, 1, 0 }, +{ 131, 4, 1, 0, 1, 0 }, +{ 131, 5, 2, 0, 1, 0 }, +{ 131, 6, 3, 0, 1, 0 }, +{ 131, 0, 4, 1, 1, 0 }, +{ 131, 1, 5, 1, 2, 1 }, +{ 131, 2, 6, 1, 2, 1 }, +{ 131, 3, 357, 51, 52, 51 }, +{ 131, 4, 358, 51, 52, 51 }, +{ 131, 5, 359, 51, 52, 51 }, +{ 131, 6, 360, 51, 52, 51 }, +{ 131, 0, 361, 52, 52, 51 }, +{ 131, 1, 362, 52, 1, 52 }, +{ 131, 2, 363, 52, 1, 52 }, +{ 131, 3, 364, 52, 1, 52 }, +{ 132, 4, 0, 0, 1, 0 }, +{ 132, 5, 1, 0, 1, 0 }, +{ 132, 6, 2, 0, 1, 0 }, +{ 132, 0, 3, 1, 1, 0 }, +{ 132, 1, 4, 1, 2, 1 }, +{ 132, 2, 5, 1, 2, 1 }, +{ 132, 3, 6, 1, 2, 1 }, +{ 132, 5, 358, 51, 52, 51 }, +{ 132, 6, 359, 51, 52, 51 }, +{ 132, 0, 360, 52, 52, 51 }, +{ 132, 1, 361, 52, 53, 52 }, +{ 132, 2, 362, 52, 53, 52 }, +{ 132, 3, 363, 52, 53, 52 }, +{ 132, 4, 364, 52, 53, 52 }, +{ 132, 5, 365, 52, 53, 52 }, +{ 133, 6, 0, 0, 53, 0 }, +{ 133, 0, 1, 1, 53, 0 }, +{ 133, 1, 2, 1, 1, 1 }, +{ 133, 2, 3, 1, 1, 1 }, +{ 133, 3, 4, 1, 1, 1 }, +{ 133, 4, 5, 1, 1, 1 }, +{ 133, 5, 6, 1, 1, 1 }, +{ 133, 6, 357, 51, 51, 51 }, +{ 133, 0, 358, 52, 51, 51 }, +{ 133, 1, 359, 52, 52, 52 }, +{ 133, 2, 360, 52, 52, 52 }, +{ 133, 3, 361, 52, 52, 52 }, +{ 133, 4, 362, 52, 52, 52 }, +{ 133, 5, 363, 52, 52, 52 }, +{ 133, 6, 364, 52, 52, 52 }, +{ 134, 0, 0, 1, 52, 0 }, +{ 134, 1, 1, 1, 1, 1 }, +{ 134, 2, 2, 1, 1, 1 }, +{ 134, 3, 3, 1, 1, 1 }, +{ 134, 4, 4, 1, 1, 1 }, +{ 134, 5, 5, 1, 1, 1 }, +{ 134, 6, 6, 1, 1, 1 }, +{ 134, 0, 357, 52, 51, 51 }, +{ 134, 1, 358, 52, 52, 52 }, +{ 134, 2, 359, 52, 52, 52 }, +{ 134, 3, 360, 52, 52, 52 }, +{ 134, 4, 361, 52, 52, 52 }, +{ 134, 5, 362, 52, 52, 52 }, +{ 134, 6, 363, 52, 52, 52 }, +{ 134, 0, 364, 53, 52, 52 }, +{ 135, 1, 0, 0, 1, 1 }, +{ 135, 2, 1, 0, 1, 1 }, +{ 135, 3, 2, 0, 1, 1 }, +{ 135, 4, 3, 0, 1, 1 }, +{ 135, 5, 4, 0, 1, 1 }, +{ 135, 6, 5, 0, 1, 1 }, +{ 135, 0, 6, 1, 1, 1 }, +{ 135, 1, 357, 51, 52, 52 }, +{ 135, 2, 358, 51, 52, 52 }, +{ 135, 3, 359, 51, 52, 52 }, +{ 135, 4, 360, 51, 52, 52 }, +{ 135, 5, 361, 51, 52, 52 }, +{ 135, 6, 362, 51, 52, 52 }, +{ 135, 0, 363, 52, 52, 52 }, +{ 135, 1, 364, 52, 1, 53 }, +{ 136, 2, 0, 0, 1, 0 }, +{ 136, 3, 1, 0, 1, 0 }, +{ 136, 4, 2, 0, 1, 0 }, +{ 136, 5, 3, 0, 1, 0 }, +{ 136, 6, 4, 0, 1, 0 }, +{ 136, 0, 5, 1, 1, 0 }, +{ 136, 1, 6, 1, 2, 1 }, +{ 136, 3, 358, 51, 52, 51 }, +{ 136, 4, 359, 51, 52, 51 }, +{ 136, 5, 360, 51, 52, 51 }, +{ 136, 6, 361, 51, 52, 51 }, +{ 136, 0, 362, 52, 52, 51 }, +{ 136, 1, 363, 52, 1, 52 }, +{ 136, 2, 364, 52, 1, 52 }, +{ 136, 3, 365, 52, 1, 52 }, +{ 137, 4, 0, 0, 1, 0 }, +{ 137, 5, 1, 0, 1, 0 }, +{ 137, 6, 2, 0, 1, 0 }, +{ 137, 0, 3, 1, 1, 0 }, +{ 137, 1, 4, 1, 2, 1 }, +{ 137, 2, 5, 1, 2, 1 }, +{ 137, 3, 6, 1, 2, 1 }, +{ 137, 4, 357, 51, 52, 51 }, +{ 137, 5, 358, 51, 52, 51 }, +{ 137, 6, 359, 51, 52, 51 }, +{ 137, 0, 360, 52, 52, 51 }, +{ 137, 1, 361, 52, 53, 52 }, +{ 137, 2, 362, 52, 53, 52 }, +{ 137, 3, 363, 52, 53, 52 }, +{ 137, 4, 364, 52, 53, 52 }, +}; + +static int test_week_calc( void ) +{ + char buffer[100]; + int rc = 1; + int i; + for ( i = 0; i < 1020; ++i ) + { + struct tm t = { 0 }; + int U, V, W; + t.tm_year = data[i][0]; + t.tm_wday = data[i][1]; + t.tm_yday = data[i][2]; + assert( strftime( buffer, 100, "%U %V %W", &t ) == 8 ); + assert( sscanf( buffer, "%d %d %d", &U, &V, &W ) == 3 ); + if ( data[i][3] != U || data[i][4] != V || data[i][5] != W ) + { + printf( "Fehler in { %d, %d, %d, %d, %d, %d } (encountered { %d, %d, %d })\n", data[i][0], data[i][1], data[i][2], data[i][3], data[i][4], data[i][5], U, V, W ); + rc = 0; + } + } + return rc; +} + +int main( void ) +{ + char buffer[100]; + /* Basic functionality */ + struct tm timeptr; + MKTIME( timeptr, 59, 30, 12, 1, 9, 72, 0, 274 ); + TESTCASE( strftime( buffer, 100, "%a ", &timeptr ) == 4 ); + TESTCASE( strcmp( buffer, "Sun " ) == 0 ); + TESTCASE( strftime( buffer, 100, "%A ", &timeptr ) == 7 ); + TESTCASE( strcmp( buffer, "Sunday " ) == 0 ); + TESTCASE( strftime( buffer, 100, "%b ", &timeptr ) == 4 ); + TESTCASE( strcmp( buffer, "Oct " ) == 0 ); + TESTCASE( strftime( buffer, 100, "%h ", &timeptr ) == 4 ); + TESTCASE( strcmp( buffer, "Oct " ) == 0 ); + TESTCASE( strftime( buffer, 100, "%B ", &timeptr ) == 8 ); + TESTCASE( strcmp( buffer, "October " ) == 0 ); + TESTCASE( strftime( buffer, 100, "%c ", &timeptr ) == 25 ); + TESTCASE( strcmp( buffer, "Sun Oct 1 12:30:59 1972 " ) == 0 ); + TESTCASE( strftime( buffer, 100, "%C ", &timeptr ) == 3 ); + TESTCASE( strcmp( buffer, "19 " ) == 0 ); + TESTCASE( strftime( buffer, 100, "%d ", &timeptr ) == 3 ); + TESTCASE( strcmp( buffer, "01 " ) == 0 ); + TESTCASE( strftime( buffer, 100, "%D ", &timeptr ) == 9 ); + TESTCASE( strcmp( buffer, "10/01/72 " ) == 0 ); + TESTCASE( strftime( buffer, 100, "%e ", &timeptr ) == 3 ); + TESTCASE( strcmp( buffer, " 1 " ) == 0 ); + TESTCASE( strftime( buffer, 100, "%F ", &timeptr ) == 11 ); + TESTCASE( strcmp( buffer, "1972-10-01 " ) == 0 ); + TESTCASE( strftime( buffer, 100, "%H ", &timeptr ) == 3 ); + TESTCASE( strcmp( buffer, "12 " ) == 0 ); + TESTCASE( strftime( buffer, 100, "%I ", &timeptr ) == 3 ); + TESTCASE( strcmp( buffer, "12 " ) == 0 ); + TESTCASE( strftime( buffer, 100, "%j ", &timeptr ) == 4 ); + TESTCASE( strcmp( buffer, "275 " ) == 0 ); + TESTCASE( strftime( buffer, 100, "%m ", &timeptr ) == 3 ); + TESTCASE( strcmp( buffer, "10 " ) == 0 ); + TESTCASE( strftime( buffer, 100, "%M ", &timeptr ) == 3 ); + TESTCASE( strcmp( buffer, "30 " ) == 0 ); + TESTCASE( strftime( buffer, 100, "%p ", &timeptr ) == 3 ); + TESTCASE( strcmp( buffer, "PM " ) == 0 ); + TESTCASE( strftime( buffer, 100, "%r ", &timeptr ) == 12 ); + TESTCASE( strcmp( buffer, "12:30:59 PM " ) == 0 ); + TESTCASE( strftime( buffer, 100, "%R ", &timeptr ) == 6 ); + TESTCASE( strcmp( buffer, "12:30 " ) == 0 ); + TESTCASE( strftime( buffer, 100, "%S ", &timeptr ) == 3 ); + TESTCASE( strcmp( buffer, "59 " ) == 0 ); + TESTCASE( strftime( buffer, 100, "%T ", &timeptr ) == 9 ); + TESTCASE( strcmp( buffer, "12:30:59 " ) == 0 ); + TESTCASE( strftime( buffer, 100, "%u ", &timeptr ) == 2 ); + TESTCASE( strcmp( buffer, "7 " ) == 0 ); + TESTCASE( strftime( buffer, 100, "%w ", &timeptr ) == 2 ); + TESTCASE( strcmp( buffer, "0 " ) == 0 ); + TESTCASE( strftime( buffer, 100, "%x ", &timeptr ) == 9 ); + TESTCASE( strcmp( buffer, "10/01/72 " ) == 0 ); + TESTCASE( strftime( buffer, 100, "%X ", &timeptr ) == 9 ); + TESTCASE( strcmp( buffer, "12:30:59 " ) == 0 ); + TESTCASE( strftime( buffer, 100, "%y ", &timeptr ) == 3 ); + TESTCASE( strcmp( buffer, "72 " ) == 0 ); + TESTCASE( strftime( buffer, 100, "%Y ", &timeptr ) == 5 ); + TESTCASE( strcmp( buffer, "1972 " ) == 0 ); + TESTCASE( strftime( buffer, 100, "%% ", &timeptr ) == 2 ); + TESTCASE( strcmp( buffer, "% " ) == 0 ); + TESTCASE( strftime( buffer, 100, "%n ", &timeptr ) == 2 ); + TESTCASE( strcmp( buffer, "\n " ) == 0 ); + TESTCASE( strftime( buffer, 100, "%t ", &timeptr ) == 2 ); + TESTCASE( strcmp( buffer, "\t " ) == 0 ); + TESTCASE( test_week_calc() ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/include/assert.h b/src/pdclib/include/assert.h new file mode 100644 index 0000000..a5c1a8e --- /dev/null +++ b/src/pdclib/include/assert.h @@ -0,0 +1,35 @@ +/* Diagnostics <assert.h> + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include "pdclib/_PDCLIB_aux.h" + +#ifndef _PDCLIB_ASSERT_H +#define _PDCLIB_ASSERT_H _PDCLIB_ASSERT_H +void _PDCLIB_assert99( const char * const, const char * const, const char * const ); +void _PDCLIB_assert89( const char * const ); +#endif + +/* If NDEBUG is set, assert() is a null operation. */ +#undef assert + +#ifdef NDEBUG +#define assert( ignore ) ( (void) 0 ) +#else +#if __STDC_VERSION__ >= 199901L +#define assert( expression ) ( ( expression ) ? (void) 0 \ + : _PDCLIB_assert99( "Assertion failed: " #expression \ + ", function ", __func__, \ + ", file " __FILE__ \ + ", line " _PDCLIB_symbol2string( __LINE__ ) \ + "." _PDCLIB_endl ) ) +#else +#define assert( expression ) ( ( expression ) ? (void) 0 \ + : _PDCLIB_assert89( "Assertion failed: " #expression \ + ", file " __FILE__ \ + ", line " _PDCLIB_symbol2string( __LINE__ ) \ + "." _PDCLIB_endl ) ) +#endif +#endif diff --git a/src/pdclib/include/ctype.h b/src/pdclib/include/ctype.h new file mode 100644 index 0000000..07fad9c --- /dev/null +++ b/src/pdclib/include/ctype.h @@ -0,0 +1,95 @@ +/* Character handling <ctype.h> + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#ifndef _PDCLIB_CTYPE_H +#define _PDCLIB_CTYPE_H _PDCLIB_CTYPE_H + +#include "pdclib/_PDCLIB_int.h" + +/* Character classification functions */ + +/* Note that there is a difference between "whitespace" (any printing, non- + graph character, like horizontal and vertical tab), and "blank" (the literal + ' ' space character). + + There will be masking macros for each of these later on, but right now I + focus on the functions only. +*/ + +/* Returns isalpha( c ) || isdigit( c ) */ +int isalnum( int c ); + +/* Returns isupper( c ) || islower( c ) in the "C" locale. + In any other locale, also returns true for a locale-specific set of + alphabetic characters which are neither control characters, digits, + punctation, or whitespace. +*/ +int isalpha( int c ); + +/* Returns true if the character isspace() and used for seperating words within + a line of text. In the "C" locale, only ' ' and '\t' are considered blanks. +*/ +int isblank( int c ); + +/* Returns true if the character is a control character. */ +int iscntrl( int c ); + +/* Returns true if the character is a decimal digit. Locale-independent. */ +int isdigit( int c ); + +/* Returns true for every printing character except space (' '). + NOTE: This definition differs from that of iswgraph() in <wctype.h>, + which considers any iswspace() character, not only ' '. +*/ +int isgraph( int c ); + +/* Returns true for lowercase letters in the "C" locale. + In any other locale, also returns true for a locale-specific set of + characters which are neither control characters, digits, punctation, or + space (' '). In a locale other than the "C" locale, a character might test + true for both islower() and isupper(). +*/ +int islower( int c ); + +/* Returns true for every printing character including space (' '). */ +int isprint( int c ); + +/* Returns true for a locale-specific set of punctuation charcters; these + may not be whitespace or alphanumeric. In the "C" locale, returns true + for every printing character that is not whitespace or alphanumeric. +*/ +int ispunct( int c ); + +/* Returns true for every standard whitespace character (' ', '\f', '\n', '\r', + '\t', '\v') in the "C" locale. In any other locale, also returns true for a + locale-specific set of characters for which isalnum() is false. +*/ +int isspace( int c ); + +/* Returns true for uppercase letters in the "C" locale. + In any other locale, also returns true for a locale-specific set of + characters which are neither control characters, digits, punctation, or + space (' '). In a locale other than the "C" locale, a character might test + true for both islower() and isupper(). +*/ +int isupper( int c ); + +/* Returns true for any hexadecimal-digit character. Locale-independent. */ +int isxdigit( int c ); + +/* Character case mapping functions */ + +/* Converts an uppercase letter to a corresponding lowercase letter. Input that + is not an uppercase letter remains unchanged. +*/ +int tolower( int c ); + +/* Converts a lowercase letter to a corresponding uppercase letter. Input that + is not a lowercase letter remains unchanged. +*/ +int toupper( int c ); + +#endif diff --git a/src/pdclib/include/errno.h b/src/pdclib/include/errno.h new file mode 100644 index 0000000..bdc99aa --- /dev/null +++ b/src/pdclib/include/errno.h @@ -0,0 +1,17 @@ +/* Errors <errno.h> + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#ifndef _PDCLIB_ERRNO_H +#define _PDCLIB_ERRNO_H _PDCLIB_ERRNO_H + +#include "pdclib/_PDCLIB_int.h" + +#define errno (*_PDCLIB_errno_func()) + +#define ERANGE _PDCLIB_ERANGE +#define EDOM _PDCLIB_EDOM + +#endif diff --git a/src/pdclib/include/inttypes.h b/src/pdclib/include/inttypes.h new file mode 100644 index 0000000..5252937 --- /dev/null +++ b/src/pdclib/include/inttypes.h @@ -0,0 +1,249 @@ +/* Format conversion of integer types <inttypes.h> + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#ifndef _PDCLIB_INTTYPES_H +#define _PDCLIB_INTTYPES_H _PDCLIB_INTTYPES_H + +#include <stdint.h> + +typedef struct _PDCLIB_imaxdiv_t imaxdiv_t; + +#define PRId8 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_8_CONV, d ) ) +#define PRId16 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_16_CONV, d ) ) +#define PRId32 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_32_CONV, d ) ) +#define PRId64 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_64_CONV, d ) ) + +#define PRIdLEAST8 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_8_CONV, d ) ) +#define PRIdLEAST16 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_16_CONV, d ) ) +#define PRIdLEAST32 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_32_CONV, d ) ) +#define PRIdLEAST64 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_64_CONV, d ) ) + +#define PRIdFAST8 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_FAST8_CONV, d ) ) +#define PRIdFAST16 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_FAST16_CONV, d ) ) +#define PRIdFAST32 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_FAST32_CONV, d ) ) +#define PRIdFAST64 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_FAST64_CONV, d ) ) + +#define PRIdMAX _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_MAX_CONV, d ) ) +#define PRIdPTR _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_PTR_CONV, d ) ) + +#define PRIi8 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_8_CONV, i ) ) +#define PRIi16 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_16_CONV, i ) ) +#define PRIi32 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_32_CONV, i ) ) +#define PRIi64 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_64_CONV, i ) ) + +#define PRIiLEAST8 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_8_CONV, i ) ) +#define PRIiLEAST16 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_16_CONV, i ) ) +#define PRIiLEAST32 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_32_CONV, i ) ) +#define PRIiLEAST64 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_64_CONV, i ) ) + +#define PRIiFAST8 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_FAST8_CONV, i ) ) +#define PRIiFAST16 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_FAST16_CONV, i ) ) +#define PRIiFAST32 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_FAST32_CONV, i ) ) +#define PRIiFAST64 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_FAST64_CONV, i ) ) + +#define PRIiMAX _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_MAX_CONV, i ) ) +#define PRIiPTR _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_PTR_CONV, i ) ) + +#define PRIo8 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_8_CONV, o ) ) +#define PRIo16 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_16_CONV, o ) ) +#define PRIo32 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_32_CONV, o ) ) +#define PRIo64 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_64_CONV, o ) ) + +#define PRIoLEAST8 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_8_CONV, o ) ) +#define PRIoLEAST16 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_16_CONV, o ) ) +#define PRIoLEAST32 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_32_CONV, o ) ) +#define PRIoLEAST64 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_64_CONV, o ) ) + +#define PRIoFAST8 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_FAST8_CONV, o ) ) +#define PRIoFAST16 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_FAST16_CONV, o ) ) +#define PRIoFAST32 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_FAST32_CONV, o ) ) +#define PRIoFAST64 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_FAST64_CONV, o ) ) + +#define PRIoMAX _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_MAX_CONV, o ) ) +#define PRIoPTR _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_PTR_CONV, o ) ) + +#define PRIu8 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_8_CONV, u ) ) +#define PRIu16 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_16_CONV, u ) ) +#define PRIu32 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_32_CONV, u ) ) +#define PRIu64 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_64_CONV, u ) ) + +#define PRIuLEAST8 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_8_CONV, u ) ) +#define PRIuLEAST16 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_16_CONV, u ) ) +#define PRIuLEAST32 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_32_CONV, u ) ) +#define PRIuLEAST64 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_64_CONV, u ) ) + +#define PRIuFAST8 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_FAST8_CONV, u ) ) +#define PRIuFAST16 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_FAST16_CONV, u ) ) +#define PRIuFAST32 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_FAST32_CONV, u ) ) +#define PRIuFAST64 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_FAST64_CONV, u ) ) + +#define PRIuMAX _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_MAX_CONV, u ) ) +#define PRIuPTR _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_PTR_CONV, u ) ) + +#define PRIx8 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_8_CONV, x ) ) +#define PRIx16 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_16_CONV, x ) ) +#define PRIx32 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_32_CONV, x ) ) +#define PRIx64 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_64_CONV, x ) ) + +#define PRIxLEAST8 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_8_CONV, x ) ) +#define PRIxLEAST16 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_16_CONV, x ) ) +#define PRIxLEAST32 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_32_CONV, x ) ) +#define PRIxLEAST64 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_64_CONV, x ) ) + +#define PRIxFAST8 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_FAST8_CONV, x ) ) +#define PRIxFAST16 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_FAST16_CONV, x ) ) +#define PRIxFAST32 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_FAST32_CONV, x ) ) +#define PRIxFAST64 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_FAST64_CONV, x ) ) + +#define PRIxMAX _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_MAX_CONV, x ) ) +#define PRIxPTR _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_PTR_CONV, x ) ) + +#define PRIX8 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_8_CONV, X ) ) +#define PRIX16 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_16_CONV, X ) ) +#define PRIX32 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_32_CONV, X ) ) +#define PRIX64 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_64_CONV, X ) ) + +#define PRIXLEAST8 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_8_CONV, X ) ) +#define PRIXLEAST16 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_16_CONV, X ) ) +#define PRIXLEAST32 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_32_CONV, X ) ) +#define PRIXLEAST64 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_64_CONV, X ) ) + +#define PRIXFAST8 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_FAST8_CONV, X ) ) +#define PRIXFAST16 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_FAST16_CONV, X ) ) +#define PRIXFAST32 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_FAST32_CONV, X ) ) +#define PRIXFAST64 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_FAST64_CONV, X ) ) + +#define PRIXMAX _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_MAX_CONV, X ) ) +#define PRIXPTR _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_PTR_CONV, X ) ) + +#define SCNd8 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_8_CONV, d ) ) +#define SCNd16 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_16_CONV, d ) ) +#define SCNd32 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_32_CONV, d ) ) +#define SCNd64 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_64_CONV, d ) ) + +#define SCNdLEAST8 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_8_CONV, d ) ) +#define SCNdLEAST16 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_16_CONV, d ) ) +#define SCNdLEAST32 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_32_CONV, d ) ) +#define SCNdLEAST64 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_64_CONV, d ) ) + +#define SCNdFAST8 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_FAST8_CONV, d ) ) +#define SCNdFAST16 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_FAST16_CONV, d ) ) +#define SCNdFAST32 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_FAST32_CONV, d ) ) +#define SCNdFAST64 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_FAST64_CONV, d ) ) + +#define SCNdMAX _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_MAX_CONV, d ) ) +#define SCNdPTR _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_PTR_CONV, d ) ) + +#define SCNi8 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_8_CONV, i ) ) +#define SCNi16 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_16_CONV, i ) ) +#define SCNi32 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_32_CONV, i ) ) +#define SCNi64 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_64_CONV, i ) ) + +#define SCNiLEAST8 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_8_CONV, i ) ) +#define SCNiLEAST16 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_16_CONV, i ) ) +#define SCNiLEAST32 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_32_CONV, i ) ) +#define SCNiLEAST64 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_64_CONV, i ) ) + +#define SCNiFAST8 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_FAST8_CONV, i ) ) +#define SCNiFAST16 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_FAST16_CONV, i ) ) +#define SCNiFAST32 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_FAST32_CONV, i ) ) +#define SCNiFAST64 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_FAST64_CONV, i ) ) + +#define SCNiMAX _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_MAX_CONV, i ) ) +#define SCNiPTR _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_PTR_CONV, i ) ) + +#define SCNo8 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_8_CONV, o ) ) +#define SCNo16 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_16_CONV, o ) ) +#define SCNo32 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_32_CONV, o ) ) +#define SCNo64 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_64_CONV, o ) ) + +#define SCNoLEAST8 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_8_CONV, o ) ) +#define SCNoLEAST16 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_16_CONV, o ) ) +#define SCNoLEAST32 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_32_CONV, o ) ) +#define SCNoLEAST64 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_64_CONV, o ) ) + +#define SCNoFAST8 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_FAST8_CONV, o ) ) +#define SCNoFAST16 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_FAST16_CONV, o ) ) +#define SCNoFAST32 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_FAST32_CONV, o ) ) +#define SCNoFAST64 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_FAST64_CONV, o ) ) + +#define SCNoMAX _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_MAX_CONV, o ) ) +#define SCNoPTR _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_PTR_CONV, o ) ) + +#define SCNu8 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_8_CONV, u ) ) +#define SCNu16 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_16_CONV, u ) ) +#define SCNu32 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_32_CONV, u ) ) +#define SCNu64 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_64_CONV, u ) ) + +#define SCNuLEAST8 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_8_CONV, u ) ) +#define SCNuLEAST16 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_16_CONV, u ) ) +#define SCNuLEAST32 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_32_CONV, u ) ) +#define SCNuLEAST64 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_64_CONV, u ) ) + +#define SCNuFAST8 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_FAST8_CONV, u ) ) +#define SCNuFAST16 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_FAST16_CONV, u ) ) +#define SCNuFAST32 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_FAST32_CONV, u ) ) +#define SCNuFAST64 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_FAST64_CONV, u ) ) + +#define SCNuMAX _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_MAX_CONV, u ) ) +#define SCNuPTR _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_PTR_CONV, u ) ) + +#define SCNx8 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_8_CONV, x ) ) +#define SCNx16 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_16_CONV, x ) ) +#define SCNx32 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_32_CONV, x ) ) +#define SCNx64 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_64_CONV, x ) ) + +#define SCNxLEAST8 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_8_CONV, x ) ) +#define SCNxLEAST16 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_16_CONV, x ) ) +#define SCNxLEAST32 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_32_CONV, x ) ) +#define SCNxLEAST64 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_64_CONV, x ) ) + +#define SCNxFAST8 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_FAST8_CONV, x ) ) +#define SCNxFAST16 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_FAST16_CONV, x ) ) +#define SCNxFAST32 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_FAST32_CONV, x ) ) +#define SCNxFAST64 _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_FAST64_CONV, x ) ) + +#define SCNxMAX _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_MAX_CONV, x ) ) +#define SCNxPTR _PDCLIB_symbol2string( _PDCLIB_concat( _PDCLIB_PTR_CONV, x ) ) + +/* 7.8.2 Functions for greatest-width integer types */ + +/* Calculate the absolute value of j */ +intmax_t imaxabs( intmax_t j ); + +/* Return quotient (quot) and remainder (rem) of an integer division in the + imaxdiv_t struct. +*/ +imaxdiv_t imaxdiv( intmax_t numer, intmax_t denom ); + +/* Seperate the character array nptr into three parts: A (possibly empty) + sequence of whitespace characters, a character representation of an integer + to the given base, and trailing invalid characters (including the terminating + null character). If base is 0, assume it to be 10, unless the integer + representation starts with 0x / 0X (setting base to 16) or 0 (setting base to + 8). If given, base can be anything from 0 to 36, using the 26 letters of the + base alphabet (both lowercase and uppercase) as digits 10 through 35. + The integer representation is then converted into the return type of the + function. It can start with a '+' or '-' sign. If the sign is '-', the result + of the conversion is negated. + If the conversion is successful, the converted value is returned. If endptr + is not a NULL pointer, a pointer to the first trailing invalid character is + returned in *endptr. + If no conversion could be performed, zero is returned (and nptr in *endptr, + if endptr is not a NULL pointer). If the converted value does not fit into + the return type, the functions return INTMAX_MIN, INTMAX_MAX, or UINTMAX_MAX, + respectively, depending on the sign of the integer representation and the + return type, and errno is set to ERANGE. +*/ +/* This function is equivalent to strtol() / strtoul() in <stdlib.h>, but on + the potentially larger type. +*/ +intmax_t strtoimax( const char * _PDCLIB_restrict nptr, char * * _PDCLIB_restrict endptr, int base ); +uintmax_t strtoumax( const char * _PDCLIB_restrict nptr, char * * _PDCLIB_restrict endptr, int base ); + +/* TODO: wcstoimax(), wcstoumax() */ + +#endif diff --git a/src/pdclib/include/iso646.h b/src/pdclib/include/iso646.h new file mode 100644 index 0000000..98a023f --- /dev/null +++ b/src/pdclib/include/iso646.h @@ -0,0 +1,22 @@ +/* Alternative spellings <iso646.h> + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#ifndef _PDCLIB_ISO646_H +#define _PDCLIB_ISO646_H _PDCLIB_ISO646_H + +#define and && +#define and_eq &= +#define bitand & +#define bitor | +#define compl ~ +#define not ! +#define not_eq != +#define or || +#define or_eq |= +#define xor ^ +#define xor_eq ^= + +#endif diff --git a/src/pdclib/include/limits.h b/src/pdclib/include/limits.h new file mode 100644 index 0000000..4349acd --- /dev/null +++ b/src/pdclib/include/limits.h @@ -0,0 +1,35 @@ +/* Sizes of integer types <limits.h> + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#ifndef _PDCLIB_LIMITS_H +#define _PDCLIB_LIMITS_H _PDCLIB_LIMITS_H + +#include "pdclib/_PDCLIB_int.h" + +/* TODO: Defined to 1 as multibyte characters are not supported yet. */ +#define MB_LEN_MAX 1 + +#define LLONG_MIN _PDCLIB_LLONG_MIN +#define LLONG_MAX _PDCLIB_LLONG_MAX +#define ULLONG_MAX _PDCLIB_ULLONG_MAX + +#define CHAR_BIT _PDCLIB_CHAR_BIT +#define CHAR_MAX _PDCLIB_CHAR_MAX +#define CHAR_MIN _PDCLIB_CHAR_MIN +#define SCHAR_MAX _PDCLIB_SCHAR_MAX +#define SCHAR_MIN _PDCLIB_SCHAR_MIN +#define UCHAR_MAX _PDCLIB_UCHAR_MAX +#define SHRT_MAX _PDCLIB_SHRT_MAX +#define SHRT_MIN _PDCLIB_SHRT_MIN +#define INT_MAX _PDCLIB_INT_MAX +#define INT_MIN _PDCLIB_INT_MIN +#define LONG_MAX _PDCLIB_LONG_MAX +#define LONG_MIN _PDCLIB_LONG_MIN +#define USHRT_MAX _PDCLIB_USHRT_MAX +#define UINT_MAX _PDCLIB_UINT_MAX +#define ULONG_MAX _PDCLIB_ULONG_MAX + +#endif diff --git a/src/pdclib/include/locale.h b/src/pdclib/include/locale.h new file mode 100644 index 0000000..c8467a8 --- /dev/null +++ b/src/pdclib/include/locale.h @@ -0,0 +1,99 @@ +/* Localization <locale.h> + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#ifndef _PDCLIB_LOCALE_H +#define _PDCLIB_LOCALE_H _PDCLIB_LOCALE_H + +#include "pdclib/_PDCLIB_int.h" + +#ifndef _PDCLIB_NULL_DEFINED +#define _PDCLIB_NULL_DEFINED _PDCLIB_NULL_DEFINED +#define NULL _PDCLIB_NULL +#endif + +/* The structure returned by localeconv(). + + The values for *_sep_by_space: + 0 - no space + 1 - if symbol and sign are adjacent, a space seperates them from the value; + otherwise a space seperates the symbol from the value + 2 - if symbol and sign are adjacent, a space seperates them; otherwise a + space seperates the sign from the value + + The values for *_sign_posn: + 0 - Parentheses surround value and symbol + 1 - sign precedes value and symbol + 2 - sign succeeds value and symbol + 3 - sign immediately precedes symbol + 4 - sign immediately succeeds symbol +*/ +struct lconv +{ + char * decimal_point; /* decimal point character */ /* LC_NUMERIC */ + char * thousands_sep; /* character for seperating groups of digits */ /* LC_NUMERIC */ + char * grouping; /* string indicating the size of digit groups */ /* LC_NUMERIC */ + char * mon_decimal_point; /* decimal point for monetary quantities */ /* LC_MONETARY */ + char * mon_thousands_sep; /* thousands_sep for monetary quantities */ /* LC_MONETARY */ + char * mon_grouping; /* grouping for monetary quantities */ /* LC_MONETARY */ + char * positive_sign; /* string indicating nonnegative mty. qty. */ /* LC_MONETARY */ + char * negative_sign; /* string indicating negative mty. qty. */ /* LC_MONETARY */ + char * currency_symbol; /* local currency symbol (e.g. '$') */ /* LC_MONETARY */ + char * int_curr_symbol; /* international currency symbol (e.g. "USD" */ /* LC_MONETARY */ + char frac_digits; /* fractional digits in local monetary qty. */ /* LC_MONETARY */ + char p_cs_precedes; /* if currency_symbol precedes positive qty. */ /* LC_MONETARY */ + char n_cs_precedes; /* if currency_symbol precedes negative qty. */ /* LC_MONETARY */ + char p_sep_by_space; /* if it is seperated by space from pos. qty. */ /* LC_MONETARY */ + char n_sep_by_space; /* if it is seperated by space from neg. qty. */ /* LC_MONETARY */ + char p_sign_posn; /* positioning of positive_sign for mon. qty. */ /* LC_MONETARY */ + char n_sign_posn; /* positioning of negative_sign for mon. qty. */ /* LC_MONETARY */ + char int_frac_digits; /* Same as above, for international format */ /* LC_MONETARY */ + char int_p_cs_precedes; /* Same as above, for international format */ /* LC_MONETARY */ + char int_n_cs_precedes; /* Same as above, for international format */ /* LC_MONETARY */ + char int_p_sep_by_space; /* Same as above, for international format */ /* LC_MONETARY */ + char int_n_sep_by_space; /* Same as above, for international format */ /* LC_MONETARY */ + char int_p_sign_posn; /* Same as above, for international format */ /* LC_MONETARY */ + char int_n_sign_posn; /* Same as above, for international format */ /* LC_MONETARY */ +}; + +/* First arguments to setlocale(). + NOTE: If you add to / modify these, look at functions/locale/setlocale.c + and keep things in sync. +*/ +/* Entire locale */ +#define LC_ALL _PDCLIB_LC_ALL +/* Collation (strcoll(), strxfrm()) */ +#define LC_COLLATE _PDCLIB_LC_COLLATE +/* Character types (<ctype.h>, <wctype.h>) */ +#define LC_CTYPE _PDCLIB_LC_CTYPE +/* Monetary formatting (as returned by localeconv) */ +#define LC_MONETARY _PDCLIB_LC_MONETARY +/* Decimal-point character (for printf() / scanf() functions), string + conversions, nonmonetary formatting as returned by localeconv +*/ +#define LC_NUMERIC _PDCLIB_LC_NUMERIC +/* Time formats (strftime(), wcsftime()) */ +#define LC_TIME _PDCLIB_LC_TIME +/* Messages (not specified but allowed by C99, and specified by POSIX) + (used by perror() / strerror()) +*/ +#define LC_MESSAGES _PDCLIB_LC_MESSAGES + +/* The category parameter can be any of the LC_* macros to specify if the call + to setlocale() shall affect the entire locale or only a portion thereof. + The category locale specifies which locale should be switched to, with "C" + being the minimal default locale, and "" being the locale-specific native + environment. A NULL pointer makes setlocale() return the *current* setting. + Otherwise, returns a pointer to a string associated with the specified + category for the new locale. +*/ +char * setlocale( int category, const char * locale ); + +/* Returns a struct lconv initialized to the values appropriate for the current + locale setting. +*/ +struct lconv * localeconv( void ); + +#endif diff --git a/src/pdclib/include/pdclib/_PDCLIB_aux.h b/src/pdclib/include/pdclib/_PDCLIB_aux.h new file mode 100644 index 0000000..d6ca14e --- /dev/null +++ b/src/pdclib/include/pdclib/_PDCLIB_aux.h @@ -0,0 +1,65 @@ +/* Auxiliary PDCLib code <_PDCLIB_aux.h> + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#ifndef _PDCLIB_AUX_H +#define _PDCLIB_AUX_H _PDCLIB_AUX_H + +/* -------------------------------------------------------------------------- */ +/* You should not have to edit anything in this file; if you DO have to, it */ +/* would be considered a bug / missing feature: notify the author(s). */ +/* -------------------------------------------------------------------------- */ + +/* -------------------------------------------------------------------------- */ +/* Standard Version */ +/* -------------------------------------------------------------------------- */ + +/* Many a compiler gets this wrong, so you might have to hardcode it instead. */ + +#if __STDC__ != 1 +#error Compiler does not define _ _STDC_ _ to 1 (not standard-compliant)! +#endif + +#if __STDC_VERSION__ < 199901L +#define _PDCLIB_restrict +#define _PDCLIB_inline +#else +#define _PDCLIB_restrict restrict +#define _PDCLIB_inline inline +#endif + +#ifndef __STDC_HOSTED__ +#error Compiler does not define _ _STDC_HOSTED_ _ (not standard-compliant)! +#elif __STDC_HOSTED__ == 0 +#define _PDCLIB_HOSTED 0 +#elif __STDC_HOSTED__ == 1 +#define _PDCLIB_HOSTED 1 +#else +#error Compiler does not define _ _STDC_HOSTED_ _ to 0 or 1 (not standard-compliant)! +#endif + +/* -------------------------------------------------------------------------- */ +/* Helper macros: */ +/* _PDCLIB_cc( x, y ) concatenates two preprocessor tokens without extending */ +/* _PDCLIB_concat( x, y ) concatenates two preprocessor tokens with extending */ +/* _PDCLIB_static_assert( e, m ) does a compile-time assertion of expression */ +/* e, with m as the failure message. */ +/* _PDCLIB_TYPE_SIGNED( type ) resolves to true if type is signed. */ +/* _PDCLIB_TWOS_COMPLEMENT( type ) resolves to true if two's complement is */ +/* used for type. */ +/* -------------------------------------------------------------------------- */ + +#define _PDCLIB_cc( x, y ) x ## y +#define _PDCLIB_concat( x, y ) _PDCLIB_cc( x, y ) + +#define _PDCLIB_static_assert( e, m ) enum { _PDCLIB_concat( _PDCLIB_assert_, __LINE__ ) = 1 / ( !!(e) ) } + +#define _PDCLIB_TYPE_SIGNED( type ) (((type) -1) < 0) +#define _PDCLIB_TWOS_COMPLEMENT( type ) ((type) ~ (type) 0 < 0 ) + +#define _PDCLIB_symbol2value( x ) #x +#define _PDCLIB_symbol2string( x ) _PDCLIB_symbol2value( x ) + +#endif diff --git a/src/pdclib/include/pdclib/_PDCLIB_glue.h b/src/pdclib/include/pdclib/_PDCLIB_glue.h new file mode 100644 index 0000000..fc1bbb2 --- /dev/null +++ b/src/pdclib/include/pdclib/_PDCLIB_glue.h @@ -0,0 +1,71 @@ +/* OS glue functions declaration <_PDCLIB_glue.h> + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#ifndef _PDCLIB_GLUE_H +#define _PDCLIB_GLUE_H _PDCLIB_GLUE_H + +#include "pdclib/_PDCLIB_int.h" + +/* -------------------------------------------------------------------------- */ +/* OS "glue", part 2 */ +/* These are the functions you will have to touch, as they are where PDCLib */ +/* interfaces with the operating system. */ +/* They operate on data types partially defined by _PDCLIB_config.h. */ +/* -------------------------------------------------------------------------- */ + +/* stdlib.h */ + +/* A system call that terminates the calling process, returning a given status + to the environment. +*/ +void _PDCLIB_Exit( int status ) _PDCLIB_NORETURN; + +/* A system call that adds n pages of memory to the process heap (if n is + positive), or releases n pages from the process heap (if n is negative). + Return a (void *) pointing to the *former* end-of-heap if successful, NULL + otherwise. +*/ +void * _PDCLIB_allocpages( int n ); + + +/* stdio.h */ + +/* A system call that opens a file identified by name in a given mode. Return + a file descriptor uniquely identifying that file. + (The mode is the return value of the _PDCLIB_filemode() function.) +*/ +_PDCLIB_fd_t _PDCLIB_open( const char * const filename, unsigned int mode ); + +/* A system call that writes a stream's buffer. + Returns 0 on success, EOF on write error. + Sets stream error flags and errno appropriately on error. +*/ +int _PDCLIB_flushbuffer( struct _PDCLIB_file_t * stream ); + +/* A system call that fills a stream's buffer. + Returns 0 on success, EOF on read error / EOF. + Sets stream EOF / error flags and errno appropriately on error. +*/ +int _PDCLIB_fillbuffer( struct _PDCLIB_file_t * stream ); + +/* A system call that repositions within a file. Returns new offset on success, + -1 / errno on error. +*/ +_PDCLIB_int64_t _PDCLIB_seek( struct _PDCLIB_file_t * stream, _PDCLIB_int64_t offset, int whence ); + +/* A system call that closes a file identified by given file descriptor. Return + zero on success, non-zero otherwise. +*/ +int _PDCLIB_close( _PDCLIB_fd_t fd ); + +/* A system call that renames a file from given old name to given new name. + Return zero on success, non-zero otherwise. In case of failure, the file + must still be accessible by old name. Any handling of open files etc. is + done by standard rename() already. +*/ +int _PDCLIB_rename( const char * old, const char * new ); + +#endif diff --git a/src/pdclib/include/pdclib/_PDCLIB_int.h b/src/pdclib/include/pdclib/_PDCLIB_int.h new file mode 100644 index 0000000..6eaded1 --- /dev/null +++ b/src/pdclib/include/pdclib/_PDCLIB_int.h @@ -0,0 +1,582 @@ +/* PDCLib internal integer logic <_PDCLIB_int.h> + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#ifndef _PDCLIB_INT_H +#define _PDCLIB_INT_H _PDCLIB_INT_H + +/* -------------------------------------------------------------------------- */ +/* You should not have to edit anything in this file; if you DO have to, it */ +/* would be considered a bug / missing feature: notify the author(s). */ +/* -------------------------------------------------------------------------- */ + +#include <stdbool.h> + +#include "pdclib/_PDCLIB_config.h" +#include "pdclib/_PDCLIB_aux.h" + +/* null pointer constant */ +#define _PDCLIB_NULL 0 + +/* -------------------------------------------------------------------------- */ +/* Limits of native datatypes */ +/* -------------------------------------------------------------------------- */ +/* The definition of minimum limits for unsigned datatypes is done because */ +/* later on we will "construct" limits for other abstract types: */ +/* USHRT -> _PDCLIB_ + USHRT + _MIN -> _PDCLIB_USHRT_MIN -> 0 */ +/* INT -> _PDCLIB_ + INT + _MIN -> _PDCLIB_INT_MIN -> ... you get the idea. */ +/* -------------------------------------------------------------------------- */ + +/* Setting 'char' limits */ +#define _PDCLIB_CHAR_BIT 8 +#define _PDCLIB_UCHAR_MIN 0 +#define _PDCLIB_UCHAR_MAX 0xff +#define _PDCLIB_SCHAR_MIN (-0x7f - 1) +#define _PDCLIB_SCHAR_MAX 0x7f +#if _PDCLIB_CHAR_SIGNED == 1 +#define _PDCLIB_CHAR_MIN _PDCLIB_SCHAR_MIN +#define _PDCLIB_CHAR_MAX _PDCLIB_SCHAR_MAX +#else +#define _PDCLIB_CHAR_MIN 0 +#define _PDCLIB_CHAR_MAX _PDCLIB_UCHAR_MAX +#endif + +/* Setting 'short' limits */ +#if _PDCLIB_SHRT_BYTES == 2 +#define _PDCLIB_SHRT_MAX 0x7fff +#define _PDCLIB_SHRT_MIN (-0x7fff - 1) +#define _PDCLIB_USHRT_MAX 0xffff +#else +#error Unsupported width of 'short' (not 16 bit). +#endif +#define _PDCLIB_USHRT_MIN 0 + +#if _PDCLIB_INT_BYTES < _PDCLIB_SHRT_BYTES +#error Bogus setting: short > int? Check _PDCLIB_config.h. +#endif + +/* Setting 'int' limits */ +#if _PDCLIB_INT_BYTES == 2 +#define _PDCLIB_INT_MAX 0x7fff +#define _PDCLIB_INT_MIN (-0x7fff - 1) +#define _PDCLIB_UINT_MAX 0xffffU +#elif _PDCLIB_INT_BYTES == 4 +#define _PDCLIB_INT_MAX 0x7fffffff +#define _PDCLIB_INT_MIN (-0x7fffffff - 1) +#define _PDCLIB_UINT_MAX 0xffffffffU +#elif _PDCLIB_INT_BYTES == 8 +#define _PDCLIB_INT_MAX 0x7fffffffffffffff +#define _PDCLIB_INT_MIN (-0x7fffffffffffffff - 1) +#define _PDCLIB_UINT_MAX 0xffffffffffffffff +#else +#error Unsupported width of 'int' (neither 16, 32, nor 64 bit). +#endif +#define _PDCLIB_UINT_MIN 0 + +/* Setting 'long' limits */ +#if _PDCLIB_LONG_BYTES == 4 +#define _PDCLIB_LONG_MAX 0x7fffffffL +#define _PDCLIB_LONG_MIN (-0x7fffffffL - 1L) +#define _PDCLIB_ULONG_MAX 0xffffffffUL +#elif _PDCLIB_LONG_BYTES == 8 +#define _PDCLIB_LONG_MAX 0x7fffffffffffffffL +#define _PDCLIB_LONG_MIN (-0x7fffffffffffffffL - 1L) +#define _PDCLIB_ULONG_MAX 0xffffffffffffffffUL +#else +#error Unsupported width of 'long' (neither 32 nor 64 bit). +#endif +#define _PDCLIB_ULONG_MIN 0 + +/* Setting 'long long' limits */ +#if _PDCLIB_LLONG_BYTES == 8 +#define _PDCLIB_LLONG_MAX 0x7fffffffffffffffLL +#define _PDCLIB_LLONG_MIN (-0x7fffffffffffffffLL - 1LL) +#define _PDCLIB_ULLONG_MAX 0xffffffffffffffffULL +#elif _PDCLIB_LLONG_BYTES == 16 +#define _PDCLIB_LLONG_MAX 0x7fffffffffffffffffffffffffffffffLL +#define _PDCLIB_LLONG_MIN (-0x7fffffffffffffffffffffffffffffffLL - 1LL) +#define _PDCLIB_ULLONG_MAX 0xffffffffffffffffffffffffffffffffULL +#else +#error Unsupported width of 'long long' (neither 64 nor 128 bit). +#endif +#define _PDCLIB_ULLONG_MIN 0 + +/* -------------------------------------------------------------------------- */ +/* <stdint.h> exact-width types and their limits */ +/* -------------------------------------------------------------------------- */ +/* Note that, for the "standard" widths of 8, 16, 32 and 64 bit, the "LEAST" */ +/* types are identical to the "exact-width" types, by definition. */ + +/* Setting 'int8_t', its limits, its literal, and conversion macros. */ +#if _PDCLIB_CHAR_BIT == 8 +typedef signed char _PDCLIB_int8_t; +typedef unsigned char _PDCLIB_uint8_t; +#define _PDCLIB_INT8_MAX _PDCLIB_CHAR_MAX +#define _PDCLIB_INT8_MIN _PDCLIB_CHAR_MIN +#define _PDCLIB_UINT8_MAX _PDCLIB_UCHAR_MAX +#define _PDCLIB_8_CONV hh +#else +#error Unsupported width of char (not 8 bits). +#endif + +/* Setting 'int16_t', its limits, its literal, and conversion macros. */ +#if _PDCLIB_INT_BYTES == 2 +typedef signed int _PDCLIB_int16_t; +typedef unsigned int _PDCLIB_uint16_t; +#define _PDCLIB_INT16_MAX _PDCLIB_INT_MAX +#define _PDCLIB_INT16_MIN _PDCLIB_INT_MIN +#define _PDCLIB_UINT16_MAX _PDCLIB_UINT_MAX +#define _PDCLIB_16_CONV +#elif _PDCLIB_SHRT_BYTES == 2 +typedef signed short _PDCLIB_int16_t; +typedef unsigned short _PDCLIB_uint16_t; +#define _PDCLIB_INT16_MAX _PDCLIB_SHRT_MAX +#define _PDCLIB_INT16_MIN _PDCLIB_SHRT_MIN +#define _PDCLIB_UINT16_MAX _PDCLIB_USHRT_MAX +#define _PDCLIB_16_CONV h +#else +#error Neither 'short' nor 'int' are 16-bit. +#endif + +/* Setting 'int32_t', its limits, its literal, and conversion macros. */ +#if _PDCLIB_INT_BYTES == 4 +typedef signed int _PDCLIB_int32_t; +typedef unsigned int _PDCLIB_uint32_t; +#define _PDCLIB_INT32_MAX _PDCLIB_INT_MAX +#define _PDCLIB_INT32_MIN _PDCLIB_INT_MIN +#define _PDCLIB_UINT32_MAX _PDCLIB_UINT_MAX +#define _PDCLIB_INT32_LITERAL +#define _PDCLIB_UINT32_LITERAL +#define _PDCLIB_32_CONV +#elif _PDCLIB_LONG_BYTES == 4 +typedef signed long _PDCLIB_int32_t; +typedef unsigned long _PDCLIB_uint32_t; +#define _PDCLIB_INT32_MAX _PDCLIB_LONG_MAX +#define _PDCLIB_INT32_MIN _PDCLIB_LONG_MIN +#define _PDCLIB_UINT32_MAX _PDCLIB_LONG_MAX +#define _PDCLIB_INT32_LITERAL l +#define _PDCLIB_UINT32_LITERAL ul +#define _PDCLIB_32_CONV l +#else +#error Neither 'int' nor 'long' are 32-bit. +#endif + +/* Setting 'int64_t', its limits, its literal, and conversion macros. */ +#if _PDCLIB_LONG_BYTES == 8 +typedef signed long _PDCLIB_int64_t; +typedef unsigned long _PDCLIB_uint64_t; +#define _PDCLIB_INT64_MAX _PDCLIB_LONG_MAX +#define _PDCLIB_INT64_MIN _PDCLIB_LONG_MIN +#define _PDCLIB_UINT64_MAX _PDCLIB_ULONG_MAX +#define _PDCLIB_INT64_LITERAL l +#define _PDCLIB_UINT64_LITERAL ul +#define _PDCLIB_64_CONV l +#elif _PDCLIB_LLONG_BYTES == 8 +typedef signed long long _PDCLIB_int64_t; +typedef unsigned long long _PDCLIB_uint64_t; +#define _PDCLIB_INT64_MAX _PDCLIB_LLONG_MAX +#define _PDCLIB_INT64_MIN _PDCLIB_LLONG_MIN +#define _PDCLIB_UINT64_MAX _PDCLIB_ULLONG_MAX +#define _PDCLIB_INT64_LITERAL ll +#define _PDCLIB_UINT64_LITERAL ull +#define _PDCLIB_64_CONV ll +#else +#error Neither 'long' nor 'long long' are 64-bit. +#endif + +/* -------------------------------------------------------------------------- */ +/* <stdint.h> "fastest" types and their limits */ +/* -------------------------------------------------------------------------- */ +/* This is, admittedly, butt-ugly. But at least it's ugly where the average */ +/* user of PDCLib will never see it, and makes <_PDCLIB_config.h> much */ +/* cleaner. */ +/* -------------------------------------------------------------------------- */ + +typedef _PDCLIB_fast8 _PDCLIB_int_fast8_t; +typedef unsigned _PDCLIB_fast8 _PDCLIB_uint_fast8_t; +#define _PDCLIB_INT_FAST8_MIN _PDCLIB_concat( _PDCLIB_concat( _PDCLIB_, _PDCLIB_FAST8 ), _MIN ) +#define _PDCLIB_INT_FAST8_MAX _PDCLIB_concat( _PDCLIB_concat( _PDCLIB_, _PDCLIB_FAST8 ), _MAX ) +#define _PDCLIB_UINT_FAST8_MAX _PDCLIB_concat( _PDCLIB_concat( _PDCLIB_U, _PDCLIB_FAST8 ), _MAX ) + +typedef _PDCLIB_fast16 _PDCLIB_int_fast16_t; +typedef unsigned _PDCLIB_fast16 _PDCLIB_uint_fast16_t; +#define _PDCLIB_INT_FAST16_MIN _PDCLIB_concat( _PDCLIB_concat( _PDCLIB_, _PDCLIB_FAST16 ), _MIN ) +#define _PDCLIB_INT_FAST16_MAX _PDCLIB_concat( _PDCLIB_concat( _PDCLIB_, _PDCLIB_FAST16 ), _MAX ) +#define _PDCLIB_UINT_FAST16_MAX _PDCLIB_concat( _PDCLIB_concat( _PDCLIB_U, _PDCLIB_FAST16 ), _MAX ) + +typedef _PDCLIB_fast32 _PDCLIB_int_fast32_t; +typedef unsigned _PDCLIB_fast32 _PDCLIB_uint_fast32_t; +#define _PDCLIB_INT_FAST32_MIN _PDCLIB_concat( _PDCLIB_concat( _PDCLIB_, _PDCLIB_FAST32 ), _MIN ) +#define _PDCLIB_INT_FAST32_MAX _PDCLIB_concat( _PDCLIB_concat( _PDCLIB_, _PDCLIB_FAST32 ), _MAX ) +#define _PDCLIB_UINT_FAST32_MAX _PDCLIB_concat( _PDCLIB_concat( _PDCLIB_U, _PDCLIB_FAST32 ), _MAX ) + +typedef _PDCLIB_fast64 _PDCLIB_int_fast64_t; +typedef unsigned _PDCLIB_fast64 _PDCLIB_uint_fast64_t; +#define _PDCLIB_INT_FAST64_MIN _PDCLIB_concat( _PDCLIB_concat( _PDCLIB_, _PDCLIB_FAST64 ), _MIN ) +#define _PDCLIB_INT_FAST64_MAX _PDCLIB_concat( _PDCLIB_concat( _PDCLIB_, _PDCLIB_FAST64 ), _MAX ) +#define _PDCLIB_UINT_FAST64_MAX _PDCLIB_concat( _PDCLIB_concat( _PDCLIB_U, _PDCLIB_FAST64 ), _MAX ) + +/* -------------------------------------------------------------------------- */ +/* Various <stddef.h> typedefs and limits */ +/* -------------------------------------------------------------------------- */ + +typedef _PDCLIB_ptrdiff _PDCLIB_ptrdiff_t; +#define _PDCLIB_PTRDIFF_MIN _PDCLIB_concat( _PDCLIB_concat( _PDCLIB_, _PDCLIB_PTRDIFF ), _MIN ) +#define _PDCLIB_PTRDIFF_MAX _PDCLIB_concat( _PDCLIB_concat( _PDCLIB_, _PDCLIB_PTRDIFF ), _MAX ) + +#define _PDCLIB_SIG_ATOMIC_MIN _PDCLIB_concat( _PDCLIB_concat( _PDCLIB_, _PDCLIB_SIG_ATOMIC ), _MIN ) +#define _PDCLIB_SIG_ATOMIC_MAX _PDCLIB_concat( _PDCLIB_concat( _PDCLIB_, _PDCLIB_SIG_ATOMIC ), _MAX ) + +typedef _PDCLIB_size _PDCLIB_size_t; +#define _PDCLIB_SIZE_MAX _PDCLIB_concat( _PDCLIB_concat( _PDCLIB_, _PDCLIB_SIZE ), _MAX ) + +typedef _PDCLIB_wchar _PDCLIB_wchar_t; +#define _PDCLIB_WCHAR_MIN _PDCLIB_concat( _PDCLIB_concat( _PDCLIB_, _PDCLIB_WCHAR ), _MIN ) +#define _PDCLIB_WCHAR_MAX _PDCLIB_concat( _PDCLIB_concat( _PDCLIB_, _PDCLIB_WCHAR ), _MAX ) + +typedef _PDCLIB_wint _PDCLIB_wint_t; +#define _PDCLIB_WINT_MIN _PDCLIB_concat( _PDCLIB_concat( _PDCLIB_, _PDCLIB_WINT ), _MIN ) +#define _PDCLIB_WINT_MAX _PDCLIB_concat( _PDCLIB_concat( _PDCLIB_, _PDCLIB_WINT ), _MAX ) + +typedef _PDCLIB_intptr _PDCLIB_intptr_t; +typedef unsigned _PDCLIB_intptr _PDCLIB_uintptr_t; +#define _PDCLIB_INTPTR_MIN _PDCLIB_concat( _PDCLIB_concat( _PDCLIB_, _PDCLIB_INTPTR ), _MIN ) +#define _PDCLIB_INTPTR_MAX _PDCLIB_concat( _PDCLIB_concat( _PDCLIB_, _PDCLIB_INTPTR ), _MAX ) +#define _PDCLIB_UINTPTR_MAX _PDCLIB_concat( _PDCLIB_concat( _PDCLIB_U, _PDCLIB_INTPTR ), _MAX ) + +typedef _PDCLIB_intmax _PDCLIB_intmax_t; +typedef unsigned _PDCLIB_intmax _PDCLIB_uintmax_t; +#define _PDCLIB_INTMAX_MIN _PDCLIB_concat( _PDCLIB_concat( _PDCLIB_, _PDCLIB_INTMAX ), _MIN ) +#define _PDCLIB_INTMAX_MAX _PDCLIB_concat( _PDCLIB_concat( _PDCLIB_, _PDCLIB_INTMAX ), _MAX ) +#define _PDCLIB_UINTMAX_MAX _PDCLIB_concat( _PDCLIB_concat( _PDCLIB_U, _PDCLIB_INTMAX ), _MAX ) +#define _PDCLIB_INTMAX_C( value ) _PDCLIB_concat( value, _PDCLIB_INTMAX_LITERAL ) +#define _PDCLIB_UINTMAX_C( value ) _PDCLIB_concat( value, _PDCLIB_concat( u, _PDCLIB_INTMAX_LITERAL ) ) + +/* -------------------------------------------------------------------------- */ +/* Various <stdio.h> internals */ +/* -------------------------------------------------------------------------- */ + +/* Flags for representing mode (see fopen()). Note these must fit the same + status field as the _IO?BF flags in <stdio.h> and the internal flags below. +*/ +#define _PDCLIB_FREAD 8u +#define _PDCLIB_FWRITE 16u +#define _PDCLIB_FAPPEND 32u +#define _PDCLIB_FRW 64u +#define _PDCLIB_FBIN 128u + +/* Internal flags, made to fit the same status field as the flags above. */ +/* -------------------------------------------------------------------------- */ +/* free() the buffer memory on closing (false for user-supplied buffer) */ +#define _PDCLIB_FREEBUFFER 512u +/* stream has encountered error / EOF */ +#define _PDCLIB_ERRORFLAG 1024u +#define _PDCLIB_EOFFLAG 2048u +/* stream is wide-oriented */ +#define _PDCLIB_WIDESTREAM 4096u +/* stream is byte-oriented */ +#define _PDCLIB_BYTESTREAM 8192u +/* file associated with stream should be remove()d on closing (tmpfile()) */ +#define _PDCLIB_DELONCLOSE 16384u +/* stream handle should not be free()d on close (stdin, stdout, stderr) */ +#define _PDCLIB_STATIC 32768u + +/* Position / status structure for getpos() / fsetpos(). */ +struct _PDCLIB_fpos_t +{ + _PDCLIB_uint64_t offset; /* File position offset */ + int status; /* Multibyte parsing state (unused, reserved) */ +}; + +/* FILE structure */ +struct _PDCLIB_file_t +{ + _PDCLIB_fd_t handle; /* OS file handle */ + char * buffer; /* Pointer to buffer memory */ + _PDCLIB_size_t bufsize; /* Size of buffer */ + _PDCLIB_size_t bufidx; /* Index of current position in buffer */ + _PDCLIB_size_t bufend; /* Index of last pre-read character in buffer */ + struct _PDCLIB_fpos_t pos; /* Offset and multibyte parsing state */ + _PDCLIB_size_t ungetidx; /* Number of ungetc()'ed characters */ + unsigned char * ungetbuf; /* ungetc() buffer */ + unsigned int status; /* Status flags; see above */ + /* multibyte parsing status to be added later */ + char * filename; /* Name the current stream has been opened with */ + struct _PDCLIB_file_t * next; /* Pointer to next struct (internal) */ +}; + +/* -------------------------------------------------------------------------- */ +/* Various <time.h> internals */ +/* -------------------------------------------------------------------------- */ + +typedef _PDCLIB_time _PDCLIB_time_t; +typedef _PDCLIB_clock _PDCLIB_clock_t; + +/* -------------------------------------------------------------------------- */ +/* Internal data types */ +/* -------------------------------------------------------------------------- */ + +/* Structure required by both atexit() and exit() for handling atexit functions */ +struct _PDCLIB_exitfunc_t +{ + struct _PDCLIB_exitfunc_t * next; + void (*func)( void ); +}; + +/* Structures required by malloc(), realloc(), and free(). */ +struct _PDCLIB_headnode_t +{ + struct _PDCLIB_memnode_t * first; + struct _PDCLIB_memnode_t * last; +}; + +struct _PDCLIB_memnode_t +{ + _PDCLIB_size_t size; + struct _PDCLIB_memnode_t * next; +}; + +/* Status structure required by _PDCLIB_print(). */ +struct _PDCLIB_status_t +{ + int base; /* base to which the value shall be converted */ + _PDCLIB_int_fast32_t flags; /* flags and length modifiers */ + _PDCLIB_size_t n; /* print: maximum characters to be written */ + /* scan: number matched conversion specifiers */ + _PDCLIB_size_t i; /* number of characters read/written */ + _PDCLIB_size_t current;/* chars read/written in the CURRENT conversion */ + char * s; /* *sprintf(): target buffer */ + /* *sscanf(): source string */ + _PDCLIB_size_t width; /* specified field width */ + int prec; /* specified field precision */ + struct _PDCLIB_file_t * stream; /* *fprintf() / *fscanf() stream */ + _PDCLIB_va_list arg; /* argument stack */ +}; + +/* -------------------------------------------------------------------------- */ +/* Declaration of helper functions (implemented in functions/_PDCLIB). */ +/* -------------------------------------------------------------------------- */ + +/* This is the main function called by atoi(), atol() and atoll(). */ +_PDCLIB_intmax_t _PDCLIB_atomax( const char * s ); + +/* Two helper functions used by strtol(), strtoul() and long long variants. */ +const char * _PDCLIB_strtox_prelim( const char * p, char * sign, int * base ); +_PDCLIB_uintmax_t _PDCLIB_strtox_main( const char ** p, unsigned int base, _PDCLIB_uintmax_t error, _PDCLIB_uintmax_t limval, int limdigit, char * sign ); + +/* Digits arrays used by various integer conversion functions */ +extern const char _PDCLIB_digits[]; +extern const char _PDCLIB_Xdigits[]; + +/* The worker for all printf() type of functions. The pointer spec should point + to the introducing '%' of a conversion specifier. The status structure is to + be that of the current printf() function, of which the members n, s, stream + and arg will be preserved; i will be updated; and all others will be trashed + by the function. + Returns a pointer to the first character not parsed as conversion specifier. +*/ +const char * _PDCLIB_print( const char * spec, struct _PDCLIB_status_t * status ); + +/* The worker for all scanf() type of functions. The pointer spec should point + to the introducing '%' of a conversion specifier. The status structure is to + be that of the current scanf() function, of which the member stream will be + preserved; n, i, and s will be updated; and all others will be trashed by + the function. + Returns a pointer to the first character not parsed as conversion specifier, + or NULL in case of error. + FIXME: Should distinguish between matching and input error +*/ +const char * _PDCLIB_scan( const char * spec, struct _PDCLIB_status_t * status ); + +/* Parsing any fopen() style filemode string into a number of flags. */ +unsigned int _PDCLIB_filemode( const char * mode ); + +/* Sanity checking and preparing of read buffer, should be called first thing + by any stdio read-data function. + Returns 0 on success, EOF on error. + On error, EOF / error flags and errno are set appropriately. +*/ +int _PDCLIB_prepread( struct _PDCLIB_file_t * stream ); + +/* Sanity checking, should be called first thing by any stdio write-data + function. + Returns 0 on success, EOF on error. + On error, error flags and errno are set appropriately. +*/ +int _PDCLIB_prepwrite( struct _PDCLIB_file_t * stream ); + +/* Closing all streams on program exit */ +void _PDCLIB_closeall( void ); + +/* Check if a given year is a leap year. Parameter is offset to 1900. */ +int _PDCLIB_is_leap( int year_offset ); + +/* Read a specified number of lines from a file stream; return a pointer to + allocated memory holding the lines (newlines replaced with zero terminators) + or NULL in case of error. +*/ +char * _PDCLIB_load_lines( struct _PDCLIB_file_t * fh, _PDCLIB_size_t lines ); + +/* -------------------------------------------------------------------------- */ +/* errno */ +/* -------------------------------------------------------------------------- */ + +/* If PDCLib would call its error number "errno" directly, there would be no way + to catch its value from underlying system calls that also use it (i.e., POSIX + operating systems). That is why we use an internal name, providing a means to + access it through <errno.h>. +*/ +extern int _PDCLIB_errno; + +/* A mechanism for delayed evaluation. (Not sure if this is really necessary, so + no detailed documentation on the "why".) +*/ +int * _PDCLIB_errno_func( void ); + +/* -------------------------------------------------------------------------- */ +/* <locale.h> support */ +/* -------------------------------------------------------------------------- */ + +#define _PDCLIB_LC_ALL 0 +#define _PDCLIB_LC_COLLATE 1 +#define _PDCLIB_LC_CTYPE 2 +#define _PDCLIB_LC_MONETARY 3 +#define _PDCLIB_LC_NUMERIC 4 +#define _PDCLIB_LC_TIME 5 +#define _PDCLIB_LC_MESSAGES 6 +#define _PDCLIB_LC_COUNT 7 + +#define _PDCLIB_CTYPE_ALPHA 1 +#define _PDCLIB_CTYPE_BLANK 2 +#define _PDCLIB_CTYPE_CNTRL 4 +#define _PDCLIB_CTYPE_GRAPH 8 +#define _PDCLIB_CTYPE_PUNCT 16 +#define _PDCLIB_CTYPE_SPACE 32 +#define _PDCLIB_CTYPE_LOWER 64 +#define _PDCLIB_CTYPE_UPPER 128 + +#define _PDCLIB_CHARSET_SIZE ( 1 << _PDCLIB_CHAR_BIT ) + +struct _PDCLIB_lc_lconv_numeric_t +{ + char * decimal_point; + char * thousands_sep; + char * grouping; +}; + +struct _PDCLIB_lc_lconv_monetary_t +{ + char * mon_decimal_point; + char * mon_thousands_sep; + char * mon_grouping; + char * positive_sign; + char * negative_sign; + char * currency_symbol; + char * int_curr_symbol; + char frac_digits; + char p_cs_precedes; + char n_cs_precedes; + char p_sep_by_space; + char n_sep_by_space; + char p_sign_posn; + char n_sign_posn; + char int_frac_digits; + char int_p_cs_precedes; + char int_n_cs_precedes; + char int_p_sep_by_space; + char int_n_sep_by_space; + char int_p_sign_posn; + char int_n_sign_posn; +}; + +struct _PDCLIB_lc_numeric_monetary_t +{ + struct lconv * lconv; + int numeric_alloced; + int monetary_alloced; +}; + +extern struct _PDCLIB_lc_numeric_monetary_t _PDCLIB_lc_numeric_monetary; + +struct _PDCLIB_lc_collate_t +{ + int alloced; + /* 1..3 code points */ + /* 1..8, 18 collation elements of 3 16-bit integers */ +}; + +extern struct _PDCLIB_lc_collate_t _PDCLIB_lc_collate; + +struct _PDCLIB_lc_ctype_entry_t +{ + _PDCLIB_uint16_t flags; + unsigned char upper; + unsigned char lower; +}; + +struct _PDCLIB_lc_ctype_t +{ + int alloced; + int digits_low; + int digits_high; + int Xdigits_low; + int Xdigits_high; + int xdigits_low; + int xdigits_high; + struct _PDCLIB_lc_ctype_entry_t * entry; +}; + +extern struct _PDCLIB_lc_ctype_t _PDCLIB_lc_ctype; + +struct _PDCLIB_lc_messages_t +{ + int alloced; + char * errno_texts[_PDCLIB_ERRNO_MAX]; /* strerror() / perror() */ +}; + +extern struct _PDCLIB_lc_messages_t _PDCLIB_lc_messages; + +struct _PDCLIB_lc_time_t +{ + int alloced; + char * month_name_abbr[12]; /* month names, abbreviated */ + char * month_name_full[12]; /* month names, full */ + char * day_name_abbr[7]; /* weekday names, abbreviated */ + char * day_name_full[7]; /* weekday names, full */ + char * date_time_format; /* date / time format for strftime( "%c" ) */ + char * time_format_12h; /* 12-hour time format for strftime( "%r" ) */ + char * date_format; /* date format for strftime( "%x" ) */ + char * time_format; /* time format for strftime( "%X" ) */ + char * am_pm[2]; /* AM / PM designation */ +}; + +extern struct _PDCLIB_lc_time_t _PDCLIB_lc_time; + +struct _PDCLIB_lc_lconv_numeric_t * _PDCLIB_load_lc_numeric( const char * path, const char * locale ); +struct _PDCLIB_lc_lconv_monetary_t * _PDCLIB_load_lc_monetary( const char * path, const char * locale ); +struct _PDCLIB_lc_collate_t * _PDCLIB_load_lc_collate( const char * path, const char * locale ); +struct _PDCLIB_lc_ctype_t * _PDCLIB_load_lc_ctype( const char * path, const char * locale ); +struct _PDCLIB_lc_time_t * _PDCLIB_load_lc_time( const char * path, const char * locale ); +struct _PDCLIB_lc_messages_t * _PDCLIB_load_lc_messages( const char * path, const char * locale ); + +/* -------------------------------------------------------------------------- */ +/* Sanity checks */ +/* -------------------------------------------------------------------------- */ + +_PDCLIB_static_assert( sizeof( short ) == _PDCLIB_SHRT_BYTES, "Compiler disagrees on _PDCLIB_SHRT_BYTES." ); +_PDCLIB_static_assert( sizeof( int ) == _PDCLIB_INT_BYTES, "Compiler disagrees on _PDCLIB_INT_BYTES." ); +_PDCLIB_static_assert( sizeof( long ) == _PDCLIB_LONG_BYTES, "Compiler disagrees on _PDCLIB_LONG_BYTES." ); +_PDCLIB_static_assert( sizeof( long long ) == _PDCLIB_LLONG_BYTES, "Compiler disagrees on _PDCLIB_LLONG_BYTES." ); + +_PDCLIB_static_assert( ( (char)-1 < 0 ) == _PDCLIB_CHAR_SIGNED, "Compiler disagrees on _PDCLIB_CHAR_SIGNED." ); +_PDCLIB_static_assert( sizeof( sizeof( int ) ) == sizeof( _PDCLIB_size ), "Compiler disagrees on _PDCLIB_size." ); + +_PDCLIB_static_assert( sizeof( _PDCLIB_wchar ) == sizeof( L'x' ), "Compiler disagrees on _PDCLIB_wchar." ); + +_PDCLIB_static_assert( sizeof( void * ) == sizeof( _PDCLIB_intptr ), "Compiler disagrees on _PDCLIB_intptr." ); + +_PDCLIB_static_assert( sizeof( &_PDCLIB_digits[1] - &_PDCLIB_digits[0] ) == sizeof( _PDCLIB_ptrdiff ), "Compiler disagrees on _PDCLIB_ptrdiff." ); + +#endif diff --git a/src/pdclib/include/stdalign.h b/src/pdclib/include/stdalign.h new file mode 100644 index 0000000..de806a1 --- /dev/null +++ b/src/pdclib/include/stdalign.h @@ -0,0 +1,17 @@ +/* Alignment <stdalign.h> + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#ifndef _PDCLIB_STDALIGN_H +#define _PDCLIB_ALIGN_H _PDCLIB_ALIGN_H + +#define alignas _Alignas +#define alignof _Alignof + +#define __alignas_is_defined 1 +#define __alignof_is_defined 1 + +#endif + diff --git a/src/pdclib/include/stdarg.h b/src/pdclib/include/stdarg.h new file mode 100644 index 0000000..84c05d2 --- /dev/null +++ b/src/pdclib/include/stdarg.h @@ -0,0 +1,19 @@ +/* Variable arguments <stdarg.h> + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#ifndef _PDCLIB_STDARG_H +#define _PDCLIB_STDARG_H _PDCLIB_STDARG_H + +#include "pdclib/_PDCLIB_config.h" + +typedef _PDCLIB_va_list va_list; + +#define va_arg( ap, type ) _PDCLIB_va_arg( ap, type ) +#define va_copy( dest, src ) _PDCLIB_va_copy( dest, src ) +#define va_end( ap ) _PDCLIB_va_end( ap ) +#define va_start( ap, parmN ) _PDCLIB_va_start( ap, parmN ) + +#endif diff --git a/src/pdclib/include/stdbool.h b/src/pdclib/include/stdbool.h new file mode 100644 index 0000000..8f6a1d0 --- /dev/null +++ b/src/pdclib/include/stdbool.h @@ -0,0 +1,15 @@ +/* Boolean type and values <stdbool.h> + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#ifndef _PDCLIB_STDBOOL_H +#define _PDCLIB_STDBOOL_H _PDCLIB_STDBOOL_H + +#define bool _Bool +#define true 1 +#define false 0 +#define __bool_true_false_are_defined 1 + +#endif diff --git a/src/pdclib/include/stddef.h b/src/pdclib/include/stddef.h new file mode 100644 index 0000000..7cba7c0 --- /dev/null +++ b/src/pdclib/include/stddef.h @@ -0,0 +1,28 @@ +/* Common definitions <stddef.h> + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#ifndef _PDCLIB_STDDEF_H +#define _PDCLIB_STDDEF_H _PDCLIB_STDDEF_H + +#include "pdclib/_PDCLIB_int.h" + +typedef _PDCLIB_ptrdiff_t ptrdiff_t; + +#ifndef _PDCLIB_SIZE_T_DEFINED +#define _PDCLIB_SIZE_T_DEFINED _PDCLIB_SIZE_T_DEFINED +typedef _PDCLIB_size_t size_t; +#endif + +typedef _PDCLIB_wchar_t wchar_t; + +#ifndef _PDCLIB_NULL_DEFINED +#define _PDCLIB_NULL_DEFINED _PDCLIB_NULL_DEFINED +#define NULL _PDCLIB_NULL +#endif + +#define offsetof( type, member ) _PDCLIB_offsetof( type, member ) + +#endif diff --git a/src/pdclib/include/stdint.h b/src/pdclib/include/stdint.h new file mode 100644 index 0000000..544d1dd --- /dev/null +++ b/src/pdclib/include/stdint.h @@ -0,0 +1,207 @@ +/* Integer types <stdint.h> + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#ifndef _PDCLIB_STDINT_H +#define _PDCLIB_STDINT_H _PDCLIB_STDINT_H + +#include "pdclib/_PDCLIB_int.h" + +/* 7.18.1.1 Exact-width integer types. */ + +typedef _PDCLIB_int8_t int8_t; +typedef _PDCLIB_int16_t int16_t; +typedef _PDCLIB_int32_t int32_t; +typedef _PDCLIB_int64_t int64_t; + +typedef _PDCLIB_uint8_t uint8_t; +typedef _PDCLIB_uint16_t uint16_t; +typedef _PDCLIB_uint32_t uint32_t; +typedef _PDCLIB_uint64_t uint64_t; + +/* 7.18.1.2 Minimum-width integer types */ + +/* You are allowed to add more types here, e.g. int_least24_t. For the standard + types, int_leastN_t is equivalent to the corresponding exact type intN_t by + definition. +*/ + +typedef int8_t int_least8_t; +typedef int16_t int_least16_t; +typedef int32_t int_least32_t; +typedef int64_t int_least64_t; + +typedef uint8_t uint_least8_t; +typedef uint16_t uint_least16_t; +typedef uint32_t uint_least32_t; +typedef uint64_t uint_least64_t; + +/* 7.18.1.3 Fastest minimum-width integer types */ + +/* You are allowed to add more types here, e.g. int_fast24_t. */ + +typedef _PDCLIB_int_fast8_t int_fast8_t; +typedef _PDCLIB_int_fast16_t int_fast16_t; +typedef _PDCLIB_int_fast32_t int_fast32_t; +typedef _PDCLIB_int_fast64_t int_fast64_t; + +typedef _PDCLIB_uint_fast8_t uint_fast8_t; +typedef _PDCLIB_uint_fast16_t uint_fast16_t; +typedef _PDCLIB_uint_fast32_t uint_fast32_t; +typedef _PDCLIB_uint_fast64_t uint_fast64_t; + +/* 7.18.1.4 Integer types capable of holding object pointers */ + +typedef _PDCLIB_intptr_t intptr_t; +typedef _PDCLIB_uintptr_t uintptr_t; + +/* 7.18.1.5 Greatest-width integer types */ + +typedef _PDCLIB_intmax_t intmax_t; +typedef _PDCLIB_uintmax_t uintmax_t; + +/* 7.18.2 Limits of specified-width integer types */ + +#ifdef __cplusplus +#ifndef __STDC_LIMIT_MACROS +#define _PDCLIB_NO_LIMIT_MACROS +#endif +#endif + +#ifndef _PDCLIB_NO_LIMIT_MACROS + +/* 7.18.2.1 Limits of exact-width integer types */ + +#define INT8_MIN _PDCLIB_INT8_MIN +#define INT8_MAX _PDCLIB_INT8_MAX +#define UINT8_MAX _PDCLIB_UINT8_MAX + +#define INT16_MIN _PDCLIB_INT16_MIN +#define INT16_MAX _PDCLIB_INT16_MAX +#define UINT16_MAX _PDCLIB_UINT16_MAX + +#define INT32_MIN _PDCLIB_INT32_MIN +#define INT32_MAX _PDCLIB_INT32_MAX +#define UINT32_MAX _PDCLIB_UINT32_MAX + +#define INT64_MIN _PDCLIB_INT64_MIN +#define INT64_MAX _PDCLIB_INT64_MAX +#define UINT64_MAX _PDCLIB_UINT64_MAX + +/* 7.18.2.2 Limits of minimum-width integer types */ + +/* For the standard widths, least and exact types are equivalent. + You are allowed to add more types here, e.g. int_least24_t. +*/ + +#define INT_LEAST8_MIN INT8_MIN +#define INT_LEAST8_MAX INT8_MAX +#define UINT_LEAST8_MAX UINT8_MAX + +#define INT_LEAST16_MIN INT16_MIN +#define INT_LEAST16_MAX INT16_MAX +#define UINT_LEAST16_MAX UINT16_MAX + +#define INT_LEAST32_MIN INT32_MIN +#define INT_LEAST32_MAX INT32_MAX +#define UINT_LEAST32_MAX UINT32_MAX + +#define INT_LEAST64_MIN INT64_MIN +#define INT_LEAST64_MAX INT64_MAX +#define UINT_LEAST64_MAX UINT64_MAX + +/* 7.18.2.3 Limits of fastest minimum-width integer types */ + +#define INT_FAST8_MIN _PDCLIB_INT_FAST8_MIN +#define INT_FAST8_MAX _PDCLIB_INT_FAST8_MAX +#define UINT_FAST8_MAX _PDCLIB_UINT_FAST8_MAX + +#define INT_FAST16_MIN _PDCLIB_INT_FAST16_MIN +#define INT_FAST16_MAX _PDCLIB_INT_FAST16_MAX +#define UINT_FAST16_MAX _PDCLIB_UINT_FAST16_MAX + +#define INT_FAST32_MIN _PDCLIB_INT_FAST32_MIN +#define INT_FAST32_MAX _PDCLIB_INT_FAST32_MAX +#define UINT_FAST32_MAX _PDCLIB_UINT_FAST32_MAX + +#define INT_FAST64_MIN _PDCLIB_INT_FAST64_MIN +#define INT_FAST64_MAX _PDCLIB_INT_FAST64_MAX +#define UINT_FAST64_MAX _PDCLIB_UINT_FAST64_MAX + +/* 7.18.2.4 Limits of integer types capable of holding object pointers */ + +#define INTPTR_MIN _PDCLIB_INTPTR_MIN +#define INTPTR_MAX _PDCLIB_INTPTR_MAX +#define UINTPTR_MAX _PDCLIB_UINTPTR_MAX + +/* 7.18.2.5 Limits of greatest-width integer types */ + +#define INTMAX_MIN _PDCLIB_INTMAX_MIN +#define INTMAX_MAX _PDCLIB_INTMAX_MAX +#define UINTMAX_MAX _PDCLIB_UINTMAX_MAX + +/* 7.18.3 Limits of other integer types */ + +#define PTRDIFF_MIN _PDCLIB_PTRDIFF_MIN +#define PTRDIFF_MAX _PDCLIB_PTRDIFF_MAX + +#define SIG_ATOMIC_MIN _PDCLIB_SIG_ATOMIC_MIN +#define SIG_ATOMIC_MAX _PDCLIB_SIG_ATOMIC_MAX + +#define SIZE_MAX _PDCLIB_SIZE_MAX + +#define WCHAR_MIN _PDCLIB_WCHAR_MIN +#define WCHAR_MAX _PDCLIB_WCHAR_MAX + +#define WINT_MIN _PDCLIB_WINT_MIN +#define WINT_MAX _PDCLIB_WINT_MAX + +#endif + +/* 7.18.4 Macros for integer constants */ + +#ifdef __cplusplus +#ifndef __STDC_CONSTANT_MACROS +#define _PDCLIB_NO_CONSTANT_MACROS +#endif +#endif + +#ifndef _PDCLIB_NO_CONSTANT_MACROS + +/* 7.18.4.1 Macros for minimum-width integer constants */ + +/* As the minimum-width types - for the required widths of 8, 16, 32, and 64 + bits - are expressed in terms of the exact-width types, the mechanism for + these macros is to append the literal of that exact-width type to the macro + parameter. + This is considered a hack, as the author is not sure his understanding of + the requirements of this macro is correct. Any input appreciated. +*/ + +/* Expand to an integer constant of specified value and type int_leastN_t */ + +#define INT8_C( value ) value +#define INT16_C( value ) value +#define INT32_C( value ) _PDCLIB_concat( value, _PDCLIB_INT32_LITERAL ) +#define INT64_C( value ) _PDCLIB_concat( value, _PDCLIB_INT64_LITERAL ) + +/* Expand to an integer constant of specified value and type uint_leastN_t */ + +#define UINT8_C( value ) value +#define UINT16_C( value ) value +#define UINT32_C( value ) _PDCLIB_concat( value, _PDCLIB_UINT32_LITERAL ) +#define UINT64_C( value ) _PDCLIB_concat( value, _PDCLIB_UINT64_LITERAL ) + +/* 7.18.4.2 Macros for greatest-width integer constants */ + +/* Expand to an integer constant of specified value and type intmax_t */ +#define INTMAX_C( value ) _PDCLIB_INTMAX_C( value ) + +/* Expand to an integer constant of specified value and type uintmax_t */ +#define UINTMAX_C( value ) _PDCLIB_UINTMAX_C( value ) + +#endif + +#endif diff --git a/src/pdclib/include/stdio.h b/src/pdclib/include/stdio.h new file mode 100644 index 0000000..d3d0a64 --- /dev/null +++ b/src/pdclib/include/stdio.h @@ -0,0 +1,786 @@ +/* Input/output <stdio.h> + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#ifndef _PDCLIB_STDIO_H +#define _PDCLIB_STDIO_H _PDCLIB_STDIO_H + +#include "pdclib/_PDCLIB_int.h" + +#ifndef _PDCLIB_SIZE_T_DEFINED +#define _PDCLIB_SIZE_T_DEFINED _PDCLIB_SIZE_T_DEFINED +typedef _PDCLIB_size_t size_t; +#endif + +#ifndef _PDCLIB_NULL_DEFINED +#define _PDCLIB_NULL_DEFINED _PDCLIB_NULL_DEFINED +#define NULL _PDCLIB_NULL +#endif + +/* See setvbuf(), third argument */ +#define _IOFBF 1 +#define _IOLBF 2 +#define _IONBF 4 + +/* The following are platform-dependant, and defined in _PDCLIB_config.h. */ +typedef struct _PDCLIB_fpos_t fpos_t; +typedef struct _PDCLIB_file_t FILE; +#define EOF -1 +#define BUFSIZ _PDCLIB_BUFSIZ +#define FOPEN_MAX _PDCLIB_FOPEN_MAX +#define FILENAME_MAX _PDCLIB_FILENAME_MAX +#define L_tmpnam _PDCLIB_L_tmpnam +#define TMP_MAX _PDCLIB_TMP_MAX + +/* See fseek(), third argument */ +#define SEEK_CUR _PDCLIB_SEEK_CUR +#define SEEK_END _PDCLIB_SEEK_END +#define SEEK_SET _PDCLIB_SEEK_SET + +extern FILE * stdin; +extern FILE * stdout; +extern FILE * stderr; + +/* Operations on files */ + +/* Remove the given file. + Returns zero if successful, non-zero otherwise. + This implementation does detect if a file of that name is currently open, + and fails the remove in this case. This does not detect two distinct names + that merely result in the same file (e.g. "/home/user/foo" vs. "~/foo"). +*/ +int remove( const char * filename ); + +/* Rename the given old file to the given new name. + Returns zero if successful, non-zero otherwise. + This implementation does detect if the old filename corresponds to an open + file, and fails the rename in this case. + If there already is a file with the new filename, behaviour is defined by + the glue code (see functions/_PDCLIB/rename.c). +*/ +int rename( const char * old, const char * new ); + +/* Open a temporary file with mode "wb+", i.e. binary-update. Remove the file + automatically if it is closed or the program exits normally (by returning + from main() or calling exit()). + Returns a pointer to a FILE handle for this file. + This implementation does not remove temporary files if the process aborts + abnormally (e.g. abort()). +*/ +FILE * tmpfile( void ); + +/* Generate a file name that is not equal to any existing filename AT THE TIME + OF GENERATION. Generate a different name each time it is called. + Returns a pointer to an internal static buffer containing the filename if s + is a NULL pointer. (This is not thread-safe!) + Returns s if it is not a NULL pointer (s is then assumed to point to an array + of at least L_tmpnam characters). + Returns NULL if unable to generate a suitable name (because all possible + names already exist, or the function has been called TMP_MAX times already). + Note that this implementation cannot guarantee a file of the name generated + is not generated between the call to this function and a subsequent fopen(). +*/ +char * tmpnam( char * s ); + +/* File access functions */ + +/* Close the file associated with the given stream (after flushing its buffers). + Returns zero if successful, EOF if any errors occur. +*/ +int fclose( FILE * stream ); + +/* Flush the buffers of the given output stream. If the stream is an input + stream, or an update stream with the last operation being an input operation, + behaviour is undefined. + If stream is a NULL pointer, perform the buffer flushing for all applicable + streams. + Returns zero if successful, EOF if a write error occurs. + Sets the error indicator of the stream if a write error occurs. +*/ +int fflush( FILE * stream ); + +/* Open the file with the given filename in the given mode, and return a stream + handle for it in which error and end-of-file indicator are cleared. Defined + values for mode are: + + READ MODES + text files binary files + without update "r" "rb" + with update "r+" "rb+" or "r+b" + + Opening in read mode fails if no file with the given filename exists, or if + cannot be read. + + WRITE MODES + text files binary files + without update "w" "wb" + with update "w+" "wb+" or "w+b" + + With write modes, if a file with the given filename already exists, it is + truncated to zero length. + + APPEND MODES + text files binary files + without update "a" "ab" + with update "a+" "ab+" or "a+b" + + With update modes, if a file with the given filename already exists, it is + not truncated to zero length, but all writes are forced to end-of-file (this + regardless to fseek() calls). Note that binary files opened in append mode + might have their end-of-file padded with '\0' characters. + + Update modes mean that both input and output functions can be performed on + the stream, but output must be terminated with a call to either fflush(), + fseek(), fsetpos(), or rewind() before input is performed, and input must + be terminated with a call to either fseek(), fsetpos(), or rewind() before + output is performed, unless input encountered end-of-file. + + If a text file is opened with update mode, the implementation is at liberty + to open a binary stream instead. This implementation honors the exact mode + given. + + The stream is fully buffered if and only if it can be determined not to + refer to an interactive device. + + If the mode string begins with but is longer than one of the above sequences + the implementation is at liberty to ignore the additional characters, or do + implementation-defined things. This implementation only accepts the exact + modes above. + + Returns a pointer to the stream handle if successfull, NULL otherwise. +*/ +FILE * fopen( const char * _PDCLIB_restrict filename, const char * _PDCLIB_restrict mode ); + +/* Close any file currently associated with the given stream. Open the file + identified by the given filename with the given mode (equivalent to fopen()), + and associate it with the given stream. If filename is a NULL pointer, + attempt to change the mode of the given stream. + This implementation allows any mode changes on "real" files, and associating + of the standard streams with files. It does *not* support mode changes on + standard streams. + (Primary use of this function is to redirect stdin, stdout, and stderr.) +*/ +FILE * freopen( const char * _PDCLIB_restrict filename, const char * _PDCLIB_restrict mode, FILE * _PDCLIB_restrict stream ); + +/* If buf is a NULL pointer, call setvbuf( stream, NULL, _IONBF, BUFSIZ ). + If buf is not a NULL pointer, call setvbuf( stream, buf, _IOFBF, BUFSIZ ). +*/ +void setbuf( FILE * _PDCLIB_restrict stream, char * _PDCLIB_restrict buf ); + +/* Set the given stream to the given buffering mode. If buf is not a NULL + pointer, use buf as file buffer (of given size). If buf is a NULL pointer, + use a buffer of given size allocated internally. _IONBF causes unbuffered + behaviour, _IOLBF causes line-buffered behaviour, _IOFBF causes fully + buffered behaviour. Calling this function is only valid right after a file is + opened, and before any other operation (except for any unsuccessful calls to + setvbuf()) has been performed. + Returns zero if successful, nonzero otherwise. +*/ +int setvbuf( FILE * _PDCLIB_restrict stream, char * _PDCLIB_restrict buf, int mode, size_t size ); + +/* Formatted input/output functions */ + +/* + Write output to the given stream, as defined by the given format string and + 0..n subsequent arguments (the argument stack). + + The format string is written to the given stream verbatim, except for any + conversion specifiers included, which start with the letter '%' and are + documented below. If the given conversion specifiers require more arguments + from the argument stack than provided, behaviour is undefined. Additional + arguments not required by conversion specifiers are evaluated but otherwise + ignored. + + (The standard specifies the format string is allowed to contain multibyte + character sequences as long as it starts and ends in initial shift state, + but this is not yet supported by this implementation, which interprets the + format string as sequence of char.) + TODO: Add multibyte support to printf() functions. + + A conversion specifier consists of: + - Zero or more flags (one of the characters "-+ #0"). + - Optional minimum field width as decimal integer. Default is padding to the + left, using spaces. Note that 0 is taken as a flag, not the beginning of a + field width. Note also that a small field width will not result in the + truncation of a value. + - Optional precision (given as ".#" with # being a decimal integer), + specifying: + - the min. number of digits to appear (diouxX), + - the max. number of digits after the decimal point (aAeEfF), + - the max. number of significant digits (gG), + - the max. number of bytes to be written (s). + - behaviour with other conversion specifiers is undefined. + - Optional length modifier specifying the size of the argument (one of "hh", + "ll", or one of the characters "hljztL"). + - Conversion specifier character specifying the type of conversion to be + applied (and the type of the next argument from the argument stack). One + of the characters "diouxXfFeEgGaAcspn%". + + Minimum field width and/or precision may be given as asterisk ('*') instead + of a decimal integer. In this case, the next argument from the argument + stack is assumed to be an int value specifying the width / precision. A + negative field width is interpreted as flag '-' followed by a positive field + width. A negative precision is interpreted as if no precision was given. + + FLAGS + - Left-justify the conversion result within its field width. + + Prefix a '+' on positive signed conversion results. Prefix a '-' on + floating conversions resulting in negative zero, or negative values + rounding to zero. + space Prefix a space on positive signed conversion results, or if a signed + conversion results in no characters. If both '+' and ' ' are given, + ' ' is ignored. + # Use an "alternative form" for + - 'o' conversion, increasing precision until the first digit of the + result is a zero; + - 'x' or 'X' conversion, prefixing "0x" or "0X" to nonzero results; + - "aAeEfF" conversions, always printing a decimal point even if no + digits are following; + - 'g' or 'G' conversions, always printing a decimal point even if no + digits are following, and not removing trailing zeroes. + - behaviour for other conversions is unspecified. + 0 Use leading zeroes instead of spaces for field width padding. If both + '-' and '0' are given, '0' is ignored. If a precision is specified for + any of the "diouxX" conversions, '0' is ignored. Behaviour is only + defined for "diouxXaAeEfFgG". + + LENGTH MODIFIERS + hh For "diouxX" conversions, the argument from the argument stack is + assumed to be of char width. (It will have been subject to integer + promotion but will be converted back.) For 'n' conversions, the argument + is assumed to be a pointer to signed char. + h For "diouxX" conversions, the argument from the argument stack is + assumed to be of short int width. (It will have been subject to integer + promotion but will be converted back.) For 'n' conversions, the argument + is assumed to be a pointer to short int. + l For "diouxX" conversions, the argument from the argument stack is + assumed to be of long int width. For 'n' conversions, the argument is + assumed to be a pointer to short int. For 'c' conversions, the argument + is assumed to be a wint_t. For 's' conversions, the argument is assumed + to be a pointer to wchar_t. No effect on "aAeEfFgG" conversions. + ll For "diouxX" conversions, the argument from the argument stack is + assumed to be of long long int width. For 'n' conversions, the argument + is assumed to be a pointer to long long int. + j For "diouxX" conversions, the argument from the argument stack is + assumed to be of intmax_t width. For 'n' conversions, the argument is + assumed to be a pointer to intmax_t. + z For "diouxX" conversions, the argument from the argument stack is + assumed to be of size_t width. For 'n' conversions, the argument is + assumed to be a pointer to size_t. + t For "diouxX" conversions, the argument from the argument stack is + assumed to be of ptrdiff_t width. For 'n' conversions, the argument is + assumed to be a pointer to ptrdiff_t. + L For "aAeEfFgG" conversions, the argument from the argument stack is + assumed to be a long double. + Length modifiers appearing for any conversions not mentioned above will have + undefined behaviour. + If a length modifier appears with any conversion specifier other than as + specified above, the behavior is undefined. + + CONVERSION SPECIFIERS + d,i The argument from the argument stack is assumed to be of type int, and + is converted to a signed decimal value with a minimum number of digits + as specified by the precision (default 1), padded with leading zeroes. + A zero value converted with precision zero yields no output. + o The argument from the argument stack is assumed to be of type unsigned + int, and is converted to an unsigned octal value, other behaviour being + as above. + u The argument from the argument stack is assumed to be of type unsigned + int, and converted to an unsigned decimal value, other behaviour being + as above. + x,X The argument from the argument stack is assumed to be of type unsigned + int, and converted to an unsigned hexadecimal value, using lowercase + "abcdef" for 'x' and uppercase "ABCDEF" for 'X' conversion, other + behaviour being as above. + f,F The argument from the argument stack is assumed to be of type double, + and converted to a decimal floating point in decimal-point notation, + with the number of digits after the decimal point as specified by the + precision (default 6) and the value being rounded appropriately. If + precision is zero (and the '#' flag is not given), no decimal point is + printed. At least one digit is always printed before the decimal point. + For 'f' conversions, an infinity value is printed as either [-]inf or + [-]infinity (, depending on the configuration of this implementation. A + NaN value is printed as [-]nan. For 'F' conversions uppercase characters + are used for these special values. The flags '-', '+' and ' ' apply as + usual to these special values, '#' and '0' have no effect. + e,E The argument from the argument stack is assumed to be of type double, + and converted to a decimal floating point in normalized exponential + notation ([?]d.ddd edd). "Normalized" means one nonzero digit before + the decimal point, unless the value is zero. The number of digits after + the decimal point is specified by the precision (default 6), the value + being rounded appropriately. If precision is zero (and the '#' flag is + not given), no decimal point is printed. The exponent has at least two + digits, and not more than necessary to represent the exponent. If the + value is zero, the exponent is zero. The 'e' written to indicate the + exponend is uppercase for 'E' conversions. + Infinity or NaN values are represented as for 'f' and 'F' conversions, + respectively. + g,G The argument from the argument stack is assumed to be of type double, + and converted according to either 'f' or 'e' format for 'g' conversions, + or 'F' or 'E' format for 'G' conversions, respectively, with the actual + conversion chosen depending on the value. 'e' / 'E' conversion is chosen + if the resulting exponent is < -4 or >= the precision (default 1). + Trailing zeroes are removed (unless the '#' flag is given). A decimal + point appears only if followed by a digit. + Infinity or NaN values are represented as for 'f' and 'F' conversions, + respectively. + a,A The argument from the argument stack is assumed to be of type double, + and converted to a floating point hexadecimal notation ([?]0xh.hhhh pd) + with one hexadecimal digit (being nonzero if the value is normalized, + and otherwise unspecified) before the decimal point, and the number of + digits after the decimal point being specified by the precision. If no + precision is given, the default is to print as many digits as nevessary + to give an exact representation of the value (if FLT_RADIX is a power of + 2). If no precision is given and FLT_RADIX is not a power of 2, the + default is to print as many digits to distinguish values of type double + (possibly omitting trailing zeroes). (A precision p is sufficient to + distinguish values of the source type if 16^p-1 > b^n where b is + FLT_RADIX and n is the number of digits in the significand (to base b) + of the source type. A smaller p might suffice depending on the + implementation's scheme for determining the digit to the left of the + decimal point.) The error has the correct sign for the current rounding + direction. + Unless the '#' flag is given, no decimal-point is given for zero + precision. + The 'a' conversion uses lowercase "abcdef", "0x" and 'p', the 'A' + conversion uppercase "ABCDEF", "0X" and 'P'. + The exponent always has at least one digit, and not more than necessary + to represent the decimal exponent of 2. If the value is zero, the + exponent is zero. + Infinity or NaN values are represented as for 'f' and 'F' conversions, + respectively. + Binary implementations are at liberty to chose the hexadecimal digit to + the left of the decimal point so that subsequent digits align to nibble + boundaries. + c The argument from the argument stack is assumed to be of type int, and + converted to a character after the value has been cast to unsigned char. + If the 'l' length modifier is given, the argument is assumed to be of + type wint_t, and converted as by a "%ls" conversion with no precision + and a pointer to a two-element wchar_t array, with the first element + being the wint_t argument and the second a '\0' wide character. + s The argument from the argument stack is assumed to be a char array (i.e. + pointer to char). Characters from that array are printed until a zero + byte is encountered or as many bytes as specified by a given precision + have been written. + If the l length modifier is given, the argument from the argument stack + is assumed to be a wchar_t array (i.e. pointer to wchar_t). Wide + characters from that array are converted to multibyte characters as by + calls to wcrtomb() (using a mbstate_t object initialized to zero prior + to the first conversion), up to and including the terminating null wide + character. The resulting multibyte character sequence is then printed up + to but not including the terminating null character. If a precision is + given, it specifies the maximum number of bytes to be written (including + shift sequences). If the given precision would require access to a wide + character one past the end of the array, the array shall contain a '\0' + wide character. In no case is a partial multibyte character written. + Redundant shift sequences may result if the multibyte characters have a + state-dependent encoding. + TODO: Clarify these statements regarding %ls. + p The argument from the argument stack is assumed to be a void pointer, + and converted to a sequence of printing characters in an implementation- + defined manner. + This implementation casts the pointer to type intptr_t, and prints the + value as if a %#x conversion specifier was given. + n The argument from the argument stack is assumed to be a pointer to a + signed integer, into which the number of characters written so far by + this call to fprintf is stored. The behaviour, should any flags, field + widths, or precisions be given is undefined. + % A verbatim '%' character is written. No argument is taken from the + argument stack. + + Returns the number of characters written if successful, a negative value + otherwise. +*/ +int fprintf( FILE * _PDCLIB_restrict stream, const char * _PDCLIB_restrict format, ... ); + +/* TODO: fscanf() documentation */ +/* + Read input from a given stream, as defined by the given format string, and + store converted input in the objects pointed to by 0..n subsequent arguments + (the argument stack). + + The format string contains a sequence of directives that are expected to + match the input. If such a directive fails to match, the function returns + (matching error). It also returns if an input error occurs (input error). + + Directives can be: + - one or more whitespaces, matching any number of whitespaces in the input; + - printing characters, matching the input verbatim; + - conversion specifications, which convert an input sequence into a value as + defined by the individual specifier, and store that value in a memory + location pointed to by the next pointer on the argument stack. Details are + documented below. If there is an insufficient number of pointers on the + argument stack, behaviour is undefined. Additional arguments not required + by any conversion specifications are evaluated, but otherwise ignored. + + (The standard specifies the format string is allowed to contain multibyte + character sequences as long as it starts and ends in initial shift state, + but this is not yet supported by this implementation, which interprets the + format string as sequence of char.) + TODO: Add multibyte support to scanf() functions. + + A conversion specifier consists of: + - Optional assignment-suppressing character ('*') that makes the conversion + read input as usual, but does not assign the conversion result. + - Optional maximum field width as decimal integer. + - Optional length modifier specifying the size of the argument (one of "hh", + "ll", or one of the characters "hljztL"). + - Conversion specifier character specifying the type of conversion to be + applied (and the type of the next argument from the argument stack). One + of the characters "diouxXaAeEfFgGcs[pn%". + + LENGTH MODIFIERS + hh For "diouxXn" conversions, the next pointer from the argument stack is + assumed to point to a variable of of char width. + h For "diouxXn" conversions, the next pointer from the argument stack is + assumed to point to a variable of short int width. + l For "diouxXn" conversions, the next pointer from the argument stack is + assumed to point to a variable of long int width. + For "aAeEfFgG" conversions, it is assumed to point to a variable of type + double. + For "cs[" conversions, it is assumed to point to a variable of type + wchar_t. + ll For "diouxXn" conversions, the next pointer from the argument stack is + assumed to point to a variable of long long int width. + j For "diouxXn" conversions, the next pointer from the argument stack is + assumed to point to a variable of intmax_t width. + z For "diouxXn" conversions, the next pointer from the argument stack is + assumed to point to a variable of size_t width. + t For "diouxXn" conversions, the next pointer from the argument stack is + assumed to point to a variable of ptrdiff_t width. + L For "aAeEfFgG" conversions, the next pointer from the argument stack is + assumed to point to a variable of type long double. + Length modifiers appearing for any conversions not mentioned above will have + undefined behaviour. + If a length modifier appears with any conversion specifier other than as + specified above, the behavior is undefined. + + CONVERSION SPECIFIERS + d Matches an (optionally signed) decimal integer of the format expected + by strtol() with base 10. The next pointer from the argument stack is + assumed to point to a signed integer. + i Matches an (optionally signed) integer of the format expected by + strtol() with base 0. The next pointer from the argument stack is + assumed to point to a signed integer. + o Matches an (optionally signed) octal integer of the format expected by + strtoul() with base 8. The next pointer from the argument stack is + assumed to point to an unsigned integer. + u Matches an (optionally signed) decimal integer of the format expected + by strtoul() with base 10. The next pointer from the argument stack is + assumed to point to an unsigned integer. + x Matches an (optionally signed) hexadecimal integer of the format + expected by strtoul() with base 16. The next pointer from the argument + stack is assumed to point to an unsigned integer. + aefg Matches an (optionally signed) floating point number, infinity, or not- + a-number-value of the format expected by strtod(). The next pointer + from the argument stack is assumed to point to a float. + c Matches a number of characters as specified by the field width (default + 1). The next pointer from the argument stack is assumed to point to a + character array large enough to hold that many characters. + If the 'l' length modifier is given, the input is assumed to match a + sequence of multibyte characters (starting in the initial shift state), + which will be converted to a wide character sequence as by successive + calls to mbrtowc() with a mbstate_t object initialized to zero prior to + the first conversion. The next pointer from the argument stack is + assumed to point to a wchar_t array large enough to hold that many + characters. + In either case, note that no '\0' character is added to terminate the + sequence. + s Matches a sequence of non-white-space characters. The next pointer from + the argument stack is assumed to point to a character array large + enough to hold the sequence including terminating '\0' character. + If the 'l' length modifier is given, the input is assumed to match a + sequence of multibyte characters (starting in the initial shift state), + which will be converted to a wide character sequence as by a call to + mbrtowc() with a mbstate_t object initialized to zero prior to the + first conversion. The next pointer from the argument stack is assumed + to point to a wchar_t array large enough to hold the sequence including + terminating '\0' character. + [ Matches a nonempty sequence consisting of any of those characters + specified between itself and a corresponding closing bracket (']'). + If the first character in the list is a circumflex ('^'), this matches + a nonempty sequence consisting of any characters NOT specified. If the + closing bracket appears as the first character in the scanset ("[]" or + "[^]", it is assumed to belong to the scanset, which then ends with the + NEXT closing bracket. + If there is a '-' character in the scanset which is not the first after + the opening bracket (or the circumflex, see above) or the last in the + scanset, behaviour is implementation-defined. This implementation + handles this character like any other. + + The extend of the input field is determined byte-by-byte for the above + conversions ('c', 's', '['), with no special provisions being made for + multibyte characters. The resulting field is nevertheless a multibyte + sequence begining in intial shift state. + + p Matches a sequence of characters as produced by the printf() "%p" + conversion. The next pointer from the argument stack is assumed to + point to a void pointer, which will be filled with the same location + as the pointer used in the printf() statement. Note that behaviour is + undefined if the input value is not the result of an earlier printf() + call. + n Does not read input. The next pointer from the argument stack is + assumed to point to a signed integer, into which the number of + characters read from input so far by this call to fscanf() is stored. + This does not affect the return value of fscanf(). The behaviour, + should an assignment-supressing character of field width be given, + is undefined. + This can be used to test the success of literal matches and suppressed + assignments. + % Matches a single, verbatim '%' character. + + A, E, F, G and X are valid, and equivalent to their lowercase counterparts. + + All conversions except [, c, or n imply that whitespace characters from the + input stream are consumed until a non-whitespace character is encountered. + Such whitespaces do not count against a maximum field width. + + Conversions push at most one character back into the input stream. That + implies that some character sequences converted by the strtol() and strtod() + function families are not converted identically by the scnaf() function + family. + + Returns the number of input items successfully assigned. This can be zero if + an early mismatch occurs. Returns EOF if an input failure occurs before the + first conversion. +*/ +int fscanf( FILE * _PDCLIB_restrict stream, const char * _PDCLIB_restrict format, ... ); + +/* Equivalent to fprintf( stdout, format, ... ). */ +int printf( const char * _PDCLIB_restrict format, ... ); + +/* Equivalent to fscanf( stdin, format, ... ). */ +int scanf( const char * _PDCLIB_restrict format, ... ); + +/* Equivalent to fprintf( stdout, format, ... ), except that the result is + written into the buffer pointed to by s, instead of stdout, and that any + characters beyond the (n-1)th are discarded. The (n)th character is + replaced by a '\0' character in this case. + Returns the number of characters that would have been written (not counting + the terminating '\0' character) if n had been sufficiently large, if + successful, and a negative number if an encoding error ocurred. +*/ +int snprintf( char * _PDCLIB_restrict s, size_t n, const char * _PDCLIB_restrict format, ... ); + +/* Equivalent to fprintf( stdout, format, ... ), except that the result is + written into the buffer pointed to by s, instead of stdout. +*/ +int sprintf( char * _PDCLIB_restrict s, const char * _PDCLIB_restrict format, ... ); + +/* Equivalent to fscanf( stdin, format, ... ), except that the input is read + from the buffer pointed to by s, instead of stdin. +*/ +int sscanf( const char * _PDCLIB_restrict s, const char * _PDCLIB_restrict format, ... ); + +/* Equivalent to fprintf( stream, format, ... ), except that the argument stack + is passed as va_list parameter. Note that va_list is not declared by + <stdio.h>. +*/ +int vfprintf( FILE * _PDCLIB_restrict stream, const char * _PDCLIB_restrict format, _PDCLIB_va_list arg ); + +/* Equivalent to fscanf( stream, format, ... ), except that the argument stack + is passed as va_list parameter. Note that va_list is not declared by + <stdio.h>. +*/ +int vfscanf( FILE * _PDCLIB_restrict stream, const char * _PDCLIB_restrict format, _PDCLIB_va_list arg ); + +/* Equivalent to fprintf( stdout, format, ... ), except that the argument stack + is passed as va_list parameter. Note that va_list is not declared by + <stdio.h>. +*/ +int vprintf( const char * _PDCLIB_restrict format, _PDCLIB_va_list arg ); + +/* Equivalent to fscanf( stdin, format, ... ), except that the argument stack + is passed as va_list parameter. Note that va_list is not declared by + <stdio.h>. +*/ +int vscanf( const char * _PDCLIB_restrict format, _PDCLIB_va_list arg ); + +/* Equivalent to snprintf( s, n, format, ... ), except that the argument stack + is passed as va_list parameter. Note that va_list is not declared by + <stdio.h>. + */ +int vsnprintf( char * _PDCLIB_restrict s, size_t n, const char * _PDCLIB_restrict format, _PDCLIB_va_list arg ); + +/* Equivalent to fprintf( stdout, format, ... ), except that the argument stack + is passed as va_list parameter, and the result is written to the buffer + pointed to by s, instead of stdout. Note that va_list is not declared by + <stdio.h>. +*/ +int vsprintf( char * _PDCLIB_restrict s, const char * _PDCLIB_restrict format, _PDCLIB_va_list arg ); + +/* Equivalent to fscanf( stdin, format, ... ), except that the argument stack + is passed as va_list parameter, and the input is read from the buffer + pointed to by s, instead of stdin. Note that va_list is not declared by + <stdio.h>. +*/ +int vsscanf( const char * _PDCLIB_restrict s, const char * _PDCLIB_restrict format, _PDCLIB_va_list arg ); + +/* Character input/output functions */ + +/* Retrieve the next character from given stream. + Returns the character, EOF otherwise. + If end-of-file is reached, the EOF indicator of the stream is set. + If a read error occurs, the error indicator of the stream is set. +*/ +int fgetc( FILE * stream ); + +/* Read at most n-1 characters from given stream into the array s, stopping at + \n or EOF. Terminate the read string with \n. If EOF is encountered before + any characters are read, leave the contents of s unchanged. + Returns s if successful, NULL otherwise. + If a read error occurs, the error indicator of the stream is set. In this + case, the contents of s are indeterminate. +*/ +char * fgets( char * _PDCLIB_restrict s, int n, FILE * _PDCLIB_restrict stream ); + +/* Write the value c (cast to unsigned char) to the given stream. + Returns c if successful, EOF otherwise. + If a write error occurs, sets the error indicator of the stream is set. +*/ +int fputc( int c, FILE * stream ); + +/* Write the string s (not including the terminating \0) to the given stream. + Returns a value >=0 if successful, EOF otherwise. + This implementation does set the error indicator of the stream if a write + error occurs. +*/ +int fputs( const char * _PDCLIB_restrict s, FILE * _PDCLIB_restrict stream ); + +/* Equivalent to fgetc( stream ), but may be overloaded by a macro that + evaluates its parameter more than once. +*/ +int getc( FILE * stream ); + +/* Equivalent to fgetc( stdin ). */ +int getchar( void ); + +/* Equivalent to fputc( c, stream ), but may be overloaded by a macro that + evaluates its parameter more than once. +*/ +int putc( int c, FILE * stream ); + +/* Equivalent to fputc( c, stdout ), but may be overloaded by a macro that + evaluates its parameter more than once. +*/ +int putchar( int c ); + +/* Write the string s (not including the terminating \0) to stdout, and append + a newline to the output. Returns a value >= 0 when successful, EOF if a + write error occurred. +*/ +int puts( const char * s ); + +/* Push the value c (cast to unsigned char) back onto the given (input) stream. + A character pushed back in this way will be delivered by subsequent read + operations (and skipped by subsequent file positioning operations) as if it + has not been read. The external representation of the stream is unaffected + by this pushback (it is a buffer operation). One character of pushback is + guaranteed, further pushbacks may fail. EOF as value for c does not change + the input stream and results in failure of the function. + For text files, the file position indicator is indeterminate until all + pushed-back characters are read. For binary files, the file position + indicator is decremented by each successful call of ungetc(). If the file + position indicator for a binary file was zero before the call of ungetc(), + behaviour is undefined. (Older versions of the library allowed such a call.) + Returns the pushed-back character if successful, EOF if it fails. +*/ +int ungetc( int c, FILE * stream ); + +/* Direct input/output functions */ + +/* Read up to nmemb elements of given size from given stream into the buffer + pointed to by ptr. Returns the number of elements successfully read, which + may be less than nmemb if a read error or EOF is encountered. If a read + error is encountered, the value of the file position indicator is + indeterminate. If a partial element is read, its value is indeterminate. + If size or nmemb are zero, the function does nothing and returns zero. +*/ +size_t fread( void * _PDCLIB_restrict ptr, size_t size, size_t nmemb, FILE * _PDCLIB_restrict stream ); + +/* Write up to nmemb elements of given size from buffer pointed to by ptr to + the given stream. Returns the number of elements successfully written, which + will be less than nmemb only if a write error is encountered. If a write + error is encountered, the value of the file position indicator is + indeterminate. If size or nmemb are zero, the function does nothing and + returns zero. +*/ +size_t fwrite( const void * _PDCLIB_restrict ptr, size_t size, size_t nmemb, FILE * _PDCLIB_restrict stream ); + +/* File positioning functions */ + +/* Store the current position indicator (and, where appropriate, the current + mbstate_t status object) for the given stream into the given pos object. The + actual contents of the object are unspecified, but it can be used as second + parameter to fsetpos() to reposition the stream to the exact position and + parse state at the time fgetpos() was called. + Returns zero if successful, nonzero otherwise. + TODO: Implementation-defined errno setting for fgetpos(). +*/ +int fgetpos( FILE * _PDCLIB_restrict stream, fpos_t * _PDCLIB_restrict pos ); + +/* Set the position indicator for the given stream to the given offset from: + - the beginning of the file if whence is SEEK_SET, + - the current value of the position indicator if whence is SEEK_CUR, + - end-of-file if whence is SEEK_END. + On text streams, non-zero offsets are only allowed with SEEK_SET, and must + have been returned by ftell() for the same file. + Any characters buffered by ungetc() are dropped, the end-of-file indicator + for the stream is cleared. If the given stream is an update stream, the next + operation after a successful fseek() may be either input or output. + Returns zero if successful, nonzero otherwise. If a read/write error occurs, + the error indicator for the given stream is set. +*/ +int fseek( FILE * stream, long int offset, int whence ); + +/* Set the position indicator (and, where appropriate the mbstate_t status + object) for the given stream to the given pos object (created by an earlier + call to fgetpos() on the same file). + Any characters buffered by ungetc() are dropped, the end-of-file indicator + for the stream is cleared. If the given stream is an update stream, the next + operation after a successful fsetpos() may be either input or output. + Returns zero if successful, nonzero otherwise. If a read/write error occurs, + the error indicator for the given stream is set. + TODO: Implementation-defined errno setting for fsetpos(). +*/ +int fsetpos( FILE * stream, const fpos_t * pos ); + +/* Return the current offset of the given stream from the beginning of the + associated file. For text streams, the exact value returned is unspecified + (and may not be equal to the number of characters), but may be used in + subsequent calls to fseek(). + Returns -1L if unsuccessful. + TODO: Implementation-defined errno setting for ftell(). +*/ +long int ftell( FILE * stream ); + +/* Equivalent to (void)fseek( stream, 0L, SEEK_SET ), except that the error + indicator for the stream is also cleared. +*/ +void rewind( FILE * stream ); + +/* Error-handling functions */ + +/* Clear the end-of-file and error indicators for the given stream. */ +void clearerr( FILE * stream ); + +/* Return zero if the end-of-file indicator for the given stream is not set, + nonzero otherwise. +*/ +int feof( FILE * stream ); + +/* Return zero if the error indicator for the given stream is not set, nonzero + otherwise. +*/ +int ferror( FILE * stream ); + +/* If s is neither a NULL pointer nor an empty string, print the string to + stderr (with appended colon (':') and a space) first. In any case, print an + error message depending on the current value of errno (being the same as if + strerror( errno ) had been called). +*/ +void perror( const char * s ); + +#endif diff --git a/src/pdclib/include/stdlib.h b/src/pdclib/include/stdlib.h new file mode 100644 index 0000000..5377bcd --- /dev/null +++ b/src/pdclib/include/stdlib.h @@ -0,0 +1,242 @@ +/* General utilities <stdlib.h> + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#ifndef _PDCLIB_STDLIB_H +#define _PDCLIB_STDLIB_H _PDCLIB_STDLIB_H + +#include "pdclib/_PDCLIB_int.h" + +#ifndef _PDCLIB_SIZE_T_DEFINED +#define _PDCLIB_SIZE_T_DEFINED _PDCLIB_SIZE_T_DEFINED +typedef _PDCLIB_size_t size_t; +#endif + +#ifndef _PDCLIB_NULL_DEFINED +#define _PDCLIB_NULL_DEFINED _PDCLIB_NULL_DEFINED +#define NULL _PDCLIB_NULL +#endif + +/* Numeric conversion functions */ + +/* TODO: atof(), strtof(), strtod(), strtold() */ + +double atof( const char * nptr ); +double strtod( const char * _PDCLIB_restrict nptr, char * * _PDCLIB_restrict endptr ); +float strtof( const char * _PDCLIB_restrict nptr, char * * _PDCLIB_restrict endptr ); +long double strtold( const char * _PDCLIB_restrict nptr, char * * _PDCLIB_restrict endptr ); + +/* Seperate the character array nptr into three parts: A (possibly empty) + sequence of whitespace characters, a character representation of an integer + to the given base, and trailing invalid characters (including the terminating + null character). If base is 0, assume it to be 10, unless the integer + representation starts with 0x / 0X (setting base to 16) or 0 (setting base to + 8). If given, base can be anything from 0 to 36, using the 26 letters of the + base alphabet (both lowercase and uppercase) as digits 10 through 35. + The integer representation is then converted into the return type of the + function. It can start with a '+' or '-' sign. If the sign is '-', the result + of the conversion is negated. + If the conversion is successful, the converted value is returned. If endptr + is not a NULL pointer, a pointer to the first trailing invalid character is + returned in *endptr. + If no conversion could be performed, zero is returned (and nptr in *endptr, + if endptr is not a NULL pointer). If the converted value does not fit into + the return type, the functions return LONG_MIN, LONG_MAX, ULONG_MAX, + LLONG_MIN, LLONG_MAX, or ULLONG_MAX respectively, depending on the sign of + the integer representation and the return type, and errno is set to ERANGE. +*/ +/* There is strtoimax() and strtoumax() in <inttypes.h> operating on intmax_t / + uintmax_t, if the long long versions do not suit your needs. +*/ +long int strtol( const char * _PDCLIB_restrict nptr, char * * _PDCLIB_restrict endptr, int base ); +long long int strtoll( const char * _PDCLIB_restrict nptr, char * * _PDCLIB_restrict endptr, int base ); +unsigned long int strtoul( const char * _PDCLIB_restrict nptr, char * * _PDCLIB_restrict endptr, int base ); +unsigned long long int strtoull( const char * _PDCLIB_restrict nptr, char * * _PDCLIB_restrict endptr, int base ); + +/* These functions are the equivalent of (int)strtol( nptr, NULL, 10 ), + strtol( nptr, NULL, 10 ) and strtoll(nptr, NULL, 10 ) respectively, with the + exception that they do not have to handle overflow situations in any defined + way. + (PDCLib does not simply forward these to their strtox() equivalents, but + provides a simpler atox() function that saves a couple of tests and simply + continues with the conversion in case of overflow.) +*/ +int atoi( const char * nptr ); +long int atol( const char * nptr ); +long long int atoll( const char * nptr ); + +/* Pseudo-random sequence generation functions */ + +extern unsigned long int _PDCLIB_seed; + +#define RAND_MAX 32767 + +/* Returns the next number in a pseudo-random sequence, which is between 0 and + RAND_MAX. + (PDCLib uses the implementation suggested by the standard document, which is + next = next * 1103515245 + 12345; return (unsigned int)(next/65536) % 32768;) +*/ +int rand( void ); + +/* Initialize a new pseudo-random sequence with the starting seed. Same seeds + result in the same pseudo-random sequence. The default seed is 1. +*/ +void srand( unsigned int seed ); + +/* Memory management functions */ + +/* Allocate a chunk of heap memory of given size. If request could not be + satisfied, return NULL. Otherwise, return a pointer to the allocated + memory. Memory contents are undefined. +*/ +void * malloc( size_t size ); + +/* Allocate a chunk of heap memory that is large enough to hold nmemb elements + of the given size, and zero-initialize that memory. If request could not be + satisfied, return NULL. Otherwise, return a pointer to the allocated + memory. +*/ +void * calloc( size_t nmemb, size_t size ); + +/* De-allocate a chunk of heap memory previously allocated using malloc(), + calloc(), or realloc(), and pointed to by ptr. If ptr does not match a + pointer previously returned by the mentioned allocation functions, or + free() has already been called for this ptr, behaviour is undefined. +*/ +void free( void * ptr ); + +/* Resize a chunk of memory previously allocated with malloc() and pointed to + by ptr to the given size (which might be larger or smaller than the original + size). Returns a pointer to the reallocated memory, or NULL if the request + could not be satisfied. Note that the resizing might include a memcpy() + from the original location to a different one, so the return value might or + might not equal ptr. If size is larger than the original size, the value of + memory beyond the original size is undefined. If ptr is NULL, realloc() + behaves like malloc(). +*/ +void * realloc( void * ptr, size_t size ); + +/* Communication with the environment */ + +/* These two can be passed to exit() or _Exit() as status values, to signal + successful and unsuccessful program termination, respectively. EXIT_SUCCESS + can be replaced by 0. How successful or unsuccessful program termination are + signaled to the environment, and what happens if exit() or _Exit() are being + called with a value that is neither of the three, is defined by the hosting + OS and its glue function. +*/ +#define EXIT_SUCCESS _PDCLIB_SUCCESS +#define EXIT_FAILURE _PDCLIB_FAILURE + +/* Initiate abnormal process termination, unless programm catches SIGABRT and + does not return from the signal handler. + This implementantion flushes all streams, closes all files, and removes any + temporary files before exiting with EXIT_FAILURE. + abort() does not return. +*/ +void abort( void ); + +/* Register a function that will be called on exit(), or when main() returns. + At least 32 functions can be registered this way, and will be called in + reverse order of registration (last-in, first-out). + Returns zero if registration is successfull, nonzero if it failed. +*/ +int atexit( void (*func)( void ) ); + +/* Normal process termination. Functions registered by atexit() (see above) are + called, streams flushed, files closed and temporary files removed before the + program is terminated with the given status. (See comment for EXIT_SUCCESS + and EXIT_FAILURE above.) + exit() does not return. +*/ +void exit( int status ); + +/* Normal process termination. Functions registered by atexit() (see above) are + NOT CALLED. This implementation DOES flush streams, close files and removes + temporary files before the program is teminated with the given status. (See + comment for EXIT_SUCCESS and EXIT_FAILURE above.) + _Exit() does not return. +*/ +void _Exit( int status ); + +/* Search an environment-provided key-value map for the given key name, and + return a pointer to the associated value string (or NULL if key name cannot + be found). The value string pointed to might be overwritten by a subsequent + call to getenv(). The library never calls getenv() itself. + Details on the provided keys and how to set / change them are determined by + the hosting OS and its glue function. +*/ +char * getenv( const char * name ); + +/* If string is a NULL pointer, system() returns nonzero if a command processor + is available, and zero otherwise. If string is not a NULL pointer, it is + passed to the command processor. If system() returns, it does so with a + value that is determined by the hosting OS and its glue function. +*/ +int system( const char * string ); + +/* Searching and sorting */ + +/* Do a binary search for a given key in the array with a given base pointer, + which consists of nmemb elements that are of the given size each. To compare + the given key with an element from the array, the given function compar is + called (with key as first parameter and a pointer to the array member as + second parameter); the function should return a value less than, equal to, + or greater than 0 if the key is considered to be less than, equal to, or + greater than the array element, respectively. + The function returns a pointer to the first matching element found, or NULL + if no match is found. +*/ +void * bsearch( const void * key, const void * base, size_t nmemb, size_t size, int (*compar)( const void *, const void * ) ); + +/* Do a quicksort on an array with a given base pointer, which consists of + nmemb elements that are of the given size each. To compare two elements from + the array, the given function compar is called, which should return a value + less than, equal to, or greater than 0 if the first argument is considered + to be less than, equal to, or greater than the second argument, respectively. + If two elements are compared equal, their order in the sorted array is not + specified. +*/ +void qsort( void * base, size_t nmemb, size_t size, int (*compar)( const void *, const void * ) ); + +/* Integer arithmetic functions */ + +/* Return the absolute value of the argument. Note that on machines using two- + complement's notation (most modern CPUs), the largest negative value cannot + be represented as positive value. In this case, behaviour is unspecified. +*/ +int abs( int j ); +long int labs( long int j ); +long long int llabs( long long int j ); + +/* These structures each have a member quot and a member rem, of type int (for + div_t), long int (for ldiv_t) and long long it (for lldiv_t) respectively. + The order of the members is platform-defined to allow the div() functions + below to be implemented efficiently. +*/ +typedef struct _PDCLIB_div_t div_t; +typedef struct _PDCLIB_ldiv_t ldiv_t; +typedef struct _PDCLIB_lldiv_t lldiv_t; + +/* Return quotient (quot) and remainder (rem) of an integer division in one of + the structs above. +*/ +div_t div( int numer, int denom ); +ldiv_t ldiv( long int numer, long int denom ); +lldiv_t lldiv( long long int numer, long long int denom ); + +/* TODO: Multibyte / wide character conversion functions */ + +/* TODO: Macro MB_CUR_MAX */ + +/* +int mblen( const char * s, size_t n ); +int mbtowc( wchar_t * _PDCLIB_restrict pwc, const char * _PDCLIB_restrict s, size_t n ); +int wctomb( char * s, wchar_t wc ); +size_t mbstowcs( wchar_t * _PDCLIB_restrict pwcs, const char * _PDCLIB_restrict s, size_t n ); +size_t wcstombs( char * _PDCLIB_restrict s, const wchar_t * _PDCLIB_restrict pwcs, size_t n ); +*/ + +#endif diff --git a/src/pdclib/include/stdnoreturn.h b/src/pdclib/include/stdnoreturn.h new file mode 100644 index 0000000..8c18143 --- /dev/null +++ b/src/pdclib/include/stdnoreturn.h @@ -0,0 +1,12 @@ +/* _Noreturn <stdnoreturn.h> + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#ifndef _PDCLIB_STDNORETURN_H +#define _PDCLIB_STDNORETURN_H _PDCLIB_STDNORETURN_H + +#define noreturn _Noreturn + +#endif diff --git a/src/pdclib/include/string.h b/src/pdclib/include/string.h new file mode 100644 index 0000000..dc0af15 --- /dev/null +++ b/src/pdclib/include/string.h @@ -0,0 +1,185 @@ +/* String handling <string.h> + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#ifndef _PDCLIB_STRING_H +#define _PDCLIB_STRING_H _PDCLIB_STRING_H + +#include "pdclib/_PDCLIB_int.h" + +#ifndef _PDCLIB_SIZE_T_DEFINED +#define _PDCLIB_SIZE_T_DEFINED _PDCLIB_SIZE_T_DEFINED +typedef _PDCLIB_size_t size_t; +#endif + +#ifndef _PDCLIB_NULL_DEFINED +#define _PDCLIB_NULL_DEFINED _PDCLIB_NULL_DEFINED +#define NULL _PDCLIB_NULL +#endif + +/* String function conventions */ + +/* + In any of the following functions taking a size_t n to specify the length of + an array or size of a memory region, n may be 0, but the pointer arguments to + the call shall still be valid unless otherwise stated. +*/ + +/* Copying functions */ + +/* Copy a number of n characters from the memory area pointed to by s2 to the + area pointed to by s1. If the two areas overlap, behaviour is undefined. + Returns the value of s1. +*/ +void * memcpy( void * _PDCLIB_restrict s1, const void * _PDCLIB_restrict s2, size_t n ); + +/* Copy a number of n characters from the memory area pointed to by s2 to the + area pointed to by s1. The two areas may overlap. + Returns the value of s1. +*/ +void * memmove( void * _PDCLIB_restrict s1, const void * _PDCLIB_restrict s2, size_t n ); + +/* Copy the character array s2 (including terminating '\0' byte) into the + character array s1. + Returns the value of s1. +*/ +char * strcpy( char * _PDCLIB_restrict s1, const char * _PDCLIB_restrict s2 ); + +/* Copy a maximum of n characters from the character array s2 into the character + array s1. If s2 is shorter than n characters, '\0' bytes will be appended to + the copy in s1 until n characters have been written. If s2 is longer than n + characters, NO terminating '\0' will be written to s1. If the arrays overlap, + behaviour is undefined. + Returns the value of s1. +*/ +char * strncpy( char * _PDCLIB_restrict s1, const char * _PDCLIB_restrict s2, size_t n ); + +/* Concatenation functions */ + +/* Append the contents of the character array s2 (including terminating '\0') to + the character array s1 (first character of s2 overwriting the '\0' of s1). If + the arrays overlap, behaviour is undefined. + Returns the value of s1. +*/ +char * strcat( char * _PDCLIB_restrict s1, const char * _PDCLIB_restrict s2 ); + +/* Append a maximum of n characters from the character array s1 to the character + array s1 (first character of s2 overwriting the '\0' of s1). A terminating + '\0' is ALWAYS appended, even if the full n characters have already been + written. If the arrays overlap, behaviour is undefined. + Returns the value of s1. +*/ +char * strncat( char * _PDCLIB_restrict s1, const char * _PDCLIB_restrict s2, size_t n ); + +/* Comparison functions */ + +/* Compare the first n characters of the memory areas pointed to by s1 and s2. + Returns 0 if s1 == s2, a negative number if s1 < s2, and a positive number if + s1 > s2. +*/ +int memcmp( const void * s1, const void * s2, size_t n ); + +/* Compare the character arrays s1 and s2. + Returns 0 if s1 == s2, a negative number if s1 < s2, and a positive number if + s1 > s2. +*/ +int strcmp( const char * s1, const char * s2 ); + +/* Compare the character arrays s1 and s2, interpreted as specified by the + LC_COLLATE category of the current locale. + Returns 0 if s1 == s2, a negative number if s1 < s2, and a positive number if + s1 > s2. + TODO: Currently a dummy wrapper for strcmp() as PDCLib does not yet support + locales. +*/ +int strcoll( const char * s1, const char * s2 ); + +/* Compare no more than the first n characters of the character arrays s1 and + s2. + Returns 0 if s1 == s2, a negative number if s1 < s2, and a positive number if + s1 > s2. +*/ +int strncmp( const char * s1, const char * s2, size_t n ); + +/* Transform the character array s2 as appropriate for the LC_COLLATE setting of + the current locale. If length of resulting string is less than n, store it in + the character array pointed to by s1. Return the length of the resulting + string. +*/ +size_t strxfrm( char * _PDCLIB_restrict s1, const char * _PDCLIB_restrict s2, size_t n ); + +/* Search functions */ + +/* Search the first n characters in the memory area pointed to by s for the + character c (interpreted as unsigned char). + Returns a pointer to the first instance found, or NULL. +*/ +void * memchr( const void * s, int c, size_t n ); + +/* Search the character array s (including terminating '\0') for the character c + (interpreted as char). + Returns a pointer to the first instance found, or NULL. +*/ +char * strchr( const char * s, int c ); + +/* Determine the length of the initial substring of character array s1 which + consists only of characters not from the character array s2. + Returns the length of that substring. +*/ +size_t strcspn( const char * s1, const char * s2 ); + +/* Search the character array s1 for any character from the character array s2. + Returns a pointer to the first occurrence, or NULL. +*/ +char * strpbrk( const char * s1, const char * s2 ); + +/* Search the character array s (including terminating '\0') for the character c + (interpreted as char). + Returns a pointer to the last instance found, or NULL. +*/ +char * strrchr( const char * s, int c ); + +/* Determine the length of the initial substring of character array s1 which + consists only of characters from the character array s2. + Returns the length of that substring. +*/ +size_t strspn( const char * s1, const char * s2 ); + +/* Search the character array s1 for the substring in character array s2. + Returns a pointer to that sbstring, or NULL. If s2 is of length zero, + returns s1. +*/ +char * strstr( const char * s1, const char * s2 ); + +/* In a series of subsequent calls, parse a C string into tokens. + On the first call to strtok(), the first argument is a pointer to the to-be- + parsed C string. On subsequent calls, the first argument is NULL unless you + want to start parsing a new string. s2 holds an array of seperator characters + which can differ from call to call. Leading seperators are skipped, the first + trailing seperator overwritten with '\0'. + Returns a pointer to the next token. + WARNING: This function uses static storage, and as such is not reentrant. +*/ +char * strtok( char * _PDCLIB_restrict s1, const char * _PDCLIB_restrict s2 ); + +/* Miscellaneous functions */ + +/* Write the character c (interpreted as unsigned char) to the first n + characters of the memory area pointed to by s. + Returns s. +*/ +void * memset( void * s, int c, size_t n ); + +/* Map an error number to a (locale-specific) error message string. Error + numbers are typically errno values, but any number is mapped to a message. + TODO: PDCLib does not yet support locales. +*/ +char * strerror( int errnum ); + +/* Returns the length of the string s (excluding terminating '\0'). +*/ +size_t strlen( const char * s ); + +#endif diff --git a/src/pdclib/include/time.h b/src/pdclib/include/time.h new file mode 100644 index 0000000..fb1af0b --- /dev/null +++ b/src/pdclib/include/time.h @@ -0,0 +1,112 @@ +/* Date and time <time.h> + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#ifndef _PDCLIB_TIME_H +#define _PDCLIB_TIME_H _PDCLIB_TIMEH + +#include "pdclib/_PDCLIB_int.h" + +#ifndef _PDCLIB_SIZE_T_DEFINED +#define _PDCLIB_SIZE_T_DEFINED _PDCLIB_SIZE_T_DEFINED +typedef _PDCLIB_size_t size_t; +#endif + +#ifndef _PDCLIB_NULL_DEFINED +#define _PDCLIB_NULL_DEFINED _PDCLIB_NULL_DEFINED +#define NULL _PDCLIB_NULL +#endif + +/* These are defined to be "real types capable of representing types", with + "range and precision of times representable in [them being] implementation- + defined". + As part of struct timespec (see below), time_t is further defined as "a + linear count of seconds", with potentially different semantics from a + "normal" time_t. + For sake of simplicity, we used just that (common) definition of "seconds + since epoch" as integer. +*/ +typedef _PDCLIB_time_t time_t; +typedef _PDCLIB_clock_t clock_t; + +#define CLOCKS_PER_SEC _PDCLIB_CLOCKS_PER_SEC +#define TIME_UTC _PDCLIB_TIME_UTC + +struct timespec +{ + time_t tv_sec; + long tv_nsec; +}; + +struct tm +{ + int tm_sec; /* 0-60 */ + int tm_min; /* 0-59 */ + int tm_hour; /* 0-23 */ + int tm_mday; /* 1-31 */ + int tm_mon; /* 0-11 */ + int tm_year; /* years since 1900 */ + int tm_wday; /* 0-6 */ + int tm_yday; /* 0-365 */ + int tm_isdst; /* >0 DST, 0 no DST, <0 information unavailable */ +}; + +/* Returns the number of "clocks" in processor time since the invocation + of the program. Divide by CLOCKS_PER_SEC to get the value in seconds. + Returns -1 if the value cannot be represented in the return type or is + not available. +*/ +clock_t clock( void ); + +/* Returns the difference between two calendar times in seconds. */ +double difftime( time_t time1, time_t time0 ); + +/* Normalizes the values in the broken-down time pointed to by timeptr. + Returns the calender time specified by the broken-down time. +*/ +time_t mktime( struct tm * timeptr ); + +/* Returns the current calender time. If timer is not a NULL pointer, stores + the current calender time at that address as well. +*/ +time_t time( time_t * timer ); + +/* Sets the interval pointed to by ts to the current calender time, based + on the specified base. + Returns base, if successful, otherwise zero. +*/ +int timespec_get( struct timespec * ts, int base ); + +/* Converts the broken-down time pointed to by timeptr into a string in the + form "Sun Sep 16 01:03:52 1973\n\0". +*/ +char * asctime( const struct tm * timeptr ); + +/* Equivalent to asctime( localtime( timer ) ). */ +char * ctime( const time_t * timer ); + +/* Converts the calender time pointed to by timer into a broken-down time + expressed as UTC. + Returns a pointer to the broken-down time, or a NULL pointer if it + cannot be represented. +*/ +struct tm * gmtime( const time_t * timer ); + +/* Converts the calender time pointed to by timer into a broken-down time + expressed as local time. + Returns a pointer to the broken-down time, or a NULL pointer if if + cannot be represented. +*/ +struct tm * localtime( const time_t * timer ); + +/* Writes the broken-down time pointed to by timeptr into the character + array pointed to by s. The string pointed to by format controls the + exact output. No more than maxsize charactrs will be written. + Returns the number of characters written (excluding the terminating + null character), or zero on failure. +*/ +size_t strftime( char * _PDCLIB_restrict s, size_t maxsize, const char * _PDCLIB_restrict format, const struct tm * _PDCLIB_restrict timeptr ); + +#endif diff --git a/src/pdclib/include/wctype.h b/src/pdclib/include/wctype.h new file mode 100644 index 0000000..5449930 --- /dev/null +++ b/src/pdclib/include/wctype.h @@ -0,0 +1,138 @@ +/* Wide character classification and mapping utilities <wctype.h> + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#ifndef _PDCLIB_WCTYPE_H +#define _PDCLIB_WCTYPE_H _PDCLIB_WCTYPE_H + +#include "pdclib/_PDCLIB_int.h" + +typedef _PDCLIB_wint_t wint_t; + +// wctrans_t +// wctype_t + +#ifndef _PDCLIB_WEOF_DEFINED +#define _PDCLIB_WEOF_DEFINED _PDCLIB_WEOF_DEFINED +#define WEOF (wint_t)-1 +#endif + +/* Wide character classification functions */ + +/* Returns iswalpha( wc ) || iswdigit( wc ) */ +int iswalnum( wint_t wc ); + +/* Returns true for wide characters for which either isupper( wc ) or + islower( wc ) is true, as well as a set of locale-specific wide + characters which are neither control characters, digits, punctuation, + or whitespace. +*/ +int iswalpha( wint_t wc ); + +/* Returns true if the character iswspace() and used for separating words + within a line of text. In the "C" locale, only L' ' and L'\t' are + considered blanks. +*/ +int iswblank( wint_t wc ); + +/* Returns true if the wide character is a control character. */ +int iswcntrl( wint_t wc ); + +/* Returns true if the wide character is a decimal digit. Locale- + independent. */ +int iswdigit( wint_t wc ); + +/* Returns iswprint( wc ) && ! iswspace( wc ). + NOTE: This definition differs from that of isgraph() in <ctype.h>, + which considers only ' ', not all isspace() characters. +*/ +int iswgraph( wint_t wc ); + +/* Returns true for lowerspace wide characters, as well as a set of + locale-specific wide characters which are neither control charcters, + digits, punctuation, or whitespace. +*/ +int iswlower( wint_t wc ); + +/* Returns true for every printing wide character. */ +int iswprint( wint_t wc ); + +/* Returns true for a locale-specific set of punctuation characters that + are neither whitespace nor alphanumeric. +*/ +int iswpunct( wint_t wc ); + +/* Returns true for a locale-specific set of whitespace characters that + are neither alphanumeric, graphic, or punctuation. +*/ +int iswspace( wint_t wc ); + +/* Returns true for upperspace wide characters, as well as a set of + locale-specific wide characters which are neither control charcters, + digits, punctuation, or whitespace. +*/ +int iswupper( wint_t wc ); + +/* Returns true if the wide character is a hexadecimal digit. Locale- + independent. */ +int iswxdigit( wint_t wc ); + +/* Extensible wide character classification functions */ + +/* Returns true if the wide character wc has the property described by + desc (which was retrieved by a previous call to wctype() without + changing the LC_CTYPE locale setting between the two calls). +*/ +int iswctype( wint_t wc, wctype_t desc ); + +/* Returns a description object for a named character property, to be + used as parameter to the iswctype() function. Supported property + names are: + "alnum" -- alphanumeric, as per iswalnum() + "alpha" -- alphabetic, as per iswalpha() + "blank" -- blank, as per iswblank() + "cntrl" -- control, as per iswcntrl() + "digit" -- decimal digit, as per iswdigit() + "graph" -- graphic, as per iswgraph() + "lower" -- lowercase, as per iswlower() + "print" -- printing, as per iswprint() + "punct" -- punctuation, as per iswprint() + "space" -- whitespace, as per iswspace() + "upper" -- uppercase, as per iswupper() + "xdigit" -- hexadecimal digit, as per iswxdigit() + For unsupported properties, the function returns zero. +*/ +wctype_t wctype( const char * property ); + +/* Wide character case mapping utilities */ + +/* Converts an uppercase letter to a corresponding lowercase letter. Input for + which no corresponding lowercase letter exists remains unchanged. +*/ +wint_t towlower( wint_t wc ); + +/* Converts a lowercase letter to a corresponding uppercase letter. Input for + which no corresponding uppercase letter exists remains unchanged. +*/ +wint_t towupper( wint_t wc ); + +/* Extensible wide character case mapping utilities */ + +/* Converts the wide character wc according to the transition described + by desc (which was retrieved by a previous call to wctrans() without + changing the LC_CTYPE locale setting between the two calls). +*/ +wint_t towctrans( wint_t wc, wctrans_t desc ); + +/* Returns a description object for a named character transformation, to + be used as parameter to the towctrans() function. Supported transformation + properties are: + "tolower" -- lowercase mapping, as per towlower() + "toupper" -- uppercase mapping, as per towupper() + For unsupported properties, the function returns zero. +*/ +wctrans_t wctrans( const char * property ); + +#endif diff --git a/src/pdclib/platform/example/Readme.txt b/src/pdclib/platform/example/Readme.txt new file mode 100644 index 0000000..07dc20e --- /dev/null +++ b/src/pdclib/platform/example/Readme.txt @@ -0,0 +1,21 @@ +"Example" Platform Overlay +========================== + +This is an example platform overlay, as described in the main Readme.txt of +this archive. For ease of development, it applies (and tests) correctly on the +machine of the author; no other guarantees can be given. +It should give you a good idea of what is REQUIRED to make a copy of PDCLib +work. There is a lot more you could do, and even some things you SHOULD do, in +order to experience anything but abysmal performance: + +- Read / write operations on binary streams, and even on text streams for + machines that do not do any text conversion, can be made much more efficient + by using some sort of page buffer instead of the linear buffer implemented + here. It requires some special and platform-dependent manipulations, though, + which is why it is not done by default. + +- Anything relating to floating point logic is written in generic C. While + this is (hopefully) highly portable and should get you started on your + platform of choice, it is also highly inefficient and should be replaced by + inline assembly. Just make sure that your assembly keeps all the promises + the C library makes. diff --git a/src/pdclib/platform/example/functions/_PDCLIB/_PDCLIB_Exit.c b/src/pdclib/platform/example/functions/_PDCLIB/_PDCLIB_Exit.c new file mode 100644 index 0000000..d2e6ee4 --- /dev/null +++ b/src/pdclib/platform/example/functions/_PDCLIB/_PDCLIB_Exit.c @@ -0,0 +1,40 @@ +/* _PDCLIB_exit( int ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +/* This is an example implementation of _PDCLIB_exit() fit for use with POSIX + kernels. +*/ + +#include <stdlib.h> + +#ifndef REGTEST + +#include "pdclib/_PDCLIB_glue.h" + +extern void _exit( int status ) _PDCLIB_NORETURN; + +void _PDCLIB_Exit( int status ) +{ + _exit( status ); +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ +#ifndef REGTEST + int UNEXPECTED_RETURN = 0; + _PDCLIB_Exit( 0 ); + TESTCASE( UNEXPECTED_RETURN ); +#endif + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/platform/example/functions/_PDCLIB/_PDCLIB__Exit.c b/src/pdclib/platform/example/functions/_PDCLIB/_PDCLIB__Exit.c new file mode 100644 index 0000000..d2e6ee4 --- /dev/null +++ b/src/pdclib/platform/example/functions/_PDCLIB/_PDCLIB__Exit.c @@ -0,0 +1,40 @@ +/* _PDCLIB_exit( int ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +/* This is an example implementation of _PDCLIB_exit() fit for use with POSIX + kernels. +*/ + +#include <stdlib.h> + +#ifndef REGTEST + +#include "pdclib/_PDCLIB_glue.h" + +extern void _exit( int status ) _PDCLIB_NORETURN; + +void _PDCLIB_Exit( int status ) +{ + _exit( status ); +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ +#ifndef REGTEST + int UNEXPECTED_RETURN = 0; + _PDCLIB_Exit( 0 ); + TESTCASE( UNEXPECTED_RETURN ); +#endif + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/platform/example/functions/_PDCLIB/_PDCLIB_allocpages.c b/src/pdclib/platform/example/functions/_PDCLIB/_PDCLIB_allocpages.c new file mode 100644 index 0000000..d46d46f --- /dev/null +++ b/src/pdclib/platform/example/functions/_PDCLIB/_PDCLIB_allocpages.c @@ -0,0 +1,86 @@ +/* _PDCLIB_allocpages( int const ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +/* This is an example implementation of _PDCLIB_allocpages() fit for use with + POSIX kernels. +*/ + +#include <stdint.h> +#include <stddef.h> + +#ifndef REGTEST + +int brk( void * ); +void * sbrk( intptr_t ); + +#include "pdclib/_PDCLIB_glue.h" + +static void * membreak = NULL; + +void * _PDCLIB_allocpages( int const n ) +{ + void * oldbreak; + if ( membreak == NULL ) + { + /* first call, make sure end-of-heap is page-aligned */ + intptr_t unaligned = 0; + membreak = sbrk( 0 ); + unaligned = _PDCLIB_PAGESIZE - (intptr_t)membreak % _PDCLIB_PAGESIZE; + if ( unaligned < _PDCLIB_PAGESIZE ) + { + /* end-of-heap not page-aligned - adjust */ + if ( sbrk( unaligned ) != membreak ) + { + /* error */ + return NULL; + } + membreak = (char *)membreak + unaligned; + } + } + /* increasing or decreasing heap - standard operation */ + oldbreak = membreak; + membreak = (void *)( (char *)membreak + ( n * _PDCLIB_PAGESIZE ) ); +#ifdef __CYGWIN__ + if ( sbrk( (char*)membreak - (char*)oldbreak ) == membreak ) +#else + if ( brk( membreak ) == 0 ) +#endif + { + /* successful */ + return oldbreak; + } + else + { + /* out of memory */ + membreak = oldbreak; + return NULL; + } +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ +#ifndef REGTEST + char * startbreak = sbrk( 0 ); + TESTCASE( _PDCLIB_allocpages( 0 ) ); + TESTCASE( ( (char *)sbrk( 0 ) - startbreak ) <= _PDCLIB_PAGESIZE ); + startbreak = sbrk( 0 ); + TESTCASE( _PDCLIB_allocpages( 1 ) ); + TESTCASE( sbrk( 0 ) == startbreak + ( 1 * _PDCLIB_PAGESIZE ) ); + TESTCASE( _PDCLIB_allocpages( 5 ) ); + TESTCASE( sbrk( 0 ) == startbreak + ( 6 * _PDCLIB_PAGESIZE ) ); + TESTCASE( _PDCLIB_allocpages( -3 ) ); + TESTCASE( sbrk( 0 ) == startbreak + ( 3 * _PDCLIB_PAGESIZE ) ); +#endif + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/platform/example/functions/_PDCLIB/_PDCLIB_close.c b/src/pdclib/platform/example/functions/_PDCLIB/_PDCLIB_close.c new file mode 100644 index 0000000..113290a --- /dev/null +++ b/src/pdclib/platform/example/functions/_PDCLIB/_PDCLIB_close.c @@ -0,0 +1,36 @@ +/* _PDCLIB_close( _PDCLIB_fd_t ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +/* This is an example implementation of _PDCLIB_close() fit for use with POSIX + kernels. +*/ + +#include <stdio.h> + +#ifndef REGTEST + +#include "pdclib/_PDCLIB_glue.h" + +extern int close( int fd ); + +int _PDCLIB_close( int fd ) +{ + return close( fd ); +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + /* No testdriver; tested in driver for _PDCLIB_open(). */ + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/platform/example/functions/_PDCLIB/_PDCLIB_fillbuffer.c b/src/pdclib/platform/example/functions/_PDCLIB/_PDCLIB_fillbuffer.c new file mode 100644 index 0000000..012eed8 --- /dev/null +++ b/src/pdclib/platform/example/functions/_PDCLIB/_PDCLIB_fillbuffer.c @@ -0,0 +1,78 @@ +/* _PDCLIB_fillbuffer( struct _PDCLIB_file_t * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +/* This is an example implementation of _PDCLIB_fillbuffer() fit for + use with POSIX kernels. +*/ + +#include <stdio.h> + +#ifndef REGTEST + +#include "pdclib/_PDCLIB_glue.h" + +#include </usr/include/errno.h> + +typedef long ssize_t; +extern ssize_t read( int fd, void * buf, size_t count ); + +int _PDCLIB_fillbuffer( struct _PDCLIB_file_t * stream ) +{ + /* No need to handle buffers > INT_MAX, as PDCLib doesn't allow them */ + ssize_t rc = read( stream->handle, stream->buffer, stream->bufsize ); + if ( rc > 0 ) + { + /* Reading successful. */ + if ( ! ( stream->status & _PDCLIB_FBIN ) ) + { + /* TODO: Text stream conversion here */ + } + stream->pos.offset += rc; + stream->bufend = rc; + stream->bufidx = 0; + return 0; + } + if ( rc < 0 ) + { + /* Reading error */ + switch ( errno ) + { + /* See comments on implementation-defined errno values in + <_PDCLIB_config.h>. + */ + case EBADF: + case EFAULT: + case EINTR: + case EINVAL: + case EIO: + _PDCLIB_errno = _PDCLIB_ERROR; + break; + default: + /* This should be something like EUNKNOWN. */ + _PDCLIB_errno = _PDCLIB_ERROR; + break; + } + stream->status |= _PDCLIB_ERRORFLAG; + return EOF; + } + /* End-of-File */ + stream->status |= _PDCLIB_EOFFLAG; + return EOF; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + /* Testing covered by ftell.c */ + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/platform/example/functions/_PDCLIB/_PDCLIB_flushbuffer.c b/src/pdclib/platform/example/functions/_PDCLIB/_PDCLIB_flushbuffer.c new file mode 100644 index 0000000..ca6b998 --- /dev/null +++ b/src/pdclib/platform/example/functions/_PDCLIB/_PDCLIB_flushbuffer.c @@ -0,0 +1,110 @@ +/* _PDCLIB_flushbuffer( struct _PDCLIB_file_t * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +/* This is an example implementation of _PDCLIB_flushbuffer() fit for + use with POSIX kernels. +*/ + +#include <stdio.h> +#include <string.h> + +#ifndef REGTEST + +#include "pdclib/_PDCLIB_glue.h" + +#include </usr/include/errno.h> + +typedef long ssize_t; +extern ssize_t write( int fd, const void * buf, size_t count ); + +/* The number of attempts to complete an output buffer flushing before giving + * up. + * */ +#define _PDCLIB_IO_RETRIES 1 + +/* What the system should do after an I/O operation did not succeed, before */ +/* trying again. (Empty by default.) */ +#define _PDCLIB_IO_RETRY_OP( stream ) + +int _PDCLIB_flushbuffer( struct _PDCLIB_file_t * stream ) +{ + /* No need to handle buffers > INT_MAX, as PDCLib doesn't allow them */ + _PDCLIB_size_t written = 0; + int rc; + unsigned int retries; + if ( ! ( stream->status & _PDCLIB_FBIN ) ) + { + /* TODO: Text stream conversion here */ + } + /* Keep trying to write data until everything is written, an error + occurs, or the configured number of retries is exceeded. + */ + for ( retries = _PDCLIB_IO_RETRIES; retries > 0; --retries ) + { + rc = (int)write( stream->handle, stream->buffer + written, stream->bufidx - written ); + if ( rc < 0 ) + { + /* Write error */ + switch ( errno ) + { + /* See <_PDCLIB_config.h>. There should be differenciated errno + handling here, possibly even a 1:1 mapping; but that is up + to the individual platform. + */ + case EBADF: + case EFAULT: + case EFBIG: + case EINTR: + case EINVAL: + case EIO: + case ENOSPC: + case EPIPE: + _PDCLIB_errno = _PDCLIB_ERROR; + break; + default: + /* This should be something like EUNKNOWN. */ + _PDCLIB_errno = _PDCLIB_ERROR; + break; + } + stream->status |= _PDCLIB_ERRORFLAG; + /* Move unwritten remains to begin of buffer. */ + stream->bufidx -= written; + memmove( stream->buffer, stream->buffer + written, stream->bufidx ); + return EOF; + } + written += (_PDCLIB_size_t)rc; + stream->pos.offset += rc; + if ( written == stream->bufidx ) + { + /* Buffer written completely. */ + stream->bufidx = 0; + return 0; + } + } + /* Number of retries exceeded. You probably want a different errno value + here. + */ + _PDCLIB_errno = _PDCLIB_ERROR; + stream->status |= _PDCLIB_ERRORFLAG; + /* Move unwritten remains to begin of buffer. */ + stream->bufidx -= written; + memmove( stream->buffer, stream->buffer + written, stream->bufidx ); + return EOF; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + /* Testing covered by ftell.c */ + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/platform/example/functions/_PDCLIB/_PDCLIB_open.c b/src/pdclib/platform/example/functions/_PDCLIB/_PDCLIB_open.c new file mode 100644 index 0000000..e35d65d --- /dev/null +++ b/src/pdclib/platform/example/functions/_PDCLIB/_PDCLIB_open.c @@ -0,0 +1,167 @@ +/* _PDCLIB_open( const char * const, int ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +/* This is an example implementation of _PDCLIB_open() fit for use with POSIX + kernels. +*/ + +#include <stdio.h> + +#ifndef REGTEST + +#include "pdclib/_PDCLIB_glue.h" + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> + +#include "/usr/include/errno.h" + +int _PDCLIB_open( const char * const filename, unsigned int mode ) +{ + /* This is an example implementation of _PDCLIB_open() fit for use with + POSIX kernels. + */ + int osmode; + int rc; + switch ( mode & ( _PDCLIB_FREAD | _PDCLIB_FWRITE | _PDCLIB_FAPPEND | _PDCLIB_FRW ) ) + { + case _PDCLIB_FREAD: /* "r" */ + osmode = O_RDONLY; + break; + case _PDCLIB_FWRITE: /* "w" */ + osmode = O_WRONLY | O_CREAT | O_TRUNC; + break; + case _PDCLIB_FAPPEND: /* "a" */ + osmode = O_WRONLY | O_APPEND | O_CREAT; + break; + case _PDCLIB_FREAD | _PDCLIB_FRW: /* "r+" */ + osmode = O_RDWR; + break; + case _PDCLIB_FWRITE | _PDCLIB_FRW: /* "w+" */ + osmode = O_RDWR | O_CREAT | O_TRUNC; + break; + case _PDCLIB_FAPPEND | _PDCLIB_FRW: /* "a+" */ + osmode = O_RDWR | O_APPEND | O_CREAT; + break; + default: /* Invalid mode */ + return -1; + } + if ( osmode & O_CREAT ) + { + rc = open( filename, osmode, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH ); + } + else + { + rc = open( filename, osmode ); + } + if ( rc == -1 ) + { + switch ( errno ) + { + /* See the comments on implementation-defined errno values in + <_PDCLIB_config.h>. + */ + case EACCES: + case EFAULT: + case EINTR: + case EISDIR: + case ELOOP: + case EMFILE: + case ENAMETOOLONG: + case ENFILE: + case ENODEV: + case ENOENT: + case ENOMEM: + case ENOSPC: + case ENOTDIR: + case EOVERFLOW: + case EROFS: + case ETXTBSY: + _PDCLIB_errno = _PDCLIB_ERROR; + break; + default: + /* This should be something like EUNKNOWN. */ + _PDCLIB_errno = _PDCLIB_ERROR; + break; + } + } + return rc; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +#include <stdlib.h> +#include <string.h> + +int main( void ) +{ +#ifndef REGTEST + /* This testdriver assumes POSIX, i.e. _PDCLIB_fd_t being int and being + incremented by one on each successful open. + */ + int fh; + char buffer[ 10 ]; + remove( testfile ); + /* Trying to read non-existent file. */ + TESTCASE( _PDCLIB_open( testfile, _PDCLIB_FREAD ) == _PDCLIB_NOHANDLE ); + /* Writing to file, trying to read from it. */ + TESTCASE( ( fh = _PDCLIB_open( testfile, _PDCLIB_FWRITE ) ) != _PDCLIB_NOHANDLE ); + TESTCASE( write( fh, "test", 4 ) == 4 ); + TESTCASE( lseek( fh, 0, SEEK_SET ) == 0 ); + TESTCASE( read( fh, buffer, 4 ) == -1 ); + TESTCASE( _PDCLIB_close( fh ) == 0 ); + /* Reading from file, trying to write to it. */ + TESTCASE( ( fh = _PDCLIB_open( testfile, _PDCLIB_FREAD ) ) != _PDCLIB_NOHANDLE ); + TESTCASE( write( fh, "test", 4 ) == -1 ); + TESTCASE( _PDCLIB_close( fh ) == 0 ); + /* Appending to file, trying to read from it. */ + TESTCASE( ( fh = _PDCLIB_open( testfile, _PDCLIB_FAPPEND ) ) != _PDCLIB_NOHANDLE ); + TESTCASE( write( fh, "app", 3 ) == 3 ); + TESTCASE( lseek( fh, 0, SEEK_SET ) == 0 ); + TESTCASE( read( fh, buffer, 10 ) == -1 ); + TESTCASE( write( fh, "end", 3 ) == 3 ); + TESTCASE( _PDCLIB_close( fh ) == 0 ); + /* Reading and writing from file ("r+"). */ + TESTCASE( ( fh = _PDCLIB_open( testfile, _PDCLIB_FREAD | _PDCLIB_FRW ) ) != _PDCLIB_NOHANDLE ); + TESTCASE( read( fh, buffer, 10 ) == 10 ); + TESTCASE( memcmp( buffer, "testappend", 10 ) == 0 ); + TESTCASE( lseek( fh, 0, SEEK_SET ) == 0 ); + TESTCASE( write( fh, "wedo", 4 ) == 4 ); + TESTCASE( lseek( fh, 0, SEEK_SET ) == 0 ); + TESTCASE( read( fh, buffer, 10 ) == 10 ); + TESTCASE( memcmp( buffer, "wedoappend", 10 ) == 0 ); + TESTCASE( _PDCLIB_close( fh ) == 0 ); + /* Writing and reading from file ("w+"). */ + TESTCASE( ( fh = _PDCLIB_open( testfile, _PDCLIB_FWRITE | _PDCLIB_FRW ) ) != _PDCLIB_NOHANDLE ); + TESTCASE( write( fh, "test", 4 ) == 4 ); + TESTCASE( lseek( fh, 1, SEEK_SET ) == 1 ); + TESTCASE( read( fh, buffer, 2 ) == 2 ); + TESTCASE( memcmp( buffer, "es", 2 ) == 0 ); + TESTCASE( write( fh, "sie", 3 ) == 3 ); + TESTCASE( lseek( fh, 0, SEEK_SET ) == 0 ); + TESTCASE( read( fh, buffer, 6 ) == 6 ); + TESTCASE( memcmp( buffer, "tessie", 6 ) == 0 ); + TESTCASE( _PDCLIB_close( fh ) == 0 ); + /* Appending and reading from file ("a+"). */ + TESTCASE( ( fh = _PDCLIB_open( testfile, _PDCLIB_FAPPEND | _PDCLIB_FRW ) ) != _PDCLIB_NOHANDLE ); + TESTCASE( write( fh, "baby", 4 ) == 4 ); + TESTCASE( lseek( fh, 0, SEEK_SET ) == 0 ); + TESTCASE( read( fh, buffer, 10 ) == 10 ); + TESTCASE( memcmp( buffer, "tessiebaby", 10 ) == 0 ); + TESTCASE( _PDCLIB_close( fh ) == 0 ); + /* Cleaning up. */ + TESTCASE( remove( testfile ) == 0 ); +#endif + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/platform/example/functions/_PDCLIB/_PDCLIB_rename.c b/src/pdclib/platform/example/functions/_PDCLIB/_PDCLIB_rename.c new file mode 100644 index 0000000..8c23f79 --- /dev/null +++ b/src/pdclib/platform/example/functions/_PDCLIB/_PDCLIB_rename.c @@ -0,0 +1,144 @@ +/* _PDCLIB_rename( const char *, const char * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +/* This is an example implementation of _PDCLIB_rename() fit for use with + POSIX kernels. + */ + +#include <stdio.h> + +#ifndef REGTEST + +#include "pdclib/_PDCLIB_glue.h" + +#include </usr/include/errno.h> + +extern int unlink( const char * pathname ); +extern int link( const char * old, const char * new ); + +int _PDCLIB_rename( const char * old, const char * new ) +{ + /* Note that the behaviour if new file exists is implementation-defined. + There is nothing wrong with either overwriting it or failing the + operation, but you might want to document whichever you chose. + This example fails if new file exists. + */ + if ( link( old, new ) == 0 ) + { + if ( unlink( old ) == EOF ) + { + switch ( errno ) + { + /* See the comments on implementation-defined errno values in + <_PDCLIB_config.h>. + */ + case EACCES: + case EFAULT: + case EIO: + case EISDIR: + case ELOOP: + case ENAMETOOLONG: + case ENOENT: + case ENOMEM: + case ENOTDIR: + case EPERM: + case EROFS: + _PDCLIB_errno = _PDCLIB_ERROR; + break; + default: + /* This should be something like EUNKNOWN. */ + _PDCLIB_errno = _PDCLIB_ERROR; + break; + } + return -1; + } + else + { + return 0; + } + } + else + { + switch ( errno ) + { + /* See the comments on implementation-defined errno values in + <_PDCLIB_config.h>. + */ + case EACCES: + case EEXIST: + case EFAULT: + case EIO: + case ELOOP: + case EMLINK: + case ENAMETOOLONG: + case ENOENT: + case ENOMEM: + case ENOSPC: + case ENOTDIR: + case EPERM: + case EROFS: + case EXDEV: + _PDCLIB_errno = _PDCLIB_ERROR; + break; + default: + /* This should be something like EUNKNOWN. */ + _PDCLIB_errno = _PDCLIB_ERROR; + break; + } + return EOF; + } +} + +#endif + +#ifdef TEST +#include "_PDCLIB_test.h" + +#include <stdlib.h> + +int main( void ) +{ +#ifndef REGTEST + FILE * file; + remove( testfile1 ); + remove( testfile2 ); + /* check that neither file exists */ + TESTCASE( fopen( testfile1, "r" ) == NULL ); + TESTCASE( fopen( testfile2, "r" ) == NULL ); + /* rename file 1 to file 2 - expected to fail */ + TESTCASE( _PDCLIB_rename( testfile1, testfile2 ) == -1 ); + /* create file 1 */ + TESTCASE( ( file = fopen( testfile1, "w" ) ) != NULL ); + TESTCASE( fputc( 'x', file ) == 'x' ); + TESTCASE( fclose( file ) == 0 ); + /* check that file 1 exists */ + TESTCASE( ( file = fopen( testfile1, "r" ) ) != NULL ); + TESTCASE( fclose( file ) == 0 ); + /* rename file 1 to file 2 */ + TESTCASE( _PDCLIB_rename( testfile1, testfile2 ) == 0 ); + /* check that file 2 exists, file 1 does not */ + TESTCASE( fopen( testfile1, "r" ) == NULL ); + TESTCASE( ( file = fopen( testfile2, "r" ) ) != NULL ); + TESTCASE( fclose( file ) == 0 ); + /* create another file 1 */ + TESTCASE( ( file = fopen( testfile1, "w" ) ) != NULL ); + TESTCASE( fputc( 'x', file ) == 'x' ); + TESTCASE( fclose( file ) == 0 ); + /* check that file 1 exists */ + TESTCASE( ( file = fopen( testfile1, "r" ) ) != NULL ); + TESTCASE( fclose( file ) == 0 ); + /* rename file 1 to file 2 - expected to fail, see comment in + _PDCLIB_rename() itself. + */ + TESTCASE( _PDCLIB_rename( testfile1, testfile2 ) == -1 ); + /* remove both files */ + remove( testfile1 ); + remove( testfile2 ); +#endif + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/platform/example/functions/_PDCLIB/_PDCLIB_seek.c b/src/pdclib/platform/example/functions/_PDCLIB/_PDCLIB_seek.c new file mode 100644 index 0000000..4d09460 --- /dev/null +++ b/src/pdclib/platform/example/functions/_PDCLIB/_PDCLIB_seek.c @@ -0,0 +1,82 @@ +/* int64_t _PDCLIB_seek( FILE *, int64_t, int ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +/* This is an example implementation of _PDCLIB_seek() fit for use with POSIX + kernels. + */ + +#include <stdio.h> + +#ifndef REGTEST + +#include "pdclib/_PDCLIB_glue.h" + +#include "/usr/include/errno.h" + +extern _PDCLIB_int64_t lseek64( int fd, _PDCLIB_int64_t offset, int whence ); +extern long lseek( int fd, long offset, int whence ); + +_PDCLIB_int64_t _PDCLIB_seek( struct _PDCLIB_file_t * stream, _PDCLIB_int64_t offset, int whence ) +{ + _PDCLIB_int64_t rc; + switch ( whence ) + { + case SEEK_SET: + case SEEK_CUR: + case SEEK_END: + /* EMPTY - OK */ + break; + default: + /* See comments on implementation-defined errno values in + <_PDCLIB_config.h>. + */ + _PDCLIB_errno = _PDCLIB_ERROR; + return EOF; + break; + } +#ifdef __CYGWIN__ + rc = lseek( stream->handle, offset, whence ); +#else + rc = lseek64( stream->handle, offset, whence ); +#endif + if ( rc != EOF ) + { + stream->ungetidx = 0; + stream->bufidx = 0; + stream->bufend = 0; + stream->pos.offset = rc; + return rc; + } + switch ( errno ) + { + case EBADF: + case EFAULT: + /* See comments on implementation-defined errno values in + <_PDCLIB_config.h>. + */ + _PDCLIB_errno = _PDCLIB_ERROR; + break; + default: + /* This should be something like EUNKNOWN. */ + _PDCLIB_errno = _PDCLIB_ERROR; + break; + } + return EOF; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + /* Testing covered by ftell.c */ + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/platform/example/functions/_PDCLIB/_PDCLIB_stdinit.c b/src/pdclib/platform/example/functions/_PDCLIB/_PDCLIB_stdinit.c new file mode 100644 index 0000000..52b0651 --- /dev/null +++ b/src/pdclib/platform/example/functions/_PDCLIB/_PDCLIB_stdinit.c @@ -0,0 +1,430 @@ +/* _PDCLIB_stdinit + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +/* This is an example initialization of stdin, stdout and stderr to the integer + file descriptors 0, 1, and 2, respectively. This applies for a great variety + of operating systems, including POSIX compliant ones. +*/ + +#include <stdio.h> +#include <locale.h> +#include <limits.h> + +#ifndef REGTEST + +/* In a POSIX system, stdin / stdout / stderr are equivalent to the (int) file + descriptors 0, 1, and 2 respectively. +*/ +/* TODO: This is proof-of-concept, requires finetuning. */ +static char _PDCLIB_sin_buffer[BUFSIZ]; +static char _PDCLIB_sout_buffer[BUFSIZ]; +static char _PDCLIB_serr_buffer[BUFSIZ]; + +static unsigned char _PDCLIB_sin_ungetbuf[_PDCLIB_UNGETCBUFSIZE]; +static unsigned char _PDCLIB_sout_ungetbuf[_PDCLIB_UNGETCBUFSIZE]; +static unsigned char _PDCLIB_serr_ungetbuf[_PDCLIB_UNGETCBUFSIZE]; + +static struct _PDCLIB_file_t _PDCLIB_serr = { 2, _PDCLIB_serr_buffer, BUFSIZ, 0, 0, { 0, 0 }, 0, _PDCLIB_serr_ungetbuf, _IONBF | _PDCLIB_FWRITE | _PDCLIB_STATIC, NULL, NULL }; +static struct _PDCLIB_file_t _PDCLIB_sout = { 1, _PDCLIB_sout_buffer, BUFSIZ, 0, 0, { 0, 0 }, 0, _PDCLIB_sout_ungetbuf, _IOLBF | _PDCLIB_FWRITE | _PDCLIB_STATIC, NULL, &_PDCLIB_serr }; +static struct _PDCLIB_file_t _PDCLIB_sin = { 0, _PDCLIB_sin_buffer, BUFSIZ, 0, 0, { 0, 0 }, 0, _PDCLIB_sin_ungetbuf, _IOLBF | _PDCLIB_FREAD | _PDCLIB_STATIC, NULL, &_PDCLIB_sout }; + +struct _PDCLIB_file_t * stdin = &_PDCLIB_sin; +struct _PDCLIB_file_t * stdout = &_PDCLIB_sout; +struct _PDCLIB_file_t * stderr = &_PDCLIB_serr; + +/* FIXME: This approach is a possible attack vector. */ +struct _PDCLIB_file_t * _PDCLIB_filelist = &_PDCLIB_sin; + +/* "C" locale - defaulting to ASCII-7. + 1 kByte (+ 4 byte) of <ctype.h> data. + Each line: flags, lowercase, uppercase, collation. +*/ +static struct _PDCLIB_lc_ctype_entry_t _ctype_entries[ _PDCLIB_CHARSET_SIZE + 1 ] = { + { /* EOF */ 0, 0, 0 }, + { /* NUL */ _PDCLIB_CTYPE_CNTRL, 0x00, 0x00 }, + { /* SOH */ _PDCLIB_CTYPE_CNTRL, 0x01, 0x01 }, + { /* STX */ _PDCLIB_CTYPE_CNTRL, 0x02, 0x02 }, + { /* ETX */ _PDCLIB_CTYPE_CNTRL, 0x03, 0x03 }, + { /* EOT */ _PDCLIB_CTYPE_CNTRL, 0x04, 0x04 }, + { /* ENQ */ _PDCLIB_CTYPE_CNTRL, 0x05, 0x05 }, + { /* ACK */ _PDCLIB_CTYPE_CNTRL, 0x06, 0x06 }, + { /* BEL */ _PDCLIB_CTYPE_CNTRL, 0x07, 0x07 }, + { /* BS */ _PDCLIB_CTYPE_CNTRL, 0x08, 0x08 }, + { /* HT */ _PDCLIB_CTYPE_CNTRL | _PDCLIB_CTYPE_BLANK | _PDCLIB_CTYPE_SPACE, 0x09, 0x09 }, + { /* LF */ _PDCLIB_CTYPE_CNTRL | _PDCLIB_CTYPE_SPACE, 0x0A, 0x0A }, + { /* VT */ _PDCLIB_CTYPE_CNTRL | _PDCLIB_CTYPE_SPACE, 0x0B, 0x0B }, + { /* FF */ _PDCLIB_CTYPE_CNTRL | _PDCLIB_CTYPE_SPACE, 0x0C, 0x0C }, + { /* CR */ _PDCLIB_CTYPE_CNTRL | _PDCLIB_CTYPE_SPACE, 0x0D, 0x0D }, + { /* SO */ _PDCLIB_CTYPE_CNTRL, 0x0E, 0x0E }, + { /* SI */ _PDCLIB_CTYPE_CNTRL, 0x0F, 0x0F }, + { /* DLE */ _PDCLIB_CTYPE_CNTRL, 0x10, 0x10 }, + { /* DC1 */ _PDCLIB_CTYPE_CNTRL, 0x11, 0x11 }, + { /* DC2 */ _PDCLIB_CTYPE_CNTRL, 0x12, 0x12 }, + { /* DC3 */ _PDCLIB_CTYPE_CNTRL, 0x13, 0x13 }, + { /* DC4 */ _PDCLIB_CTYPE_CNTRL, 0x14, 0x14 }, + { /* NAK */ _PDCLIB_CTYPE_CNTRL, 0x15, 0x15 }, + { /* SYN */ _PDCLIB_CTYPE_CNTRL, 0x16, 0x16 }, + { /* ETB */ _PDCLIB_CTYPE_CNTRL, 0x17, 0x17 }, + { /* CAN */ _PDCLIB_CTYPE_CNTRL, 0x18, 0x18 }, + { /* EM */ _PDCLIB_CTYPE_CNTRL, 0x19, 0x19 }, + { /* SUB */ _PDCLIB_CTYPE_CNTRL, 0x1A, 0x1A }, + { /* ESC */ _PDCLIB_CTYPE_CNTRL, 0x1B, 0x1B }, + { /* FS */ _PDCLIB_CTYPE_CNTRL, 0x1C, 0x1C }, + { /* GS */ _PDCLIB_CTYPE_CNTRL, 0x1D, 0x1D }, + { /* RS */ _PDCLIB_CTYPE_CNTRL, 0x1E, 0x1E }, + { /* US */ _PDCLIB_CTYPE_CNTRL, 0x1F, 0x1F }, + { /* SP */ _PDCLIB_CTYPE_BLANK | _PDCLIB_CTYPE_SPACE, 0x20, 0x20 }, + { /* '!' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x21, 0x21 }, + { /* '"' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x22, 0x22 }, + { /* '#' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x23, 0x23 }, + { /* '$' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x24, 0x24 }, + { /* '%' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x25, 0x25 }, + { /* '&' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x26, 0x26 }, + { /* ''' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x27, 0x27 }, + { /* '(' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x28, 0x28 }, + { /* ')' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x29, 0x29 }, + { /* '*' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x2A, 0x2A }, + { /* '+' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x2B, 0x2B }, + { /* ',' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x2C, 0x2C }, + { /* '-' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x2D, 0x2D }, + { /* '.' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x2E, 0x2E }, + { /* '/' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x2F, 0x2F }, + { /* '0' */ _PDCLIB_CTYPE_GRAPH, 0x30, 0x30 }, + { /* '1' */ _PDCLIB_CTYPE_GRAPH, 0x31, 0x31 }, + { /* '2' */ _PDCLIB_CTYPE_GRAPH, 0x32, 0x32 }, + { /* '3' */ _PDCLIB_CTYPE_GRAPH, 0x33, 0x33 }, + { /* '4' */ _PDCLIB_CTYPE_GRAPH, 0x34, 0x34 }, + { /* '5' */ _PDCLIB_CTYPE_GRAPH, 0x35, 0x35 }, + { /* '6' */ _PDCLIB_CTYPE_GRAPH, 0x36, 0x36 }, + { /* '7' */ _PDCLIB_CTYPE_GRAPH, 0x37, 0x37 }, + { /* '8' */ _PDCLIB_CTYPE_GRAPH, 0x38, 0x38 }, + { /* '9' */ _PDCLIB_CTYPE_GRAPH, 0x39, 0x39 }, + { /* ':' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x3A, 0x3A }, + { /* ';' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x3B, 0x3B }, + { /* '<' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x3C, 0x3C }, + { /* '=' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x3D, 0x3D }, + { /* '>' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x3E, 0x3E }, + { /* '?' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x3F, 0x3F }, + { /* '@' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x40, 0x40 }, + { /* 'A' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x41, 0x61 }, + { /* 'B' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x42, 0x62 }, + { /* 'C' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x43, 0x63 }, + { /* 'D' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x44, 0x64 }, + { /* 'E' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x45, 0x65 }, + { /* 'F' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x46, 0x66 }, + { /* 'G' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x47, 0x67 }, + { /* 'H' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x48, 0x68 }, + { /* 'I' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x49, 0x69 }, + { /* 'J' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x4A, 0x6A }, + { /* 'K' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x4B, 0x6B }, + { /* 'L' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x4C, 0x6C }, + { /* 'M' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x4D, 0x6D }, + { /* 'N' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x4E, 0x6E }, + { /* 'O' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x4F, 0x6F }, + { /* 'P' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x50, 0x70 }, + { /* 'Q' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x51, 0x71 }, + { /* 'R' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x52, 0x72 }, + { /* 'S' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x53, 0x73 }, + { /* 'T' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x54, 0x74 }, + { /* 'U' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x55, 0x75 }, + { /* 'V' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x56, 0x76 }, + { /* 'W' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x57, 0x77 }, + { /* 'X' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x58, 0x78 }, + { /* 'Y' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x59, 0x79 }, + { /* 'Z' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x5A, 0x7A }, + { /* '[' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x5B, 0x5B }, + { /* '\' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x5C, 0x5C }, + { /* ']' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x5D, 0x5D }, + { /* '^' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x5E, 0x5E }, + { /* '_' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x5F, 0x5F }, + { /* '`' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x60, 0x60 }, + { /* 'a' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x41, 0x61 }, + { /* 'b' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x42, 0x62 }, + { /* 'c' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x43, 0x63 }, + { /* 'd' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x44, 0x64 }, + { /* 'e' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x45, 0x65 }, + { /* 'f' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x46, 0x66 }, + { /* 'g' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x47, 0x67 }, + { /* 'h' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x48, 0x68 }, + { /* 'i' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x49, 0x69 }, + { /* 'j' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x4A, 0x6A }, + { /* 'k' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x4B, 0x6B }, + { /* 'l' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x4C, 0x6C }, + { /* 'm' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x4D, 0x6D }, + { /* 'n' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x4E, 0x6E }, + { /* 'o' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x4F, 0x6F }, + { /* 'p' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x50, 0x70 }, + { /* 'q' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x51, 0x71 }, + { /* 'r' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x52, 0x72 }, + { /* 's' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x53, 0x73 }, + { /* 't' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x54, 0x74 }, + { /* 'u' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x55, 0x75 }, + { /* 'v' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x56, 0x76 }, + { /* 'w' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x57, 0x77 }, + { /* 'x' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x58, 0x78 }, + { /* 'y' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x59, 0x79 }, + { /* 'z' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x5A, 0x7A }, + { /* '{' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x7B, 0x7B }, + { /* '|' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x7C, 0x7C }, + { /* '}' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x7D, 0x7D }, + { /* '~' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x7E, 0x7E }, + { /* DEL */ _PDCLIB_CTYPE_CNTRL, 0x7F, 0x7F }, + { 0x00, 0x80, 0x80 }, + { 0x00, 0x81, 0x81 }, + { 0x00, 0x82, 0x82 }, + { 0x00, 0x83, 0x83 }, + { 0x00, 0x84, 0x84 }, + { 0x00, 0x85, 0x85 }, + { 0x00, 0x86, 0x86 }, + { 0x00, 0x87, 0x87 }, + { 0x00, 0x88, 0x88 }, + { 0x00, 0x89, 0x89 }, + { 0x00, 0x8A, 0x8A }, + { 0x00, 0x8B, 0x8B }, + { 0x00, 0x8C, 0x8C }, + { 0x00, 0x8D, 0x8D }, + { 0x00, 0x8E, 0x8E }, + { 0x00, 0x8F, 0x8F }, + { 0x00, 0x90, 0x90 }, + { 0x00, 0x91, 0x91 }, + { 0x00, 0x92, 0x92 }, + { 0x00, 0x93, 0x93 }, + { 0x00, 0x94, 0x94 }, + { 0x00, 0x95, 0x95 }, + { 0x00, 0x96, 0x96 }, + { 0x00, 0x97, 0x97 }, + { 0x00, 0x98, 0x98 }, + { 0x00, 0x99, 0x99 }, + { 0x00, 0x9A, 0x9A }, + { 0x00, 0x9B, 0x9B }, + { 0x00, 0x9C, 0x9C }, + { 0x00, 0x9D, 0x9D }, + { 0x00, 0x9E, 0x9E }, + { 0x00, 0x9F, 0x9F }, + { 0x00, 0xA0, 0xA0 }, + { 0x00, 0xA1, 0xA1 }, + { 0x00, 0xA2, 0xA2 }, + { 0x00, 0xA3, 0xA3 }, + { 0x00, 0xA4, 0xA4 }, + { 0x00, 0xA5, 0xA5 }, + { 0x00, 0xA6, 0xA6 }, + { 0x00, 0xA7, 0xA7 }, + { 0x00, 0xA8, 0xA8 }, + { 0x00, 0xA9, 0xA9 }, + { 0x00, 0xAA, 0xAA }, + { 0x00, 0xAB, 0xAB }, + { 0x00, 0xAC, 0xAC }, + { 0x00, 0xAD, 0xAD }, + { 0x00, 0xAE, 0xAE }, + { 0x00, 0xAF, 0xAF }, + { 0x00, 0xB0, 0xB0 }, + { 0x00, 0xB1, 0xB1 }, + { 0x00, 0xB2, 0xB2 }, + { 0x00, 0xB3, 0xB3 }, + { 0x00, 0xB4, 0xB4 }, + { 0x00, 0xB5, 0xB5 }, + { 0x00, 0xB6, 0xB6 }, + { 0x00, 0xB7, 0xB7 }, + { 0x00, 0xB8, 0xB8 }, + { 0x00, 0xB9, 0xB9 }, + { 0x00, 0xBA, 0xBA }, + { 0x00, 0xBB, 0xBB }, + { 0x00, 0xBC, 0xBC }, + { 0x00, 0xBD, 0xBD }, + { 0x00, 0xBE, 0xBE }, + { 0x00, 0xBF, 0xBF }, + { 0x00, 0xC0, 0xC0 }, + { 0x00, 0xC1, 0xC1 }, + { 0x00, 0xC2, 0xC2 }, + { 0x00, 0xC3, 0xC3 }, + { 0x00, 0xC4, 0xC4 }, + { 0x00, 0xC5, 0xC5 }, + { 0x00, 0xC6, 0xC6 }, + { 0x00, 0xC7, 0xC7 }, + { 0x00, 0xC8, 0xC8 }, + { 0x00, 0xC9, 0xC9 }, + { 0x00, 0xCA, 0xCA }, + { 0x00, 0xCB, 0xCB }, + { 0x00, 0xCC, 0xCC }, + { 0x00, 0xCD, 0xCD }, + { 0x00, 0xCE, 0xCE }, + { 0x00, 0xCF, 0xCF }, + { 0x00, 0xD0, 0xD0 }, + { 0x00, 0xD1, 0xD1 }, + { 0x00, 0xD2, 0xD2 }, + { 0x00, 0xD3, 0xD3 }, + { 0x00, 0xD4, 0xD4 }, + { 0x00, 0xD5, 0xD5 }, + { 0x00, 0xD6, 0xD6 }, + { 0x00, 0xD7, 0xD7 }, + { 0x00, 0xD8, 0xD8 }, + { 0x00, 0xD9, 0xD9 }, + { 0x00, 0xDA, 0xDA }, + { 0x00, 0xDB, 0xDB }, + { 0x00, 0xDC, 0xDC }, + { 0x00, 0xDD, 0xDD }, + { 0x00, 0xDE, 0xDE }, + { 0x00, 0xDF, 0xDF }, + { 0x00, 0xE0, 0xE0 }, + { 0x00, 0xE1, 0xE1 }, + { 0x00, 0xE2, 0xE2 }, + { 0x00, 0xE3, 0xE3 }, + { 0x00, 0xE4, 0xE4 }, + { 0x00, 0xE5, 0xE5 }, + { 0x00, 0xE6, 0xE6 }, + { 0x00, 0xE7, 0xE7 }, + { 0x00, 0xE8, 0xE8 }, + { 0x00, 0xE9, 0xE9 }, + { 0x00, 0xEA, 0xEA }, + { 0x00, 0xEB, 0xEB }, + { 0x00, 0xEC, 0xEC }, + { 0x00, 0xED, 0xED }, + { 0x00, 0xEE, 0xEE }, + { 0x00, 0xEF, 0xEF }, + { 0x00, 0xF0, 0xF0 }, + { 0x00, 0xF1, 0xF1 }, + { 0x00, 0xF2, 0xF2 }, + { 0x00, 0xF3, 0xF3 }, + { 0x00, 0xF4, 0xF4 }, + { 0x00, 0xF5, 0xF5 }, + { 0x00, 0xF6, 0xF6 }, + { 0x00, 0xF7, 0xF7 }, + { 0x00, 0xF8, 0xF8 }, + { 0x00, 0xF9, 0xF9 }, + { 0x00, 0xFA, 0xFA }, + { 0x00, 0xFB, 0xFB }, + { 0x00, 0xFC, 0xFC }, + { 0x00, 0xFD, 0xFD }, + { 0x00, 0xFE, 0xFE }, + { 0x00, 0xFF, 0xFF } +}; + +struct _PDCLIB_lc_ctype_t _PDCLIB_lc_ctype = { 0, 0x30, 0x39, 0x41, 0x46, 0x61, 0x66, &_ctype_entries[1] }; + +struct _PDCLIB_lc_collate_t _PDCLIB_lc_collate = { 0 }; + +struct lconv _PDCLIB_lconv = { + /* decimal_point */ (char *)".", + /* thousands_sep */ (char *)"", + /* grouping */ (char *)"", + /* mon_decimal_point */ (char *)"", + /* mon_thousands_sep */ (char *)"", + /* mon_grouping */ (char *)"", + /* positive_sign */ (char *)"", + /* negative_sign */ (char *)"", + /* currency_symbol */ (char *)"", + /* int_curr_symbol */ (char *)"", + /* frac_digits */ CHAR_MAX, + /* p_cs_precedes */ CHAR_MAX, + /* n_cs_precedes */ CHAR_MAX, + /* p_sep_by_space */ CHAR_MAX, + /* n_sep_by_space */ CHAR_MAX, + /* p_sign_posn */ CHAR_MAX, + /* n_sign_posn */ CHAR_MAX, + /* int_frac_digits */ CHAR_MAX, + /* int_p_cs_precedes */ CHAR_MAX, + /* int_n_cs_precedes */ CHAR_MAX, + /* int_p_sep_by_space */ CHAR_MAX, + /* int_n_sep_by_space */ CHAR_MAX, + /* int_p_sign_posn */ CHAR_MAX, + /* int_n_sign_posn */ CHAR_MAX +}; + +struct _PDCLIB_lc_numeric_monetary_t _PDCLIB_lc_numeric_monetary = { + &_PDCLIB_lconv, + 0, /* numeric_allocated */ + 0 /* monetary_allocated */ +}; + +struct _PDCLIB_lc_messages_t _PDCLIB_lc_messages = { + 0, + /* _PDCLIB_errno_texts */ + { + /* no error */ (char *)"", + /* ERANGE */ (char *)"ERANGE (Range error)", + /* EDOM */ (char *)"EDOM (Domain error)", + /* EILSEQ */ (char *)"EILSEQ (Illegal sequence)" + } +}; + +struct _PDCLIB_lc_time_t _PDCLIB_lc_time = { + 0, + /* _PDCLIB_month_name_abbr */ + { + (char *)"Jan", + (char *)"Feb", + (char *)"Mar", + (char *)"Apr", + (char *)"May", + (char *)"Jun", + (char *)"Jul", + (char *)"Aug", + (char *)"Sep", + (char *)"Oct", + (char *)"Now", + (char *)"Dec" + }, + /* _PDCLIB_month_name_full */ + { + (char *)"January", + (char *)"February", + (char *)"March", + (char *)"April", + (char *)"May", + (char *)"June", + (char *)"July", + (char *)"August", + (char *)"September", + (char *)"October", + (char *)"November", + (char *)"December" + }, + /* _PDCLIB_day_name_abbr */ + { + (char *)"Sun", + (char *)"Mon", + (char *)"Tue", + (char *)"Wed", + (char *)"Thu", + (char *)"Fri", + (char *)"Sat" + }, + /* _PDCLIB_day_name_full */ + { + (char *)"Sunday", + (char *)"Monday", + (char *)"Tuesday", + (char *)"Wednesday", + (char *)"Thursday", + (char *)"Friday", + (char *)"Saturday" + }, + /* date / time format */ (char *)"%a %b %e %T %Y", + /* 12h time format */ (char *)"%I:%M:%S %p", + /* date format */ (char *)"%m/%d/%y", + /* time format */ (char *)"%T", + /* AM / PM designation */ + { + (char *)"AM", + (char *)"PM" + } +}; + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + /* Testing covered by several other testdrivers using stdin / stdout / + stderr. + */ + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/platform/example/functions/signal/raise.c b/src/pdclib/platform/example/functions/signal/raise.c new file mode 100644 index 0000000..59ccc9f --- /dev/null +++ b/src/pdclib/platform/example/functions/signal/raise.c @@ -0,0 +1,114 @@ +/* raise( int ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <signal.h> + +#ifndef REGTEST + +#include <stdio.h> +#include <stdlib.h> + +extern void (*_PDCLIB_sigabrt)( int ); +extern void (*_PDCLIB_sigfpe)( int ); +extern void (*_PDCLIB_sigill)( int ); +extern void (*_PDCLIB_sigint)( int ); +extern void (*_PDCLIB_sigsegv)( int ); +extern void (*_PDCLIB_sigterm)( int ); + +int raise( int sig ) +{ + void (*sighandler)( int ); + const char * message; + switch ( sig ) + { + case SIGABRT: + sighandler = _PDCLIB_sigabrt; + message = "Abnormal termination (SIGABRT)"; + break; + case SIGFPE: + sighandler = _PDCLIB_sigfpe; + message = "Arithmetic exception (SIGFPE)"; + break; + case SIGILL: + sighandler = _PDCLIB_sigill; + message = "Illegal instruction (SIGILL)"; + break; + case SIGINT: + sighandler = _PDCLIB_sigint; + message = "Interactive attention signal (SIGINT)"; + break; + case SIGSEGV: + sighandler = _PDCLIB_sigsegv; + message = "Invalid memory access (SIGSEGV)"; + break; + case SIGTERM: + sighandler = _PDCLIB_sigterm; + message = "Termination request (SIGTERM)"; + break; + default: + fprintf( stderr, "Unknown signal #%d\n", sig ); + _Exit( EXIT_FAILURE ); + } + if ( sighandler == SIG_DFL ) + { + fputs( message, stderr ); + _Exit( EXIT_FAILURE ); + } + else if ( sighandler != SIG_IGN ) + { + sighandler = signal( sig, SIG_DFL ); + sighandler( sig ); + } + return 0; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +#include <stdlib.h> + +static volatile sig_atomic_t flag = 0; + +static int expected_signal = 0; + +static void test_handler( int sig ) +{ + TESTCASE( sig == expected_signal ); + flag = 1; +} + +int main( void ) +{ + /* Could be other than SIG_DFL if you changed the implementation. */ + TESTCASE( signal( SIGABRT, SIG_IGN ) == SIG_DFL ); + /* Should be ignored. */ + TESTCASE( raise( SIGABRT ) == 0 ); + /* Installing test handler, old handler should be returned */ + TESTCASE( signal( SIGABRT, test_handler ) == SIG_IGN ); + /* Raising and checking SIGABRT */ + expected_signal = SIGABRT; + TESTCASE( raise( SIGABRT ) == 0 ); + TESTCASE( flag == 1 ); + /* Re-installing test handler, should have been reset to default */ + /* Could be other than SIG_DFL if you changed the implementation. */ + TESTCASE( signal( SIGABRT, test_handler ) == SIG_DFL ); + /* Raising and checking SIGABRT */ + flag = 0; + TESTCASE( raise( SIGABRT ) == 0 ); + TESTCASE( flag == 1 ); + /* Installing test handler for different signal... */ + TESTCASE( signal( SIGTERM, test_handler ) == SIG_DFL ); + /* Raising and checking SIGTERM */ + expected_signal = SIGTERM; + TESTCASE( raise( SIGTERM ) == 0 ); + TESTCASE( flag == 1 ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/platform/example/functions/signal/signal.c b/src/pdclib/platform/example/functions/signal/signal.c new file mode 100644 index 0000000..e6775e7 --- /dev/null +++ b/src/pdclib/platform/example/functions/signal/signal.c @@ -0,0 +1,75 @@ +/* signal( int, void (*)( int ) ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <signal.h> + +#ifndef REGTEST + +#include <stdlib.h> + +void (*_PDCLIB_sigabrt)( int ) = SIG_DFL; +void (*_PDCLIB_sigfpe)( int ) = SIG_DFL; +void (*_PDCLIB_sigill)( int ) = SIG_DFL; +void (*_PDCLIB_sigint)( int ) = SIG_DFL; +void (*_PDCLIB_sigsegv)( int ) = SIG_DFL; +void (*_PDCLIB_sigterm)( int ) = SIG_DFL; + +void (*signal( int sig, void (*func)( int ) ) )( int ) +{ + void (*oldhandler)( int ); + if ( sig <= 0 || func == SIG_ERR ) + { + return SIG_ERR; + } + switch ( sig ) + { + case SIGABRT: + oldhandler = _PDCLIB_sigabrt; + _PDCLIB_sigabrt = func; + break; + case SIGFPE: + oldhandler = _PDCLIB_sigfpe; + _PDCLIB_sigfpe = func; + break; + case SIGILL: + oldhandler = _PDCLIB_sigill; + _PDCLIB_sigill = func; + break; + case SIGINT: + oldhandler = _PDCLIB_sigint; + _PDCLIB_sigint = func; + break; + case SIGSEGV: + oldhandler = _PDCLIB_sigsegv; + _PDCLIB_sigsegv = func; + break; + case SIGTERM: + oldhandler = _PDCLIB_sigterm; + _PDCLIB_sigterm = func; + break; + default: + /* The standard calls for an unspecified "positive value". You + will probably want to define a specific value for this. + */ + _PDCLIB_errno = 1; + return SIG_ERR; + } + return oldhandler; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + /* Testing covered by raise.c */ + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/platform/example/functions/stdio/remove.c b/src/pdclib/platform/example/functions/stdio/remove.c new file mode 100644 index 0000000..aca3eaf --- /dev/null +++ b/src/pdclib/platform/example/functions/stdio/remove.c @@ -0,0 +1,75 @@ +/* remove( const char * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +/* This is an example implementation of remove() fit for use with POSIX kernels. +*/ + +#include <stdio.h> + +#ifndef REGTEST + +#include <string.h> + +#include "/usr/include/errno.h" + +extern struct _PDCLIB_file_t * _PDCLIB_filelist; + +extern int unlink( const char * pathname ); + +int remove( const char * pathname ) +{ + int rc; + struct _PDCLIB_file_t * current = _PDCLIB_filelist; + while ( current != NULL ) + { + if ( ( current->filename != NULL ) && ( strcmp( current->filename, pathname ) == 0 ) ) + { + return EOF; + } + current = current->next; + } + if ( ( rc = unlink( pathname ) ) == -1 ) + { + switch ( errno ) + { + /* See the comments on implementation-defined errno values in + <_PDCLIB_config.h>. + */ + case EACCES: + case EFAULT: + case EIO: + case EISDIR: + case ELOOP: + case ENAMETOOLONG: + case ENOENT: + case ENOMEM: + case ENOTDIR: + case EPERM: + case EROFS: + _PDCLIB_errno = _PDCLIB_ERROR; + break; + default: + /* This should be something like EUNKNOWN. */ + _PDCLIB_errno = _PDCLIB_ERROR; + break; + } + } + return rc; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + /* Testing covered by ftell.c (and several others) */ + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/platform/example/functions/stdio/tmpfile.c b/src/pdclib/platform/example/functions/stdio/tmpfile.c new file mode 100644 index 0000000..585a61d --- /dev/null +++ b/src/pdclib/platform/example/functions/stdio/tmpfile.c @@ -0,0 +1,114 @@ +/* tmpfile( void ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdio.h> + +#ifndef REGTEST + +#include "pdclib/_PDCLIB_glue.h" + +#include <inttypes.h> +#include <stdlib.h> +#include <string.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> + +extern struct _PDCLIB_file_t * _PDCLIB_filelist; + +/* This is an example implementation of tmpfile() fit for use with POSIX + kernels. +*/ +struct _PDCLIB_file_t * tmpfile( void ) +{ + FILE * rc; + /* This is the chosen way to get high-quality randomness. Replace as + appropriate. + */ + FILE * randomsource = fopen( "/proc/sys/kernel/random/uuid", "rb" ); + char filename[ L_tmpnam ]; + _PDCLIB_fd_t fd; + if ( randomsource == NULL ) + { + return NULL; + } + for ( ;; ) + { + /* Get a filename candidate. What constitutes a valid filename and + where temporary files are usually located is platform-dependent, + which is one reason why this function is located in the platform + overlay. The other reason is that a *good* implementation should + use high-quality randomness instead of a pseudo-random sequence to + generate the filename candidate, which is *also* platform-dependent. + */ + unsigned int random; + fscanf( randomsource, "%u", &random ); + sprintf( filename, "/tmp/%u.tmp", random ); + /* Check if file of this name exists. Note that fopen() is a very weak + check, which does not take e.g. access permissions into account + (file might exist but not readable). Replace with something more + appropriate. + */ + fd = open( filename, O_CREAT | O_EXCL | O_RDWR, S_IRUSR | S_IWUSR ); + if ( fd != -1 ) + { + break; + } + close( fd ); + } + fclose( randomsource ); + /* See fopen(). */ + if ( ( rc = calloc( 1, sizeof( struct _PDCLIB_file_t ) + _PDCLIB_UNGETCBUFSIZE + L_tmpnam + BUFSIZ ) ) == NULL ) + { + /* No memory to set up FILE structure */ + close( fd ); + return NULL; + } + rc->status = _PDCLIB_filemode( "wb+" ) | _IOLBF | _PDCLIB_DELONCLOSE; + rc->handle = fd; + rc->ungetbuf = (unsigned char *)rc + sizeof( struct _PDCLIB_file_t ); + rc->filename = (char *)rc->ungetbuf + _PDCLIB_UNGETCBUFSIZE; + rc->buffer = rc->filename + L_tmpnam; + strcpy( rc->filename, filename ); + rc->bufsize = BUFSIZ; + rc->bufidx = 0; + rc->ungetidx = 0; + rc->next = _PDCLIB_filelist; + _PDCLIB_filelist = rc; + return rc; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +#include <string.h> + +int main( void ) +{ + FILE * fh; +#ifndef REGTEST + char filename[ L_tmpnam ]; + FILE * fhtest; +#endif + TESTCASE( ( fh = tmpfile() ) != NULL ); + TESTCASE( fputc( 'x', fh ) == 'x' ); + /* Checking that file is actually there */ + TESTCASE_NOREG( strcpy( filename, fh->filename ) == filename ); + TESTCASE_NOREG( ( fhtest = fopen( filename, "r" ) ) != NULL ); + TESTCASE_NOREG( fclose( fhtest ) == 0 ); + /* Closing tmpfile */ + TESTCASE( fclose( fh ) == 0 ); + /* Checking that file was deleted */ + TESTCASE_NOREG( fopen( filename, "r" ) == NULL ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/platform/example/functions/stdlib/getenv.c b/src/pdclib/platform/example/functions/stdlib/getenv.c new file mode 100644 index 0000000..72bbcd2 --- /dev/null +++ b/src/pdclib/platform/example/functions/stdlib/getenv.c @@ -0,0 +1,45 @@ +/* getenv( const char * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +/* This is an example implementation of getenv() fit for use with POSIX kernels. +*/ + +#include <string.h> +#include <stdlib.h> + +#ifndef REGTEST + +extern char * * environ; + +char * getenv( const char * name ) +{ + size_t len = strlen( name ); + size_t index = 0; + while ( environ[ index ] != NULL ) + { + if ( strncmp( environ[ index ], name, len ) == 0 ) + { + return environ[ index ] + len + 1; + } + index++; + } + return NULL; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + TESTCASE( strcmp( getenv( "SHELL" ), "/bin/bash" ) == 0 ); + /* TESTCASE( strcmp( getenv( "SHELL" ), "/bin/sh" ) == 0 ); */ + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/platform/example/functions/stdlib/system.c b/src/pdclib/platform/example/functions/stdlib/system.c new file mode 100644 index 0000000..15603c3 --- /dev/null +++ b/src/pdclib/platform/example/functions/stdlib/system.c @@ -0,0 +1,57 @@ +/* system( const char * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdlib.h> + +/* This is an example implementation of system() fit for use with POSIX kernels. +*/ + +extern int fork( void ); +extern int execve( const char * filename, char * const argv[], char * const envp[] ); +extern int wait( int * status ); + +int system( const char * string ) +{ + const char * argv[] = { "sh", "-c", NULL, NULL }; + argv[2] = string; + if ( string != NULL ) + { + int pid = fork(); + if ( pid == 0 ) + { + execve( "/bin/sh", (char * * const)argv, NULL ); + } + else if ( pid > 0 ) + { + while( wait( NULL ) != pid ); + } + } + return -1; +} + +#ifdef TEST + +#include "_PDCLIB_test.h" + +#define SHELLCOMMAND "echo 'SUCCESS testing system()'" + +int main( void ) +{ + FILE * fh; + char buffer[25]; + buffer[24] = 'x'; + TESTCASE( ( fh = freopen( testfile, "wb+", stdout ) ) != NULL ); + TESTCASE( system( SHELLCOMMAND ) ); + rewind( fh ); + TESTCASE( fread( buffer, 1, 24, fh ) == 24 ); + TESTCASE( memcmp( buffer, "SUCCESS testing system()", 24 ) == 0 ); + TESTCASE( buffer[24] == 'x' ); + TESTCASE( fclose( fh ) == 0 ); + TESTCASE( remove( testfile ) == 0 ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/platform/example/functions/time/clock.c b/src/pdclib/platform/example/functions/time/clock.c new file mode 100644 index 0000000..825e040 --- /dev/null +++ b/src/pdclib/platform/example/functions/time/clock.c @@ -0,0 +1,35 @@ +/* clock( void ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <time.h> + +#ifndef REGTEST + +#include <sys/times.h> + +clock_t clock( void ) +{ + struct tms buf; + if ( times( &buf ) != (clock_t)-1 ) + { + return buf.tms_utime + buf.tms_stime; + } + return -1; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + TESTCASE( NO_TESTDRIVER ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/platform/example/functions/time/time.c b/src/pdclib/platform/example/functions/time/time.c new file mode 100644 index 0000000..cbb29e1 --- /dev/null +++ b/src/pdclib/platform/example/functions/time/time.c @@ -0,0 +1,41 @@ +/* time( time_t * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <time.h> + +#ifndef REGTEST + +#include <sys/time.h> + +/* See comments in time.h on the semantics of time_t. */ + +time_t time( time_t * timer ) +{ + struct timeval tv; + if ( gettimeofday( &tv, NULL ) == 0 ) + { + if ( timer != NULL ) + { + *timer = tv.tv_sec; + } + return tv.tv_sec; + } + return -1; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + TESTCASE( NO_TESTDRIVER ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/platform/example/functions/time/timespec_get.c b/src/pdclib/platform/example/functions/time/timespec_get.c new file mode 100644 index 0000000..d8cbab7 --- /dev/null +++ b/src/pdclib/platform/example/functions/time/timespec_get.c @@ -0,0 +1,42 @@ +/* timespec_get( struct timespec *, int ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <time.h> + +#ifndef REGTEST + +#include <sys/time.h> + +int timespec_get( struct timespec * ts, int base ) +{ + if ( base == TIME_UTC ) + { + /* We can make do with a really thin wrapper here. */ + struct timeval tv; + if ( gettimeofday( &tv, NULL ) == 0 ) + { + ts->tv_sec = tv.tv_sec; + ts->tv_nsec = tv.tv_usec * 1000; + return base; + } + } + /* Not supporting any other time base than TIME_UTC for now. */ + return 0; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + TESTCASE( NO_TESTDRIVER ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/platform/example/include/float.h b/src/pdclib/platform/example/include/float.h new file mode 100644 index 0000000..538d69e --- /dev/null +++ b/src/pdclib/platform/example/include/float.h @@ -0,0 +1,75 @@ +/* Characteristics of floating types <float.h> + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#ifndef _PDCLIB_FLOAT_H +#define _PDCLIB_FLOAT_H _PDCLIB_FLOAT_H + +#include "pdclib/_PDCLIB_config.h" + +#define FLT_ROUNDS _PDCLIB_FLT_ROUNDS +#define FLT_EVAL_METHOD _PDCLIB_FLT_EVAL_METHOD +#define DECIMAL_DIG _PDCLIB_DECIMAL_DIG + + /* Radix of exponent representation */ +#define FLT_RADIX __FLT_RADIX__ + /* Number of base-FLT_RADIX digits in the significand of a float */ +#define FLT_MANT_DIG __FLT_MANT_DIG__ + /* Number of decimal digits of precision in a float */ +#define FLT_DIG __FLT_DIG__ + /* Difference between 1.0 and the minimum float greater than 1.0 */ +#define FLT_EPSILON __FLT_EPSILON__ + /* Minimum int x such that FLT_RADIX**(x-1) is a normalised float */ +#define FLT_MIN_EXP __FLT_MIN_EXP__ + /* Minimum normalised float */ +#define FLT_MIN __FLT_MIN__ + /* Minimum int x such that 10**x is a normalised float */ +#define FLT_MIN_10_EXP __FLT_MIN_10_EXP__ + /* Maximum int x such that FLT_RADIX**(x-1) is a representable float */ +#define FLT_MAX_EXP __FLT_MAX_EXP__ + /* Maximum float */ +#define FLT_MAX __FLT_MAX__ + /* Maximum int x such that 10**x is a representable float */ +#define FLT_MAX_10_EXP __FLT_MAX_10_EXP__ + + /* Number of base-FLT_RADIX digits in the significand of a double */ +#define DBL_MANT_DIG __DBL_MANT_DIG__ + /* Number of decimal digits of precision in a double */ +#define DBL_DIG __DBL_DIG__ + /* Difference between 1.0 and the minimum double greater than 1.0 */ +#define DBL_EPSILON __DBL_EPSILON__ + /* Minimum int x such that FLT_RADIX**(x-1) is a normalised double */ +#define DBL_MIN_EXP __DBL_MIN_EXP__ + /* Minimum normalised double */ +#define DBL_MIN __DBL_MIN__ + /* Minimum int x such that 10**x is a normalised double */ +#define DBL_MIN_10_EXP __DBL_MIN_10_EXP__ + /* Maximum int x such that FLT_RADIX**(x-1) is a representable double */ +#define DBL_MAX_EXP __DBL_MAX_EXP__ + /* Maximum double */ +#define DBL_MAX __DBL_MAX__ + /* Maximum int x such that 10**x is a representable double */ +#define DBL_MAX_10_EXP __DBL_MAX_10_EXP__ + + /* Number of base-FLT_RADIX digits in the significand of a long double */ +#define LDBL_MANT_DIG __LDBL_MANT_DIG__ + /* Number of decimal digits of precision in a long double */ +#define LDBL_DIG __LDBL_DIG__ + /* Difference between 1.0 and the minimum long double greater than 1.0 */ +#define LDBL_EPSILON __LDBL_EPSILON__ + /* Minimum int x such that FLT_RADIX**(x-1) is a normalised long double */ +#define LDBL_MIN_EXP __LDBL_MIN_EXP__ + /* Minimum normalised long double */ +#define LDBL_MIN __LDBL_MIN__ + /* Minimum int x such that 10**x is a normalised long double */ +#define LDBL_MIN_10_EXP __LDBL_MIN_10_EXP__ + /* Maximum int x such that FLT_RADIX**(x-1) is a representable long double */ +#define LDBL_MAX_EXP __LDBL_MAX_EXP__ + /* Maximum long double */ +#define LDBL_MAX __LDBL_MAX__ + /* Maximum int x such that 10**x is a representable long double */ +#define LDBL_MAX_10_EXP __LDBL_MAX_10_EXP__ + +#endif diff --git a/src/pdclib/platform/example/include/pdclib/_PDCLIB_config.h b/src/pdclib/platform/example/include/pdclib/_PDCLIB_config.h new file mode 100644 index 0000000..9731f86 --- /dev/null +++ b/src/pdclib/platform/example/include/pdclib/_PDCLIB_config.h @@ -0,0 +1,426 @@ +/* Internal PDCLib configuration <_PDCLIB_config.h> + (Generic Template) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#ifndef _PDCLIB_CONFIG_H +#define _PDCLIB_CONFIG_H _PDCLIB_CONFIG_H + +/* -------------------------------------------------------------------------- */ +/* Misc */ +/* -------------------------------------------------------------------------- */ + +/* The character (sequence) your platform uses as newline. */ +#define _PDCLIB_endl "\n" + +/* exit() can signal success to the host environment by the value of zero or */ +/* the constant EXIT_SUCCESS. Failure is signaled by EXIT_FAILURE. Note that */ +/* any other return value is "implementation-defined", i.e. your environment */ +/* is not required to handle it gracefully. Set your definitions here. */ +#define _PDCLIB_SUCCESS 0 +#define _PDCLIB_FAILURE -1 + +/* qsort() in <stdlib.h> requires a function that swaps two memory areas. */ +/* Below is a naive implementation that can be improved significantly for */ +/* specific platforms, e.g. by swapping int instead of char. */ +#define _PDCLIB_memswp( i, j, size ) char tmp; do { tmp = *i; *i++ = *j; *j++ = tmp; } while ( --size ); + +/* Define this to some compiler directive that can be written after the */ +/* parameter list of a function declaration to indicate the function does */ +/* never return. If your compiler does not support such a directive, define */ +/* to nothing. (This is to avoid warnings with the exit functions under GCC.) */ +#define _PDCLIB_NORETURN __attribute__(( noreturn )) + +/* -------------------------------------------------------------------------- */ +/* Integers */ +/* -------------------------------------------------------------------------- */ +/* Assuming 8-bit char, two's-complement architecture here. 'short' being */ +/* 16 bit, 'int' being either 16, 32 or 64 bit, 'long' being either 32 or 64 */ +/* bit (but 64 bit only if 'int' is 32 bit), and 'long long' being 64 bit if */ +/* 'long' is not, 64 or 128 bit otherwise. */ +/* Author is quite willing to support other systems but would like to hear of */ +/* interest in such support and details on the to-be-supported architecture */ +/* first, before going to lengths about it. */ +/* -------------------------------------------------------------------------- */ + +/* Set to 0 if your 'char' type is unsigned. */ +#ifdef __CHAR_UNSIGNED__ +#define _PDCLIB_CHAR_SIGNED 0 +#else +#define _PDCLIB_CHAR_SIGNED 1 +#endif + +/* Width of the integer types short, int, long, and long long, in bytes. */ +/* SHRT == 2, INT >= SHRT, LONG >= INT >= 4, LLONG >= LONG - check your */ +/* compiler manuals. */ +#define _PDCLIB_SHRT_BYTES 2 +#define _PDCLIB_INT_BYTES 4 +#ifdef __LP64__ +#define _PDCLIB_LONG_BYTES 8 +#else +#define _PDCLIB_LONG_BYTES 4 +#endif +#define _PDCLIB_LLONG_BYTES 8 + +/* <stdlib.h> defines the div() function family that allows taking quotient */ +/* and remainder of an integer division in one operation. Many platforms */ +/* support this in hardware / opcode, and the standard permits ordering of */ +/* the return structure in any way to fit the hardware. That is why those */ +/* structs can be configured here. */ + +struct _PDCLIB_div_t +{ + int quot; + int rem; +}; + +struct _PDCLIB_ldiv_t +{ + long int quot; + long int rem; +}; + +struct _PDCLIB_lldiv_t +{ + long long int quot; + long long int rem; +}; + +/* -------------------------------------------------------------------------- */ +/* <stdint.h> defines a set of integer types that are of a minimum width, and */ +/* "usually fastest" on the system. (If, for example, accessing a single char */ +/* requires the CPU to access a complete int and then mask out the char, the */ +/* "usually fastest" type of at least 8 bits would be int, not char.) */ +/* If you do not have information on the relative performance of the types, */ +/* the standard allows you to define any type that meets minimum width and */ +/* signedness requirements. */ +/* The defines below are just configuration for the real typedefs and limit */ +/* definitions done in <_PDCLIB_int.h>. The uppercase define shall be either */ +/* SHRT, INT, LONG, or LLONG (telling which values to use for the *_MIN and */ +/* *_MAX limits); the lowercase define either short, int, long, or long long */ +/* (telling the actual type to use). */ +/* The third define is the length modifier used for the type in printf() and */ +/* scanf() functions (used in <inttypes.h>). */ +/* If you require a non-standard datatype to define the "usually fastest" */ +/* types, PDCLib as-is doesn't support that. Please contact the author with */ +/* details on your platform in that case, so support can be added. */ +/* -------------------------------------------------------------------------- */ + +#define _PDCLIB_FAST8 INT +#define _PDCLIB_fast8 int +#define _PDCLIB_FAST8_CONV + +#define _PDCLIB_FAST16 INT +#define _PDCLIB_fast16 int +#define _PDCLIB_FAST16_CONV + +#define _PDCLIB_FAST32 INT +#define _PDCLIB_fast32 int +#define _PDCLIB_FAST32_CONV + +#define _PDCLIB_FAST64 LONG +#define _PDCLIB_fast64 long +#define _PDCLIB_FAST64_CONV l + +/* -------------------------------------------------------------------------- */ +/* What follows are a couple of "special" typedefs and their limits. Again, */ +/* the actual definition of the limits is done in <_PDCLIB_int.h>, and the */ +/* defines here are merely "configuration". See above for details. */ +/* -------------------------------------------------------------------------- */ + +/* The result type of substracting two pointers */ +#define _PDCLIB_ptrdiff long +#define _PDCLIB_PTRDIFF LONG +#define _PDCLIB_PTR_CONV l + +/* An integer type that can be accessed as atomic entity (think asynchronous + interrupts). The type itself is not defined in a freestanding environment, + but its limits are. (Don't ask.) +*/ +#define _PDCLIB_sig_atomic int +#define _PDCLIB_SIG_ATOMIC INT + +/* Result type of the 'sizeof' operator (must be unsigned) */ +#define _PDCLIB_size unsigned long +#define _PDCLIB_SIZE ULONG + +/* Large enough an integer to hold all character codes of the largest supported + locale. +*/ +#define _PDCLIB_wchar unsigned int +#define _PDCLIB_WCHAR UINT + +/* Large enough an integer to hold all character codes of the largest supported + locale plus WEOF (which needs not to be equal to EOF, nor needs to be of + negative value). +*/ +#define _PDCLIB_wint unsigned int +#define _PDCLIB_WINT UINT + +/* (Signed) integer type capable of taking the (cast) value of a void *, and + having the value cast back to void *, comparing equal to the original. +*/ +#define _PDCLIB_intptr long +#define _PDCLIB_INTPTR LONG + +/* Largest supported integer type. Implementation note: see _PDCLIB_atomax(). */ +#define _PDCLIB_intmax long long int +#define _PDCLIB_INTMAX LLONG +#define _PDCLIB_MAX_CONV ll +/* You are also required to state the literal suffix for the intmax type */ +#define _PDCLIB_INTMAX_LITERAL ll + +/* <inttypes.h> defines imaxdiv(), which is equivalent to the div() function */ +/* family (see further above) with intmax_t as basis. */ + +struct _PDCLIB_imaxdiv_t +{ + _PDCLIB_intmax quot; + _PDCLIB_intmax rem; +}; + +/* -------------------------------------------------------------------------- */ +/* Time types */ +/* -------------------------------------------------------------------------- */ + +/* See <time.h> for a couple of comments on these types and their semantics. */ + +#define _PDCLIB_time long + +#define _PDCLIB_clock long +#define _PDCLIB_CLOCKS_PER_SEC 1000000 + +#define _PDCLIB_TIME_UTC 1 + +/* -------------------------------------------------------------------------- */ +/* Floating Point */ +/* -------------------------------------------------------------------------- */ + +/* Whether the implementation rounds toward zero (0), to nearest (1), toward + positive infinity (2), or toward negative infinity (3). (-1) signifies + indeterminable rounding, any other value implementation-specific rounding. +*/ +#define _PDCLIB_FLT_ROUNDS -1 + +/* Whether the implementation uses exact-width precision (0), promotes float + to double (1), or promotes float and double to long double (2). (-1) + signifies indeterminable behaviour, any other value implementation-specific + behaviour. +*/ +#define _PDCLIB_FLT_EVAL_METHOD -1 + +/* "Number of the decimal digits (n), such that any floating-point number in the + widest supported floating type with p(max) radix (b) digits can be rounded to + a floating-point number with (n) decimal digits and back again without change + to the value p(max) log(10)b if (b) is a power of 10, [1 + p(max) log(10)b] + otherwise." + 64bit IEC 60559 double format (53bit mantissa) is DECIMAL_DIG 17. + 80bit IEC 60559 double-extended format (64bit mantissa) is DECIMAL_DIG 21. +*/ +#define _PDCLIB_DECIMAL_DIG 17 + +/* -------------------------------------------------------------------------- */ +/* Platform-dependent macros defined by the standard headers. */ +/* -------------------------------------------------------------------------- */ + +/* The offsetof macro + Contract: Expand to an integer constant expression of type size_t, which + represents the offset in bytes to the structure member from the beginning + of the structure. If the specified member is a bitfield, behaviour is + undefined. + There is no standard-compliant way to do this. + This implementation casts an integer zero to 'pointer to type', and then + takes the address of member. This is undefined behaviour but should work on + most compilers. +*/ +#define _PDCLIB_offsetof( type, member ) ( (size_t) &( ( (type *) 0 )->member ) ) + +/* Variable Length Parameter List Handling (<stdarg.h>) + The macros defined by <stdarg.h> are highly dependent on the calling + conventions used, and you probably have to replace them with builtins of + your compiler. +*/ + +#if defined( __i386 ) + +/* The following generic implementation works only for pure + stack-based architectures, and only if arguments are aligned to pointer + type. Credits to Michael Moody, who contributed this to the Public Domain. +*/ + +/* Internal helper macro. va_round is not part of <stdarg.h>. */ +#define _PDCLIB_va_round( type ) ( (sizeof(type) + sizeof(void *) - 1) & ~(sizeof(void *) - 1) ) + +typedef char * _PDCLIB_va_list; +#define _PDCLIB_va_arg( ap, type ) ( (ap) += (_PDCLIB_va_round(type)), ( *(type*) ( (ap) - (_PDCLIB_va_round(type)) ) ) ) +#define _PDCLIB_va_copy( dest, src ) ( (dest) = (src), (void)0 ) +#define _PDCLIB_va_end( ap ) ( (ap) = (void *)0, (void)0 ) +#define _PDCLIB_va_start( ap, parmN ) ( (ap) = (char *) &parmN + ( _PDCLIB_va_round(parmN) ), (void)0 ) + +#elif defined( __x86_64 ) || defined( __arm__ ) + +/* No way to cover x86_64 or arm with a generic implementation, as it uses + register-based parameter passing. Using compiler builtins here. +*/ +typedef __builtin_va_list _PDCLIB_va_list; +#define _PDCLIB_va_arg( ap, type ) ( __builtin_va_arg( ap, type ) ) +#define _PDCLIB_va_copy( dest, src ) ( __builtin_va_copy( dest, src ) ) +#define _PDCLIB_va_end( ap ) ( __builtin_va_end( ap ) ) +#define _PDCLIB_va_start( ap, parmN ) ( __builtin_va_start( ap, parmN ) ) + +#else + +#error Please create your own _PDCLIB_config.h. Using the existing one as-is will not work. + +#endif + +/* -------------------------------------------------------------------------- */ +/* OS "glue", part 1 */ +/* These are values and data type definitions that you would have to adapt to */ +/* the capabilities and requirements of your OS. */ +/* The actual *functions* of the OS interface are declared in _PDCLIB_glue.h. */ +/* -------------------------------------------------------------------------- */ + +/* Memory management -------------------------------------------------------- */ + +/* Set this to the page size of your OS. If your OS does not support paging, set + to an appropriate value. (Too small, and malloc() will call the kernel too + often. Too large, and you will waste memory.) +*/ +#define _PDCLIB_PAGESIZE 4096 + +/* Set this to the minimum memory node size. Any malloc() for a smaller size + will be satisfied by a malloc() of this size instead (to avoid excessive + fragmentation). +*/ +#define _PDCLIB_MINALLOC 8 + +/* I/O ---------------------------------------------------------------------- */ + +/* The type of the file descriptor returned by _PDCLIB_open(). */ +typedef int _PDCLIB_fd_t; + +/* The value (of type _PDCLIB_fd_t) returned by _PDCLIB_open() if the operation + failed. +*/ +#define _PDCLIB_NOHANDLE ( (_PDCLIB_fd_t) -1 ) + +/* The default size for file buffers. Must be at least 256. */ +#define _PDCLIB_BUFSIZ 1024 + +/* The minimum number of files the implementation can open simultaneously. Must + be at least 8. Depends largely on how the bookkeeping is done by fopen() / + freopen() / fclose(). The example implementation limits the number of open + files only by available memory. +*/ +#define _PDCLIB_FOPEN_MAX 8 + +/* Length of the longest filename the implementation guarantees to support. */ +#define _PDCLIB_FILENAME_MAX 128 + +/* Maximum length of filenames generated by tmpnam(). (See tmpfile.c.) */ +#define _PDCLIB_L_tmpnam 46 + +/* Number of distinct file names that can be generated by tmpnam(). */ +#define _PDCLIB_TMP_MAX 50 + +/* The values of SEEK_SET, SEEK_CUR and SEEK_END, used by fseek(). + Since at least one platform (POSIX) uses the same symbols for its own "seek" + function, we use whatever the host defines (if it does define them). +*/ +#define _PDCLIB_SEEK_SET 0 +#define _PDCLIB_SEEK_CUR 1 +#define _PDCLIB_SEEK_END 2 + +/* The number of characters that can be buffered with ungetc(). The standard + guarantees only one (1); anything larger would make applications relying on + this capability dependent on implementation-defined behaviour (not good). +*/ +#define _PDCLIB_UNGETCBUFSIZE 1 + +/* errno -------------------------------------------------------------------- */ + +/* These are the values that _PDCLIB_errno can be set to by the library. + + By keeping PDCLib's errno in the _PDCLIB_* namespace, the library is capable + to "translate" between errno values used by the hosting operating system and + those used and passed out by the library. + + Example: In the example platform, the remove() function uses the unlink() + system call as backend. Linux sets its errno to EISDIR if you try to unlink() + a directory, but POSIX demands EPERM. Within the remove() function, you can + catch the 'errno == EISDIR', and set '_PDCLIB_errno = _PDCLIB_EPERM'. Anyone + using PDCLib's <errno.h> will "see" EPERM instead of EISDIR (the _PDCLIB_* + prefix removed by <errno.h> mechanics). + + If you do not want that kind of translation, you might want to "match" the + values used by PDCLib with those used by the host OS, as to avoid confusion. + + The standard only defines three distinct errno values: ERANGE, EDOM, and + EILSEQ. The standard leaves it up to "the implementation" whether there are + any more beyond those three. There is some controversy as to whether errno is + such a good idea at all, so you might want to come up with a different error + reporting facility for your platform. Since errno values beyond the three + defined by the standard are not portable anyway (unless you look at POSIX), + having your own error reporting facility would not hurt anybody either. +*/ +#define _PDCLIB_ERANGE 1 +#define _PDCLIB_EDOM 2 +#define _PDCLIB_EILSEQ 3 + +/* The following is not strictly "configuration", but there is no better place + to explain it than here. + + PDCLib strives to be as generic as possible, so by default it does NOT define + any values beyond the three standard ones above, even where it would have + been prudent and convenient to do so. Any errno "caught" from the host OS, + and some internal error conditions as well, are all lumped together into the + value of '_PDCLIB_ERROR'. + + '_PDCLIB_ERROR' is STRICLY meant as a PLACEHOLDER only. + + You should NEVER ship an adaption of PDCLib still using that particular + value. You should NEVER write code that *tests* for that value. Indeed it is + not even conforming, since errno values should be defined as beginning with + an uppercase 'E', and there is no mechanics in <errno.h> to unmask that + particular value (for exactly that reason). + + There also is no error message available for this value through either the + strerror() or perror() functions. It is being reported as "unknown" error. + + The idea is that you scan the source of PDCLib for occurrences of this macro + and replace _PDCLIB_ERROR with whatever additional errno value you came up + with for your platform. + + If you cannot find it within you to do that, tell your clients to check for + an errno value larger than zero. That, at least, would be standard compliant + (and fully portable). +*/ +#define _PDCLIB_ERROR 4 + +/* The maximum value that errno can be set to. This is used to set the size */ +/* of the array in struct _PDCLIB_lc_text_t holding error messages for the */ +/* strerror() and perror() functions. (If you change this value because you */ +/* are using additional errno values, you *HAVE* to provide appropriate error */ +/* messages for *ALL* locales.) */ +/* Default is 4 (0, ERANGE, EDOM, EILSEQ). */ +#define _PDCLIB_ERRNO_MAX 4 + +/* locale data -------------------------------------------------------------- */ + +/* The default path where PDCLib should look for its locale data. */ +/* Must end with the appropriate separator character. */ +#define _PDCLIB_LOCALE_PATH "/usr/share/pdclib/i18n" + +/* The name of the environment variable that can be used to override that */ +/* path setting. */ +#define _PDCLIB_LOCALE_PATH_ENV PDCLIB_I18N + +#ifdef __CYGWIN__ +typedef unsigned int wint_t; +#endif + + +#endif diff --git a/src/pdclib/platform/example/include/signal.h b/src/pdclib/platform/example/include/signal.h new file mode 100644 index 0000000..c5f6f28 --- /dev/null +++ b/src/pdclib/platform/example/include/signal.h @@ -0,0 +1,84 @@ +/* Signal handling <string.h> + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#ifndef _PDCLIB_SIGNAL_H +#define _PDCLIB_SIGNAL_H _PDCLIB_SIGNAL_H + +#include "pdclib/_PDCLIB_config.h" + +/* Signals ------------------------------------------------------------------ */ + +/* A word on signals, to the people using PDCLib in their OS projects. + + The definitions of the C standard leave about everything that *could* be + useful to be "implementation defined". Without additional, non-standard + arrangements, it is not possible to turn them into a useful tool. + + This example implementation chose to "not generate any of these signals, + except as a result of explicit calls to the raise function", which is + allowed by the standard but of course does nothing for the usefulness of + <signal.h>. + + A useful signal handling would: + 1) make signal() a system call that registers the signal handler with the OS + 2) make raise() a system call triggering an OS signal to the running process + 3) make provisions that further signals of the same type are blocked until + the signal handler returns (optional for SIGILL) +*/ + +/* These are the values used by Linux. */ + +/* Abnormal termination / abort() */ +#define SIGABRT 6 +/* Arithmetic exception / division by zero / overflow */ +#define SIGFPE 8 +/* Illegal instruction */ +#define SIGILL 4 +/* Interactive attention signal */ +#define SIGINT 2 +/* Invalid memory access */ +#define SIGSEGV 11 +/* Termination request */ +#define SIGTERM 15 + +/* The following should be defined to pointer values that could NEVER point to + a valid signal handler function. (They are used as special arguments to + signal().) Again, these are the values used by Linux. +*/ +#define SIG_DFL (void (*)( int ))0 +#define SIG_ERR (void (*)( int ))-1 +#define SIG_IGN (void (*)( int ))1 + +typedef _PDCLIB_sig_atomic sig_atomic_t; + +/* Installs a signal handler "func" for the given signal. + A signal handler is a function that takes an integer as argument (the signal + number) and returns void. + + Note that a signal handler can do very little else than: + 1) assign a value to a static object of type "volatile sig_atomic_t", + 2) call signal() with the value of sig equal to the signal received, + 3) call _Exit(), + 4) call abort(). + Virtually everything else is undefind. + + The signal() function returns the previous installed signal handler, which + at program start may be SIG_DFL or SIG_ILL. (This implementation uses + SIG_DFL for all handlers.) If the request cannot be honored, SIG_ERR is + returned and errno is set to an unspecified positive value. +*/ +void (*signal( int sig, void (*func)( int ) ) )( int ); + +/* Raises the given signal (executing the registered signal handler with the + given signal number as parameter). + This implementation does not prevent further signals of the same time from + occuring, but executes signal( sig, SIG_DFL ) before entering the signal + handler (i.e., a second signal before the signal handler re-registers itself + or SIG_IGN will end the program). + Returns zero if successful, nonzero otherwise. */ +int raise( int sig ); + +#endif diff --git a/src/pdclib/platform/stmos/Readme.txt b/src/pdclib/platform/stmos/Readme.txt new file mode 100644 index 0000000..07dc20e --- /dev/null +++ b/src/pdclib/platform/stmos/Readme.txt @@ -0,0 +1,21 @@ +"Example" Platform Overlay +========================== + +This is an example platform overlay, as described in the main Readme.txt of +this archive. For ease of development, it applies (and tests) correctly on the +machine of the author; no other guarantees can be given. +It should give you a good idea of what is REQUIRED to make a copy of PDCLib +work. There is a lot more you could do, and even some things you SHOULD do, in +order to experience anything but abysmal performance: + +- Read / write operations on binary streams, and even on text streams for + machines that do not do any text conversion, can be made much more efficient + by using some sort of page buffer instead of the linear buffer implemented + here. It requires some special and platform-dependent manipulations, though, + which is why it is not done by default. + +- Anything relating to floating point logic is written in generic C. While + this is (hopefully) highly portable and should get you started on your + platform of choice, it is also highly inefficient and should be replaced by + inline assembly. Just make sure that your assembly keeps all the promises + the C library makes. diff --git a/src/pdclib/platform/stmos/functions/_PDCLIB/_PDCLIB_Exit.c b/src/pdclib/platform/stmos/functions/_PDCLIB/_PDCLIB_Exit.c new file mode 100644 index 0000000..12b5c7f --- /dev/null +++ b/src/pdclib/platform/stmos/functions/_PDCLIB/_PDCLIB_Exit.c @@ -0,0 +1,40 @@ +/* _PDCLIB_exit( int ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +/* This is an example implementation of _PDCLIB_exit() fit for use with POSIX + kernels. +*/ + +#include <syscalls.h> + +#ifndef REGTEST + +#include "pdclib/_PDCLIB_glue.h" + +//extern void _exit( int status ) _PDCLIB_NORETURN; + +void _PDCLIB_Exit( int status ) +{ + _exit( status ); +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ +#ifndef REGTEST + int UNEXPECTED_RETURN = 0; + _PDCLIB_Exit( 0 ); + TESTCASE( UNEXPECTED_RETURN ); +#endif + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/platform/stmos/functions/_PDCLIB/_PDCLIB__Exit.c b/src/pdclib/platform/stmos/functions/_PDCLIB/_PDCLIB__Exit.c new file mode 100644 index 0000000..12b5c7f --- /dev/null +++ b/src/pdclib/platform/stmos/functions/_PDCLIB/_PDCLIB__Exit.c @@ -0,0 +1,40 @@ +/* _PDCLIB_exit( int ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +/* This is an example implementation of _PDCLIB_exit() fit for use with POSIX + kernels. +*/ + +#include <syscalls.h> + +#ifndef REGTEST + +#include "pdclib/_PDCLIB_glue.h" + +//extern void _exit( int status ) _PDCLIB_NORETURN; + +void _PDCLIB_Exit( int status ) +{ + _exit( status ); +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ +#ifndef REGTEST + int UNEXPECTED_RETURN = 0; + _PDCLIB_Exit( 0 ); + TESTCASE( UNEXPECTED_RETURN ); +#endif + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/platform/stmos/functions/_PDCLIB/_PDCLIB_allocpages.c b/src/pdclib/platform/stmos/functions/_PDCLIB/_PDCLIB_allocpages.c new file mode 100644 index 0000000..085857f --- /dev/null +++ b/src/pdclib/platform/stmos/functions/_PDCLIB/_PDCLIB_allocpages.c @@ -0,0 +1,82 @@ +/* _PDCLIB_allocpages( int const ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +/* This is an example implementation of _PDCLIB_allocpages() fit for use with + POSIX kernels. +*/ + +#include <syscalls.h> + +#include <stdint.h> +#include <stddef.h> + +#ifndef REGTEST + +#include "pdclib/_PDCLIB_glue.h" + +static void * membreak = NULL; + +void * _PDCLIB_allocpages( int const n ) +{ + void * oldbreak; + if ( membreak == NULL ) + { + /* first call, make sure end-of-heap is page-aligned */ + intptr_t unaligned = 0; + membreak = sbrk( 0 ); + unaligned = _PDCLIB_PAGESIZE - (intptr_t)membreak % _PDCLIB_PAGESIZE; + if ( unaligned < _PDCLIB_PAGESIZE ) + { + /* end-of-heap not page-aligned - adjust */ + if ( sbrk( unaligned ) != membreak ) + { + /* error */ + return NULL; + } + membreak = (char *)membreak + unaligned; + } + } + /* increasing or decreasing heap - standard operation */ + oldbreak = membreak; + membreak = (void *)( (char *)membreak + ( n * _PDCLIB_PAGESIZE ) ); + + if ( sbrk( (char*)membreak - (char*)oldbreak ) == membreak ) + { + /* successful */ + return oldbreak; + } + else + { + /* out of memory */ + membreak = oldbreak; + return NULL; + } +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ +#ifndef REGTEST + char * startbreak = sbrk( 0 ); + TESTCASE( _PDCLIB_allocpages( 0 ) ); + TESTCASE( ( (char *)sbrk( 0 ) - startbreak ) <= _PDCLIB_PAGESIZE ); + startbreak = sbrk( 0 ); + TESTCASE( _PDCLIB_allocpages( 1 ) ); + TESTCASE( sbrk( 0 ) == startbreak + ( 1 * _PDCLIB_PAGESIZE ) ); + TESTCASE( _PDCLIB_allocpages( 5 ) ); + TESTCASE( sbrk( 0 ) == startbreak + ( 6 * _PDCLIB_PAGESIZE ) ); + TESTCASE( _PDCLIB_allocpages( -3 ) ); + TESTCASE( sbrk( 0 ) == startbreak + ( 3 * _PDCLIB_PAGESIZE ) ); +#endif + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/platform/stmos/functions/_PDCLIB/_PDCLIB_close.c b/src/pdclib/platform/stmos/functions/_PDCLIB/_PDCLIB_close.c new file mode 100644 index 0000000..3737ab6 --- /dev/null +++ b/src/pdclib/platform/stmos/functions/_PDCLIB/_PDCLIB_close.c @@ -0,0 +1,34 @@ +/* _PDCLIB_close( _PDCLIB_fd_t ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +/* This is an example implementation of _PDCLIB_close() fit for use with POSIX + kernels. +*/ + +#include <syscalls.h> + +#ifndef REGTEST + +#include "pdclib/_PDCLIB_glue.h" + +int _PDCLIB_close( int fd ) +{ + return close( fd ); +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + /* No testdriver; tested in driver for _PDCLIB_open(). */ + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/platform/stmos/functions/_PDCLIB/_PDCLIB_fillbuffer.c b/src/pdclib/platform/stmos/functions/_PDCLIB/_PDCLIB_fillbuffer.c new file mode 100644 index 0000000..c13f9ba --- /dev/null +++ b/src/pdclib/platform/stmos/functions/_PDCLIB/_PDCLIB_fillbuffer.c @@ -0,0 +1,79 @@ +/* _PDCLIB_fillbuffer( struct _PDCLIB_file_t * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +/* This is an example implementation of _PDCLIB_fillbuffer() fit for + use with POSIX kernels. +*/ + +#include <syscalls.h> + +#ifndef REGTEST + +#include "pdclib/_PDCLIB_glue.h" + +//#include </usr/include/errno.h> + +//typedef long ssize_t; +//extern ssize_t read( int fd, void * buf, size_t count ); + +int _PDCLIB_fillbuffer( struct _PDCLIB_file_t * stream ) +{ + /* No need to handle buffers > INT_MAX, as PDCLib doesn't allow them */ + //ssize_t rc = read( stream->handle, stream->buffer, stream->bufsize ); + int rc = read(stream->handle, stream->bufsize, stream->buffer); + if ( rc > 0 ) + { + /* Reading successful. */ + if ( ! ( stream->status & _PDCLIB_FBIN ) ) + { + /* TODO: Text stream conversion here */ + } + stream->pos.offset += rc; + stream->bufend = rc; + stream->bufidx = 0; + return 0; + } + if ( rc < 0 ) + { + /* Reading error */ + //switch ( errno ) + //{ + /* See comments on implementation-defined errno values in + <_PDCLIB_config.h>. + */ + // case EBADF: + // case EFAULT: + // case EINTR: + // case EINVAL: + // case EIO: + // _PDCLIB_errno = _PDCLIB_ERROR; + // break; + // default: + /* This should be something like EUNKNOWN. */ + _PDCLIB_errno = _PDCLIB_ERROR; + // break; + //} + stream->status |= _PDCLIB_ERRORFLAG; + return EOF; + } + /* End-of-File */ + stream->status |= _PDCLIB_EOFFLAG; + return EOF; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + /* Testing covered by ftell.c */ + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/platform/stmos/functions/_PDCLIB/_PDCLIB_flushbuffer.c b/src/pdclib/platform/stmos/functions/_PDCLIB/_PDCLIB_flushbuffer.c new file mode 100644 index 0000000..d3b8842 --- /dev/null +++ b/src/pdclib/platform/stmos/functions/_PDCLIB/_PDCLIB_flushbuffer.c @@ -0,0 +1,110 @@ +/* _PDCLIB_flushbuffer( struct _PDCLIB_file_t * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +/* This is an example implementation of _PDCLIB_flushbuffer() fit for + use with POSIX kernels. +*/ + +#include <syscalls.h> +#include <string.h> + +#ifndef REGTEST + +#include "pdclib/_PDCLIB_glue.h" + +//#include </usr/include/errno.h> + +//typedef long ssize_t; +//extern ssize_t write( int fd, const void * buf, size_t count ); + +/* The number of attempts to complete an output buffer flushing before giving + * up. + * */ +#define _PDCLIB_IO_RETRIES 1 + +/* What the system should do after an I/O operation did not succeed, before */ +/* trying again. (Empty by default.) */ +#define _PDCLIB_IO_RETRY_OP( stream ) + +int _PDCLIB_flushbuffer( struct _PDCLIB_file_t * stream ) +{ + /* No need to handle buffers > INT_MAX, as PDCLib doesn't allow them */ + _PDCLIB_size_t written = 0; + int rc; + unsigned int retries; + if ( ! ( stream->status & _PDCLIB_FBIN ) ) + { + /* TODO: Text stream conversion here */ + } + /* Keep trying to write data until everything is written, an error + occurs, or the configured number of retries is exceeded. + */ + for ( retries = _PDCLIB_IO_RETRIES; retries > 0; --retries ) + { + rc = (int)write(stream->handle, stream->bufidx - written, stream->buffer + written); + if ( rc < 0 ) + { + /* Write error */ + //switch ( errno ) + //{ + /* See <_PDCLIB_config.h>. There should be differenciated errno + handling here, possibly even a 1:1 mapping; but that is up + to the individual platform. + */ + // case EBADF: + // case EFAULT: + // case EFBIG: + // case EINTR: + // case EINVAL: + // case EIO: + // case ENOSPC: + // case EPIPE: + // _PDCLIB_errno = _PDCLIB_ERROR; + // break; + // default: + /* This should be something like EUNKNOWN. */ + _PDCLIB_errno = _PDCLIB_ERROR; + // break; + //} + stream->status |= _PDCLIB_ERRORFLAG; + /* Move unwritten remains to begin of buffer. */ + stream->bufidx -= written; + memmove( stream->buffer, stream->buffer + written, stream->bufidx ); + return EOF; + } + written += (_PDCLIB_size_t)rc; + stream->pos.offset += rc; + if ( written == stream->bufidx ) + { + /* Buffer written completely. */ + stream->bufidx = 0; + return 0; + } + } + /* Number of retries exceeded. You probably want a different errno value + here. + */ + _PDCLIB_errno = _PDCLIB_ERROR; + stream->status |= _PDCLIB_ERRORFLAG; + /* Move unwritten remains to begin of buffer. */ + stream->bufidx -= written; + memmove( stream->buffer, stream->buffer + written, stream->bufidx ); + return EOF; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + /* Testing covered by ftell.c */ + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/platform/stmos/functions/_PDCLIB/_PDCLIB_open.c b/src/pdclib/platform/stmos/functions/_PDCLIB/_PDCLIB_open.c new file mode 100644 index 0000000..fb4f769 --- /dev/null +++ b/src/pdclib/platform/stmos/functions/_PDCLIB/_PDCLIB_open.c @@ -0,0 +1,158 @@ +/* _PDCLIB_open( const char * const, int ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +/* This is an example implementation of _PDCLIB_open() fit for use with POSIX + kernels. +*/ + +#include <syscalls.h> + +#ifndef REGTEST + +#include "pdclib/_PDCLIB_glue.h" + +//#include <sys/types.h> +//#include <sys/stat.h> +//#include <fcntl.h> +//#include <unistd.h> + +//#include "/usr/include/errno.h" + +int _PDCLIB_open( const char * const filename, unsigned int mode ) +{ + /* This is an example implementation of _PDCLIB_open() fit for use with + POSIX kernels. + */ + uint32_t flags; + int rc; + switch ( mode & ( _PDCLIB_FREAD | _PDCLIB_FWRITE | _PDCLIB_FAPPEND | _PDCLIB_FRW ) ) + { + case _PDCLIB_FREAD: /* "r" */ + flags = VFS_FILE_READ; + break; + case _PDCLIB_FWRITE: /* "w" */ + flags = VFS_FILE_WRITE; + break; + case _PDCLIB_FAPPEND: /* "a" */ + flags = VFS_FILE_WRITE; + break; + case _PDCLIB_FREAD | _PDCLIB_FRW: /* "r+" */ + case _PDCLIB_FWRITE | _PDCLIB_FRW: /* "w+" */ + case _PDCLIB_FAPPEND | _PDCLIB_FRW: /* "a+" */ + flags = VFS_FILE_READ | VFS_FILE_WRITE; + break; + default: /* Invalid mode */ + return -1; + } + + rc = open(filename, flags); + + if ( rc == -1 ) + { + //switch ( errno ) + //{ + /* See the comments on implementation-defined errno values in + <_PDCLIB_config.h>. + */ + // case EACCES: + // case EFAULT: + // case EINTR: + // case EISDIR: + // case ELOOP: + // case EMFILE: + // case ENAMETOOLONG: + // case ENFILE: + // case ENODEV: + // case ENOENT: + // case ENOMEM: + // case ENOSPC: + // case ENOTDIR: + // case EOVERFLOW: + // case EROFS: + // case ETXTBSY: + // _PDCLIB_errno = _PDCLIB_ERROR; + // break; + // default: + /* This should be something like EUNKNOWN. */ + _PDCLIB_errno = _PDCLIB_ERROR; + // break; + //} + } + return rc; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +#include <stdlib.h> +#include <string.h> + +int main( void ) +{ +#ifndef REGTEST + /* This testdriver assumes POSIX, i.e. _PDCLIB_fd_t being int and being + incremented by one on each successful open. + */ + int fh; + char buffer[ 10 ]; + remove( testfile ); + /* Trying to read non-existent file. */ + TESTCASE( _PDCLIB_open( testfile, _PDCLIB_FREAD ) == _PDCLIB_NOHANDLE ); + /* Writing to file, trying to read from it. */ + TESTCASE( ( fh = _PDCLIB_open( testfile, _PDCLIB_FWRITE ) ) != _PDCLIB_NOHANDLE ); + TESTCASE( write( fh, "test", 4 ) == 4 ); + TESTCASE( lseek( fh, 0, SEEK_SET ) == 0 ); + TESTCASE( read( fh, buffer, 4 ) == -1 ); + TESTCASE( _PDCLIB_close( fh ) == 0 ); + /* Reading from file, trying to write to it. */ + TESTCASE( ( fh = _PDCLIB_open( testfile, _PDCLIB_FREAD ) ) != _PDCLIB_NOHANDLE ); + TESTCASE( write( fh, "test", 4 ) == -1 ); + TESTCASE( _PDCLIB_close( fh ) == 0 ); + /* Appending to file, trying to read from it. */ + TESTCASE( ( fh = _PDCLIB_open( testfile, _PDCLIB_FAPPEND ) ) != _PDCLIB_NOHANDLE ); + TESTCASE( write( fh, "app", 3 ) == 3 ); + TESTCASE( lseek( fh, 0, SEEK_SET ) == 0 ); + TESTCASE( read( fh, buffer, 10 ) == -1 ); + TESTCASE( write( fh, "end", 3 ) == 3 ); + TESTCASE( _PDCLIB_close( fh ) == 0 ); + /* Reading and writing from file ("r+"). */ + TESTCASE( ( fh = _PDCLIB_open( testfile, _PDCLIB_FREAD | _PDCLIB_FRW ) ) != _PDCLIB_NOHANDLE ); + TESTCASE( read( fh, buffer, 10 ) == 10 ); + TESTCASE( memcmp( buffer, "testappend", 10 ) == 0 ); + TESTCASE( lseek( fh, 0, SEEK_SET ) == 0 ); + TESTCASE( write( fh, "wedo", 4 ) == 4 ); + TESTCASE( lseek( fh, 0, SEEK_SET ) == 0 ); + TESTCASE( read( fh, buffer, 10 ) == 10 ); + TESTCASE( memcmp( buffer, "wedoappend", 10 ) == 0 ); + TESTCASE( _PDCLIB_close( fh ) == 0 ); + /* Writing and reading from file ("w+"). */ + TESTCASE( ( fh = _PDCLIB_open( testfile, _PDCLIB_FWRITE | _PDCLIB_FRW ) ) != _PDCLIB_NOHANDLE ); + TESTCASE( write( fh, "test", 4 ) == 4 ); + TESTCASE( lseek( fh, 1, SEEK_SET ) == 1 ); + TESTCASE( read( fh, buffer, 2 ) == 2 ); + TESTCASE( memcmp( buffer, "es", 2 ) == 0 ); + TESTCASE( write( fh, "sie", 3 ) == 3 ); + TESTCASE( lseek( fh, 0, SEEK_SET ) == 0 ); + TESTCASE( read( fh, buffer, 6 ) == 6 ); + TESTCASE( memcmp( buffer, "tessie", 6 ) == 0 ); + TESTCASE( _PDCLIB_close( fh ) == 0 ); + /* Appending and reading from file ("a+"). */ + TESTCASE( ( fh = _PDCLIB_open( testfile, _PDCLIB_FAPPEND | _PDCLIB_FRW ) ) != _PDCLIB_NOHANDLE ); + TESTCASE( write( fh, "baby", 4 ) == 4 ); + TESTCASE( lseek( fh, 0, SEEK_SET ) == 0 ); + TESTCASE( read( fh, buffer, 10 ) == 10 ); + TESTCASE( memcmp( buffer, "tessiebaby", 10 ) == 0 ); + TESTCASE( _PDCLIB_close( fh ) == 0 ); + /* Cleaning up. */ + TESTCASE( remove( testfile ) == 0 ); +#endif + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/platform/stmos/functions/_PDCLIB/_PDCLIB_rename.c b/src/pdclib/platform/stmos/functions/_PDCLIB/_PDCLIB_rename.c new file mode 100644 index 0000000..c9f54b0 --- /dev/null +++ b/src/pdclib/platform/stmos/functions/_PDCLIB/_PDCLIB_rename.c @@ -0,0 +1,144 @@ +/* _PDCLIB_rename( const char *, const char * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +/* This is an example implementation of _PDCLIB_rename() fit for use with + POSIX kernels. + */ + +//#include <stdio.h> + +#ifndef REGTEST + +#include "pdclib/_PDCLIB_glue.h" + +//#include </usr/include/errno.h> + +//extern int unlink( const char * pathname ); +//extern int link( const char * old, const char * new ); + +int _PDCLIB_rename( const char * old, const char * new ) +{ + /* Note that the behaviour if new file exists is implementation-defined. + There is nothing wrong with either overwriting it or failing the + operation, but you might want to document whichever you chose. + This example fails if new file exists. + */ +// if ( link( old, new ) == 0 ) +// { +// if ( unlink( old ) == EOF ) +// { +// switch ( errno ) +// { +// /* See the comments on implementation-defined errno values in +// <_PDCLIB_config.h>. +// */ +// case EACCES: +// case EFAULT: +// case EIO: +// case EISDIR: +// case ELOOP: +// case ENAMETOOLONG: +// case ENOENT: +// case ENOMEM: +// case ENOTDIR: +// case EPERM: +// case EROFS: +// _PDCLIB_errno = _PDCLIB_ERROR; +// break; +// default: +// /* This should be something like EUNKNOWN. */ + _PDCLIB_errno = _PDCLIB_ERROR; +// break; +// } + return -1; +// } +// else +// { +// return 0; +// } +// } +// else +// { +// switch ( errno ) +// { +// /* See the comments on implementation-defined errno values in +// <_PDCLIB_config.h>. +// */ +// case EACCES: +// case EEXIST: +// case EFAULT: +// case EIO: +// case ELOOP: +// case EMLINK: +// case ENAMETOOLONG: +// case ENOENT: +// case ENOMEM: +// case ENOSPC: +// case ENOTDIR: +// case EPERM: +// case EROFS: +// case EXDEV: +// _PDCLIB_errno = _PDCLIB_ERROR; +// break; +// default: +// /* This should be something like EUNKNOWN. */ +// _PDCLIB_errno = _PDCLIB_ERROR; +// break; +// } +// return EOF; +// } +} + +#endif + +#ifdef TEST +#include "_PDCLIB_test.h" + +#include <stdlib.h> + +int main( void ) +{ +#ifndef REGTEST + FILE * file; + remove( testfile1 ); + remove( testfile2 ); + /* check that neither file exists */ + TESTCASE( fopen( testfile1, "r" ) == NULL ); + TESTCASE( fopen( testfile2, "r" ) == NULL ); + /* rename file 1 to file 2 - expected to fail */ + TESTCASE( _PDCLIB_rename( testfile1, testfile2 ) == -1 ); + /* create file 1 */ + TESTCASE( ( file = fopen( testfile1, "w" ) ) != NULL ); + TESTCASE( fputc( 'x', file ) == 'x' ); + TESTCASE( fclose( file ) == 0 ); + /* check that file 1 exists */ + TESTCASE( ( file = fopen( testfile1, "r" ) ) != NULL ); + TESTCASE( fclose( file ) == 0 ); + /* rename file 1 to file 2 */ + TESTCASE( _PDCLIB_rename( testfile1, testfile2 ) == 0 ); + /* check that file 2 exists, file 1 does not */ + TESTCASE( fopen( testfile1, "r" ) == NULL ); + TESTCASE( ( file = fopen( testfile2, "r" ) ) != NULL ); + TESTCASE( fclose( file ) == 0 ); + /* create another file 1 */ + TESTCASE( ( file = fopen( testfile1, "w" ) ) != NULL ); + TESTCASE( fputc( 'x', file ) == 'x' ); + TESTCASE( fclose( file ) == 0 ); + /* check that file 1 exists */ + TESTCASE( ( file = fopen( testfile1, "r" ) ) != NULL ); + TESTCASE( fclose( file ) == 0 ); + /* rename file 1 to file 2 - expected to fail, see comment in + _PDCLIB_rename() itself. + */ + TESTCASE( _PDCLIB_rename( testfile1, testfile2 ) == -1 ); + /* remove both files */ + remove( testfile1 ); + remove( testfile2 ); +#endif + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/platform/stmos/functions/_PDCLIB/_PDCLIB_seek.c b/src/pdclib/platform/stmos/functions/_PDCLIB/_PDCLIB_seek.c new file mode 100644 index 0000000..a7935fa --- /dev/null +++ b/src/pdclib/platform/stmos/functions/_PDCLIB/_PDCLIB_seek.c @@ -0,0 +1,82 @@ +/* int64_t _PDCLIB_seek( FILE *, int64_t, int ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +/* This is an example implementation of _PDCLIB_seek() fit for use with POSIX + kernels. + */ + +#include <syscalls.h> + +#ifndef REGTEST + +#include "pdclib/_PDCLIB_glue.h" + +//#include "/usr/include/errno.h" + +//extern _PDCLIB_int64_t lseek64( int fd, _PDCLIB_int64_t offset, int whence ); +//extern long lseek( int fd, long offset, int whence ); + +_PDCLIB_int64_t _PDCLIB_seek( struct _PDCLIB_file_t * stream, _PDCLIB_int64_t offset, int whence ) +{ +// _PDCLIB_int64_t rc; +// switch ( whence ) +// { +// case SEEK_SET: +// case SEEK_CUR: +// case SEEK_END: +// /* EMPTY - OK */ +// break; +// default: +// /* See comments on implementation-defined errno values in +// <_PDCLIB_config.h>. +// */ + _PDCLIB_errno = _PDCLIB_ERROR; + return EOF; +// break; +// } +//#ifdef __CYGWIN__ +// rc = lseek( stream->handle, offset, whence ); +//#else +// rc = lseek64( stream->handle, offset, whence ); +//#endif +// if ( rc != EOF ) +// { +// stream->ungetidx = 0; +// stream->bufidx = 0; +// stream->bufend = 0; +// stream->pos.offset = rc; +// return rc; +// } +// switch ( errno ) +// { +// case EBADF: +// case EFAULT: +// /* See comments on implementation-defined errno values in +// <_PDCLIB_config.h>. +// */ +// _PDCLIB_errno = _PDCLIB_ERROR; +// break; +// default: +// /* This should be something like EUNKNOWN. */ +// _PDCLIB_errno = _PDCLIB_ERROR; +// break; +// } +// return EOF; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + /* Testing covered by ftell.c */ + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/platform/stmos/functions/_PDCLIB/_PDCLIB_stdinit.c b/src/pdclib/platform/stmos/functions/_PDCLIB/_PDCLIB_stdinit.c new file mode 100644 index 0000000..52b0651 --- /dev/null +++ b/src/pdclib/platform/stmos/functions/_PDCLIB/_PDCLIB_stdinit.c @@ -0,0 +1,430 @@ +/* _PDCLIB_stdinit + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +/* This is an example initialization of stdin, stdout and stderr to the integer + file descriptors 0, 1, and 2, respectively. This applies for a great variety + of operating systems, including POSIX compliant ones. +*/ + +#include <stdio.h> +#include <locale.h> +#include <limits.h> + +#ifndef REGTEST + +/* In a POSIX system, stdin / stdout / stderr are equivalent to the (int) file + descriptors 0, 1, and 2 respectively. +*/ +/* TODO: This is proof-of-concept, requires finetuning. */ +static char _PDCLIB_sin_buffer[BUFSIZ]; +static char _PDCLIB_sout_buffer[BUFSIZ]; +static char _PDCLIB_serr_buffer[BUFSIZ]; + +static unsigned char _PDCLIB_sin_ungetbuf[_PDCLIB_UNGETCBUFSIZE]; +static unsigned char _PDCLIB_sout_ungetbuf[_PDCLIB_UNGETCBUFSIZE]; +static unsigned char _PDCLIB_serr_ungetbuf[_PDCLIB_UNGETCBUFSIZE]; + +static struct _PDCLIB_file_t _PDCLIB_serr = { 2, _PDCLIB_serr_buffer, BUFSIZ, 0, 0, { 0, 0 }, 0, _PDCLIB_serr_ungetbuf, _IONBF | _PDCLIB_FWRITE | _PDCLIB_STATIC, NULL, NULL }; +static struct _PDCLIB_file_t _PDCLIB_sout = { 1, _PDCLIB_sout_buffer, BUFSIZ, 0, 0, { 0, 0 }, 0, _PDCLIB_sout_ungetbuf, _IOLBF | _PDCLIB_FWRITE | _PDCLIB_STATIC, NULL, &_PDCLIB_serr }; +static struct _PDCLIB_file_t _PDCLIB_sin = { 0, _PDCLIB_sin_buffer, BUFSIZ, 0, 0, { 0, 0 }, 0, _PDCLIB_sin_ungetbuf, _IOLBF | _PDCLIB_FREAD | _PDCLIB_STATIC, NULL, &_PDCLIB_sout }; + +struct _PDCLIB_file_t * stdin = &_PDCLIB_sin; +struct _PDCLIB_file_t * stdout = &_PDCLIB_sout; +struct _PDCLIB_file_t * stderr = &_PDCLIB_serr; + +/* FIXME: This approach is a possible attack vector. */ +struct _PDCLIB_file_t * _PDCLIB_filelist = &_PDCLIB_sin; + +/* "C" locale - defaulting to ASCII-7. + 1 kByte (+ 4 byte) of <ctype.h> data. + Each line: flags, lowercase, uppercase, collation. +*/ +static struct _PDCLIB_lc_ctype_entry_t _ctype_entries[ _PDCLIB_CHARSET_SIZE + 1 ] = { + { /* EOF */ 0, 0, 0 }, + { /* NUL */ _PDCLIB_CTYPE_CNTRL, 0x00, 0x00 }, + { /* SOH */ _PDCLIB_CTYPE_CNTRL, 0x01, 0x01 }, + { /* STX */ _PDCLIB_CTYPE_CNTRL, 0x02, 0x02 }, + { /* ETX */ _PDCLIB_CTYPE_CNTRL, 0x03, 0x03 }, + { /* EOT */ _PDCLIB_CTYPE_CNTRL, 0x04, 0x04 }, + { /* ENQ */ _PDCLIB_CTYPE_CNTRL, 0x05, 0x05 }, + { /* ACK */ _PDCLIB_CTYPE_CNTRL, 0x06, 0x06 }, + { /* BEL */ _PDCLIB_CTYPE_CNTRL, 0x07, 0x07 }, + { /* BS */ _PDCLIB_CTYPE_CNTRL, 0x08, 0x08 }, + { /* HT */ _PDCLIB_CTYPE_CNTRL | _PDCLIB_CTYPE_BLANK | _PDCLIB_CTYPE_SPACE, 0x09, 0x09 }, + { /* LF */ _PDCLIB_CTYPE_CNTRL | _PDCLIB_CTYPE_SPACE, 0x0A, 0x0A }, + { /* VT */ _PDCLIB_CTYPE_CNTRL | _PDCLIB_CTYPE_SPACE, 0x0B, 0x0B }, + { /* FF */ _PDCLIB_CTYPE_CNTRL | _PDCLIB_CTYPE_SPACE, 0x0C, 0x0C }, + { /* CR */ _PDCLIB_CTYPE_CNTRL | _PDCLIB_CTYPE_SPACE, 0x0D, 0x0D }, + { /* SO */ _PDCLIB_CTYPE_CNTRL, 0x0E, 0x0E }, + { /* SI */ _PDCLIB_CTYPE_CNTRL, 0x0F, 0x0F }, + { /* DLE */ _PDCLIB_CTYPE_CNTRL, 0x10, 0x10 }, + { /* DC1 */ _PDCLIB_CTYPE_CNTRL, 0x11, 0x11 }, + { /* DC2 */ _PDCLIB_CTYPE_CNTRL, 0x12, 0x12 }, + { /* DC3 */ _PDCLIB_CTYPE_CNTRL, 0x13, 0x13 }, + { /* DC4 */ _PDCLIB_CTYPE_CNTRL, 0x14, 0x14 }, + { /* NAK */ _PDCLIB_CTYPE_CNTRL, 0x15, 0x15 }, + { /* SYN */ _PDCLIB_CTYPE_CNTRL, 0x16, 0x16 }, + { /* ETB */ _PDCLIB_CTYPE_CNTRL, 0x17, 0x17 }, + { /* CAN */ _PDCLIB_CTYPE_CNTRL, 0x18, 0x18 }, + { /* EM */ _PDCLIB_CTYPE_CNTRL, 0x19, 0x19 }, + { /* SUB */ _PDCLIB_CTYPE_CNTRL, 0x1A, 0x1A }, + { /* ESC */ _PDCLIB_CTYPE_CNTRL, 0x1B, 0x1B }, + { /* FS */ _PDCLIB_CTYPE_CNTRL, 0x1C, 0x1C }, + { /* GS */ _PDCLIB_CTYPE_CNTRL, 0x1D, 0x1D }, + { /* RS */ _PDCLIB_CTYPE_CNTRL, 0x1E, 0x1E }, + { /* US */ _PDCLIB_CTYPE_CNTRL, 0x1F, 0x1F }, + { /* SP */ _PDCLIB_CTYPE_BLANK | _PDCLIB_CTYPE_SPACE, 0x20, 0x20 }, + { /* '!' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x21, 0x21 }, + { /* '"' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x22, 0x22 }, + { /* '#' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x23, 0x23 }, + { /* '$' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x24, 0x24 }, + { /* '%' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x25, 0x25 }, + { /* '&' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x26, 0x26 }, + { /* ''' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x27, 0x27 }, + { /* '(' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x28, 0x28 }, + { /* ')' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x29, 0x29 }, + { /* '*' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x2A, 0x2A }, + { /* '+' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x2B, 0x2B }, + { /* ',' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x2C, 0x2C }, + { /* '-' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x2D, 0x2D }, + { /* '.' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x2E, 0x2E }, + { /* '/' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x2F, 0x2F }, + { /* '0' */ _PDCLIB_CTYPE_GRAPH, 0x30, 0x30 }, + { /* '1' */ _PDCLIB_CTYPE_GRAPH, 0x31, 0x31 }, + { /* '2' */ _PDCLIB_CTYPE_GRAPH, 0x32, 0x32 }, + { /* '3' */ _PDCLIB_CTYPE_GRAPH, 0x33, 0x33 }, + { /* '4' */ _PDCLIB_CTYPE_GRAPH, 0x34, 0x34 }, + { /* '5' */ _PDCLIB_CTYPE_GRAPH, 0x35, 0x35 }, + { /* '6' */ _PDCLIB_CTYPE_GRAPH, 0x36, 0x36 }, + { /* '7' */ _PDCLIB_CTYPE_GRAPH, 0x37, 0x37 }, + { /* '8' */ _PDCLIB_CTYPE_GRAPH, 0x38, 0x38 }, + { /* '9' */ _PDCLIB_CTYPE_GRAPH, 0x39, 0x39 }, + { /* ':' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x3A, 0x3A }, + { /* ';' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x3B, 0x3B }, + { /* '<' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x3C, 0x3C }, + { /* '=' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x3D, 0x3D }, + { /* '>' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x3E, 0x3E }, + { /* '?' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x3F, 0x3F }, + { /* '@' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x40, 0x40 }, + { /* 'A' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x41, 0x61 }, + { /* 'B' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x42, 0x62 }, + { /* 'C' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x43, 0x63 }, + { /* 'D' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x44, 0x64 }, + { /* 'E' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x45, 0x65 }, + { /* 'F' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x46, 0x66 }, + { /* 'G' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x47, 0x67 }, + { /* 'H' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x48, 0x68 }, + { /* 'I' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x49, 0x69 }, + { /* 'J' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x4A, 0x6A }, + { /* 'K' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x4B, 0x6B }, + { /* 'L' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x4C, 0x6C }, + { /* 'M' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x4D, 0x6D }, + { /* 'N' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x4E, 0x6E }, + { /* 'O' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x4F, 0x6F }, + { /* 'P' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x50, 0x70 }, + { /* 'Q' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x51, 0x71 }, + { /* 'R' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x52, 0x72 }, + { /* 'S' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x53, 0x73 }, + { /* 'T' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x54, 0x74 }, + { /* 'U' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x55, 0x75 }, + { /* 'V' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x56, 0x76 }, + { /* 'W' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x57, 0x77 }, + { /* 'X' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x58, 0x78 }, + { /* 'Y' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x59, 0x79 }, + { /* 'Z' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x5A, 0x7A }, + { /* '[' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x5B, 0x5B }, + { /* '\' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x5C, 0x5C }, + { /* ']' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x5D, 0x5D }, + { /* '^' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x5E, 0x5E }, + { /* '_' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x5F, 0x5F }, + { /* '`' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x60, 0x60 }, + { /* 'a' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x41, 0x61 }, + { /* 'b' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x42, 0x62 }, + { /* 'c' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x43, 0x63 }, + { /* 'd' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x44, 0x64 }, + { /* 'e' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x45, 0x65 }, + { /* 'f' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x46, 0x66 }, + { /* 'g' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x47, 0x67 }, + { /* 'h' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x48, 0x68 }, + { /* 'i' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x49, 0x69 }, + { /* 'j' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x4A, 0x6A }, + { /* 'k' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x4B, 0x6B }, + { /* 'l' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x4C, 0x6C }, + { /* 'm' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x4D, 0x6D }, + { /* 'n' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x4E, 0x6E }, + { /* 'o' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x4F, 0x6F }, + { /* 'p' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x50, 0x70 }, + { /* 'q' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x51, 0x71 }, + { /* 'r' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x52, 0x72 }, + { /* 's' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x53, 0x73 }, + { /* 't' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x54, 0x74 }, + { /* 'u' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x55, 0x75 }, + { /* 'v' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x56, 0x76 }, + { /* 'w' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x57, 0x77 }, + { /* 'x' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x58, 0x78 }, + { /* 'y' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x59, 0x79 }, + { /* 'z' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x5A, 0x7A }, + { /* '{' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x7B, 0x7B }, + { /* '|' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x7C, 0x7C }, + { /* '}' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x7D, 0x7D }, + { /* '~' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x7E, 0x7E }, + { /* DEL */ _PDCLIB_CTYPE_CNTRL, 0x7F, 0x7F }, + { 0x00, 0x80, 0x80 }, + { 0x00, 0x81, 0x81 }, + { 0x00, 0x82, 0x82 }, + { 0x00, 0x83, 0x83 }, + { 0x00, 0x84, 0x84 }, + { 0x00, 0x85, 0x85 }, + { 0x00, 0x86, 0x86 }, + { 0x00, 0x87, 0x87 }, + { 0x00, 0x88, 0x88 }, + { 0x00, 0x89, 0x89 }, + { 0x00, 0x8A, 0x8A }, + { 0x00, 0x8B, 0x8B }, + { 0x00, 0x8C, 0x8C }, + { 0x00, 0x8D, 0x8D }, + { 0x00, 0x8E, 0x8E }, + { 0x00, 0x8F, 0x8F }, + { 0x00, 0x90, 0x90 }, + { 0x00, 0x91, 0x91 }, + { 0x00, 0x92, 0x92 }, + { 0x00, 0x93, 0x93 }, + { 0x00, 0x94, 0x94 }, + { 0x00, 0x95, 0x95 }, + { 0x00, 0x96, 0x96 }, + { 0x00, 0x97, 0x97 }, + { 0x00, 0x98, 0x98 }, + { 0x00, 0x99, 0x99 }, + { 0x00, 0x9A, 0x9A }, + { 0x00, 0x9B, 0x9B }, + { 0x00, 0x9C, 0x9C }, + { 0x00, 0x9D, 0x9D }, + { 0x00, 0x9E, 0x9E }, + { 0x00, 0x9F, 0x9F }, + { 0x00, 0xA0, 0xA0 }, + { 0x00, 0xA1, 0xA1 }, + { 0x00, 0xA2, 0xA2 }, + { 0x00, 0xA3, 0xA3 }, + { 0x00, 0xA4, 0xA4 }, + { 0x00, 0xA5, 0xA5 }, + { 0x00, 0xA6, 0xA6 }, + { 0x00, 0xA7, 0xA7 }, + { 0x00, 0xA8, 0xA8 }, + { 0x00, 0xA9, 0xA9 }, + { 0x00, 0xAA, 0xAA }, + { 0x00, 0xAB, 0xAB }, + { 0x00, 0xAC, 0xAC }, + { 0x00, 0xAD, 0xAD }, + { 0x00, 0xAE, 0xAE }, + { 0x00, 0xAF, 0xAF }, + { 0x00, 0xB0, 0xB0 }, + { 0x00, 0xB1, 0xB1 }, + { 0x00, 0xB2, 0xB2 }, + { 0x00, 0xB3, 0xB3 }, + { 0x00, 0xB4, 0xB4 }, + { 0x00, 0xB5, 0xB5 }, + { 0x00, 0xB6, 0xB6 }, + { 0x00, 0xB7, 0xB7 }, + { 0x00, 0xB8, 0xB8 }, + { 0x00, 0xB9, 0xB9 }, + { 0x00, 0xBA, 0xBA }, + { 0x00, 0xBB, 0xBB }, + { 0x00, 0xBC, 0xBC }, + { 0x00, 0xBD, 0xBD }, + { 0x00, 0xBE, 0xBE }, + { 0x00, 0xBF, 0xBF }, + { 0x00, 0xC0, 0xC0 }, + { 0x00, 0xC1, 0xC1 }, + { 0x00, 0xC2, 0xC2 }, + { 0x00, 0xC3, 0xC3 }, + { 0x00, 0xC4, 0xC4 }, + { 0x00, 0xC5, 0xC5 }, + { 0x00, 0xC6, 0xC6 }, + { 0x00, 0xC7, 0xC7 }, + { 0x00, 0xC8, 0xC8 }, + { 0x00, 0xC9, 0xC9 }, + { 0x00, 0xCA, 0xCA }, + { 0x00, 0xCB, 0xCB }, + { 0x00, 0xCC, 0xCC }, + { 0x00, 0xCD, 0xCD }, + { 0x00, 0xCE, 0xCE }, + { 0x00, 0xCF, 0xCF }, + { 0x00, 0xD0, 0xD0 }, + { 0x00, 0xD1, 0xD1 }, + { 0x00, 0xD2, 0xD2 }, + { 0x00, 0xD3, 0xD3 }, + { 0x00, 0xD4, 0xD4 }, + { 0x00, 0xD5, 0xD5 }, + { 0x00, 0xD6, 0xD6 }, + { 0x00, 0xD7, 0xD7 }, + { 0x00, 0xD8, 0xD8 }, + { 0x00, 0xD9, 0xD9 }, + { 0x00, 0xDA, 0xDA }, + { 0x00, 0xDB, 0xDB }, + { 0x00, 0xDC, 0xDC }, + { 0x00, 0xDD, 0xDD }, + { 0x00, 0xDE, 0xDE }, + { 0x00, 0xDF, 0xDF }, + { 0x00, 0xE0, 0xE0 }, + { 0x00, 0xE1, 0xE1 }, + { 0x00, 0xE2, 0xE2 }, + { 0x00, 0xE3, 0xE3 }, + { 0x00, 0xE4, 0xE4 }, + { 0x00, 0xE5, 0xE5 }, + { 0x00, 0xE6, 0xE6 }, + { 0x00, 0xE7, 0xE7 }, + { 0x00, 0xE8, 0xE8 }, + { 0x00, 0xE9, 0xE9 }, + { 0x00, 0xEA, 0xEA }, + { 0x00, 0xEB, 0xEB }, + { 0x00, 0xEC, 0xEC }, + { 0x00, 0xED, 0xED }, + { 0x00, 0xEE, 0xEE }, + { 0x00, 0xEF, 0xEF }, + { 0x00, 0xF0, 0xF0 }, + { 0x00, 0xF1, 0xF1 }, + { 0x00, 0xF2, 0xF2 }, + { 0x00, 0xF3, 0xF3 }, + { 0x00, 0xF4, 0xF4 }, + { 0x00, 0xF5, 0xF5 }, + { 0x00, 0xF6, 0xF6 }, + { 0x00, 0xF7, 0xF7 }, + { 0x00, 0xF8, 0xF8 }, + { 0x00, 0xF9, 0xF9 }, + { 0x00, 0xFA, 0xFA }, + { 0x00, 0xFB, 0xFB }, + { 0x00, 0xFC, 0xFC }, + { 0x00, 0xFD, 0xFD }, + { 0x00, 0xFE, 0xFE }, + { 0x00, 0xFF, 0xFF } +}; + +struct _PDCLIB_lc_ctype_t _PDCLIB_lc_ctype = { 0, 0x30, 0x39, 0x41, 0x46, 0x61, 0x66, &_ctype_entries[1] }; + +struct _PDCLIB_lc_collate_t _PDCLIB_lc_collate = { 0 }; + +struct lconv _PDCLIB_lconv = { + /* decimal_point */ (char *)".", + /* thousands_sep */ (char *)"", + /* grouping */ (char *)"", + /* mon_decimal_point */ (char *)"", + /* mon_thousands_sep */ (char *)"", + /* mon_grouping */ (char *)"", + /* positive_sign */ (char *)"", + /* negative_sign */ (char *)"", + /* currency_symbol */ (char *)"", + /* int_curr_symbol */ (char *)"", + /* frac_digits */ CHAR_MAX, + /* p_cs_precedes */ CHAR_MAX, + /* n_cs_precedes */ CHAR_MAX, + /* p_sep_by_space */ CHAR_MAX, + /* n_sep_by_space */ CHAR_MAX, + /* p_sign_posn */ CHAR_MAX, + /* n_sign_posn */ CHAR_MAX, + /* int_frac_digits */ CHAR_MAX, + /* int_p_cs_precedes */ CHAR_MAX, + /* int_n_cs_precedes */ CHAR_MAX, + /* int_p_sep_by_space */ CHAR_MAX, + /* int_n_sep_by_space */ CHAR_MAX, + /* int_p_sign_posn */ CHAR_MAX, + /* int_n_sign_posn */ CHAR_MAX +}; + +struct _PDCLIB_lc_numeric_monetary_t _PDCLIB_lc_numeric_monetary = { + &_PDCLIB_lconv, + 0, /* numeric_allocated */ + 0 /* monetary_allocated */ +}; + +struct _PDCLIB_lc_messages_t _PDCLIB_lc_messages = { + 0, + /* _PDCLIB_errno_texts */ + { + /* no error */ (char *)"", + /* ERANGE */ (char *)"ERANGE (Range error)", + /* EDOM */ (char *)"EDOM (Domain error)", + /* EILSEQ */ (char *)"EILSEQ (Illegal sequence)" + } +}; + +struct _PDCLIB_lc_time_t _PDCLIB_lc_time = { + 0, + /* _PDCLIB_month_name_abbr */ + { + (char *)"Jan", + (char *)"Feb", + (char *)"Mar", + (char *)"Apr", + (char *)"May", + (char *)"Jun", + (char *)"Jul", + (char *)"Aug", + (char *)"Sep", + (char *)"Oct", + (char *)"Now", + (char *)"Dec" + }, + /* _PDCLIB_month_name_full */ + { + (char *)"January", + (char *)"February", + (char *)"March", + (char *)"April", + (char *)"May", + (char *)"June", + (char *)"July", + (char *)"August", + (char *)"September", + (char *)"October", + (char *)"November", + (char *)"December" + }, + /* _PDCLIB_day_name_abbr */ + { + (char *)"Sun", + (char *)"Mon", + (char *)"Tue", + (char *)"Wed", + (char *)"Thu", + (char *)"Fri", + (char *)"Sat" + }, + /* _PDCLIB_day_name_full */ + { + (char *)"Sunday", + (char *)"Monday", + (char *)"Tuesday", + (char *)"Wednesday", + (char *)"Thursday", + (char *)"Friday", + (char *)"Saturday" + }, + /* date / time format */ (char *)"%a %b %e %T %Y", + /* 12h time format */ (char *)"%I:%M:%S %p", + /* date format */ (char *)"%m/%d/%y", + /* time format */ (char *)"%T", + /* AM / PM designation */ + { + (char *)"AM", + (char *)"PM" + } +}; + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + /* Testing covered by several other testdrivers using stdin / stdout / + stderr. + */ + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/platform/stmos/functions/signal/raise.c b/src/pdclib/platform/stmos/functions/signal/raise.c new file mode 100644 index 0000000..59ccc9f --- /dev/null +++ b/src/pdclib/platform/stmos/functions/signal/raise.c @@ -0,0 +1,114 @@ +/* raise( int ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <signal.h> + +#ifndef REGTEST + +#include <stdio.h> +#include <stdlib.h> + +extern void (*_PDCLIB_sigabrt)( int ); +extern void (*_PDCLIB_sigfpe)( int ); +extern void (*_PDCLIB_sigill)( int ); +extern void (*_PDCLIB_sigint)( int ); +extern void (*_PDCLIB_sigsegv)( int ); +extern void (*_PDCLIB_sigterm)( int ); + +int raise( int sig ) +{ + void (*sighandler)( int ); + const char * message; + switch ( sig ) + { + case SIGABRT: + sighandler = _PDCLIB_sigabrt; + message = "Abnormal termination (SIGABRT)"; + break; + case SIGFPE: + sighandler = _PDCLIB_sigfpe; + message = "Arithmetic exception (SIGFPE)"; + break; + case SIGILL: + sighandler = _PDCLIB_sigill; + message = "Illegal instruction (SIGILL)"; + break; + case SIGINT: + sighandler = _PDCLIB_sigint; + message = "Interactive attention signal (SIGINT)"; + break; + case SIGSEGV: + sighandler = _PDCLIB_sigsegv; + message = "Invalid memory access (SIGSEGV)"; + break; + case SIGTERM: + sighandler = _PDCLIB_sigterm; + message = "Termination request (SIGTERM)"; + break; + default: + fprintf( stderr, "Unknown signal #%d\n", sig ); + _Exit( EXIT_FAILURE ); + } + if ( sighandler == SIG_DFL ) + { + fputs( message, stderr ); + _Exit( EXIT_FAILURE ); + } + else if ( sighandler != SIG_IGN ) + { + sighandler = signal( sig, SIG_DFL ); + sighandler( sig ); + } + return 0; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +#include <stdlib.h> + +static volatile sig_atomic_t flag = 0; + +static int expected_signal = 0; + +static void test_handler( int sig ) +{ + TESTCASE( sig == expected_signal ); + flag = 1; +} + +int main( void ) +{ + /* Could be other than SIG_DFL if you changed the implementation. */ + TESTCASE( signal( SIGABRT, SIG_IGN ) == SIG_DFL ); + /* Should be ignored. */ + TESTCASE( raise( SIGABRT ) == 0 ); + /* Installing test handler, old handler should be returned */ + TESTCASE( signal( SIGABRT, test_handler ) == SIG_IGN ); + /* Raising and checking SIGABRT */ + expected_signal = SIGABRT; + TESTCASE( raise( SIGABRT ) == 0 ); + TESTCASE( flag == 1 ); + /* Re-installing test handler, should have been reset to default */ + /* Could be other than SIG_DFL if you changed the implementation. */ + TESTCASE( signal( SIGABRT, test_handler ) == SIG_DFL ); + /* Raising and checking SIGABRT */ + flag = 0; + TESTCASE( raise( SIGABRT ) == 0 ); + TESTCASE( flag == 1 ); + /* Installing test handler for different signal... */ + TESTCASE( signal( SIGTERM, test_handler ) == SIG_DFL ); + /* Raising and checking SIGTERM */ + expected_signal = SIGTERM; + TESTCASE( raise( SIGTERM ) == 0 ); + TESTCASE( flag == 1 ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/platform/stmos/functions/signal/signal.c b/src/pdclib/platform/stmos/functions/signal/signal.c new file mode 100644 index 0000000..e6775e7 --- /dev/null +++ b/src/pdclib/platform/stmos/functions/signal/signal.c @@ -0,0 +1,75 @@ +/* signal( int, void (*)( int ) ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <signal.h> + +#ifndef REGTEST + +#include <stdlib.h> + +void (*_PDCLIB_sigabrt)( int ) = SIG_DFL; +void (*_PDCLIB_sigfpe)( int ) = SIG_DFL; +void (*_PDCLIB_sigill)( int ) = SIG_DFL; +void (*_PDCLIB_sigint)( int ) = SIG_DFL; +void (*_PDCLIB_sigsegv)( int ) = SIG_DFL; +void (*_PDCLIB_sigterm)( int ) = SIG_DFL; + +void (*signal( int sig, void (*func)( int ) ) )( int ) +{ + void (*oldhandler)( int ); + if ( sig <= 0 || func == SIG_ERR ) + { + return SIG_ERR; + } + switch ( sig ) + { + case SIGABRT: + oldhandler = _PDCLIB_sigabrt; + _PDCLIB_sigabrt = func; + break; + case SIGFPE: + oldhandler = _PDCLIB_sigfpe; + _PDCLIB_sigfpe = func; + break; + case SIGILL: + oldhandler = _PDCLIB_sigill; + _PDCLIB_sigill = func; + break; + case SIGINT: + oldhandler = _PDCLIB_sigint; + _PDCLIB_sigint = func; + break; + case SIGSEGV: + oldhandler = _PDCLIB_sigsegv; + _PDCLIB_sigsegv = func; + break; + case SIGTERM: + oldhandler = _PDCLIB_sigterm; + _PDCLIB_sigterm = func; + break; + default: + /* The standard calls for an unspecified "positive value". You + will probably want to define a specific value for this. + */ + _PDCLIB_errno = 1; + return SIG_ERR; + } + return oldhandler; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + /* Testing covered by raise.c */ + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/platform/stmos/functions/stdio/remove.c b/src/pdclib/platform/stmos/functions/stdio/remove.c new file mode 100644 index 0000000..aca3eaf --- /dev/null +++ b/src/pdclib/platform/stmos/functions/stdio/remove.c @@ -0,0 +1,75 @@ +/* remove( const char * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +/* This is an example implementation of remove() fit for use with POSIX kernels. +*/ + +#include <stdio.h> + +#ifndef REGTEST + +#include <string.h> + +#include "/usr/include/errno.h" + +extern struct _PDCLIB_file_t * _PDCLIB_filelist; + +extern int unlink( const char * pathname ); + +int remove( const char * pathname ) +{ + int rc; + struct _PDCLIB_file_t * current = _PDCLIB_filelist; + while ( current != NULL ) + { + if ( ( current->filename != NULL ) && ( strcmp( current->filename, pathname ) == 0 ) ) + { + return EOF; + } + current = current->next; + } + if ( ( rc = unlink( pathname ) ) == -1 ) + { + switch ( errno ) + { + /* See the comments on implementation-defined errno values in + <_PDCLIB_config.h>. + */ + case EACCES: + case EFAULT: + case EIO: + case EISDIR: + case ELOOP: + case ENAMETOOLONG: + case ENOENT: + case ENOMEM: + case ENOTDIR: + case EPERM: + case EROFS: + _PDCLIB_errno = _PDCLIB_ERROR; + break; + default: + /* This should be something like EUNKNOWN. */ + _PDCLIB_errno = _PDCLIB_ERROR; + break; + } + } + return rc; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + /* Testing covered by ftell.c (and several others) */ + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/platform/stmos/functions/stdio/tmpfile.c b/src/pdclib/platform/stmos/functions/stdio/tmpfile.c new file mode 100644 index 0000000..585a61d --- /dev/null +++ b/src/pdclib/platform/stmos/functions/stdio/tmpfile.c @@ -0,0 +1,114 @@ +/* tmpfile( void ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdio.h> + +#ifndef REGTEST + +#include "pdclib/_PDCLIB_glue.h" + +#include <inttypes.h> +#include <stdlib.h> +#include <string.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> + +extern struct _PDCLIB_file_t * _PDCLIB_filelist; + +/* This is an example implementation of tmpfile() fit for use with POSIX + kernels. +*/ +struct _PDCLIB_file_t * tmpfile( void ) +{ + FILE * rc; + /* This is the chosen way to get high-quality randomness. Replace as + appropriate. + */ + FILE * randomsource = fopen( "/proc/sys/kernel/random/uuid", "rb" ); + char filename[ L_tmpnam ]; + _PDCLIB_fd_t fd; + if ( randomsource == NULL ) + { + return NULL; + } + for ( ;; ) + { + /* Get a filename candidate. What constitutes a valid filename and + where temporary files are usually located is platform-dependent, + which is one reason why this function is located in the platform + overlay. The other reason is that a *good* implementation should + use high-quality randomness instead of a pseudo-random sequence to + generate the filename candidate, which is *also* platform-dependent. + */ + unsigned int random; + fscanf( randomsource, "%u", &random ); + sprintf( filename, "/tmp/%u.tmp", random ); + /* Check if file of this name exists. Note that fopen() is a very weak + check, which does not take e.g. access permissions into account + (file might exist but not readable). Replace with something more + appropriate. + */ + fd = open( filename, O_CREAT | O_EXCL | O_RDWR, S_IRUSR | S_IWUSR ); + if ( fd != -1 ) + { + break; + } + close( fd ); + } + fclose( randomsource ); + /* See fopen(). */ + if ( ( rc = calloc( 1, sizeof( struct _PDCLIB_file_t ) + _PDCLIB_UNGETCBUFSIZE + L_tmpnam + BUFSIZ ) ) == NULL ) + { + /* No memory to set up FILE structure */ + close( fd ); + return NULL; + } + rc->status = _PDCLIB_filemode( "wb+" ) | _IOLBF | _PDCLIB_DELONCLOSE; + rc->handle = fd; + rc->ungetbuf = (unsigned char *)rc + sizeof( struct _PDCLIB_file_t ); + rc->filename = (char *)rc->ungetbuf + _PDCLIB_UNGETCBUFSIZE; + rc->buffer = rc->filename + L_tmpnam; + strcpy( rc->filename, filename ); + rc->bufsize = BUFSIZ; + rc->bufidx = 0; + rc->ungetidx = 0; + rc->next = _PDCLIB_filelist; + _PDCLIB_filelist = rc; + return rc; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +#include <string.h> + +int main( void ) +{ + FILE * fh; +#ifndef REGTEST + char filename[ L_tmpnam ]; + FILE * fhtest; +#endif + TESTCASE( ( fh = tmpfile() ) != NULL ); + TESTCASE( fputc( 'x', fh ) == 'x' ); + /* Checking that file is actually there */ + TESTCASE_NOREG( strcpy( filename, fh->filename ) == filename ); + TESTCASE_NOREG( ( fhtest = fopen( filename, "r" ) ) != NULL ); + TESTCASE_NOREG( fclose( fhtest ) == 0 ); + /* Closing tmpfile */ + TESTCASE( fclose( fh ) == 0 ); + /* Checking that file was deleted */ + TESTCASE_NOREG( fopen( filename, "r" ) == NULL ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/platform/stmos/functions/stdlib/getenv.c b/src/pdclib/platform/stmos/functions/stdlib/getenv.c new file mode 100644 index 0000000..72bbcd2 --- /dev/null +++ b/src/pdclib/platform/stmos/functions/stdlib/getenv.c @@ -0,0 +1,45 @@ +/* getenv( const char * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +/* This is an example implementation of getenv() fit for use with POSIX kernels. +*/ + +#include <string.h> +#include <stdlib.h> + +#ifndef REGTEST + +extern char * * environ; + +char * getenv( const char * name ) +{ + size_t len = strlen( name ); + size_t index = 0; + while ( environ[ index ] != NULL ) + { + if ( strncmp( environ[ index ], name, len ) == 0 ) + { + return environ[ index ] + len + 1; + } + index++; + } + return NULL; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + TESTCASE( strcmp( getenv( "SHELL" ), "/bin/bash" ) == 0 ); + /* TESTCASE( strcmp( getenv( "SHELL" ), "/bin/sh" ) == 0 ); */ + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/platform/stmos/functions/stdlib/system.c b/src/pdclib/platform/stmos/functions/stdlib/system.c new file mode 100644 index 0000000..15603c3 --- /dev/null +++ b/src/pdclib/platform/stmos/functions/stdlib/system.c @@ -0,0 +1,57 @@ +/* system( const char * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <stdlib.h> + +/* This is an example implementation of system() fit for use with POSIX kernels. +*/ + +extern int fork( void ); +extern int execve( const char * filename, char * const argv[], char * const envp[] ); +extern int wait( int * status ); + +int system( const char * string ) +{ + const char * argv[] = { "sh", "-c", NULL, NULL }; + argv[2] = string; + if ( string != NULL ) + { + int pid = fork(); + if ( pid == 0 ) + { + execve( "/bin/sh", (char * * const)argv, NULL ); + } + else if ( pid > 0 ) + { + while( wait( NULL ) != pid ); + } + } + return -1; +} + +#ifdef TEST + +#include "_PDCLIB_test.h" + +#define SHELLCOMMAND "echo 'SUCCESS testing system()'" + +int main( void ) +{ + FILE * fh; + char buffer[25]; + buffer[24] = 'x'; + TESTCASE( ( fh = freopen( testfile, "wb+", stdout ) ) != NULL ); + TESTCASE( system( SHELLCOMMAND ) ); + rewind( fh ); + TESTCASE( fread( buffer, 1, 24, fh ) == 24 ); + TESTCASE( memcmp( buffer, "SUCCESS testing system()", 24 ) == 0 ); + TESTCASE( buffer[24] == 'x' ); + TESTCASE( fclose( fh ) == 0 ); + TESTCASE( remove( testfile ) == 0 ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/platform/stmos/functions/time/clock.c b/src/pdclib/platform/stmos/functions/time/clock.c new file mode 100644 index 0000000..825e040 --- /dev/null +++ b/src/pdclib/platform/stmos/functions/time/clock.c @@ -0,0 +1,35 @@ +/* clock( void ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <time.h> + +#ifndef REGTEST + +#include <sys/times.h> + +clock_t clock( void ) +{ + struct tms buf; + if ( times( &buf ) != (clock_t)-1 ) + { + return buf.tms_utime + buf.tms_stime; + } + return -1; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + TESTCASE( NO_TESTDRIVER ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/platform/stmos/functions/time/time.c b/src/pdclib/platform/stmos/functions/time/time.c new file mode 100644 index 0000000..cbb29e1 --- /dev/null +++ b/src/pdclib/platform/stmos/functions/time/time.c @@ -0,0 +1,41 @@ +/* time( time_t * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <time.h> + +#ifndef REGTEST + +#include <sys/time.h> + +/* See comments in time.h on the semantics of time_t. */ + +time_t time( time_t * timer ) +{ + struct timeval tv; + if ( gettimeofday( &tv, NULL ) == 0 ) + { + if ( timer != NULL ) + { + *timer = tv.tv_sec; + } + return tv.tv_sec; + } + return -1; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + TESTCASE( NO_TESTDRIVER ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/platform/stmos/functions/time/timespec_get.c b/src/pdclib/platform/stmos/functions/time/timespec_get.c new file mode 100644 index 0000000..d8cbab7 --- /dev/null +++ b/src/pdclib/platform/stmos/functions/time/timespec_get.c @@ -0,0 +1,42 @@ +/* timespec_get( struct timespec *, int ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include <time.h> + +#ifndef REGTEST + +#include <sys/time.h> + +int timespec_get( struct timespec * ts, int base ) +{ + if ( base == TIME_UTC ) + { + /* We can make do with a really thin wrapper here. */ + struct timeval tv; + if ( gettimeofday( &tv, NULL ) == 0 ) + { + ts->tv_sec = tv.tv_sec; + ts->tv_nsec = tv.tv_usec * 1000; + return base; + } + } + /* Not supporting any other time base than TIME_UTC for now. */ + return 0; +} + +#endif + +#ifdef TEST + +#include "_PDCLIB_test.h" + +int main( void ) +{ + TESTCASE( NO_TESTDRIVER ); + return TEST_RESULTS; +} + +#endif diff --git a/src/pdclib/platform/stmos/include/float.h b/src/pdclib/platform/stmos/include/float.h new file mode 100644 index 0000000..538d69e --- /dev/null +++ b/src/pdclib/platform/stmos/include/float.h @@ -0,0 +1,75 @@ +/* Characteristics of floating types <float.h> + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#ifndef _PDCLIB_FLOAT_H +#define _PDCLIB_FLOAT_H _PDCLIB_FLOAT_H + +#include "pdclib/_PDCLIB_config.h" + +#define FLT_ROUNDS _PDCLIB_FLT_ROUNDS +#define FLT_EVAL_METHOD _PDCLIB_FLT_EVAL_METHOD +#define DECIMAL_DIG _PDCLIB_DECIMAL_DIG + + /* Radix of exponent representation */ +#define FLT_RADIX __FLT_RADIX__ + /* Number of base-FLT_RADIX digits in the significand of a float */ +#define FLT_MANT_DIG __FLT_MANT_DIG__ + /* Number of decimal digits of precision in a float */ +#define FLT_DIG __FLT_DIG__ + /* Difference between 1.0 and the minimum float greater than 1.0 */ +#define FLT_EPSILON __FLT_EPSILON__ + /* Minimum int x such that FLT_RADIX**(x-1) is a normalised float */ +#define FLT_MIN_EXP __FLT_MIN_EXP__ + /* Minimum normalised float */ +#define FLT_MIN __FLT_MIN__ + /* Minimum int x such that 10**x is a normalised float */ +#define FLT_MIN_10_EXP __FLT_MIN_10_EXP__ + /* Maximum int x such that FLT_RADIX**(x-1) is a representable float */ +#define FLT_MAX_EXP __FLT_MAX_EXP__ + /* Maximum float */ +#define FLT_MAX __FLT_MAX__ + /* Maximum int x such that 10**x is a representable float */ +#define FLT_MAX_10_EXP __FLT_MAX_10_EXP__ + + /* Number of base-FLT_RADIX digits in the significand of a double */ +#define DBL_MANT_DIG __DBL_MANT_DIG__ + /* Number of decimal digits of precision in a double */ +#define DBL_DIG __DBL_DIG__ + /* Difference between 1.0 and the minimum double greater than 1.0 */ +#define DBL_EPSILON __DBL_EPSILON__ + /* Minimum int x such that FLT_RADIX**(x-1) is a normalised double */ +#define DBL_MIN_EXP __DBL_MIN_EXP__ + /* Minimum normalised double */ +#define DBL_MIN __DBL_MIN__ + /* Minimum int x such that 10**x is a normalised double */ +#define DBL_MIN_10_EXP __DBL_MIN_10_EXP__ + /* Maximum int x such that FLT_RADIX**(x-1) is a representable double */ +#define DBL_MAX_EXP __DBL_MAX_EXP__ + /* Maximum double */ +#define DBL_MAX __DBL_MAX__ + /* Maximum int x such that 10**x is a representable double */ +#define DBL_MAX_10_EXP __DBL_MAX_10_EXP__ + + /* Number of base-FLT_RADIX digits in the significand of a long double */ +#define LDBL_MANT_DIG __LDBL_MANT_DIG__ + /* Number of decimal digits of precision in a long double */ +#define LDBL_DIG __LDBL_DIG__ + /* Difference between 1.0 and the minimum long double greater than 1.0 */ +#define LDBL_EPSILON __LDBL_EPSILON__ + /* Minimum int x such that FLT_RADIX**(x-1) is a normalised long double */ +#define LDBL_MIN_EXP __LDBL_MIN_EXP__ + /* Minimum normalised long double */ +#define LDBL_MIN __LDBL_MIN__ + /* Minimum int x such that 10**x is a normalised long double */ +#define LDBL_MIN_10_EXP __LDBL_MIN_10_EXP__ + /* Maximum int x such that FLT_RADIX**(x-1) is a representable long double */ +#define LDBL_MAX_EXP __LDBL_MAX_EXP__ + /* Maximum long double */ +#define LDBL_MAX __LDBL_MAX__ + /* Maximum int x such that 10**x is a representable long double */ +#define LDBL_MAX_10_EXP __LDBL_MAX_10_EXP__ + +#endif diff --git a/src/pdclib/platform/stmos/include/pdclib/_PDCLIB_config.h b/src/pdclib/platform/stmos/include/pdclib/_PDCLIB_config.h new file mode 100644 index 0000000..9731f86 --- /dev/null +++ b/src/pdclib/platform/stmos/include/pdclib/_PDCLIB_config.h @@ -0,0 +1,426 @@ +/* Internal PDCLib configuration <_PDCLIB_config.h> + (Generic Template) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#ifndef _PDCLIB_CONFIG_H +#define _PDCLIB_CONFIG_H _PDCLIB_CONFIG_H + +/* -------------------------------------------------------------------------- */ +/* Misc */ +/* -------------------------------------------------------------------------- */ + +/* The character (sequence) your platform uses as newline. */ +#define _PDCLIB_endl "\n" + +/* exit() can signal success to the host environment by the value of zero or */ +/* the constant EXIT_SUCCESS. Failure is signaled by EXIT_FAILURE. Note that */ +/* any other return value is "implementation-defined", i.e. your environment */ +/* is not required to handle it gracefully. Set your definitions here. */ +#define _PDCLIB_SUCCESS 0 +#define _PDCLIB_FAILURE -1 + +/* qsort() in <stdlib.h> requires a function that swaps two memory areas. */ +/* Below is a naive implementation that can be improved significantly for */ +/* specific platforms, e.g. by swapping int instead of char. */ +#define _PDCLIB_memswp( i, j, size ) char tmp; do { tmp = *i; *i++ = *j; *j++ = tmp; } while ( --size ); + +/* Define this to some compiler directive that can be written after the */ +/* parameter list of a function declaration to indicate the function does */ +/* never return. If your compiler does not support such a directive, define */ +/* to nothing. (This is to avoid warnings with the exit functions under GCC.) */ +#define _PDCLIB_NORETURN __attribute__(( noreturn )) + +/* -------------------------------------------------------------------------- */ +/* Integers */ +/* -------------------------------------------------------------------------- */ +/* Assuming 8-bit char, two's-complement architecture here. 'short' being */ +/* 16 bit, 'int' being either 16, 32 or 64 bit, 'long' being either 32 or 64 */ +/* bit (but 64 bit only if 'int' is 32 bit), and 'long long' being 64 bit if */ +/* 'long' is not, 64 or 128 bit otherwise. */ +/* Author is quite willing to support other systems but would like to hear of */ +/* interest in such support and details on the to-be-supported architecture */ +/* first, before going to lengths about it. */ +/* -------------------------------------------------------------------------- */ + +/* Set to 0 if your 'char' type is unsigned. */ +#ifdef __CHAR_UNSIGNED__ +#define _PDCLIB_CHAR_SIGNED 0 +#else +#define _PDCLIB_CHAR_SIGNED 1 +#endif + +/* Width of the integer types short, int, long, and long long, in bytes. */ +/* SHRT == 2, INT >= SHRT, LONG >= INT >= 4, LLONG >= LONG - check your */ +/* compiler manuals. */ +#define _PDCLIB_SHRT_BYTES 2 +#define _PDCLIB_INT_BYTES 4 +#ifdef __LP64__ +#define _PDCLIB_LONG_BYTES 8 +#else +#define _PDCLIB_LONG_BYTES 4 +#endif +#define _PDCLIB_LLONG_BYTES 8 + +/* <stdlib.h> defines the div() function family that allows taking quotient */ +/* and remainder of an integer division in one operation. Many platforms */ +/* support this in hardware / opcode, and the standard permits ordering of */ +/* the return structure in any way to fit the hardware. That is why those */ +/* structs can be configured here. */ + +struct _PDCLIB_div_t +{ + int quot; + int rem; +}; + +struct _PDCLIB_ldiv_t +{ + long int quot; + long int rem; +}; + +struct _PDCLIB_lldiv_t +{ + long long int quot; + long long int rem; +}; + +/* -------------------------------------------------------------------------- */ +/* <stdint.h> defines a set of integer types that are of a minimum width, and */ +/* "usually fastest" on the system. (If, for example, accessing a single char */ +/* requires the CPU to access a complete int and then mask out the char, the */ +/* "usually fastest" type of at least 8 bits would be int, not char.) */ +/* If you do not have information on the relative performance of the types, */ +/* the standard allows you to define any type that meets minimum width and */ +/* signedness requirements. */ +/* The defines below are just configuration for the real typedefs and limit */ +/* definitions done in <_PDCLIB_int.h>. The uppercase define shall be either */ +/* SHRT, INT, LONG, or LLONG (telling which values to use for the *_MIN and */ +/* *_MAX limits); the lowercase define either short, int, long, or long long */ +/* (telling the actual type to use). */ +/* The third define is the length modifier used for the type in printf() and */ +/* scanf() functions (used in <inttypes.h>). */ +/* If you require a non-standard datatype to define the "usually fastest" */ +/* types, PDCLib as-is doesn't support that. Please contact the author with */ +/* details on your platform in that case, so support can be added. */ +/* -------------------------------------------------------------------------- */ + +#define _PDCLIB_FAST8 INT +#define _PDCLIB_fast8 int +#define _PDCLIB_FAST8_CONV + +#define _PDCLIB_FAST16 INT +#define _PDCLIB_fast16 int +#define _PDCLIB_FAST16_CONV + +#define _PDCLIB_FAST32 INT +#define _PDCLIB_fast32 int +#define _PDCLIB_FAST32_CONV + +#define _PDCLIB_FAST64 LONG +#define _PDCLIB_fast64 long +#define _PDCLIB_FAST64_CONV l + +/* -------------------------------------------------------------------------- */ +/* What follows are a couple of "special" typedefs and their limits. Again, */ +/* the actual definition of the limits is done in <_PDCLIB_int.h>, and the */ +/* defines here are merely "configuration". See above for details. */ +/* -------------------------------------------------------------------------- */ + +/* The result type of substracting two pointers */ +#define _PDCLIB_ptrdiff long +#define _PDCLIB_PTRDIFF LONG +#define _PDCLIB_PTR_CONV l + +/* An integer type that can be accessed as atomic entity (think asynchronous + interrupts). The type itself is not defined in a freestanding environment, + but its limits are. (Don't ask.) +*/ +#define _PDCLIB_sig_atomic int +#define _PDCLIB_SIG_ATOMIC INT + +/* Result type of the 'sizeof' operator (must be unsigned) */ +#define _PDCLIB_size unsigned long +#define _PDCLIB_SIZE ULONG + +/* Large enough an integer to hold all character codes of the largest supported + locale. +*/ +#define _PDCLIB_wchar unsigned int +#define _PDCLIB_WCHAR UINT + +/* Large enough an integer to hold all character codes of the largest supported + locale plus WEOF (which needs not to be equal to EOF, nor needs to be of + negative value). +*/ +#define _PDCLIB_wint unsigned int +#define _PDCLIB_WINT UINT + +/* (Signed) integer type capable of taking the (cast) value of a void *, and + having the value cast back to void *, comparing equal to the original. +*/ +#define _PDCLIB_intptr long +#define _PDCLIB_INTPTR LONG + +/* Largest supported integer type. Implementation note: see _PDCLIB_atomax(). */ +#define _PDCLIB_intmax long long int +#define _PDCLIB_INTMAX LLONG +#define _PDCLIB_MAX_CONV ll +/* You are also required to state the literal suffix for the intmax type */ +#define _PDCLIB_INTMAX_LITERAL ll + +/* <inttypes.h> defines imaxdiv(), which is equivalent to the div() function */ +/* family (see further above) with intmax_t as basis. */ + +struct _PDCLIB_imaxdiv_t +{ + _PDCLIB_intmax quot; + _PDCLIB_intmax rem; +}; + +/* -------------------------------------------------------------------------- */ +/* Time types */ +/* -------------------------------------------------------------------------- */ + +/* See <time.h> for a couple of comments on these types and their semantics. */ + +#define _PDCLIB_time long + +#define _PDCLIB_clock long +#define _PDCLIB_CLOCKS_PER_SEC 1000000 + +#define _PDCLIB_TIME_UTC 1 + +/* -------------------------------------------------------------------------- */ +/* Floating Point */ +/* -------------------------------------------------------------------------- */ + +/* Whether the implementation rounds toward zero (0), to nearest (1), toward + positive infinity (2), or toward negative infinity (3). (-1) signifies + indeterminable rounding, any other value implementation-specific rounding. +*/ +#define _PDCLIB_FLT_ROUNDS -1 + +/* Whether the implementation uses exact-width precision (0), promotes float + to double (1), or promotes float and double to long double (2). (-1) + signifies indeterminable behaviour, any other value implementation-specific + behaviour. +*/ +#define _PDCLIB_FLT_EVAL_METHOD -1 + +/* "Number of the decimal digits (n), such that any floating-point number in the + widest supported floating type with p(max) radix (b) digits can be rounded to + a floating-point number with (n) decimal digits and back again without change + to the value p(max) log(10)b if (b) is a power of 10, [1 + p(max) log(10)b] + otherwise." + 64bit IEC 60559 double format (53bit mantissa) is DECIMAL_DIG 17. + 80bit IEC 60559 double-extended format (64bit mantissa) is DECIMAL_DIG 21. +*/ +#define _PDCLIB_DECIMAL_DIG 17 + +/* -------------------------------------------------------------------------- */ +/* Platform-dependent macros defined by the standard headers. */ +/* -------------------------------------------------------------------------- */ + +/* The offsetof macro + Contract: Expand to an integer constant expression of type size_t, which + represents the offset in bytes to the structure member from the beginning + of the structure. If the specified member is a bitfield, behaviour is + undefined. + There is no standard-compliant way to do this. + This implementation casts an integer zero to 'pointer to type', and then + takes the address of member. This is undefined behaviour but should work on + most compilers. +*/ +#define _PDCLIB_offsetof( type, member ) ( (size_t) &( ( (type *) 0 )->member ) ) + +/* Variable Length Parameter List Handling (<stdarg.h>) + The macros defined by <stdarg.h> are highly dependent on the calling + conventions used, and you probably have to replace them with builtins of + your compiler. +*/ + +#if defined( __i386 ) + +/* The following generic implementation works only for pure + stack-based architectures, and only if arguments are aligned to pointer + type. Credits to Michael Moody, who contributed this to the Public Domain. +*/ + +/* Internal helper macro. va_round is not part of <stdarg.h>. */ +#define _PDCLIB_va_round( type ) ( (sizeof(type) + sizeof(void *) - 1) & ~(sizeof(void *) - 1) ) + +typedef char * _PDCLIB_va_list; +#define _PDCLIB_va_arg( ap, type ) ( (ap) += (_PDCLIB_va_round(type)), ( *(type*) ( (ap) - (_PDCLIB_va_round(type)) ) ) ) +#define _PDCLIB_va_copy( dest, src ) ( (dest) = (src), (void)0 ) +#define _PDCLIB_va_end( ap ) ( (ap) = (void *)0, (void)0 ) +#define _PDCLIB_va_start( ap, parmN ) ( (ap) = (char *) &parmN + ( _PDCLIB_va_round(parmN) ), (void)0 ) + +#elif defined( __x86_64 ) || defined( __arm__ ) + +/* No way to cover x86_64 or arm with a generic implementation, as it uses + register-based parameter passing. Using compiler builtins here. +*/ +typedef __builtin_va_list _PDCLIB_va_list; +#define _PDCLIB_va_arg( ap, type ) ( __builtin_va_arg( ap, type ) ) +#define _PDCLIB_va_copy( dest, src ) ( __builtin_va_copy( dest, src ) ) +#define _PDCLIB_va_end( ap ) ( __builtin_va_end( ap ) ) +#define _PDCLIB_va_start( ap, parmN ) ( __builtin_va_start( ap, parmN ) ) + +#else + +#error Please create your own _PDCLIB_config.h. Using the existing one as-is will not work. + +#endif + +/* -------------------------------------------------------------------------- */ +/* OS "glue", part 1 */ +/* These are values and data type definitions that you would have to adapt to */ +/* the capabilities and requirements of your OS. */ +/* The actual *functions* of the OS interface are declared in _PDCLIB_glue.h. */ +/* -------------------------------------------------------------------------- */ + +/* Memory management -------------------------------------------------------- */ + +/* Set this to the page size of your OS. If your OS does not support paging, set + to an appropriate value. (Too small, and malloc() will call the kernel too + often. Too large, and you will waste memory.) +*/ +#define _PDCLIB_PAGESIZE 4096 + +/* Set this to the minimum memory node size. Any malloc() for a smaller size + will be satisfied by a malloc() of this size instead (to avoid excessive + fragmentation). +*/ +#define _PDCLIB_MINALLOC 8 + +/* I/O ---------------------------------------------------------------------- */ + +/* The type of the file descriptor returned by _PDCLIB_open(). */ +typedef int _PDCLIB_fd_t; + +/* The value (of type _PDCLIB_fd_t) returned by _PDCLIB_open() if the operation + failed. +*/ +#define _PDCLIB_NOHANDLE ( (_PDCLIB_fd_t) -1 ) + +/* The default size for file buffers. Must be at least 256. */ +#define _PDCLIB_BUFSIZ 1024 + +/* The minimum number of files the implementation can open simultaneously. Must + be at least 8. Depends largely on how the bookkeeping is done by fopen() / + freopen() / fclose(). The example implementation limits the number of open + files only by available memory. +*/ +#define _PDCLIB_FOPEN_MAX 8 + +/* Length of the longest filename the implementation guarantees to support. */ +#define _PDCLIB_FILENAME_MAX 128 + +/* Maximum length of filenames generated by tmpnam(). (See tmpfile.c.) */ +#define _PDCLIB_L_tmpnam 46 + +/* Number of distinct file names that can be generated by tmpnam(). */ +#define _PDCLIB_TMP_MAX 50 + +/* The values of SEEK_SET, SEEK_CUR and SEEK_END, used by fseek(). + Since at least one platform (POSIX) uses the same symbols for its own "seek" + function, we use whatever the host defines (if it does define them). +*/ +#define _PDCLIB_SEEK_SET 0 +#define _PDCLIB_SEEK_CUR 1 +#define _PDCLIB_SEEK_END 2 + +/* The number of characters that can be buffered with ungetc(). The standard + guarantees only one (1); anything larger would make applications relying on + this capability dependent on implementation-defined behaviour (not good). +*/ +#define _PDCLIB_UNGETCBUFSIZE 1 + +/* errno -------------------------------------------------------------------- */ + +/* These are the values that _PDCLIB_errno can be set to by the library. + + By keeping PDCLib's errno in the _PDCLIB_* namespace, the library is capable + to "translate" between errno values used by the hosting operating system and + those used and passed out by the library. + + Example: In the example platform, the remove() function uses the unlink() + system call as backend. Linux sets its errno to EISDIR if you try to unlink() + a directory, but POSIX demands EPERM. Within the remove() function, you can + catch the 'errno == EISDIR', and set '_PDCLIB_errno = _PDCLIB_EPERM'. Anyone + using PDCLib's <errno.h> will "see" EPERM instead of EISDIR (the _PDCLIB_* + prefix removed by <errno.h> mechanics). + + If you do not want that kind of translation, you might want to "match" the + values used by PDCLib with those used by the host OS, as to avoid confusion. + + The standard only defines three distinct errno values: ERANGE, EDOM, and + EILSEQ. The standard leaves it up to "the implementation" whether there are + any more beyond those three. There is some controversy as to whether errno is + such a good idea at all, so you might want to come up with a different error + reporting facility for your platform. Since errno values beyond the three + defined by the standard are not portable anyway (unless you look at POSIX), + having your own error reporting facility would not hurt anybody either. +*/ +#define _PDCLIB_ERANGE 1 +#define _PDCLIB_EDOM 2 +#define _PDCLIB_EILSEQ 3 + +/* The following is not strictly "configuration", but there is no better place + to explain it than here. + + PDCLib strives to be as generic as possible, so by default it does NOT define + any values beyond the three standard ones above, even where it would have + been prudent and convenient to do so. Any errno "caught" from the host OS, + and some internal error conditions as well, are all lumped together into the + value of '_PDCLIB_ERROR'. + + '_PDCLIB_ERROR' is STRICLY meant as a PLACEHOLDER only. + + You should NEVER ship an adaption of PDCLib still using that particular + value. You should NEVER write code that *tests* for that value. Indeed it is + not even conforming, since errno values should be defined as beginning with + an uppercase 'E', and there is no mechanics in <errno.h> to unmask that + particular value (for exactly that reason). + + There also is no error message available for this value through either the + strerror() or perror() functions. It is being reported as "unknown" error. + + The idea is that you scan the source of PDCLib for occurrences of this macro + and replace _PDCLIB_ERROR with whatever additional errno value you came up + with for your platform. + + If you cannot find it within you to do that, tell your clients to check for + an errno value larger than zero. That, at least, would be standard compliant + (and fully portable). +*/ +#define _PDCLIB_ERROR 4 + +/* The maximum value that errno can be set to. This is used to set the size */ +/* of the array in struct _PDCLIB_lc_text_t holding error messages for the */ +/* strerror() and perror() functions. (If you change this value because you */ +/* are using additional errno values, you *HAVE* to provide appropriate error */ +/* messages for *ALL* locales.) */ +/* Default is 4 (0, ERANGE, EDOM, EILSEQ). */ +#define _PDCLIB_ERRNO_MAX 4 + +/* locale data -------------------------------------------------------------- */ + +/* The default path where PDCLib should look for its locale data. */ +/* Must end with the appropriate separator character. */ +#define _PDCLIB_LOCALE_PATH "/usr/share/pdclib/i18n" + +/* The name of the environment variable that can be used to override that */ +/* path setting. */ +#define _PDCLIB_LOCALE_PATH_ENV PDCLIB_I18N + +#ifdef __CYGWIN__ +typedef unsigned int wint_t; +#endif + + +#endif diff --git a/src/pdclib/platform/stmos/include/signal.h b/src/pdclib/platform/stmos/include/signal.h new file mode 100644 index 0000000..c5f6f28 --- /dev/null +++ b/src/pdclib/platform/stmos/include/signal.h @@ -0,0 +1,84 @@ +/* Signal handling <string.h> + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#ifndef _PDCLIB_SIGNAL_H +#define _PDCLIB_SIGNAL_H _PDCLIB_SIGNAL_H + +#include "pdclib/_PDCLIB_config.h" + +/* Signals ------------------------------------------------------------------ */ + +/* A word on signals, to the people using PDCLib in their OS projects. + + The definitions of the C standard leave about everything that *could* be + useful to be "implementation defined". Without additional, non-standard + arrangements, it is not possible to turn them into a useful tool. + + This example implementation chose to "not generate any of these signals, + except as a result of explicit calls to the raise function", which is + allowed by the standard but of course does nothing for the usefulness of + <signal.h>. + + A useful signal handling would: + 1) make signal() a system call that registers the signal handler with the OS + 2) make raise() a system call triggering an OS signal to the running process + 3) make provisions that further signals of the same type are blocked until + the signal handler returns (optional for SIGILL) +*/ + +/* These are the values used by Linux. */ + +/* Abnormal termination / abort() */ +#define SIGABRT 6 +/* Arithmetic exception / division by zero / overflow */ +#define SIGFPE 8 +/* Illegal instruction */ +#define SIGILL 4 +/* Interactive attention signal */ +#define SIGINT 2 +/* Invalid memory access */ +#define SIGSEGV 11 +/* Termination request */ +#define SIGTERM 15 + +/* The following should be defined to pointer values that could NEVER point to + a valid signal handler function. (They are used as special arguments to + signal().) Again, these are the values used by Linux. +*/ +#define SIG_DFL (void (*)( int ))0 +#define SIG_ERR (void (*)( int ))-1 +#define SIG_IGN (void (*)( int ))1 + +typedef _PDCLIB_sig_atomic sig_atomic_t; + +/* Installs a signal handler "func" for the given signal. + A signal handler is a function that takes an integer as argument (the signal + number) and returns void. + + Note that a signal handler can do very little else than: + 1) assign a value to a static object of type "volatile sig_atomic_t", + 2) call signal() with the value of sig equal to the signal received, + 3) call _Exit(), + 4) call abort(). + Virtually everything else is undefind. + + The signal() function returns the previous installed signal handler, which + at program start may be SIG_DFL or SIG_ILL. (This implementation uses + SIG_DFL for all handlers.) If the request cannot be honored, SIG_ERR is + returned and errno is set to an unspecified positive value. +*/ +void (*signal( int sig, void (*func)( int ) ) )( int ); + +/* Raises the given signal (executing the registered signal handler with the + given signal number as parameter). + This implementation does not prevent further signals of the same time from + occuring, but executes signal( sig, SIG_DFL ) before entering the signal + handler (i.e., a second signal before the signal handler re-registers itself + or SIG_IGN will end the program). + Returns zero if successful, nonzero otherwise. */ +int raise( int sig ); + +#endif diff --git a/src/pdclib/testing/_PDCLIB_iotest.h b/src/pdclib/testing/_PDCLIB_iotest.h new file mode 100644 index 0000000..ef4d771 --- /dev/null +++ b/src/pdclib/testing/_PDCLIB_iotest.h @@ -0,0 +1,223 @@ +/* PDCLib testing suite <_PDCLIB_test.h> + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +/* -------------------------------------------------------------------------- */ +/* Helper macros for printf() / scanf() tests */ +/* -------------------------------------------------------------------------- */ +/* Tucked away in a seperate header because these are ugly, complex, and not */ +/* needed in 95% of all test cases. */ +/* -------------------------------------------------------------------------- */ + +/* ...printf() tests */ +#if defined( _PDCLIB_FILEIO ) + #define GET_RESULT \ + rewind( target ); \ + if ( (int)fread( result_buffer, 1, actual_rc, target ) != actual_rc ) \ + { \ + fprintf( stderr, "GET_RESULT failed." ); \ + } + #define RESULT_MISMATCH( act, exp ) strcmp( result_buffer, exp ) != 0 + #define RESULT_STRING( tgt ) result_buffer +#elif defined( _PDCLIB_STRINGIO ) + #define RESULT_MISMATCH( act, exp ) strcmp( act, exp ) != 0 + #define GET_RESULT + #define RESULT_STRING( tgt ) tgt +#endif + +#ifdef _PDCLIB_FILEIO +#define PREP_RESULT_BUFFER char result_buffer[100] = { 0 }; rewind( target ); +#else +#define PREP_RESULT_BUFFER +#endif + +#define GETFMT( fmt, ... ) (fmt) +#define PRINTF_TEST( expected_rc, expected_string, ... ) do { \ + int actual_rc; \ + PREP_RESULT_BUFFER \ + actual_rc = testprintf( target, __VA_ARGS__ ); \ + GET_RESULT \ + if ( ( actual_rc != expected_rc ) || \ + ( RESULT_MISMATCH( target, expected_string ) ) ) \ + { \ + ++TEST_RESULTS; \ + fprintf( stderr, \ + "FAILED: " __FILE__ " (" _PDCLIB_FILEID "), line %d\n" \ + " format string \"%s\"\n" \ + " expected %2d, \"%s\"\n" \ + " actual %2d, \"%s\"\n", \ + __LINE__, GETFMT(__VA_ARGS__, 0), expected_rc, \ + expected_string, actual_rc, RESULT_STRING( target ) ); \ + } \ + } while ( 0 ) + +/* ...scanf() tests */ +#if defined( _PDCLIB_FILEIO ) + #define PREPARE_SOURCE( input_string ) \ + rewind( source ); \ + fwrite( input_string, 1, sizeof( input_string ), source ); \ + rewind( source ); +#elif defined( _PDCLIB_STRINGIO ) + #define PREPARE_SOURCE( input_string ) \ + memcpy( source, input_string, sizeof( input_string ) ); +#endif + +#define SCANF_TEST( expected_rc, input_string, ... ) do { \ + int actual_rc; \ + PREPARE_SOURCE( input_string ); \ + actual_rc = testscanf( source, __VA_ARGS__ ); \ + if ( actual_rc != expected_rc ) \ + { \ + ++TEST_RESULTS; \ + fprintf( stderr, "FAILED: " __FILE__ " (" _PDCLIB_FILEID "), line %d\n expected %2d, actual %2d\n", __LINE__, expected_rc, actual_rc ); \ + } \ + } while ( 0 ) + +/* Virtually everything in the printf() / scanf() test drivers is heavily + depending on the platform, i.e. the width of the integer values. To do + proper domain tests, we need the limits of the integers (largest and + smallest value), which we can get from <limits.h>. But we also need the + string representations of these numbers, to the various bases, which of + course vary depending on how the platform defines 'int' and 'long'. +*/ + +#define sym2v( x ) #x +#define sym2s( x ) sym2v( x ) + +#if INT_MAX >> 15 == 1 + +#define UINT_DIG 5 +#define INT_DIG 5 +#define INT_DIG_LESS1 "4" +#define INT_DIG_PLUS1 "6" +#define INT_DIG_PLUS2 "7" +#define INT_HEXDIG "FFF" +#define INT_hexdig "fff" +#define INT_OCTDIG "177777" +#define INT_MAX_DEZ_STR "32767" +#define INT_MIN_DEZ_STR "32768" +#define UINT_MAX_DEZ_STR "65535" +#define INT_MAX_OCT_STR +#define INT_MIN_OCT_STR +#define UINT_MAX_OCT_STR +#define INT_MAX_HEX_STR +#define INT_MIN_HEX_STR +#define UINT_MAX_HEX_STR + +#elif UINT_MAX >> 31 == 1 + +#define UINT_DIG 10 +#define INT_DIG 10 +#define INT_DIG_LESS1 "9" +#define INT_DIG_PLUS1 "11" +#define INT_DIG_PLUS2 "12" +#define INT_HEXDIG "FFFFFFF" +#define INT_hexdig "fffffff" +#define INT_OCTDIG "37777777777" +#define INT_MAX_DEZ_STR "2147483647" +#define INT_MIN_DEZ_STR "2147483648" +#define UINT_MAX_DEZ_STR "4294967295" +#define INT_MAX_OCT_STR +#define INT_MIN_OCT_STR +#define UINT_MAX_OCT_STR +#define INT_MAX_HEX_STR +#define INT_MIN_HEX_STR +#define UINT_MAX_HEX_STR + +#elif UINT_MAX >> 63 == 1 + +#define UINT_DIG 20 +#define INT_DIG 19 +#define INT_DIG_LESS1 "18" +#define INT_DIG_PLUS1 "20" +#define INT_DIG_PLUS2 "21" +#define INT_HEXDIG "FFFFFFFFFFFFFFF" +#define INT_hexdig "fffffffffffffff" +#define INT_OCTDIG "1777777777777777777777" +#define INT_MAX_DEZ_STR "9223372036854775807" +#define INT_MIN_DEZ_STR "9223372036854775808" +#define UINT_MAX_DEZ_STR "18446744073709551615" +#define INT_MAX_OCT_STR +#define INT_MIN_OCT_STR +#define UINT_MAX_OCT_STR +#define INT_MAX_HEX_STR +#define INT_MIN_HEX_STR +#define UINT_MAX_HEX_STR + +#else + +#error Unsupported width of 'int' (neither 16, 32, nor 64 bit). + +#endif + + +#if ULONG_MAX >> 31 == 1 + +#define ULONG_DIG 10 +#define LONG_DIG 10 +#define LONG_MAX_DEZ_STR "2147483647" +#define LONG_MIN_DEZ_STR "2147483648" +#define ULONG_MAX_DEZ_STR "4294967295" +#define LONG_MAX_OCT_STR +#define LONG_MIN_OCT_STR +#define ULONG_MAX_OCT_STR +#define LONG_MAX_HEX_STR +#define LONG_MIN_HEX_STR +#define ULONG_MAX_HEX_STR + +#elif ULONG_MAX >> 63 == 1 + +#define ULONG_DIG 20 +#define LONG_DIG 19 +#define LONG_MAX_DEZ_STR "9223372036854775807" +#define LONG_MIN_DEZ_STR "9223372036854775808" +#define ULONG_MAX_DEZ_STR "18446744073709551615" +#define LONG_MAX_OCT_STR +#define LONG_MIN_OCT_STR +#define ULONG_MAX_OCT_STR +#define LONG_MAX_HEX_STR +#define LONG_MIN_HEX_STR +#define ULONG_MAX_HEX_STR + +#else + +#error Unsupported width of 'long' (neither 32 nor 64 bit). + +#endif + + +#if ULLONG_MAX >> 63 == 1 + +#define ULLONG_DIG 20 +#define LLONG_DIG 19 +#define LLONG_MAX_DEZ_STR "9223372036854775807" +#define LLONG_MIN_DEZ_STR "9223372036854775808" +#define ULLONG_MAX_DEZ_STR "18446744073709551615" +#define LLONG_MAX_OCT_STR +#define LLONG_MIN_OCT_STR +#define ULLONG_MAX_OCT_STR +#define LLONG_MAX_HEX_STR +#define LLONG_MIN_HEX_STR +#define ULLONG_MAX_HEX_STR + +#elif ULLONG_MAX >> 127 == 1 + +#define ULLONG_DIG 38 +#define LLONG_DIG 38 +#define LLONG_MAX_DEZ_STR "170141183460469231731687303715884105727" +#define LLONG_MIN_DEZ_STR "170141183460469231731687303715884105728" +#define ULLONG_MAX_DEZ_STR "340282366920938463463374607431768211455" +#define LLONG_MAX_OCT_STR +#define LLONG_MIN_OCT_STR +#define ULLONG_MAX_OCT_STR +#define LLONG_MAX_HEX_STR +#define LLONG_MIN_HEX_STR +#define ULLONG_MAX_HEX_STR + +#else + +#error Unsupported width of 'long long' (neither 64 nor 128 bit). + +#endif diff --git a/src/pdclib/testing/_PDCLIB_test.h b/src/pdclib/testing/_PDCLIB_test.h new file mode 100644 index 0000000..65cf5b5 --- /dev/null +++ b/src/pdclib/testing/_PDCLIB_test.h @@ -0,0 +1,45 @@ +/* PDCLib testing suite <_PDCLIB_test.h> + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +/* -------------------------------------------------------------------------- */ +/* Helper macros for test drivers */ +/* -------------------------------------------------------------------------- */ + +#include <stdio.h> +#include <limits.h> +#include <string.h> +#include <assert.h> + +/* Some strings used for <string.h> and <stdlib.h> testing. */ +static const char abcde[] = "abcde"; +static const char abcdx[] = "abcdx"; +static const char teststring[] = "1234567890\nABCDEFGHIJKLMNOPQRSTUVWXYZ\nabcdefghijklmnopqrstuvwxyz\n"; + +/* Temporary file names */ +static const char testfile[]="testing/testfile"; +static const char testfile1[]="testing/testfile1"; +static const char testfile2[]="testing/testfile2"; + +#define NO_TESTDRIVER 0 + +static int TEST_RESULTS = 0; + +/* TESTCASE() - generic test */ +#define TESTCASE( x ) if ( x ) {} \ + else { TEST_RESULTS += 1; printf( "FAILED: " __FILE__ ", line %d - %s\n", __LINE__, #x ); } + +/* TESTCASE_NOREG() - PDCLib-only test */ +#ifndef REGTEST + #define TESTCASE_NOREG( x ) TESTCASE( x ) +#else + #define TESTCASE_NOREG( x ) +#endif + +/* Include printf() / scanf() test macros if required */ + +#if defined( _PDCLIB_FILEIO ) || defined( _PDCLIB_STRINGIO ) +#include "_PDCLIB_iotest.h" +#endif diff --git a/src/pdclib/testing/printf_testcases.h b/src/pdclib/testing/printf_testcases.h new file mode 100644 index 0000000..c714499 --- /dev/null +++ b/src/pdclib/testing/printf_testcases.h @@ -0,0 +1,434 @@ + { +#if CHAR_MIN == -128 + assert(CHAR_MIN == -128); + PRINTF_TEST( 4, "-128", "%hhd", CHAR_MIN ); + assert(CHAR_MAX == 127); + PRINTF_TEST( 3, "127", "%hhd", CHAR_MAX ); +#else + assert(CHAR_MIN == 0); + PRINTF_TEST( 1, "0", "%hhu", CHAR_MIN ); + assert(CHAR_MAX == 255); + PRINTF_TEST( 3, "255", "%hhu", CHAR_MAX ); +#endif + PRINTF_TEST( 1, "0", "%hhd", 0 ); + assert(SHRT_MIN == -32768); + PRINTF_TEST( 6, "-32768", "%hd", SHRT_MIN ); + assert(SHRT_MAX == 32767); + PRINTF_TEST( 5, "32767", "%hd", SHRT_MAX ); + PRINTF_TEST( 1, "0", "%hd", 0 ); + PRINTF_TEST( INT_DIG + 1, "-" INT_MIN_DEZ_STR, "%d", INT_MIN ); + PRINTF_TEST( INT_DIG, INT_MAX_DEZ_STR, "%d", INT_MAX ); + PRINTF_TEST( 1, "0", "%d", 0 ); + PRINTF_TEST( LONG_DIG + 1, "-" LONG_MIN_DEZ_STR, "%ld", LONG_MIN ); + PRINTF_TEST( LONG_DIG, LONG_MAX_DEZ_STR, "%ld", LONG_MAX ); + PRINTF_TEST( 1, "0", "%ld", 0l ); + PRINTF_TEST( LLONG_DIG + 1, "-" LLONG_MIN_DEZ_STR, "%lld", LLONG_MIN ); + PRINTF_TEST( LLONG_DIG, LLONG_MAX_DEZ_STR, "%lld", LLONG_MAX ); + PRINTF_TEST( 1, "0", "%lld", 0ll ); + PRINTF_TEST( 3, "255", "%hhu", UCHAR_MAX ); + PRINTF_TEST( 3, "255", "%hhu", (unsigned char)-1 ); + PRINTF_TEST( 5, "65535", "%hu", USHRT_MAX ); + PRINTF_TEST( 5, "65535", "%hu", (unsigned short)-1 ); + PRINTF_TEST( UINT_DIG, UINT_MAX_DEZ_STR, "%u", UINT_MAX ); + PRINTF_TEST( UINT_DIG, UINT_MAX_DEZ_STR, "%u", -1u ); + PRINTF_TEST( ULONG_DIG, ULONG_MAX_DEZ_STR, "%lu", ULONG_MAX ); + PRINTF_TEST( ULONG_DIG, ULONG_MAX_DEZ_STR, "%lu", -1ul ); + PRINTF_TEST( ULLONG_DIG, ULLONG_MAX_DEZ_STR, "%llu", ULLONG_MAX ); + PRINTF_TEST( ULLONG_DIG, ULLONG_MAX_DEZ_STR, "%llu", -1ull ); + PRINTF_TEST( (int)strlen( INT_HEXDIG ) + 1, "F" INT_HEXDIG, "%X", UINT_MAX ); + PRINTF_TEST( (int)strlen( INT_HEXDIG ) + 3, "0XF" INT_HEXDIG, "%#X", -1u ); + PRINTF_TEST( (int)strlen( INT_HEXDIG ) + 1, "f" INT_hexdig, "%x", UINT_MAX ); + PRINTF_TEST( (int)strlen( INT_HEXDIG ) + 3, "0xf" INT_hexdig, "%#x", -1u ); + PRINTF_TEST( (int)strlen( INT_OCTDIG ), INT_OCTDIG, "%o", UINT_MAX ); + PRINTF_TEST( (int)strlen( INT_OCTDIG ) + 1, "0" INT_OCTDIG, "%#o", -1u ); +#if 0 + /* TODO: This test case is broken, doesn't test what it was intended to. */ + PRINTF_TEST( 5, "%.0#o", "%.0#o", 0 ); +#endif + PRINTF_TEST( INT_DIG + 1, "-" INT_MIN_DEZ_STR, "%+d", INT_MIN ); + PRINTF_TEST( INT_DIG + 1, "+" INT_MAX_DEZ_STR, "%+d", INT_MAX ); + PRINTF_TEST( 2, "+0", "%+d", 0 ); + PRINTF_TEST( UINT_DIG, UINT_MAX_DEZ_STR, "%+u", UINT_MAX ); + PRINTF_TEST( UINT_DIG, UINT_MAX_DEZ_STR, "%+u", -1u ); + PRINTF_TEST( INT_DIG + 1, "-" INT_MIN_DEZ_STR, "% d", INT_MIN ); + PRINTF_TEST( INT_DIG + 1, " " INT_MAX_DEZ_STR, "% d", INT_MAX ); + PRINTF_TEST( 2, " 0", "% d", 0 ); + PRINTF_TEST( UINT_DIG, UINT_MAX_DEZ_STR, "% u", UINT_MAX ); + PRINTF_TEST( UINT_DIG, UINT_MAX_DEZ_STR, "% u", -1u ); + PRINTF_TEST( INT_DIG + 1, "-" INT_MIN_DEZ_STR, "%" INT_DIG_LESS1 "d", INT_MIN ); + PRINTF_TEST( INT_DIG, INT_MAX_DEZ_STR, "%" INT_DIG_LESS1 "d", INT_MAX ); + PRINTF_TEST( INT_DIG + 1, "-" INT_MIN_DEZ_STR, "%" sym2s(INT_DIG) "d", INT_MIN ); + PRINTF_TEST( INT_DIG, INT_MAX_DEZ_STR, "%" sym2s(INT_DIG) "d", INT_MAX ); + PRINTF_TEST( INT_DIG + 1, "-" INT_MIN_DEZ_STR, "%" INT_DIG_PLUS1 "d", INT_MIN ); + PRINTF_TEST( INT_DIG + 1, " " INT_MAX_DEZ_STR, "%" INT_DIG_PLUS1 "d", INT_MAX ); + PRINTF_TEST( INT_DIG + 2, " -" INT_MIN_DEZ_STR, "%" INT_DIG_PLUS2 "d", INT_MIN ); + PRINTF_TEST( INT_DIG + 2, " " INT_MAX_DEZ_STR, "%" INT_DIG_PLUS2 "d", INT_MAX ); + PRINTF_TEST( INT_DIG + 1, "-" INT_MIN_DEZ_STR, "%-" INT_DIG_LESS1 "d", INT_MIN ); + PRINTF_TEST( INT_DIG, INT_MAX_DEZ_STR, "%-" INT_DIG_LESS1 "d", INT_MAX ); + PRINTF_TEST( INT_DIG + 1, "-" INT_MIN_DEZ_STR, "%-" sym2s(INT_DIG) "d", INT_MIN ); + PRINTF_TEST( INT_DIG, INT_MAX_DEZ_STR, "%-" sym2s(INT_DIG) "d", INT_MAX ); + PRINTF_TEST( INT_DIG + 1, "-" INT_MIN_DEZ_STR, "%-" INT_DIG_PLUS1 "d", INT_MIN ); + PRINTF_TEST( INT_DIG + 1, INT_MAX_DEZ_STR " ", "%-" INT_DIG_PLUS1 "d", INT_MAX ); + PRINTF_TEST( INT_DIG + 2, "-" INT_MIN_DEZ_STR " ", "%-" INT_DIG_PLUS2 "d", INT_MIN ); + PRINTF_TEST( INT_DIG + 2, INT_MAX_DEZ_STR " ", "%-" INT_DIG_PLUS2 "d", INT_MAX ); + PRINTF_TEST( INT_DIG + 1, "-" INT_MIN_DEZ_STR, "%0" INT_DIG_LESS1 "d", INT_MIN ); + PRINTF_TEST( INT_DIG, INT_MAX_DEZ_STR, "%0" INT_DIG_LESS1 "d", INT_MAX ); + PRINTF_TEST( INT_DIG + 1, "-" INT_MIN_DEZ_STR, "%0" sym2s(INT_DIG) "d", INT_MIN ); + PRINTF_TEST( INT_DIG, INT_MAX_DEZ_STR, "%0" sym2s(INT_DIG) "d", INT_MAX ); + PRINTF_TEST( INT_DIG + 1, "-" INT_MIN_DEZ_STR, "%0" INT_DIG_PLUS1 "d", INT_MIN ); + PRINTF_TEST( INT_DIG + 1, "0" INT_MAX_DEZ_STR, "%0" INT_DIG_PLUS1 "d", INT_MAX ); + PRINTF_TEST( INT_DIG + 2, "-0" INT_MIN_DEZ_STR, "%0" INT_DIG_PLUS2 "d", INT_MIN ); + PRINTF_TEST( INT_DIG + 2, "00" INT_MAX_DEZ_STR, "%0" INT_DIG_PLUS2 "d", INT_MAX ); + PRINTF_TEST( INT_DIG + 1, "-" INT_MIN_DEZ_STR, "%-0" INT_DIG_LESS1 "d", INT_MIN ); + PRINTF_TEST( INT_DIG, INT_MAX_DEZ_STR, "%-0" INT_DIG_LESS1 "d", INT_MAX ); + PRINTF_TEST( INT_DIG + 1, "-" INT_MIN_DEZ_STR, "%-0" sym2s(INT_DIG) "d", INT_MIN ); + PRINTF_TEST( INT_DIG, INT_MAX_DEZ_STR, "%-0" sym2s(INT_DIG) "d", INT_MAX ); + PRINTF_TEST( INT_DIG + 1, "-" INT_MIN_DEZ_STR, "%-0" INT_DIG_PLUS1 "d", INT_MIN ); + PRINTF_TEST( INT_DIG + 1, INT_MAX_DEZ_STR " ", "%-0" INT_DIG_PLUS1 "d", INT_MAX ); + PRINTF_TEST( INT_DIG + 2, "-" INT_MIN_DEZ_STR " ", "%-0" INT_DIG_PLUS2 "d", INT_MIN ); + PRINTF_TEST( INT_DIG + 2, INT_MAX_DEZ_STR " ", "%-0" INT_DIG_PLUS2 "d", INT_MAX ); + /* FIXME: This test not yet 32/64 bit agnostic */ + PRINTF_TEST( 30, " 00000000002147483647", "%030.20d", INT_MAX ); + PRINTF_TEST( (int)strlen( INT_HEXDIG ) + 1, "f" INT_hexdig, "%.6x", UINT_MAX ); + PRINTF_TEST( (int)strlen( INT_HEXDIG ) + 3, "0xf" INT_hexdig, "%#6.3x", UINT_MAX ); + PRINTF_TEST( (int)strlen( INT_HEXDIG ) + 3, "0xf" INT_hexdig, "%#3.6x", UINT_MAX ); + PRINTF_TEST( INT_DIG + 1, "-" INT_MIN_DEZ_STR, "%.6d", INT_MIN ); + PRINTF_TEST( INT_DIG + 1, "-" INT_MIN_DEZ_STR, "%6.3d", INT_MIN ); + PRINTF_TEST( INT_DIG + 1, "-" INT_MIN_DEZ_STR, "%3.6d", INT_MIN ); + PRINTF_TEST( UINT_DIG, "0xf" INT_hexdig, "%#0.6x", UINT_MAX ); + PRINTF_TEST( UINT_DIG, "0xf" INT_hexdig, "%#06.3x", UINT_MAX ); + PRINTF_TEST( UINT_DIG, "0xf" INT_hexdig, "%#03.6x", UINT_MAX ); + PRINTF_TEST( INT_DIG, INT_MAX_DEZ_STR, "%#0.6d", INT_MAX ); + PRINTF_TEST( INT_DIG, INT_MAX_DEZ_STR, "%#06.3d", INT_MAX ); + PRINTF_TEST( INT_DIG, INT_MAX_DEZ_STR, "%#03.6d", INT_MAX ); + PRINTF_TEST( INT_DIG + 1, "+" INT_MAX_DEZ_STR, "%#+.6d", INT_MAX ); + PRINTF_TEST( INT_DIG + 1, "+" INT_MAX_DEZ_STR, "%#+6.3d", INT_MAX ); + PRINTF_TEST( INT_DIG + 1, "+" INT_MAX_DEZ_STR, "%#+3.6d", INT_MAX ); + PRINTF_TEST( INT_DIG + 1, "+" INT_MAX_DEZ_STR, "%+0.6d", INT_MAX ); + PRINTF_TEST( INT_DIG + 1, "+" INT_MAX_DEZ_STR, "%+06.3d", INT_MAX ); + PRINTF_TEST( INT_DIG + 1, "+" INT_MAX_DEZ_STR, "%+03.6d", INT_MAX ); +#ifndef TEST_CONVERSION_ONLY + PRINTF_TEST( INT_DIG + 2, "- " INT_MAX_DEZ_STR, "- %d", INT_MAX ); + PRINTF_TEST( INT_DIG * 2 + 6, "- " INT_MAX_DEZ_STR " % -" INT_MIN_DEZ_STR, "- %d %% %d", INT_MAX, INT_MIN ); +#endif + PRINTF_TEST( 1, "x", "%c", 'x' ); + PRINTF_TEST( 6, "abcdef", "%s", "abcdef" ); + /* FIXME: This test not yet 32/64 bit agnostic */ + PRINTF_TEST( 10, "0xdeadbeef", "%p", (void *)0xdeadbeef ); + PRINTF_TEST( 6, " 0x1", "%#6x", 1 ); +#ifndef TEST_CONVERSION_ONLY + { + int val1, val2; + PRINTF_TEST( 9, "123456789", "123456%n789%n", &val1, &val2 ); + TESTCASE( val1 == 6 ); + TESTCASE( val2 == 9 ); + } +#endif + } + /* PDCLIB-20: Verify "unusual" combinations of length and signedness */ + PRINTF_TEST( 1, "1", "%tu", (ptrdiff_t) 1); /* unsigned prtdiff_t */ + PRINTF_TEST( 2, "-1", "%jd", (intmax_t) -1); /* intmax_t */ + PRINTF_TEST( 1, "1", "%ju", (uintmax_t) 1); /* uintmax_t */ + PRINTF_TEST( 1, "1", "%zd", (size_t) 1); /* signed size_t */ + +/****************************************************************************** + * NOTE: The following test cases are imported from the Tyndur project. They * + * are therefore under the license of said project, not CC0. * + * As said code comprises test cases, it does not form part of the * + * final compiled library, and has no bearing on its licensing. * + * * + * See bug PDCLIB-6 for full details * + ******************************************************************************/ +/* + * Copyright (c) 2011 The tyndur Project. All rights reserved. + * + * This code is derived from software contributed to the tyndur Project + * by Kevin Wolf. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + { +#ifndef TEST_CONVERSION_ONLY + /* Ein String ohne alles */ + PRINTF_TEST(12, "Hallo heimur", "Hallo heimur"); +#endif + /* Einfache Konvertierungen */ + PRINTF_TEST(12, "Hallo heimur", "%s", "Hallo heimur"); + PRINTF_TEST(4, "1024", "%d", 1024); + PRINTF_TEST(5, "-1024", "%d", -1024); + PRINTF_TEST(4, "1024", "%i", 1024); + PRINTF_TEST(5, "-1024", "%i", -1024); + PRINTF_TEST(4, "1024", "%u", 1024u); + PRINTF_TEST(10, "4294966272", "%u", -1024u); + PRINTF_TEST(3, "777", "%o", 0777u); + PRINTF_TEST(11, "37777777001", "%o", -0777u); + PRINTF_TEST(8, "1234abcd", "%x", 0x1234abcdu); + PRINTF_TEST(8, "edcb5433", "%x", -0x1234abcdu); + PRINTF_TEST(8, "1234ABCD", "%X", 0x1234abcdu); + PRINTF_TEST(8, "EDCB5433", "%X", -0x1234abcdu); + PRINTF_TEST(1, "x", "%c", 'x'); + PRINTF_TEST(1, "%", "%%"); + /* Mit %c kann man auch Nullbytes ausgeben */ + PRINTF_TEST(1, "\0", "%c", '\0'); + /* Vorzeichen erzwingen (Flag +) */ + PRINTF_TEST(12, "Hallo heimur", "%+s", "Hallo heimur"); + PRINTF_TEST(5, "+1024", "%+d", 1024); + PRINTF_TEST(5, "-1024", "%+d", -1024); + PRINTF_TEST(5, "+1024", "%+i", 1024); + PRINTF_TEST(5, "-1024", "%+i", -1024); + PRINTF_TEST(4, "1024", "%+u", 1024u); + PRINTF_TEST(10, "4294966272", "%+u", -1024u); + PRINTF_TEST(3, "777", "%+o", 0777u); + PRINTF_TEST(11, "37777777001", "%+o", -0777u); + PRINTF_TEST(8, "1234abcd", "%+x", 0x1234abcdu); + PRINTF_TEST(8, "edcb5433", "%+x", -0x1234abcdu); + PRINTF_TEST(8, "1234ABCD", "%+X", 0x1234abcdu); + PRINTF_TEST(8, "EDCB5433", "%+X", -0x1234abcdu); + PRINTF_TEST(1, "x", "%+c", 'x'); + /* Vorzeichenplatzhalter erzwingen (Flag <space>) */ + PRINTF_TEST(12, "Hallo heimur", "% s", "Hallo heimur"); + PRINTF_TEST(5, " 1024", "% d", 1024); + PRINTF_TEST(5, "-1024", "% d", -1024); + PRINTF_TEST(5, " 1024", "% i", 1024); + PRINTF_TEST(5, "-1024", "% i", -1024); + PRINTF_TEST(4, "1024", "% u", 1024u); + PRINTF_TEST(10, "4294966272", "% u", -1024u); + PRINTF_TEST(3, "777", "% o", 0777u); + PRINTF_TEST(11, "37777777001", "% o", -0777u); + PRINTF_TEST(8, "1234abcd", "% x", 0x1234abcdu); + PRINTF_TEST(8, "edcb5433", "% x", -0x1234abcdu); + PRINTF_TEST(8, "1234ABCD", "% X", 0x1234abcdu); + PRINTF_TEST(8, "EDCB5433", "% X", -0x1234abcdu); + PRINTF_TEST(1, "x", "% c", 'x'); + /* Flag + hat Vorrang über <space> */ + PRINTF_TEST(12, "Hallo heimur", "%+ s", "Hallo heimur"); + PRINTF_TEST(5, "+1024", "%+ d", 1024); + PRINTF_TEST(5, "-1024", "%+ d", -1024); + PRINTF_TEST(5, "+1024", "%+ i", 1024); + PRINTF_TEST(5, "-1024", "%+ i", -1024); + PRINTF_TEST(4, "1024", "%+ u", 1024u); + PRINTF_TEST(10, "4294966272", "%+ u", -1024u); + PRINTF_TEST(3, "777", "%+ o", 0777u); + PRINTF_TEST(11, "37777777001", "%+ o", -0777u); + PRINTF_TEST(8, "1234abcd", "%+ x", 0x1234abcdu); + PRINTF_TEST(8, "edcb5433", "%+ x", -0x1234abcdu); + PRINTF_TEST(8, "1234ABCD", "%+ X", 0x1234abcdu); + PRINTF_TEST(8, "EDCB5433", "%+ X", -0x1234abcdu); + PRINTF_TEST(1, "x", "%+ c", 'x'); + /* Alternative Form */ + PRINTF_TEST(4, "0777", "%#o", 0777u); + PRINTF_TEST(12, "037777777001", "%#o", -0777u); + PRINTF_TEST(10, "0x1234abcd", "%#x", 0x1234abcdu); + PRINTF_TEST(10, "0xedcb5433", "%#x", -0x1234abcdu); + PRINTF_TEST(10, "0X1234ABCD", "%#X", 0x1234abcdu); + PRINTF_TEST(10, "0XEDCB5433", "%#X", -0x1234abcdu); + PRINTF_TEST(1, "0", "%#o", 0u); + PRINTF_TEST(1, "0", "%#x", 0u); + PRINTF_TEST(1, "0", "%#X", 0u); + /* Feldbreite: Kleiner als Ausgabe */ + PRINTF_TEST(12, "Hallo heimur", "%1s", "Hallo heimur"); + PRINTF_TEST(4, "1024", "%1d", 1024); + PRINTF_TEST(5, "-1024", "%1d", -1024); + PRINTF_TEST(4, "1024", "%1i", 1024); + PRINTF_TEST(5, "-1024", "%1i", -1024); + PRINTF_TEST(4, "1024", "%1u", 1024u); + PRINTF_TEST(10, "4294966272", "%1u", -1024u); + PRINTF_TEST(3, "777", "%1o", 0777u); + PRINTF_TEST(11, "37777777001", "%1o", -0777u); + PRINTF_TEST(8, "1234abcd", "%1x", 0x1234abcdu); + PRINTF_TEST(8, "edcb5433", "%1x", -0x1234abcdu); + PRINTF_TEST(8, "1234ABCD", "%1X", 0x1234abcdu); + PRINTF_TEST(8, "EDCB5433", "%1X", -0x1234abcdu); + PRINTF_TEST(1, "x", "%1c", 'x'); + /* Feldbreite: Größer als Ausgabe */ + PRINTF_TEST(20, " Hallo", "%20s", "Hallo"); + PRINTF_TEST(20, " 1024", "%20d", 1024); + PRINTF_TEST(20, " -1024", "%20d", -1024); + PRINTF_TEST(20, " 1024", "%20i", 1024); + PRINTF_TEST(20, " -1024", "%20i", -1024); + PRINTF_TEST(20, " 1024", "%20u", 1024u); + PRINTF_TEST(20, " 4294966272", "%20u", -1024u); + PRINTF_TEST(20, " 777", "%20o", 0777u); + PRINTF_TEST(20, " 37777777001", "%20o", -0777u); + PRINTF_TEST(20, " 1234abcd", "%20x", 0x1234abcdu); + PRINTF_TEST(20, " edcb5433", "%20x", -0x1234abcdu); + PRINTF_TEST(20, " 1234ABCD", "%20X", 0x1234abcdu); + PRINTF_TEST(20, " EDCB5433", "%20X", -0x1234abcdu); + PRINTF_TEST(20, " x", "%20c", 'x'); + /* Feldbreite: Linksbündig */ + PRINTF_TEST(20, "Hallo ", "%-20s", "Hallo"); + PRINTF_TEST(20, "1024 ", "%-20d", 1024); + PRINTF_TEST(20, "-1024 ", "%-20d", -1024); + PRINTF_TEST(20, "1024 ", "%-20i", 1024); + PRINTF_TEST(20, "-1024 ", "%-20i", -1024); + PRINTF_TEST(20, "1024 ", "%-20u", 1024u); + PRINTF_TEST(20, "4294966272 ", "%-20u", -1024u); + PRINTF_TEST(20, "777 ", "%-20o", 0777u); + PRINTF_TEST(20, "37777777001 ", "%-20o", -0777u); + PRINTF_TEST(20, "1234abcd ", "%-20x", 0x1234abcdu); + PRINTF_TEST(20, "edcb5433 ", "%-20x", -0x1234abcdu); + PRINTF_TEST(20, "1234ABCD ", "%-20X", 0x1234abcdu); + PRINTF_TEST(20, "EDCB5433 ", "%-20X", -0x1234abcdu); + PRINTF_TEST(20, "x ", "%-20c", 'x'); + /* Feldbreite: Padding mit 0 */ + PRINTF_TEST(20, "00000000000000001024", "%020d", 1024); + PRINTF_TEST(20, "-0000000000000001024", "%020d", -1024); + PRINTF_TEST(20, "00000000000000001024", "%020i", 1024); + PRINTF_TEST(20, "-0000000000000001024", "%020i", -1024); + PRINTF_TEST(20, "00000000000000001024", "%020u", 1024u); + PRINTF_TEST(20, "00000000004294966272", "%020u", -1024u); + PRINTF_TEST(20, "00000000000000000777", "%020o", 0777u); + PRINTF_TEST(20, "00000000037777777001", "%020o", -0777u); + PRINTF_TEST(20, "0000000000001234abcd", "%020x", 0x1234abcdu); + PRINTF_TEST(20, "000000000000edcb5433", "%020x", -0x1234abcdu); + PRINTF_TEST(20, "0000000000001234ABCD", "%020X", 0x1234abcdu); + PRINTF_TEST(20, "000000000000EDCB5433", "%020X", -0x1234abcdu); + /* Feldbreite: Padding und alternative Form */ + PRINTF_TEST(20, " 0777", "%#20o", 0777u); + PRINTF_TEST(20, " 037777777001", "%#20o", -0777u); + PRINTF_TEST(20, " 0x1234abcd", "%#20x", 0x1234abcdu); + PRINTF_TEST(20, " 0xedcb5433", "%#20x", -0x1234abcdu); + PRINTF_TEST(20, " 0X1234ABCD", "%#20X", 0x1234abcdu); + PRINTF_TEST(20, " 0XEDCB5433", "%#20X", -0x1234abcdu); + PRINTF_TEST(20, "00000000000000000777", "%#020o", 0777u); + PRINTF_TEST(20, "00000000037777777001", "%#020o", -0777u); + PRINTF_TEST(20, "0x00000000001234abcd", "%#020x", 0x1234abcdu); + PRINTF_TEST(20, "0x0000000000edcb5433", "%#020x", -0x1234abcdu); + PRINTF_TEST(20, "0X00000000001234ABCD", "%#020X", 0x1234abcdu); + PRINTF_TEST(20, "0X0000000000EDCB5433", "%#020X", -0x1234abcdu); + /* Feldbreite: - hat Vorrang vor 0 */ + PRINTF_TEST(20, "Hallo ", "%0-20s", "Hallo"); + PRINTF_TEST(20, "1024 ", "%0-20d", 1024); + PRINTF_TEST(20, "-1024 ", "%0-20d", -1024); + PRINTF_TEST(20, "1024 ", "%0-20i", 1024); + PRINTF_TEST(20, "-1024 ", "%0-20i", -1024); + PRINTF_TEST(20, "1024 ", "%0-20u", 1024u); + PRINTF_TEST(20, "4294966272 ", "%0-20u", -1024u); + PRINTF_TEST(20, "777 ", "%-020o", 0777u); + PRINTF_TEST(20, "37777777001 ", "%-020o", -0777u); + PRINTF_TEST(20, "1234abcd ", "%-020x", 0x1234abcdu); + PRINTF_TEST(20, "edcb5433 ", "%-020x", -0x1234abcdu); + PRINTF_TEST(20, "1234ABCD ", "%-020X", 0x1234abcdu); + PRINTF_TEST(20, "EDCB5433 ", "%-020X", -0x1234abcdu); + PRINTF_TEST(20, "x ", "%-020c", 'x'); + /* Feldbreite: Aus Parameter */ + PRINTF_TEST(20, " Hallo", "%*s", 20, "Hallo"); + PRINTF_TEST(20, " 1024", "%*d", 20, 1024); + PRINTF_TEST(20, " -1024", "%*d", 20, -1024); + PRINTF_TEST(20, " 1024", "%*i", 20, 1024); + PRINTF_TEST(20, " -1024", "%*i", 20, -1024); + PRINTF_TEST(20, " 1024", "%*u", 20, 1024u); + PRINTF_TEST(20, " 4294966272", "%*u", 20, -1024u); + PRINTF_TEST(20, " 777", "%*o", 20, 0777u); + PRINTF_TEST(20, " 37777777001", "%*o", 20, -0777u); + PRINTF_TEST(20, " 1234abcd", "%*x", 20, 0x1234abcdu); + PRINTF_TEST(20, " edcb5433", "%*x", 20, -0x1234abcdu); + PRINTF_TEST(20, " 1234ABCD", "%*X", 20, 0x1234abcdu); + PRINTF_TEST(20, " EDCB5433", "%*X", 20, -0x1234abcdu); + PRINTF_TEST(20, " x", "%*c", 20, 'x'); + /* Präzision / Mindestanzahl von Ziffern */ + PRINTF_TEST(12, "Hallo heimur", "%.20s", "Hallo heimur"); + PRINTF_TEST(20, "00000000000000001024", "%.20d", 1024); + PRINTF_TEST(21, "-00000000000000001024", "%.20d", -1024); + PRINTF_TEST(20, "00000000000000001024", "%.20i", 1024); + PRINTF_TEST(21, "-00000000000000001024", "%.20i", -1024); + PRINTF_TEST(20, "00000000000000001024", "%.20u", 1024u); + PRINTF_TEST(20, "00000000004294966272", "%.20u", -1024u); + PRINTF_TEST(20, "00000000000000000777", "%.20o", 0777u); + PRINTF_TEST(20, "00000000037777777001", "%.20o", -0777u); + PRINTF_TEST(20, "0000000000001234abcd", "%.20x", 0x1234abcdu); + PRINTF_TEST(20, "000000000000edcb5433", "%.20x", -0x1234abcdu); + PRINTF_TEST(20, "0000000000001234ABCD", "%.20X", 0x1234abcdu); + PRINTF_TEST(20, "000000000000EDCB5433", "%.20X", -0x1234abcdu); + /* Feldbreite und Präzision */ + PRINTF_TEST(20, " Hallo", "%20.5s", "Hallo heimur"); + PRINTF_TEST(20, " 01024", "%20.5d", 1024); + PRINTF_TEST(20, " -01024", "%20.5d", -1024); + PRINTF_TEST(20, " 01024", "%20.5i", 1024); + PRINTF_TEST(20, " -01024", "%20.5i", -1024); + PRINTF_TEST(20, " 01024", "%20.5u", 1024u); + PRINTF_TEST(20, " 4294966272", "%20.5u", -1024u); + PRINTF_TEST(20, " 00777", "%20.5o", 0777u); + PRINTF_TEST(20, " 37777777001", "%20.5o", -0777u); + PRINTF_TEST(20, " 1234abcd", "%20.5x", 0x1234abcdu); + PRINTF_TEST(20, " 00edcb5433", "%20.10x", -0x1234abcdu); + PRINTF_TEST(20, " 1234ABCD", "%20.5X", 0x1234abcdu); + PRINTF_TEST(20, " 00EDCB5433", "%20.10X", -0x1234abcdu); + /* Präzision: 0 wird ignoriert */ + PRINTF_TEST(20, " Hallo", "%020.5s", "Hallo heimur"); + PRINTF_TEST(20, " 01024", "%020.5d", 1024); + PRINTF_TEST(20, " -01024", "%020.5d", -1024); + PRINTF_TEST(20, " 01024", "%020.5i", 1024); + PRINTF_TEST(20, " -01024", "%020.5i", -1024); + PRINTF_TEST(20, " 01024", "%020.5u", 1024u); + PRINTF_TEST(20, " 4294966272", "%020.5u", -1024u); + PRINTF_TEST(20, " 00777", "%020.5o", 0777u); + PRINTF_TEST(20, " 37777777001", "%020.5o", -0777u); + PRINTF_TEST(20, " 1234abcd", "%020.5x", 0x1234abcdu); + PRINTF_TEST(20, " 00edcb5433", "%020.10x", -0x1234abcdu); + PRINTF_TEST(20, " 1234ABCD", "%020.5X", 0x1234abcdu); + PRINTF_TEST(20, " 00EDCB5433", "%020.10X", -0x1234abcdu); + /* Präzision 0 */ + PRINTF_TEST(0, "", "%.0s", "Hallo heimur"); + PRINTF_TEST(20, " ", "%20.0s", "Hallo heimur"); + PRINTF_TEST(0, "", "%.s", "Hallo heimur"); + PRINTF_TEST(20, " ", "%20.s", "Hallo heimur"); + PRINTF_TEST(20, " 1024", "%20.0d", 1024); + PRINTF_TEST(20, " -1024", "%20.d", -1024); + PRINTF_TEST(20, " ", "%20.d", 0); + PRINTF_TEST(20, " 1024", "%20.0i", 1024); + PRINTF_TEST(20, " -1024", "%20.i", -1024); + PRINTF_TEST(20, " ", "%20.i", 0); + PRINTF_TEST(20, " 1024", "%20.u", 1024u); + PRINTF_TEST(20, " 4294966272", "%20.0u", -1024u); + PRINTF_TEST(20, " ", "%20.u", 0u); + PRINTF_TEST(20, " 777", "%20.o", 0777u); + PRINTF_TEST(20, " 37777777001", "%20.0o", -0777u); + PRINTF_TEST(20, " ", "%20.o", 0u); + PRINTF_TEST(20, " 1234abcd", "%20.x", 0x1234abcdu); + PRINTF_TEST(20, " edcb5433", "%20.0x", -0x1234abcdu); + PRINTF_TEST(20, " ", "%20.x", 0u); + PRINTF_TEST(20, " 1234ABCD", "%20.X", 0x1234abcdu); + PRINTF_TEST(20, " EDCB5433", "%20.0X", -0x1234abcdu); + PRINTF_TEST(20, " ", "%20.X", 0u); + /* Negative Präzision wird ignoriert */ + /* XXX glibc tut nicht, was ich erwartet habe, vorerst deaktiviert... */ + /* + * Präzision und Feldbreite aus Parameter. + * + hat Vorrang vor <space>, - hat Vorrang vor 0 (das eh ignoriert wird, + * weil eine Präzision angegeben ist) + */ + PRINTF_TEST(20, "Hallo ", "% -0+*.*s", 20, 5, "Hallo heimur"); + PRINTF_TEST(20, "+01024 ", "% -0+*.*d", 20, 5, 1024); + PRINTF_TEST(20, "-01024 ", "% -0+*.*d", 20, 5, -1024); + PRINTF_TEST(20, "+01024 ", "% -0+*.*i", 20, 5, 1024); + PRINTF_TEST(20, "-01024 ", "% 0-+*.*i", 20, 5, -1024); + PRINTF_TEST(20, "01024 ", "% 0-+*.*u", 20, 5, 1024u); + PRINTF_TEST(20, "4294966272 ", "% 0-+*.*u", 20, 5, -1024u); + PRINTF_TEST(20, "00777 ", "%+ -0*.*o", 20, 5, 0777u); + PRINTF_TEST(20, "37777777001 ", "%+ -0*.*o", 20, 5, -0777u); + PRINTF_TEST(20, "1234abcd ", "%+ -0*.*x", 20, 5, 0x1234abcdu); + PRINTF_TEST(20, "00edcb5433 ", "%+ -0*.*x", 20, 10, -0x1234abcdu); + PRINTF_TEST(20, "1234ABCD ", "% -+0*.*X", 20, 5, 0x1234abcdu); + PRINTF_TEST(20, "00EDCB5433 ", "% -+0*.*X", 20, 10, -0x1234abcdu); + } +/******************************************************************************/ diff --git a/src/pdclib/testing/scanf_testcases.h b/src/pdclib/testing/scanf_testcases.h new file mode 100644 index 0000000..f9007d6 --- /dev/null +++ b/src/pdclib/testing/scanf_testcases.h @@ -0,0 +1,87 @@ +{ + char buffer[100]; + int i; + unsigned int u; + int * p; + /* basic: reading of three-char string */ + SCANF_TEST( 1, "foo", "%3c", buffer ); + TESTCASE( memcmp( buffer, "foo", 3 ) == 0 ); +#ifndef TEST_CONVERSION_ONLY + /* %% for single % */ + SCANF_TEST( 1, "%x", "%%%c", buffer ); + TESTCASE( buffer[0] == 'x' ); + /* * to skip assignment */ + SCANF_TEST( 1, "3xfoo", "%*dx%3c", buffer ); + TESTCASE( memcmp( buffer, "foo", 3 ) == 0 ); +#endif + /* domain testing on 'int' type */ + SCANF_TEST( 1, "-" INT_MIN_DEZ_STR, "%d", &i ); + TESTCASE( i == INT_MIN ); + SCANF_TEST( 1, INT_MAX_DEZ_STR, "%d", &i ); + TESTCASE( i == INT_MAX ); + SCANF_TEST( 1, "-1", "%d", &i ); + TESTCASE( i == -1 ); + SCANF_TEST( 1, "0", "%d", &i ); + TESTCASE( i == 0 ); + SCANF_TEST( 1, "1", "%d", &i ); + TESTCASE( i == 1 ); + SCANF_TEST( 1, "-" INT_MIN_DEZ_STR, "%i", &i ); + TESTCASE( i == INT_MIN ); + SCANF_TEST( 1, INT_MAX_DEZ_STR, "%i", &i ); + TESTCASE( i == INT_MAX ); + SCANF_TEST( 1, "-1", "%i", &i ); + TESTCASE( i == -1 ); + SCANF_TEST( 1, "0", "%i", &i ); + TESTCASE( i == 0 ); + SCANF_TEST( 1, "1", "%i", &i ); + TESTCASE( i == 1 ); + SCANF_TEST( 1, "0x7" INT_HEXDIG, "%i", &i ); + TESTCASE( i == INT_MAX ); + SCANF_TEST( 1, "0x0", "%i", &i ); + TESTCASE( i == 0 ); +#ifndef TEST_CONVERSION_ONLY + SCANF_TEST( 1, "00", "%i%n", &i, &u ); + TESTCASE( i == 0 ); + TESTCASE( u == 2 ); +#endif + /* domain testing on 'unsigned int' type */ + SCANF_TEST( 1, UINT_MAX_DEZ_STR, "%u", &u ); + TESTCASE( u == UINT_MAX ); + SCANF_TEST( 1, "0", "%u", &u ); + TESTCASE( u == 0 ); + SCANF_TEST( 1, "f" INT_HEXDIG, "%x", &u ); + TESTCASE( u == UINT_MAX ); + SCANF_TEST( 1, "7" INT_HEXDIG, "%x", &u ); + TESTCASE( u == INT_MAX ); + SCANF_TEST( 1, "0", "%o", &u ); + TESTCASE( u == 0 ); + SCANF_TEST( 1, INT_OCTDIG, "%o", &u ); + TESTCASE( u == UINT_MAX ); + /* testing %c */ + memset( buffer, '\0', 100 ); + SCANF_TEST( 1, "x", "%c", buffer ); + TESTCASE( memcmp( buffer, "x\0", 2 ) == 0 ); + /* testing %s */ + memset( buffer, '\0', 100 ); + SCANF_TEST( 1, "foo bar", "%s", buffer ); + TESTCASE( memcmp( buffer, "foo\0", 4 ) == 0 ); +#ifndef TEST_CONVERSION_ONLY + SCANF_TEST( 2, "foo bar baz", "%s %s %n", buffer, buffer + 4, &u ); + TESTCASE( u == 9 ); + TESTCASE( memcmp( buffer, "foo\0bar\0", 8 ) == 0 ); +#endif + /* testing %[ */ + SCANF_TEST( 1, "abcdefg", "%[cba]", buffer ); + TESTCASE( memcmp( buffer, "abc\0", 4 ) == 0 ); + /* testing %p */ + p = NULL; + sprintf( buffer, "%p", p ); + p = &i; + SCANF_TEST( 1, buffer, "%p", &p ); + TESTCASE( p == NULL ); + p = &i; + sprintf( buffer, "%p", p ); + p = NULL; + SCANF_TEST( 1, buffer, "%p", &p ); + TESTCASE( p == &i ); +} |