177 lines
7.2 KiB
OpenEdge ABL
177 lines
7.2 KiB
OpenEdge ABL
[Foundation::] Foundation Module.
|
|
|
|
Starting up and shutting down.
|
|
|
|
@h Introduction.
|
|
The Foundation module supplies some of the conveniences of more modern
|
|
programming languages to ANSI C. It offers the usual stuff of standard
|
|
libraries everywhere: memory management, collection classes, filename
|
|
and file system accesss, regular-expression matching and so on. At one
|
|
time the higher-level material formed a second module called "Foundation
|
|
and Empire", but now it's all consolidated into a single everything-you-need
|
|
module. Almost all functionality is optional and can be ignored if not
|
|
wanted. With a few provisos, the code is thread-safe, sturdy and well
|
|
tested, since it forms the support code for the Inform programming
|
|
language's compiler and outlying tools, including Inweb itself. If you
|
|
need to write a command-line utility in ANSI C with no dependencies on
|
|
other tools or libraries to speak of, you could do worse.
|
|
|
|
To use |foundation|, the Contents section of a web should include:
|
|
= (text)
|
|
Import: foundation
|
|
=
|
|
before beginning the chapter rundown. There are then a few conventions
|
|
which must be followed. The |main| routine for the client should, as one
|
|
of its very first acts, call |Foundation::start()|, and should similarly, just
|
|
before it exits, call |Foundation::end()|. Any other module used should be
|
|
started after Foundation starts, and ended before Foundation ends.
|
|
|
|
In addition, the client's source code needs to define a few symbols to indicate
|
|
what it needs in the way of memory allocation. For an example, see the code
|
|
for Inweb itself.
|
|
|
|
@h Basic definitions.
|
|
These are all from the ANSI C standard library (or the pthread POSIX standard),
|
|
which means that Inweb will tangle them up to the top of the C source code.
|
|
Because pthread is not normally available on Windows, a special header is
|
|
supplied instead for that case.
|
|
|
|
= (very early code)
|
|
#include <ctype.h>
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#include <math.h>
|
|
#include <wchar.h>
|
|
|
|
@ =
|
|
text_stream *DL = NULL; /* Current destination of debugging text: kept |NULL| until opened */
|
|
|
|
@ We'll use three truth states, the third of which can also mean "unknown".
|
|
|
|
@d TRUE 1
|
|
@d FALSE 0
|
|
@d NOT_APPLICABLE 2
|
|
|
|
@ And we recognise two different encodings for narrow (i.e., |char *|) C strings.
|
|
|
|
@d UTF8_ENC 1 /* Write as UTF-8 without BOM */
|
|
@d ISO_ENC 2 /* Write as ISO Latin-1 (i.e., no conversion needed) */
|
|
|
|
@ It is assumed that our host filing system can manage at least 30-character
|
|
filenames, that space is legal as a character in a filename, and that trailing
|
|
extensions can be longer than 3 characters (in particular, that |.html| is
|
|
allowed). There are no clear rules but on Windows |MAX_PATH| can be as low as
|
|
260, and on Mac OS X the equivalent limit is 1024; both systems can house
|
|
files buried more deeply, but in both cases the user interface to the
|
|
operating system fails to recognise them. Some Linux implementations raise the
|
|
equivalent |PATH_MAX| limit as high as 4096. This seems a reasonable
|
|
compromise in practice:
|
|
|
|
@d MAX_FILENAME_LENGTH 1025
|
|
|
|
@ Very occasionally we'll store a pointer as data:
|
|
|
|
=
|
|
typedef long int pointer_sized_int;
|
|
|
|
@h The beginning and the end.
|
|
As noted above, the client needs to call these when starting up and when
|
|
shutting down.
|
|
|
|
The Inweb notation |[[textliterals]]| inserts declarations of I-literals,
|
|
that is, literal |text_stream *| values written as |I"strings"|. It should
|
|
never be used anywhere but here.
|
|
|
|
=
|
|
void Foundation::start(int argc, char **argv) {
|
|
CommandLine::set_locale(argc, argv);
|
|
Platform::configure_terminal();
|
|
Memory::start();
|
|
@<Register the default stream writers@>;
|
|
[[textliterals]];
|
|
Time::begin();
|
|
Pathnames::start();
|
|
@<Register the default debugging log aspects@>;
|
|
@<Register the default debugging log writers@>;
|
|
@<Register the default command line switches@>;
|
|
}
|
|
|
|
@ After calling |Foundation::start()|, the client can register further stream
|
|
writing routines, following these models: they define the meaning of escape
|
|
characters in |WRITE|, our version of formatted printing. |%f|, for example,
|
|
prints a filename by calling |Filenames::writer|.
|
|
|
|
@<Register the default stream writers@> =
|
|
Writers::register_writer('f', &Filenames::writer);
|
|
Writers::register_writer('p', &Pathnames::writer);
|
|
Writers::register_writer('v', &VersionNumbers::writer);
|
|
Writers::register_writer('S', &Streams::writer);
|
|
|
|
@ We provide a full logging service, in which different "aspects" can be
|
|
switched on or off. Each aspect represents an activity of the program about
|
|
which a narrative is printed, or not printed, to the debugging log file.
|
|
The following are always provided, but are all off by default.
|
|
|
|
@<Register the default debugging log aspects@> =
|
|
Log::declare_aspect(DEBUGGING_LOG_INCLUSIONS_DA, L"debugging log inclusions", FALSE, FALSE);
|
|
Log::declare_aspect(SHELL_USAGE_DA, L"shell usage", FALSE, FALSE);
|
|
Log::declare_aspect(MEMORY_USAGE_DA, L"memory usage", FALSE, FALSE);
|
|
Log::declare_aspect(TEXT_FILES_DA, L"text files", FALSE, FALSE);
|
|
|
|
@ Debugging log writers are similar to stream writers, but implement the |$|
|
|
escapes only available to the debugging log. For example, |$S| calls the
|
|
|Streams::log| function to print a textual representation of the current
|
|
state of a stream.
|
|
|
|
@<Register the default debugging log writers@> =
|
|
Writers::register_logger('a', &Tries::log_avinue);
|
|
Writers::register_logger('S', &Streams::log);
|
|
|
|
@ We provide an optional service for parsing the command line. By default,
|
|
the |-log A| switch makes that aspect active, though it's hyphenated, so
|
|
for example |-log memory-usage| or |-log no-memory-usage|. |-fixtime| is
|
|
used to ease automated testing: we don't want to reject the output from
|
|
some tool just because it contains today's date and not the date when the
|
|
test was set up. |-crash| tells the tool to crash on a fatal error, rather
|
|
than to exit cleanly, to make it easier to diagnose in a debugger.
|
|
|
|
@e LOG_CLSW from 0
|
|
@e VERSION_CLSW
|
|
@e CRASH_CLSW
|
|
@e HELP_CLSW
|
|
@e FIXTIME_CLSW
|
|
@e AT_CLSW
|
|
@e LOCALE_CLSW
|
|
|
|
@<Register the default command line switches@> =
|
|
CommandLine::begin_group(FOUNDATION_CLSG, NULL);
|
|
CommandLine::declare_switch(LOG_CLSW, L"log", 2,
|
|
L"write the debugging log to include diagnostics on X");
|
|
CommandLine::declare_switch(VERSION_CLSW, L"version", 1,
|
|
L"print out version number");
|
|
CommandLine::declare_boolean_switch(CRASH_CLSW, L"crash", 1,
|
|
L"intentionally crash on internal errors, for backtracing", FALSE);
|
|
CommandLine::declare_switch(HELP_CLSW, L"help", 1,
|
|
L"print this help information");
|
|
CommandLine::declare_boolean_switch(FIXTIME_CLSW, L"fixtime", 1,
|
|
L"pretend the time is 11 a.m. on 28 March 2016 for testing", FALSE);
|
|
CommandLine::declare_switch(AT_CLSW, L"at", 2,
|
|
L"specify that this tool is installed at X");
|
|
CommandLine::declare_switch(LOCALE_CLSW, L"locale", 2,
|
|
L"set locales as 'L=E', L being shell or console, E platform, utf-8 or iso-latin1");
|
|
CommandLine::end_group();
|
|
|
|
@ Once the following has been called, it is not safe to use any of the
|
|
|foundation| facilities. It should be called on any normal exit, but not on
|
|
an early termination due to a fatal error, as this may lead to thread
|
|
safety problems.
|
|
|
|
=
|
|
void Foundation::end(void) {
|
|
if (Log::aspect_switched_on(MEMORY_USAGE_DA)) Memory::log_statistics();
|
|
Log::close();
|
|
Memory::free();
|
|
}
|