forked from DevSolar/pdclib
-
Notifications
You must be signed in to change notification settings - Fork 8
/
Internals.txt
159 lines (127 loc) · 7.25 KB
/
Internals.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
Internals
=========
Namespacing
-----------
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.
Structure and Porting
---------------------
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 separate 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.
Internal Dependencies
---------------------
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.