foundation-module: Preliminaries: Nowebify.
This commit is contained in:
parent
dea875195b
commit
844b7f2148
1 changed files with 104 additions and 104 deletions
|
@ -2,7 +2,7 @@ A Brief Guide to Foundation.
|
||||||
|
|
||||||
Notes on getting started with the Foundation library.
|
Notes on getting started with the Foundation library.
|
||||||
|
|
||||||
@h Introduction.
|
@ \section{Introduction.}
|
||||||
The Foundation module supplies some of the conveniences of more modern
|
The Foundation module supplies some of the conveniences of more modern
|
||||||
programming languages to ANSI C. It offers the usual stuff of standard
|
programming languages to ANSI C. It offers the usual stuff of standard
|
||||||
libraries everywhere: memory management, collection classes, filename and file
|
libraries everywhere: memory management, collection classes, filename and file
|
||||||
|
@ -25,28 +25,28 @@ can be found in //foundation-test//.
|
||||||
@ To use //foundation//, a program must at minimum do three things.
|
@ To use //foundation//, a program must at minimum do three things.
|
||||||
|
|
||||||
1. The Contents section of its web must import Foundation as a module, thus:
|
1. The Contents section of its web must import Foundation as a module, thus:
|
||||||
= (text as Inweb)
|
|
||||||
Import: foundation
|
Import: foundation
|
||||||
=
|
|
||||||
Import lines appear after the metadata, but before the roster of sections
|
Import lines appear after the metadata, but before the roster of sections
|
||||||
and chapters.
|
and chapters.
|
||||||
|
|
||||||
2. The constant |PROGRAM_NAME| must be defined equal to a C string with a
|
2. The constant [[PROGRAM_NAME]] must be defined equal to a C string with a
|
||||||
brief version of the program's name. For example,
|
brief version of the program's name. For example,
|
||||||
= (text as Inweb)
|
|
||||||
@d PROGRAM_NAME "declutter"
|
|
||||||
=
|
|
||||||
|
|
||||||
3. The |main| function for the client should, as one of its very first acts,
|
@d PROGRAM_NAME "declutter"
|
||||||
call |Foundation::start()|, and should similarly, just before it exits, call
|
|
||||||
|Foundation::end()|. Any other module used should be started after Foundation
|
|
||||||
|
3. The [[main]] function 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.
|
starts, and ended before Foundation ends.
|
||||||
|
|
||||||
@h Truth.
|
@ \section{Truth.}
|
||||||
Every large C program starts by defining constants for truth and falsity. So
|
Every large C program starts by defining constants for truth and falsity. So
|
||||||
does Foundation: |TRUE|, |FALSE|, and a third state |NOT_APPLICABLE|.
|
does Foundation: [[TRUE]], [[FALSE]], and a third state [[NOT_APPLICABLE]].
|
||||||
|
|
||||||
@h Text streams and formatted output.
|
@ \section{Text streams and formatted output.}
|
||||||
Perhaps the most useful feature of Foundation is that it provides for
|
Perhaps the most useful feature of Foundation is that it provides for
|
||||||
memory-managed strings of Unicode text. These are unified with text files
|
memory-managed strings of Unicode text. These are unified with text files
|
||||||
which are open for output, in a type called //text_stream//. It's expected
|
which are open for output, in a type called //text_stream//. It's expected
|
||||||
|
@ -54,38 +54,38 @@ that they may be very large indeed, and appending text to or finding the
|
||||||
length of a text in memory runs in $O(1)$ time.
|
length of a text in memory runs in $O(1)$ time.
|
||||||
|
|
||||||
A typical function writing to one of these might be:
|
A typical function writing to one of these might be:
|
||||||
= (text as InC)
|
|
||||||
void Hypothetical::writer(text_stream *OUT, text_stream *authority, int N) {
|
void Hypothetical::writer(text_stream *OUT, text_stream *authority, int N) {
|
||||||
WRITE("According to %S, the square of %d is %d.\n", authority, N, N*N);
|
WRITE("According to %S, the square of %d is %d.\n", authority, N, N*N);
|
||||||
}
|
}
|
||||||
=
|
|
||||||
Here |WRITE| is a variadic macro rather like |printf|, and note the use of
|
Here [[WRITE]] is a variadic macro rather like [[printf]], and note the use of
|
||||||
the escape |%S| to write a text stream. It writes formatted output into the
|
the escape [[%S]] to write a text stream. It writes formatted output into the
|
||||||
stream |OUT|, and is actually an abbreviation for this:
|
stream [[OUT]], and is actually an abbreviation for this:
|
||||||
= (text as InC)
|
|
||||||
void Hypothetical::writer(text_stream *OUT, text_stream *authority, int N) {
|
void Hypothetical::writer(text_stream *OUT, text_stream *authority, int N) {
|
||||||
WRITE_TO(OUT, "According to %S, the square of %d is %d.\n", authority, N, N*N);
|
WRITE_TO(OUT, "According to %S, the square of %d is %d.\n", authority, N, N*N);
|
||||||
}
|
}
|
||||||
=
|
|
||||||
The function |Hypothetical::writer| can write equally to a text file or to a
|
The function [[Hypothetical::writer]] can write equally to a text file or to a
|
||||||
string, whichever it's given, and doesn't need to worry about memory management
|
string, whichever it's given, and doesn't need to worry about memory management
|
||||||
or text encodings.
|
or text encodings.
|
||||||
|
|
||||||
The standard output and standard error "files" on Unix-based systems are
|
The standard output and standard error "files" on Unix-based systems are
|
||||||
referred to as |STDOUT| and |STDERR|, both constants of type |text_stream *|
|
referred to as [[STDOUT]] and [[STDERR]], both constants of type [[text_stream *]]
|
||||||
defined by Foundation. The value |NULL|, used as a text stream, is valid and
|
defined by Foundation. The value [[NULL]], used as a text stream, is valid and
|
||||||
prints as the empty string, while ignoring any content written to it.
|
prints as the empty string, while ignoring any content written to it.
|
||||||
All of these capitalised macros are defined in //Streams//.
|
All of these capitalised macros are defined in //Streams//.
|
||||||
|
|
||||||
|PRINT("...")| is an abbreviation for |WRITE_TO(STDOUT, "...")|, and
|
[[PRINT("...")]] is an abbreviation for [[WRITE_TO(STDOUT, "...")]], and
|
||||||
|LOG("...")| similarly writes to the log file. (See //Debugging Log//.)
|
[[LOG("...")]] similarly writes to the log file. (See //Debugging Log//.)
|
||||||
|
|
||||||
@ If you're using //inweb: The InC Dialect//, the slight extension to C made
|
@ If you're using //inweb: The InC Dialect//, the slight extension to C made
|
||||||
by Inweb, there's a simple notation for constants of this type:
|
by Inweb, there's a simple notation for constants of this type:
|
||||||
= (text as InC)
|
|
||||||
text_stream *error_message = I"quadro-triticale stocks depleted";
|
text_stream *error_message = I"quadro-triticale stocks depleted";
|
||||||
=
|
|
||||||
The |I| prefix is meant to imitate the |L| used in standard C99 for long string
|
The [[I]] prefix is meant to imitate the [[L]] used in standard C99 for long string
|
||||||
constants. But this is a feature of //inweb// rather than of Foundation.
|
constants. But this is a feature of //inweb// rather than of Foundation.
|
||||||
|
|
||||||
@ Programs doing a lot of parsing need to create and throw away strings all
|
@ Programs doing a lot of parsing need to create and throw away strings all
|
||||||
|
@ -95,20 +95,20 @@ existing one. But these are permanent creations, and not easy to deallocate
|
||||||
(though calling //Str::clear// to empty out their text will free any large
|
(though calling //Str::clear// to empty out their text will free any large
|
||||||
amount of memory they might be using). If you want a string just for a
|
amount of memory they might be using). If you want a string just for a
|
||||||
momentary period, do this:
|
momentary period, do this:
|
||||||
= (text as InC)
|
|
||||||
TEMPORARY_TEXT(alpha)
|
TEMPORARY_TEXT(alpha)
|
||||||
WRITE_TO(alpha, "This is temporary");
|
WRITE_TO(alpha, "This is temporary");
|
||||||
...
|
...
|
||||||
DISCARD_TEXT(alpha)
|
DISCARD_TEXT(alpha)
|
||||||
=
|
|
||||||
Between the use of these two macros, |alpha| is a valid |text_stream *|,
|
Between the use of these two macros, [[alpha]] is a valid [[text_stream *]],
|
||||||
and is a string capable of growing to arbitrary size.
|
and is a string capable of growing to arbitrary size.
|
||||||
|
|
||||||
@ Foundation provides an elaborate system for providing new string escapes
|
@ Foundation provides an elaborate system for providing new string escapes
|
||||||
like |%S|: see //Writers and Loggers//. A similar system manages a debugging
|
like [[%S]]: see //Writers and Loggers//. A similar system manages a debugging
|
||||||
log, to which it's easy to make "dollar escapes" for pretty-printing internal
|
log, to which it's easy to make "dollar escapes" for pretty-printing internal
|
||||||
data structures: for example, if you've made a structure called |recipe|, you
|
data structures: for example, if you've made a structure called [[recipe]], you
|
||||||
could make |$R| pretty-print one.
|
could make [[$R]] pretty-print one.
|
||||||
|
|
||||||
@ Foundation also has an extensive library of string-handling routines,
|
@ Foundation also has an extensive library of string-handling routines,
|
||||||
providing the sort of facilities you would expect in a typical scripting
|
providing the sort of facilities you would expect in a typical scripting
|
||||||
|
@ -122,129 +122,129 @@ For slicing, see the //string_position// type, representing positions for the
|
||||||
benefit of functions like //Str::substr//.
|
benefit of functions like //Str::substr//.
|
||||||
|
|
||||||
@ Individual characters are represented in Foundation using the standard
|
@ Individual characters are represented in Foundation using the standard
|
||||||
POSIX type |wchar_t|, which on all modern systems is a very wide integer,
|
POSIX type [[wchar_t]], which on all modern systems is a very wide integer,
|
||||||
whether or not signed. It's safe to assume it can hold all normal Unicode
|
whether or not signed. It's safe to assume it can hold all normal Unicode
|
||||||
code points. See //Characters// for class functions like //Characters::isdigit//,
|
code points. See //Characters// for class functions like //Characters::isdigit//,
|
||||||
which have been carefully written to work equivalently on either Windows or
|
which have been carefully written to work equivalently on either Windows or
|
||||||
Unix-based systems.
|
Unix-based systems.
|
||||||
|
|
||||||
//C Strings// and //Wide Strings// provide bare-minimum facilities for handling
|
//C Strings// and //Wide Strings// provide bare-minimum facilities for handling
|
||||||
traditional null-terminated |char| and |wchar_t| arrays, but don't use these.
|
traditional null-terminated [[char]] and [[wchar_t]] arrays, but don't use these.
|
||||||
Texts are just better.
|
Texts are just better.
|
||||||
|
|
||||||
@h Objects.
|
@ \section{Objects.}
|
||||||
To a very limited extent, Foundation enables C programs to have "classes",
|
To a very limited extent, Foundation enables C programs to have "classes",
|
||||||
"objects" and "methods", and it makes use of that ability itself, too. (See
|
"objects" and "methods", and it makes use of that ability itself, too. (See
|
||||||
//Foundation Classes// for the list of classes made by //foundation//.) For
|
//Foundation Classes// for the list of classes made by //foundation//.) For
|
||||||
example, suppose we are writing a program to store recipes, and we want
|
example, suppose we are writing a program to store recipes, and we want
|
||||||
something in C which corresponds to objects of the class |recipe|. We need to
|
something in C which corresponds to objects of the class [[recipe]]. We need to
|
||||||
do three things:
|
do three things:
|
||||||
|
|
||||||
1. Declare an enumerated constant ending |_CLASS| to represent this type in the
|
1. Declare an enumerated constant ending [[_CLASS]] to represent this type in the
|
||||||
memory manager, and then make a matching use of a macro to define some associated
|
memory manager, and then make a matching use of a macro to define some associated
|
||||||
functions, which we never see or think about. For example:
|
functions, which we never see or think about. For example:
|
||||||
= (text as Inweb)
|
|
||||||
@ Here are my classes...
|
@ Here are my classes...
|
||||||
|
|
||||||
@e recipe_CLASS
|
@e recipe_CLASS
|
||||||
|
|
||||||
=
|
=
|
||||||
DECLARE_CLASS(recipe)
|
DECLARE_CLASS(recipe)
|
||||||
=
|
|
||||||
The mention of "individually" is because this is for data structures where
|
The mention of "individually" is because this is for data structures where
|
||||||
we expect to have relatively few instances. If we expect to have huge numbers
|
we expect to have relatively few instances. If we expect to have huge numbers
|
||||||
of throwaway instances, we would instead write:
|
of throwaway instances, we would instead write:
|
||||||
= (text as Inweb)
|
|
||||||
@ Here are my classes...
|
@ Here are my classes...
|
||||||
|
|
||||||
@e salt_grain_CLASS
|
@e salt_grain_CLASS
|
||||||
|
|
||||||
=
|
=
|
||||||
DECLARE_CLASS_ALLOCATED_IN_ARRAYS(salt_grain, 1000)
|
DECLARE_CLASS_ALLOCATED_IN_ARRAYS(salt_grain, 1000)
|
||||||
=
|
|
||||||
The memory manager then claims these in blocks of 1000. Use this only if it's
|
The memory manager then claims these in blocks of 1000. Use this only if it's
|
||||||
actually needed; note that |DESTROY| cannot be used with objects created
|
actually needed; note that [[DESTROY]] cannot be used with objects created
|
||||||
this way.
|
this way.
|
||||||
|
|
||||||
2. We have to declare the actual structure, and |typedef| the name to it. For
|
2. We have to declare the actual structure, and [[typedef]] the name to it. For
|
||||||
example:
|
example:
|
||||||
= (text as InC)
|
|
||||||
typedef struct recipe {
|
typedef struct recipe {
|
||||||
struct text_stream *name_of_dish;
|
struct text_stream *name_of_dish;
|
||||||
int oven_temperature;
|
int oven_temperature;
|
||||||
CLASS_DEFINITION
|
CLASS_DEFINITION
|
||||||
} recipe;
|
} recipe;
|
||||||
=
|
|
||||||
Here |CLASS_DEFINITION| is a macro defined in //Memory// which expands to the
|
Here [[CLASS_DEFINITION]] is a macro defined in //Memory// which expands to the
|
||||||
necessary field(s) to keep track of this. We won't use those fields, or ever
|
necessary field(s) to keep track of this. We won't use those fields, or ever
|
||||||
think about them.
|
think about them.
|
||||||
|
|
||||||
3. In fact we've now finished. The macro |CREATE(recipe)| returns a new
|
3. In fact we've now finished. The macro [[CREATE(recipe)]] returns a new
|
||||||
instance, and |DESTROY(R)| would destroy an existing one, |R|. Unless manually
|
instance, and [[DESTROY(R)]] would destroy an existing one, [[R]]. Unless manually
|
||||||
destroyed, objects last forever; there is no garbage collection. In practice
|
destroyed, objects last forever; there is no garbage collection. In practice
|
||||||
the Inform tools suite, for which Foundation was written, almost never destroy
|
the Inform tools suite, for which Foundation was written, almost never destroy
|
||||||
objects.
|
objects.
|
||||||
|
|
||||||
Customarily, though, we wrap the use of |CREATE| in a constructor function:
|
Customarily, though, we wrap the use of [[CREATE]] in a constructor function:
|
||||||
= (text as InC)
|
|
||||||
recipe *Recipes::new(text_stream *name) {
|
recipe *Recipes::new(text_stream *name) {
|
||||||
recipe *R = CREATE(recipe);
|
recipe *R = CREATE(recipe);
|
||||||
R->name_of_dish = Str::duplicate(name);
|
R->name_of_dish = Str::duplicate(name);
|
||||||
R->oven_temperature = 200;
|
R->oven_temperature = 200;
|
||||||
return R;
|
return R;
|
||||||
}
|
}
|
||||||
=
|
|
||||||
|
|
||||||
We also often use the convenient |LOOP_OVER| macro:
|
|
||||||
= (text as InC)
|
We also often use the convenient [[LOOP_OVER]] macro:
|
||||||
|
|
||||||
void Recipes::list_all(text_stream *OUT) {
|
void Recipes::list_all(text_stream *OUT) {
|
||||||
WRITE("I know about the following recipes:\n");
|
WRITE("I know about the following recipes:\n");
|
||||||
recipe *R;
|
recipe *R;
|
||||||
LOOP_OVER(R, recipe)
|
LOOP_OVER(R, recipe)
|
||||||
WRITE("- %S\n", R->name_of_dish);
|
WRITE("- %S\n", R->name_of_dish);
|
||||||
}
|
}
|
||||||
=
|
|
||||||
|LOOP_OVER| loops through all created |recipe| instances (which have not been
|
[[LOOP_OVER]] loops through all created [[recipe]] instances (which have not been
|
||||||
destroyed).
|
destroyed).
|
||||||
|
|
||||||
There are a few other facilities, for which see //Memory//, and also ways to
|
There are a few other facilities, for which see //Memory//, and also ways to
|
||||||
allocate memory for arrays -- see //Memory::calloc// and //Memory::malloc//.
|
allocate memory for arrays -- see //Memory::calloc// and //Memory::malloc//.
|
||||||
|
|
||||||
@h Methods.
|
@ \section{Methods.}
|
||||||
It's also possible to have method calls on object instances, though the
|
It's also possible to have method calls on object instances, though the
|
||||||
syntax is not as tidy as it would be in an object-oriented language. To allow
|
syntax is not as tidy as it would be in an object-oriented language. To allow
|
||||||
this for |recipe|, we would have to add another line to the structure:
|
this for [[recipe]], we would have to add another line to the structure:
|
||||||
= (text as InC)
|
|
||||||
typedef struct recipe {
|
typedef struct recipe {
|
||||||
struct text_stream *name_of_dish;
|
struct text_stream *name_of_dish;
|
||||||
int oven_temperature;
|
int oven_temperature;
|
||||||
struct method_set *methods;
|
struct method_set *methods;
|
||||||
CLASS_DEFINITION
|
CLASS_DEFINITION
|
||||||
} recipe;
|
} recipe;
|
||||||
=
|
|
||||||
and another line to the constructor function:
|
and another line to the constructor function:
|
||||||
= (text as InC)
|
|
||||||
R->methods = Methods::new_set();
|
R->methods = Methods::new_set();
|
||||||
=
|
|
||||||
The object |R| is then ready to receive method calls. Each different call needs
|
The object [[R]] is then ready to receive method calls. Each different call needs
|
||||||
an enumerated constant ending |_MTID| to identify it, and an indication of the
|
an enumerated constant ending [[_MTID]] to identify it, and an indication of the
|
||||||
type of the function call involved:
|
type of the function call involved:
|
||||||
= (text as Inweb)
|
|
||||||
@ Here is my "cook the recipe" method call:
|
@ Here is my "cook the recipe" method call:
|
||||||
|
|
||||||
@e COOK_MTID
|
@e COOK_MTID
|
||||||
|
|
||||||
=
|
=
|
||||||
VOID_METHOD_TYPE(COOK_MTID, recipe *R, int time_in_oven)
|
VOID_METHOD_TYPE(COOK_MTID, recipe *R, int time_in_oven)
|
||||||
=
|
|
||||||
It's now possible to call this on any recipe:
|
It's now possible to call this on any recipe:
|
||||||
= (text as InC)
|
|
||||||
VOID_METHOD_CALL(duck_a_l_orange, COOK_MTID, 45);
|
VOID_METHOD_CALL(duck_a_l_orange, COOK_MTID, 45);
|
||||||
=
|
|
||||||
What then happens? Nothing at all, unless the recipe instance in question --
|
What then happens? Nothing at all, unless the recipe instance in question --
|
||||||
here, |duck_a_l_orange| -- has been given a receiver function. Let's revisit
|
here, [[duck_a_l_orange]] -- has been given a receiver function. Let's revisit
|
||||||
the constructor function for recipes:
|
the constructor function for recipes:
|
||||||
= (text as InC)
|
|
||||||
recipe *Recipes::new(text_stream *name) {
|
recipe *Recipes::new(text_stream *name) {
|
||||||
recipe *R = CREATE(recipe);
|
recipe *R = CREATE(recipe);
|
||||||
R->name_of_dish = Str::duplicate(name);
|
R->name_of_dish = Str::duplicate(name);
|
||||||
|
@ -253,50 +253,50 @@ the constructor function for recipes:
|
||||||
METHOD_ADD(R, COOK_MTID, Recipes::cook);
|
METHOD_ADD(R, COOK_MTID, Recipes::cook);
|
||||||
return R;
|
return R;
|
||||||
}
|
}
|
||||||
=
|
|
||||||
and now add:
|
and now add:
|
||||||
= (text as InC)
|
|
||||||
void Recipes::cook(recipe *R, int time_in_oven) {
|
void Recipes::cook(recipe *R, int time_in_oven) {
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
=
|
|
||||||
using the arguments promised in the declaration above. With all this done,
|
using the arguments promised in the declaration above. With all this done,
|
||||||
the effect of
|
the effect of
|
||||||
= (text as InC)
|
|
||||||
VOID_METHOD_CALL(duck_a_l_orange, COOK_MTID, 45);
|
VOID_METHOD_CALL(duck_a_l_orange, COOK_MTID, 45);
|
||||||
=
|
|
||||||
is to call:
|
is to call:
|
||||||
= (text as InC)
|
|
||||||
Recipes::cook(duck_a_l_orange, 45);
|
Recipes::cook(duck_a_l_orange, 45);
|
||||||
=
|
|
||||||
|
|
||||||
@ In fact it's possible to attach multiple receivers to the same object, in
|
@ In fact it's possible to attach multiple receivers to the same object, in
|
||||||
which case they each run in turn. As a variant on this, methods can also return
|
which case they each run in turn. As a variant on this, methods can also return
|
||||||
their "success". If multiple receivers run, the first to return |TRUE| has
|
their "success". If multiple receivers run, the first to return [[TRUE]] has
|
||||||
claimed the right to act, and subsequent receivers aren't consulted.
|
claimed the right to act, and subsequent receivers aren't consulted.
|
||||||
|
|
||||||
Such methods must be defined with |INT_METHOD_CALL| and are rarely needed. See
|
Such methods must be defined with [[INT_METHOD_CALL]] and are rarely needed. See
|
||||||
//Methods// for more.
|
//Methods// for more.
|
||||||
|
|
||||||
@h Collections.
|
@ \section{Collections.}
|
||||||
Foundation provides three sorts of "collection": see //Linked Lists and Stacks//,
|
Foundation provides three sorts of "collection": see //Linked Lists and Stacks//,
|
||||||
and also //Dictionaries//. These all collect values which are expected to be
|
and also //Dictionaries//. These all collect values which are expected to be
|
||||||
pointers: for example, text streams (of type |text_stream *|) or objects like
|
pointers: for example, text streams (of type [[text_stream *]]) or objects like
|
||||||
the ones created above. For example,
|
the ones created above. For example,
|
||||||
= (text as InC)
|
|
||||||
linked_list *cookbook = NEW_LINKED_LIST(recipe);
|
linked_list *cookbook = NEW_LINKED_LIST(recipe);
|
||||||
=
|
|
||||||
initialises a list as ready to use. It's then accessed by macros:
|
initialises a list as ready to use. It's then accessed by macros:
|
||||||
= (text as InC)
|
|
||||||
recipe *lobster_thermidor = Recipes::new(I"lobster thermidor", 200);
|
recipe *lobster_thermidor = Recipes::new(I"lobster thermidor", 200);
|
||||||
ADD_TO_LINKED_LIST(lobster_thermidor, recipe, cookbook);
|
ADD_TO_LINKED_LIST(lobster_thermidor, recipe, cookbook);
|
||||||
=
|
|
||||||
Similarly:
|
Similarly:
|
||||||
= (text as InC)
|
|
||||||
recipe *R;
|
recipe *R;
|
||||||
LOOP_OVER_LINKED_LIST(R, recipe, cookbook)
|
LOOP_OVER_LINKED_LIST(R, recipe, cookbook)
|
||||||
PRINT("I can make %S.\n", R->name_of_dish);
|
PRINT("I can make %S.\n", R->name_of_dish);
|
||||||
=
|
|
||||||
That's about all you can do with linked lists: they are not nearly so well
|
That's about all you can do with linked lists: they are not nearly so well
|
||||||
worked-through as texts.
|
worked-through as texts.
|
||||||
|
|
||||||
|
@ -310,7 +310,7 @@ able to hold a rooted tree in which nodes can be a variety of different
|
||||||
objects, rather than having to be uniform. Functions are provided to
|
objects, rather than having to be uniform. Functions are provided to
|
||||||
build and verify such trees.
|
build and verify such trees.
|
||||||
|
|
||||||
@h Files and paths.
|
@ \section{Files and paths.}
|
||||||
Filenames and pathnames are, perhaps controversially, represented by two
|
Filenames and pathnames are, perhaps controversially, represented by two
|
||||||
different types: //filename// and //pathname//. The latter should perhaps
|
different types: //filename// and //pathname//. The latter should perhaps
|
||||||
have been called "directoryname", but that ship has sailed.
|
have been called "directoryname", but that ship has sailed.
|
||||||
|
@ -324,20 +324,20 @@ These both hold names, not actual files: they are places where files or
|
||||||
directories might be.
|
directories might be.
|
||||||
|
|
||||||
Both tend to refer relative to the current working directory, represented by
|
Both tend to refer relative to the current working directory, represented by
|
||||||
the null |pathname| pointer. //Pathnames::up// and //Pathnames::down// go
|
the null [[pathname]] pointer. //Pathnames::up// and //Pathnames::down// go
|
||||||
to parent or subdirectories, respectively. A filename cannot exist without
|
to parent or subdirectories, respectively. A filename cannot exist without
|
||||||
a pathname; for example,
|
a pathname; for example,
|
||||||
= (text as InC)
|
|
||||||
pathname *P = Pathnames::down(NULL, I"App")
|
pathname *P = Pathnames::down(NULL, I"App")
|
||||||
P = Pathnames::down(P, I"Config")
|
P = Pathnames::down(P, I"Config")
|
||||||
filename *F = Filenames::in(P, I"options.txt");
|
filename *F = Filenames::in(P, I"options.txt");
|
||||||
PRINT("I have arrived at %f.\n", F);
|
PRINT("I have arrived at %f.\n", F);
|
||||||
=
|
|
||||||
produces, on platforms where |/| is used as the file system dividing character,
|
produces, on platforms where [[/]] is used as the file system dividing character,
|
||||||
= (text)
|
|
||||||
I have arrived at App/Config/options.txt.
|
I have arrived at App/Config/options.txt.
|
||||||
=
|
|
||||||
Note the use of the escape |%f| for printing filenames; there's also |%p| for
|
Note the use of the escape [[%f]] for printing filenames; there's also [[%p]] for
|
||||||
pathnames.
|
pathnames.
|
||||||
|
|
||||||
See //Filenames// and //Pathnames// for more.
|
See //Filenames// and //Pathnames// for more.
|
||||||
|
@ -356,9 +356,9 @@ useful for testing the correctness of our tools.
|
||||||
@ //Text Files// allows us to read text files. Its most useful function is
|
@ //Text Files// allows us to read text files. Its most useful function is
|
||||||
//TextFiles::read//, which opens a file, can print an error if it doesn't
|
//TextFiles::read//, which opens a file, can print an error if it doesn't
|
||||||
exist, and if it does, then feeds the lines one at a time to an iterator.
|
exist, and if it does, then feeds the lines one at a time to an iterator.
|
||||||
For example, if |F| is a filename, the following reads the file into a
|
For example, if [[F]] is a filename, the following reads the file into a
|
||||||
linked list of texts:
|
linked list of texts:
|
||||||
= (text as InC)
|
|
||||||
linked_list *Hypothetical::list_from_file(filename *F) {
|
linked_list *Hypothetical::list_from_file(filename *F) {
|
||||||
linked_list *L = NEW_LINKED_LIST(text_stream);
|
linked_list *L = NEW_LINKED_LIST(text_stream);
|
||||||
TextFiles::read(F, FALSE, "can't open colony file",
|
TextFiles::read(F, FALSE, "can't open colony file",
|
||||||
|
@ -370,12 +370,12 @@ linked list of texts:
|
||||||
linked_list *L = (linked_list *) v_L;
|
linked_list *L = (linked_list *) v_L;
|
||||||
ADD_TO_LINKED_LIST(text, line, L);
|
ADD_TO_LINKED_LIST(text, line, L);
|
||||||
}
|
}
|
||||||
=
|
|
||||||
The //text_file_position// here keeps track of where we are, and in particular,
|
The //text_file_position// here keeps track of where we are, and in particular,
|
||||||
functions from //Error Messages// can then report errors where they occur:
|
functions from //Error Messages// can then report errors where they occur:
|
||||||
= (text as InC)
|
|
||||||
Errors::in_text_file("bad syntax here", tfp);
|
Errors::in_text_file("bad syntax here", tfp);
|
||||||
=
|
|
||||||
|
|
||||||
@ The //Preprocessor// provides simple iteration and macro expansion in order
|
@ The //Preprocessor// provides simple iteration and macro expansion in order
|
||||||
to turn a marked-up script into a plain text file.
|
to turn a marked-up script into a plain text file.
|
||||||
|
@ -383,7 +383,7 @@ to turn a marked-up script into a plain text file.
|
||||||
@ See //JSON// for convenient ways to encode and decode data to the JSON
|
@ See //JSON// for convenient ways to encode and decode data to the JSON
|
||||||
interchange format.
|
interchange format.
|
||||||
|
|
||||||
@h Handling webs.
|
@ \section{Handling webs.}
|
||||||
Foundation provides routines which can read the metadata of a web, i.e., a
|
Foundation provides routines which can read the metadata of a web, i.e., a
|
||||||
literate program in the //inweb// format, from a copy in the file system.
|
literate program in the //inweb// format, from a copy in the file system.
|
||||||
The main function here is //WebMetadata::get//, which returns a //web_md//
|
The main function here is //WebMetadata::get//, which returns a //web_md//
|
||||||
|
@ -392,12 +392,12 @@ object. You can then access its bibliographic data using
|
||||||
its modules (instances of //module//), chapters (of //chapter_md//) and
|
its modules (instances of //module//), chapters (of //chapter_md//) and
|
||||||
sections (of //section_md//).
|
sections (of //section_md//).
|
||||||
|
|
||||||
@h Miscellaneous other features.
|
@ \section{Miscellaneous other features.}
|
||||||
What else? Well:
|
What else? Well:
|
||||||
(a) //Time// for the time of day and the date of Easter (no, really), and
|
(a) //Time// for the time of day and the date of Easter (no, really), and
|
||||||
for timing internal program activity using //Time::start_stopwatch// and
|
for timing internal program activity using //Time::start_stopwatch// and
|
||||||
//Time::stop_stopwatch//;
|
//Time::stop_stopwatch//;
|
||||||
(b) //Shell// for issuing shell commands via the C library's |system| function,
|
(b) //Shell// for issuing shell commands via the C library's [[system]] function,
|
||||||
or its equivalent;
|
or its equivalent;
|
||||||
(c) //HTML// and //Epub Ebooks// for generating web pages and ebooks;
|
(c) //HTML// and //Epub Ebooks// for generating web pages and ebooks;
|
||||||
(d) //Image Dimensions// and //Sound Durations// for handling videos and music;
|
(d) //Image Dimensions// and //Sound Durations// for handling videos and music;
|
Loading…
Reference in a new issue