feat:replace boost library with C++11 std library
This commit is contained in:
+399
@@ -0,0 +1,399 @@
|
||||
<HTML>
|
||||
<HEAD><TITLE>APR Design Document</TITLE></HEAD>
|
||||
<BODY>
|
||||
<h1>Design of APR</h1>
|
||||
|
||||
<p>The Apache Portable Run-time libraries have been designed to provide a common
|
||||
interface to low level routines across any platform. The original goal of APR
|
||||
was to combine all code in Apache to one common code base. This is not the
|
||||
correct approach however, so the goal of APR has changed. There are places
|
||||
where common code is not a good thing. For example, how to map requests
|
||||
to either threads or processes should be platform specific. APR's place
|
||||
is now to combine any code that can be safely combined without sacrificing
|
||||
performance.</p>
|
||||
|
||||
<p>To this end we have created a set of operations that are required for cross
|
||||
platform development. There may be other types that are desired and those
|
||||
will be implemented in the future.</p>
|
||||
|
||||
<p>This document will discuss the structure of APR, and how best to contribute
|
||||
code to the effort.</p>
|
||||
|
||||
<h2>APR On Windows and Netware</h2>
|
||||
|
||||
<p>APR on Windows and Netware is different from APR on all other systems,
|
||||
because those platforms don't use autoconf. On Unix, apr_private.h (private to
|
||||
APR) and apr.h (public, used by applications that use APR) are generated by
|
||||
autoconf from acconfig.h and apr.h.in respectively. On Windows (and Netware),
|
||||
apr_private.h and apr.h are created from apr_private.hw (apr_private.hwn)
|
||||
and apr.hw (apr.hwn) respectively.</p>
|
||||
|
||||
<p> <strong>
|
||||
If you add code to acconfig.h or tests to configure.in or aclocal.m4,
|
||||
please give some thought to whether or not Windows and Netware need
|
||||
these additions as well. A general rule of thumb, is that if it is
|
||||
a feature macro, such as APR_HAS_THREADS, Windows and Netware need it.
|
||||
In other words, if the definition is going to be used in a public APR
|
||||
header file, such as apr_general.h, Windows needs it.
|
||||
|
||||
The only time it is safe to add a macro or test without also adding
|
||||
the macro to apr*.h[n]w, is if the macro tells APR how to build. For
|
||||
example, a test for a header file does not need to be added to Windows.
|
||||
</strong></p>
|
||||
|
||||
<h2>APR Features</h2>
|
||||
|
||||
<p>One of the goals of APR is to provide a common set of features across all
|
||||
platforms. This is an admirable goal, it is also not realistic. We cannot
|
||||
expect to be able to implement ALL features on ALL platforms. So we are
|
||||
going to do the next best thing. Provide a common interface to ALL APR
|
||||
features on MOST platforms.</p>
|
||||
|
||||
<p>APR developers should create FEATURE MACROS for any feature that is not
|
||||
available on ALL platforms. This should be a simple definition which has
|
||||
the form:</p>
|
||||
|
||||
<code>APR_HAS_FEATURE</code>
|
||||
|
||||
<p>This macro should evaluate to true if APR has this feature on this platform.
|
||||
For example, Linux and Windows have mmap'ed files, and APR is providing an
|
||||
interface for mmapp'ing a file. On both Linux and Windows, APR_HAS_MMAP
|
||||
should evaluate to one, and the ap_mmap_* functions should map files into
|
||||
memory and return the appropriate status codes.</p>
|
||||
|
||||
<p>If your OS of choice does not have mmap'ed files, APR_HAS_MMAP should
|
||||
evaluate to zero, and all ap_mmap_* functions should not be defined. The
|
||||
second step is a precaution that will allow us to break at compile time if a
|
||||
programmer tries to use unsupported functions.</p>
|
||||
|
||||
<h2>APR types</h2>
|
||||
|
||||
<p>The base types in APR</p>
|
||||
|
||||
<ul>
|
||||
<li>dso<br>
|
||||
Shared library routines
|
||||
<li>mmap<br>
|
||||
Memory-mapped files
|
||||
<li>poll<br>
|
||||
Polling I/O
|
||||
<li>time<br>
|
||||
Time
|
||||
<li>user<br>
|
||||
Users and groups
|
||||
<li>locks<br>
|
||||
Process and thread locks (critical sections)
|
||||
<li>shmem<br>
|
||||
Shared memory
|
||||
<li>file_io<br>
|
||||
File I/O, including pipes
|
||||
<li>atomic<br>
|
||||
Atomic integer operations
|
||||
<li>strings<br>
|
||||
String handling routines
|
||||
<li>memory<br>
|
||||
Pool-based memory allocation
|
||||
<li>passwd<br>
|
||||
Reading passwords from the terminal
|
||||
<li>tables<br>
|
||||
Tables and hashes
|
||||
<li>network_io<br>
|
||||
Network I/O
|
||||
<li>threadproc<br>
|
||||
Threads and processes
|
||||
<li>misc<br>
|
||||
Any APR type which doesn't have any other place to belong. This
|
||||
should be used sparingly.
|
||||
<li>support<br>
|
||||
Functions meant to be used across multiple APR types. This area
|
||||
is for internal functions only. If a function is exposed, it should
|
||||
not be put here.
|
||||
</ul>
|
||||
|
||||
<h2>Directory Structure</h2>
|
||||
|
||||
<p>Each type has a base directory. Inside this base directory, are
|
||||
subdirectories, which contain the actual code. These subdirectories are named
|
||||
after the platforms the are compiled on. Unix is also used as a common
|
||||
directory. If the code you are writing is POSIX based, you should look at the
|
||||
code in the unix directory. A good rule of thumb, is that if more than half
|
||||
your code needs to be ifdef'ed out, and the structures required for your code
|
||||
are substantively different from the POSIX code, you should create a new
|
||||
directory.</p>
|
||||
|
||||
<p>Currently, the APR code is written for Unix, BeOS, Windows, and OS/2. An
|
||||
example of the directory structure is the file I/O directory:</p>
|
||||
|
||||
<pre>
|
||||
apr
|
||||
|
|
||||
-> file_io
|
||||
|
|
||||
-> unix The Unix and common base code
|
||||
|
|
||||
-> win32 The Windows code
|
||||
|
|
||||
-> os2 The OS/2 code
|
||||
</pre>
|
||||
|
||||
<p>Obviously, BeOS does not have a directory. This is because BeOS is currently
|
||||
using the Unix directory for it's file_io.</p>
|
||||
|
||||
<p>There are a few special top level directories. These are test and include.
|
||||
Test is a directory which stores all test programs. It is expected
|
||||
that if a new type is developed, there will also be a new test program, to
|
||||
help people port this new type to different platforms. A small document
|
||||
describing how to create new tests that integrate with the test suite can be
|
||||
found in the test/ directory. Include is a directory which stores all
|
||||
required APR header files for external use.</p>
|
||||
|
||||
<h2>Creating an APR Type</h2>
|
||||
|
||||
<p>The current design of APR requires that most APR types be incomplete.
|
||||
It is not possible to write flexible portable code if programs can access
|
||||
the internals of APR types. This is because different platforms are
|
||||
likely to define different native types. There are only two exceptions to
|
||||
this rule:</p>
|
||||
|
||||
<ul>
|
||||
<li>The first exception to this rule is if the type can only reasonably be
|
||||
implemented one way. For example, time is a complete type because there
|
||||
is only one reasonable time implementation.
|
||||
|
||||
<li>The second exception to the incomplete type rule can be found in
|
||||
apr_portable.h. This file defines the native types for each platform.
|
||||
Using these types, it is possible to extract native types for any APR type.</p>
|
||||
</ul>
|
||||
|
||||
<p>For this reason, each platform defines a structure in their own directories.
|
||||
Those structures are then typedef'ed in an external header file. For example
|
||||
in file_io/unix/fileio.h:</p>
|
||||
|
||||
<pre>
|
||||
struct ap_file_t {
|
||||
apr_pool_t *cntxt;
|
||||
int filedes;
|
||||
FILE *filehand;
|
||||
...
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>In include/apr_file_io.h:</p>
|
||||
</pre>
|
||||
typedef struct ap_file_t ap_file_t;
|
||||
</pre>
|
||||
|
||||
<p> This will cause a compiler error if somebody tries to access the filedes
|
||||
field in this structure. Windows does not have a filedes field, so obviously,
|
||||
it is important that programs not be able to access these.</p>
|
||||
|
||||
<p>You may notice the apr_pool_t field. Most APR types have this field. This
|
||||
type is used to allocate memory within APR. Because every APR type has a pool,
|
||||
any APR function can allocate memory if it needs to. This is very important
|
||||
and it is one of the reasons that APR works. If you create a new type, you
|
||||
must add a pool to it. If you do not, then all functions that operate on that
|
||||
type will need a pool argument.</p>
|
||||
|
||||
<h2>New Function</h2>
|
||||
|
||||
<p>When creating a new function, please try to adhere to these rules.</p>
|
||||
|
||||
<ul>
|
||||
<li> Result arguments should be the first arguments.
|
||||
<li> If a function needs a pool, it should be the last argument.
|
||||
<li> These rules are flexible, especially if it makes the code easier
|
||||
to understand because it mimics a standard function.
|
||||
</ul>
|
||||
|
||||
<h2>Documentation</h2>
|
||||
|
||||
<p>Whenever a new function is added to APR, it MUST be documented. New
|
||||
functions will not be committed unless there are docs to go along with them.
|
||||
The documentation should be a comment block above the function in the header
|
||||
file.</p>
|
||||
|
||||
<p>The format for the comment block is:</p>
|
||||
|
||||
<pre>
|
||||
/**
|
||||
* Brief description of the function
|
||||
* @param parma_1_name explanation
|
||||
* @param parma_2_name explanation
|
||||
* @param parma_n_name explanation
|
||||
* @tip Any extra information people should know.
|
||||
* @deffunc function prototype if required
|
||||
*/
|
||||
</pre>
|
||||
|
||||
<p>For an actual example, look at any file in the include directory. The
|
||||
reason the docs are in the header files is to ensure that the docs always
|
||||
reflect the current code. If you change parameters or return values for a
|
||||
function, please be sure to update the documentation.</p>
|
||||
|
||||
<h2>APR Error reporting</h2>
|
||||
|
||||
<p>Most APR functions should return an ap_status_t type. The only time an
|
||||
APR function does not return an ap_status_t is if it absolutely CAN NOT
|
||||
fail. Examples of this would be filling out an array when you know you are
|
||||
not beyond the array's range. If it cannot fail on your platform, but it
|
||||
could conceivably fail on another platform, it should return an ap_status_t.
|
||||
Unless you are sure, return an ap_status_t.</p>
|
||||
|
||||
<strong>
|
||||
This includes functions that return TRUE/FALSE values. How that
|
||||
is handled is discussed below
|
||||
</strong>
|
||||
|
||||
<p>All platforms return errno values unchanged. Each platform can also have
|
||||
one system error type, which can be returned after an offset is added.
|
||||
There are five types of error values in APR, each with its own offset.</p>
|
||||
|
||||
<!-- This should be turned into a table, but I am lazy today -->
|
||||
<pre>
|
||||
Name Purpose
|
||||
0) This is 0 for all platforms and isn't really defined
|
||||
anywhere, but it is the offset for errno values.
|
||||
(This has no name because it isn't actually defined,
|
||||
but for completeness we are discussing it here).
|
||||
|
||||
1) APR_OS_START_ERROR This is platform dependent, and is the offset at which
|
||||
APR errors start to be defined. Error values are
|
||||
defined as anything which caused the APR function to
|
||||
fail. APR errors in this range should be named
|
||||
APR_E* (i.e. APR_ENOSOCKET)
|
||||
|
||||
2) APR_OS_START_STATUS This is platform dependent, and is the offset at which
|
||||
APR status values start. Status values do not indicate
|
||||
success or failure, and should be returned if
|
||||
APR_SUCCESS does not make sense. APR status codes in
|
||||
this range should be name APR_* (i.e. APR_DETACH)
|
||||
|
||||
4) APR_OS_START_USEERR This is platform dependent, and is the offset at which
|
||||
APR apps can begin to add their own error codes.
|
||||
|
||||
3) APR_OS_START_SYSERR This is platform dependent, and is the offset at which
|
||||
system error values begin.
|
||||
</pre>
|
||||
|
||||
<strong>The difference in naming between APR_OS_START_ERROR and
|
||||
APR_OS_START_STATUS mentioned above allows programmers to easily determine if
|
||||
the error code indicates an error condition or a status condition.</strong>
|
||||
|
||||
<p>If your function has multiple return codes that all indicate success, but
|
||||
with different results, or if your function can only return PASS/FAIL, you
|
||||
should still return an apr_status_t. In the first case, define one
|
||||
APR status code for each return value, an example of this is
|
||||
<code>apr_proc_wait</code>, which can only return APR_CHILDDONE,
|
||||
APR_CHILDNOTDONE, or an error code. In the second case, please return
|
||||
APR_SUCCESS for PASS, and define a new APR status code for failure, an
|
||||
example of this is <code>apr_compare_users</code>, which can only return
|
||||
APR_SUCCESS, APR_EMISMATCH, or an error code.</p>
|
||||
|
||||
<p>All of these definitions can be found in apr_errno.h for all platforms. When
|
||||
an error occurs in an APR function, the function must return an error code.
|
||||
If the error occurred in a system call and that system call uses errno to
|
||||
report an error, then the code is returned unchanged. For example: </p>
|
||||
|
||||
<pre>
|
||||
if (open(fname, oflags, 0777) < 0)
|
||||
return errno;
|
||||
</pre>
|
||||
|
||||
<p>The next place an error can occur is a system call that uses some error value
|
||||
other than the primary error value on a platform. This can also be handled
|
||||
by APR applications. For example:</p>
|
||||
|
||||
<pre>
|
||||
if (CreateFile(fname, oflags, sharemod, NULL,
|
||||
createflags, attributes, 0) == INVALID_HANDLE_VALUE
|
||||
return (GetLAstError() + APR_OS_START_SYSERR);
|
||||
</pre>
|
||||
|
||||
<p>These two examples implement the same function for two different platforms.
|
||||
Obviously even if the underlying problem is the same on both platforms, this
|
||||
will result in two different error codes being returned. This is OKAY, and
|
||||
is correct for APR. APR relies on the fact that most of the time an error
|
||||
occurs, the program logs the error and continues, it does not try to
|
||||
programatically solve the problem. This does not mean we have not provided
|
||||
support for programmatically solving the problem, it just isn't the default
|
||||
case. We'll get to how this problem is solved in a little while.</p>
|
||||
|
||||
<p>If the error occurs in an APR function but it is not due to a system call,
|
||||
but it is actually an APR error or just a status code from APR, then the
|
||||
appropriate code should be returned. These codes are defined in apr_errno.h
|
||||
and should be self explanatory.</p>
|
||||
|
||||
<p>No APR code should ever return a code between APR_OS_START_USEERR and
|
||||
APR_OS_START_SYSERR, those codes are reserved for APR applications.</p>
|
||||
|
||||
<p>To programmatically correct an error in a running application, the error
|
||||
codes need to be consistent across platforms. This should make sense. APR
|
||||
has provided macros to test for status code equivalency. For example, to
|
||||
determine if the code that you received from the APR function means EOF, you
|
||||
would use the macro APR_STATUS_IS_EOF().</p>
|
||||
|
||||
<p>Why did APR take this approach? There are two ways to deal with error
|
||||
codes portably.</p>
|
||||
|
||||
<ol type=1>
|
||||
<li> Return the same error code across all platforms.
|
||||
<li> Return platform specific error codes and convert them when necessary.
|
||||
</ol>
|
||||
|
||||
<p>The problem with option number one is that it takes time to convert error
|
||||
codes to a common code, and most of the time programs want to just output
|
||||
an error string. If we convert all errors to a common subset, we have four
|
||||
steps to output an error string:</p>
|
||||
|
||||
<p>The second problem with option 1, is that it is a lossy conversion. For
|
||||
example, Windows and OS/2 have a couple hundred error codes, but POSIX errno
|
||||
only defines about 50 errno values. This means that if we convert to a
|
||||
canonical error value immediately, there is no way for the programmer to
|
||||
get the actual system error.</p>
|
||||
|
||||
<pre>
|
||||
make syscall that fails
|
||||
convert to common error code step 1
|
||||
return common error code
|
||||
check for success
|
||||
call error output function step 2
|
||||
convert back to system error step 3
|
||||
output error string step 4
|
||||
</pre>
|
||||
|
||||
<p>By keeping the errors platform specific, we can output error strings in two
|
||||
steps.</p>
|
||||
|
||||
<pre>
|
||||
make syscall that fails
|
||||
return error code
|
||||
check for success
|
||||
call error output function step 1
|
||||
output error string step 2
|
||||
</pre>
|
||||
|
||||
<p>Less often, programs change their execution based on what error was returned.
|
||||
This is no more expensive using option 2 than it is using option 1, but we
|
||||
put the onus of converting the error code on the programmer themselves.
|
||||
For example, using option 1:</p>
|
||||
|
||||
<pre>
|
||||
make syscall that fails
|
||||
convert to common error code
|
||||
return common error code
|
||||
decide execution based on common error code
|
||||
</pre>
|
||||
|
||||
<p>Using option 2:</p>
|
||||
|
||||
<pre>
|
||||
make syscall that fails
|
||||
return error code
|
||||
convert to common error code (using ap_canonical_error)
|
||||
decide execution based on common error code
|
||||
</pre>
|
||||
|
||||
<p>Finally, there is one more operation on error codes. You can get a string
|
||||
that explains in human readable form what has happened. To do this using
|
||||
APR, call ap_strerror().</p>
|
||||
|
||||
@@ -0,0 +1,156 @@
|
||||
<HTML>
|
||||
<HEAD><TITLE>APR Canonical Filenames</TITLE></HEAD>
|
||||
<BODY>
|
||||
<h1>APR Canonical Filename</h1>
|
||||
|
||||
<h2>Requirements</h2>
|
||||
|
||||
<p>APR porters need to address the underlying discrepancies between
|
||||
file systems. To achieve a reasonable degree of security, the
|
||||
program depending upon APR needs to know that two paths may be
|
||||
compared, and that a mismatch is guaranteed to reflect that the
|
||||
two paths do not return the same resource</p>.
|
||||
|
||||
<p>The first discrepancy is in volume roots. Unix and pure derivatives
|
||||
have only one root path, "/". Win32 and OS2 share root paths of
|
||||
the form "D:/", D: is the volume designation. However, this can
|
||||
be specified as "//./D:/" as well, indicating D: volume of the
|
||||
'this' machine. Win32 and OS2 also may employ a UNC root path,
|
||||
of the form "//server/share/" where share is a share-point of the
|
||||
specified network server. Finally, NetWare root paths are of the
|
||||
form "server/volume:/", or the simpler "volume:/" syntax for 'this'
|
||||
machine. All these non-Unix file systems accept volume:path,
|
||||
without a slash following the colon, as a path relative to the
|
||||
current working directory, which APR will treat as ambiguous, that
|
||||
is, neither an absolute nor a relative path per se.</p>
|
||||
|
||||
<p>The second discrepancy is in the meaning of the 'this' directory.
|
||||
In general, 'this' must be eliminated from the path where it occurs.
|
||||
The syntax "path/./" and "path/" are both aliases to path. However,
|
||||
this isn't file system independent, since the double slash "//" has
|
||||
a special meaning on OS2 and Win32 at the start of the path name,
|
||||
and is invalid on those platforms before the "//server/share/" UNC
|
||||
root path is completed. Finally, as noted above, "//./volume/" is
|
||||
legal root syntax on WinNT, and perhaps others.</p>
|
||||
|
||||
<p>The third discrepancy is in the context of the 'parent' directory.
|
||||
When "parent/path/.." occurs, the path must be unwound to "parent".
|
||||
It's also critical to simply truncate leading "/../" paths to "/",
|
||||
since the parent of the root is root. This gets tricky on the
|
||||
Win32 and OS2 platforms, since the ".." element is invalid before
|
||||
the "//server/share/" is complete, and the "//server/share/../"
|
||||
sequence is the complete UNC root "//server/share/". In relative
|
||||
paths, leading ".." elements are significant, until they are merged
|
||||
with an absolute path. The relative form must only retain the ".."
|
||||
segments as leading segments, to be resolved once merged to another
|
||||
relative or an absolute path.</p>
|
||||
|
||||
<p>The fourth discrepancy occurs with acceptance of alternate character
|
||||
codes for the same element. Path separators are not retained within
|
||||
the APR canonical forms. The OS filesystem and APR (slashed) forms
|
||||
can both be returned as strings, to be used in the proper context.
|
||||
Unix, Win32 and Netware all accept slashes and backslashes as the
|
||||
same path separator symbol, although unix strictly accepts slashes.
|
||||
While the APR form of the name strictly uses slashes, always consider
|
||||
that there could be a platform that actually accepts slashes as a
|
||||
character within a segment name.</p>
|
||||
|
||||
<p>The fifth and worst discrepancy plagues Win32, OS2, Netware, and some
|
||||
filesystems mounted in Unix. Case insensitivity can permit the same
|
||||
file to slip through in both it's proper case and alternate cases.
|
||||
Simply changing the case is insufficient for any character set beyond
|
||||
ASCII, since various dialectic forms of characters suffer from one to
|
||||
many or many to one translations. An example would be u-umlaut, which
|
||||
might be accepted as a single character u-umlaut, a two character
|
||||
sequence u and the zero-width umlaut, the upper case form of the same,
|
||||
or perhaps even a capital U alone. This can be handled in different
|
||||
ways depending on the purposes of the APR based program, but the one
|
||||
requirement is that the path must be absolute in order to resolve these
|
||||
ambiguities. Methods employed include comparison of device and inode
|
||||
file uniqifiers, which is a fairly fast operation, or querying the OS
|
||||
for the true form of the name, which can be much slower. Only the
|
||||
acknowledgement of the file names by the OS can validate the equality
|
||||
of two different cases of the same filename.</p>
|
||||
|
||||
<p>The sixth discrepancy, illegal or insignificant characters, is especially
|
||||
significant in non-unix file systems. Trailing periods are accepted
|
||||
but never stored, therefore trailing periods must be ignored for any
|
||||
form of comparison. And all OS's have certain expectations of what
|
||||
characters are illegal (or undesirable due to confusion.)</p>
|
||||
|
||||
<p>A final warning, canonical functions don't transform or resolve case
|
||||
or character ambiguity issues until they are resolved into an absolute
|
||||
path. The relative canonical path, while useful, while useful for URL
|
||||
or similar identifiers, cannot be used for testing or comparison of file
|
||||
system objects.</p>
|
||||
|
||||
<hr>
|
||||
|
||||
<h2>Canonical API</h2>
|
||||
|
||||
Functions to manipulate the apr_canon_file_t (an opaque type) include:
|
||||
|
||||
<ul>
|
||||
<li>Create canon_file_t (from char* path and canon_file_t parent path)
|
||||
<li>Merged canon_file_t (from path and parent, both canon_file_t)
|
||||
<li>Get char* path of all or some segments
|
||||
<li>Get path flags of IsRelative, IsVirtualRoot, and IsAbsolute
|
||||
<li>Compare two canon_file_t structures for file equality
|
||||
</ul>
|
||||
|
||||
<p>The path is corrected to the file system case only if is in absolute
|
||||
form. The apr_canon_file_t should be preserved as long as possible and
|
||||
used as the parent to create child entries to reduce the number of expensive
|
||||
stat and case canonicalization calls to the OS.</p>
|
||||
|
||||
<p>The comparison operation provides that the APR can postpone correction
|
||||
of case by simply relying upon the device and inode for equivalence. The
|
||||
stat implementation provides that two files are the same, while their
|
||||
strings are not equivalent, and eliminates the need for the operating
|
||||
system to return the proper form of the name.</p>
|
||||
|
||||
<p>In any case, returning the char* path, with a flag to request the proper
|
||||
case, forces the OS calls to resolve the true names of each segment. Where
|
||||
there is a penalty for this operation and the stat device and inode test
|
||||
is faster, case correction is postponed until the char* result is requested.
|
||||
On platforms that identify the inode, device, or proper name interchangably
|
||||
with no penalties, this may occur when the name is initially processed.</p>
|
||||
|
||||
<hr>
|
||||
|
||||
<h2>Unix Example</h2>
|
||||
|
||||
<p>First the simplest case:</p>
|
||||
|
||||
<pre>
|
||||
Parse Canonical Name
|
||||
accepts parent path as canonical_t
|
||||
this path as string
|
||||
|
||||
Split this path Segments on '/'
|
||||
|
||||
For each of this path Segments
|
||||
If first Segment
|
||||
If this Segment is Empty ([nothing]/)
|
||||
Append this Root Segment (don't merge)
|
||||
Continue to next Segment
|
||||
Else is relative
|
||||
Append parent Segments (to merge)
|
||||
Continue with this Segment
|
||||
If Segment is '.' or empty (2 slashes)
|
||||
Discard this Segment
|
||||
Continue with next Segment
|
||||
If Segment is '..'
|
||||
If no previous Segment or previous Segment is '..'
|
||||
Append this Segment
|
||||
Continue with next Segment
|
||||
If previous Segment and previous is not Root Segment
|
||||
Discard previous Segment
|
||||
Discard this Segment
|
||||
Continue with next Segment
|
||||
Append this Relative Segment
|
||||
Continue with next Segment
|
||||
</pre>
|
||||
|
||||
</BODY>
|
||||
</HTML>
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
PROJECT_NAME="Apache Portable Runtime"
|
||||
|
||||
INPUT=.
|
||||
QUIET=YES
|
||||
RECURSIVE=YES
|
||||
FILE_PATTERNS=*.h
|
||||
|
||||
OUTPUT_DIRECTORY=docs/dox
|
||||
|
||||
MACRO_EXPANSION=YES
|
||||
EXPAND_ONLY_PREDEF=YES
|
||||
#EXPAND_AS_DEFINED=
|
||||
# not sure why this doesn't work as EXPAND_AS_DEFINED, it should!
|
||||
PREDEFINED="APR_DECLARE(x)=x" \
|
||||
"APR_DECLARE_NONSTD(x)=x" \
|
||||
"APR_DECLARE_DATA" \
|
||||
"APR_POOL_DECLARE_ACCESSOR(x)=apr_pool_t* apr_##x##_pool_get (const apr_##x##_t *the##x)" \
|
||||
"APR_DECLARE_INHERIT_SET(x)=apr_status_t apr_##x##_inherit_set(apr_##x##_t *the##x)" \
|
||||
"APR_DECLARE_INHERIT_UNSET(x)=apr_status_t apr_##x##_inherit_unset(apr_##x##_t *the##x)" \
|
||||
"APR_HAS_THREADS" \
|
||||
"__attribute__(x)=" \
|
||||
DOXYGEN=
|
||||
|
||||
OPTIMIZE_OUTPUT_FOR_C=YES
|
||||
STRIP_CODE_COMMENTS=NO
|
||||
|
||||
FULL_PATH_NAMES=NO
|
||||
CASE_SENSE_NAMES=NO
|
||||
# some autoconf guru needs to make configure set this correctly...
|
||||
# in the meantime, simply listing the headers should be alright
|
||||
#STRIP_FROM_PATH=/buildpath/apr
|
||||
|
||||
EXCLUDE_PATTERNS="*/acconfig.h" \
|
||||
"*/test/*" \
|
||||
"*/arch/*"
|
||||
|
||||
GENERATE_TAGFILE=docs/dox/apr.tag
|
||||
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
The question has been asked multiple times, "Why is APR using Incomplete
|
||||
types?" This document will try to explain that.
|
||||
|
||||
Incomplete types are used in APR because they can enforce portability, and
|
||||
they make the APR developers job easier, as well as allowing APR to use native
|
||||
types on all platforms. Imagine a scenario where APR wasn't using incomplete
|
||||
types. The ap_file_t type would have to be defined as:
|
||||
|
||||
typedef struct ap_file_t {
|
||||
ap_pool_t *pool
|
||||
char *fname;
|
||||
int eof_hit;
|
||||
int pipe;
|
||||
ap_interval_time_t timeout;
|
||||
#ifdef WIN32
|
||||
HANDLE file_handle;
|
||||
DWORD dwFileAttributes;
|
||||
#elif defined(OS2)
|
||||
HFILE filedes;
|
||||
HEV PipeSem
|
||||
#else
|
||||
int filedes;
|
||||
int ungetchar;
|
||||
#endif
|
||||
|
||||
#ifndef WIN32
|
||||
int buffered;
|
||||
ap_int32_flags
|
||||
int isopen;
|
||||
|
||||
/* Stuff for buffered mode */
|
||||
char *buffer;
|
||||
int bufpos;
|
||||
unsigned long dataRead;
|
||||
int direction;
|
||||
unsigned long filePtr;
|
||||
ap_lock_t *mutex;
|
||||
#endif
|
||||
} ap_file_t;
|
||||
|
||||
This captures the essence of what is currently being defined for ap_file_t
|
||||
using incomplete types. However, using this structure leads developers to
|
||||
believe that they are safe accessing any of the fields in this structure.
|
||||
This is not true. On some platforms, such as Windows, about half of the
|
||||
structure disappears. We could combine some of these definitions with
|
||||
macros, for example:
|
||||
|
||||
#ifdef WIN32
|
||||
#define filetype HANDLE
|
||||
#elif OS2
|
||||
#define filetype HFILE
|
||||
#else
|
||||
#define filetype int
|
||||
#endif
|
||||
|
||||
And then in the definition for ap_file_t, we could say:
|
||||
filetype filedes;
|
||||
|
||||
This gets rid of some of the complexity, by moving it off to the side, but
|
||||
it is still not safe for a programmers to access the filedes field directly
|
||||
outside of APR, because the programmer has no way of knowing what the actual
|
||||
type is. So for example printing the filedes using printf would yield wildly
|
||||
varying results on Windows and OS2 when compared to Unix.
|
||||
|
||||
Another option also presents itself. Stick strictly to POSIX. This means
|
||||
that all code can be shared on any POSIX compliant platform. The problem
|
||||
with this is performance. One of the benefits to APR, is that it allows
|
||||
developers to easily use native types on all platforms with the same code.
|
||||
This has proven to provide a substantial performance boost on most non-Unix
|
||||
platforms.
|
||||
|
||||
Having said all of that, sometimes incomplete types just don't make sense.
|
||||
For example, the first implementation of time functions used incomplete types,
|
||||
which added a layer of complexity that turned out to be unnecessary. If
|
||||
a platform cannot provide a simple number that represents the number of seconds
|
||||
elapsed since a specified date and time, then APR doesn't really want to
|
||||
provide support for that platform.
|
||||
|
||||
APR is trying hard to provide a balance of incomplete and complete types,
|
||||
but like all things, sometimes the developers make mistakes. If you are
|
||||
using APR and find that there is an incomplete type that doesn't need to be
|
||||
an incomplete type, please let us know, we are more than willing to listen
|
||||
and design parts of APR that do not use incomplete types.
|
||||
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
How do I use APR'ized programs in connection with programs that don't
|
||||
use APR? These darn incomplete types don't let me fill out the APR types.
|
||||
|
||||
The APR developers acknowledge that most programs are not using APR, and
|
||||
we don't expect them to migrate to using APR just because APR has been
|
||||
released. So, we have provided a way for non-APR'ized programs to interact
|
||||
very cleanly with APR.
|
||||
|
||||
There are a set of functions, all documented in apr_portable.h, which allow
|
||||
a programmer to either get a native type from an APR type, or to setup an
|
||||
APR type from a native type.
|
||||
|
||||
For example, if you are writing an add-on to another program that does not use
|
||||
APR for file I/O, but you (in your infinite wisdom) want to use APR to make
|
||||
sure your section is portable. Assume the program provides a type foo_t with
|
||||
a file descriptor in it (fd).
|
||||
|
||||
void function_using_apr(foo_t non_apr_struct, ap_pool_t *p)
|
||||
{
|
||||
ap_file_t *apr_file = NULL;
|
||||
|
||||
ap_put_os_file(&apr_file, &non_apr_struct->fd, p);
|
||||
|
||||
...
|
||||
}
|
||||
|
||||
There are portable functions for each APR incomplete type. They are all
|
||||
called ap_put_os_foobar(), and they each take the same basic arguments, a
|
||||
pointer to a pointer to the incomplete type (the last pointer in that list
|
||||
should be NULL), a pointer to the native type, and a pool. Each of these can
|
||||
be found in apr_portable.h.
|
||||
|
||||
If you have to do the exact opposite (take an APR type and convert it to a
|
||||
native type, there are functions for that too. For example:
|
||||
|
||||
void function_not_using_apr(apr_file_t *apr_file)
|
||||
{
|
||||
int unix_file_desc;
|
||||
|
||||
ap_get_os_file(&unix_file_desc, apr_file);
|
||||
|
||||
...
|
||||
}
|
||||
|
||||
For each ap_put_os_foobar, there is a corresponding ap_get_os_file. These are
|
||||
also documented in apr_portable.h.
|
||||
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html><head>
|
||||
<title>Using APR Pools</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Using APR Pools</h1>
|
||||
|
||||
<p>
|
||||
From <a href="http://subversion.tigris.org/">Subversion</a>, we
|
||||
have learned a <em>lot</em> about how to use pools in a heavily
|
||||
structured/object-based environment.
|
||||
<a href="http://httpd.apache.org/">Apache httpd</a> is a
|
||||
completely different beast: "allocate a request pool. use
|
||||
it. destroy it."
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In a complex app, that request-style of behavior is not
|
||||
present. Luckily, the "proper" use of pools can be described in
|
||||
just a few rules:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
Objects should not have their own pools. An object is
|
||||
allocated into a pool defined by the constructor's caller. The
|
||||
<strong>caller</strong> knows the lifetime of the object and
|
||||
will manage it via the pool. Generally, this also means that
|
||||
objects will not have a "close" or a "free" since those
|
||||
operations will happen implicitly as part of the destruction
|
||||
of the pool the objects live within.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<p>
|
||||
Functions should not create/destroy pools for their
|
||||
operation; they should use a pool provided by the
|
||||
caller. Again, the <strong>caller</strong> knows more about
|
||||
how the function will be used, how often, how many times,
|
||||
etc. Thus, it should be in charge of the function's memory
|
||||
usage.
|
||||
</p>
|
||||
<p>
|
||||
As an example, the caller might know that the app will exit
|
||||
upon the function's return. Thus, the function would be
|
||||
creating extra work if it built and destroyed a
|
||||
pool. Instead, it should use the passed-in pool, which the
|
||||
caller is going to be tossing as part of app-exit anyways.
|
||||
</p>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<p>
|
||||
Whenever an unbounded iteration occurs, a subpool should be
|
||||
used. The general pattern is:
|
||||
</p>
|
||||
<blockquote>
|
||||
<pre>
|
||||
subpool = apr_create_subpool(pool);
|
||||
for (i = 0; i < n; ++i) {
|
||||
apr_pool_clear(subpool);
|
||||
|
||||
do_operation(..., subpool);
|
||||
}
|
||||
apr_pool_destroy(subpool);</pre>
|
||||
</blockquote>
|
||||
<p>
|
||||
This pattern prevents the 'pool' from growing unbounded and
|
||||
consuming all of memory. Note that it is slightly more
|
||||
optimal to clear the pool on loop-entry. This pattern also
|
||||
allows for a '<tt>continue</tt>' to occur within the loop,
|
||||
yet still ensure the pool will be cleared.
|
||||
</p>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
Given all of the above, it is pretty well mandatory to pass a
|
||||
pool to <em>every</em> function. Since objects are not
|
||||
recording pools for themselves, and the caller is always
|
||||
supposed to be managing memory, then each function needs a
|
||||
pool, rather than relying on some hidden magic pool. In
|
||||
limited cases, objects may record the pool used for their
|
||||
construction so that they can construct sub-parts, but these
|
||||
cases should be examined carefully. Internal pools can lead to
|
||||
unbounded pool usage if the object is not careful.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<hr>
|
||||
<address>Greg Stein</address>
|
||||
<!-- Created: Wed Jun 25 14:39:57 PDT 2003 -->
|
||||
<!-- hhmts start -->
|
||||
Last modified: Wed Jun 25 14:50:19 PDT 2003
|
||||
<!-- hhmts end -->
|
||||
|
||||
</body></html>
|
||||
@@ -0,0 +1,57 @@
|
||||
<HTML>
|
||||
<HEAD><TITLE>APR Win32 Builds and Debugging</TITLE></HEAD>
|
||||
<BODY>
|
||||
<h1>APR Win32 Builds and Debugging</h1>
|
||||
|
||||
<h2>Configuration and Flavors</h2>
|
||||
|
||||
<p>The Win32 APR Developer Studio projects consist of</p>
|
||||
|
||||
<dl>
|
||||
<dt>apr/apr.dsp</dt>
|
||||
<dd>Builds the static apr.lib library (-D APR_DECLARE_STATIC)</dd>
|
||||
<dt>apr/libapr.dsp</dt>
|
||||
<dd>Builds the dynamic libapr.dll library (no define required)</dd>
|
||||
<dt>apr-util/aprutil.dsp</dt>
|
||||
<dd>Builds the static aprutil.lib library (-D APU_DECLARE_STATIC)</dd>
|
||||
<dt>apr-util/libaprutil.dsp</dt>
|
||||
<dd>Builds the dynamic libaprutil.dll library (no define required)</dd>
|
||||
<dt>apr-iconv/apriconv.dsp</dt>
|
||||
<dd>Builds the static apriconv.lib library (-D API_DECLARE_STATIC)</dd>
|
||||
<dt>apr-iconv/libapriconv.dsp</dt>
|
||||
<dd>Builds the dynamic libapriconv.dll library (no define required)</dd>
|
||||
</dl>
|
||||
|
||||
<p>In order to prepare to use one of the <em>static</em> libraries above,
|
||||
your application must be compiled with the define shown above, so that the
|
||||
correct linkage is created. The APR authors intended the use of dynamic
|
||||
libraries by default, so application authors do not need any special
|
||||
defines in order to link to the dynamic library flavors.</p>
|
||||
|
||||
<p>In order to build APR, you must use the proper dependencies. A good
|
||||
example of those dependencies is given in the apr-util/aprutil.dsw
|
||||
Developer Studio workspace. You can borrow the parts of that structure
|
||||
your application needs, that workspace defines both the dynamic and static
|
||||
library dependencies.</p>
|
||||
|
||||
<p>The APR libraries (dynamic and static) are compiled with debugging symbols,
|
||||
even in Release builds. The dynamic library symbols are always usable,
|
||||
simply keep the correspond .pdb file in the same path as the library .dll.
|
||||
(E.g. both libapr.dll and libapr.pdb should be copied to the same path.)</p>
|
||||
|
||||
<p>The static symbols will only be fully usable if your application does <em>not<em>
|
||||
link with the /pdbtype:sept flag! At the time your application links to
|
||||
an APR library, the corresponding _src.pdb file should exist in the original
|
||||
path the library was built, or it may be sufficient to keep the _src.pdb file
|
||||
in the same path as the library file. (E.g. apr.lib and apr_src.pdb should
|
||||
reside together in your lib directory.) The later option is unconfirmed.</p>
|
||||
|
||||
<p>In order to keep the symbols compiled into the static library, your application
|
||||
must use the linker's /debug flag. If you do not want the application to be
|
||||
debuggable with its corresponding .pdb file, omit the /debug flag and all debug
|
||||
symbolic information is discarded. Note that your application can only be
|
||||
debugged with the corresponding .pdb file created by the linker, unless you use
|
||||
/debugtype:coff or /debugtype:both in your link options.</p>
|
||||
|
||||
</BODY>
|
||||
</HTML>
|
||||
Reference in New Issue
Block a user