| 1 | %%% -*-latex-*- |
| 2 | %%% |
| 3 | %%% The runtime library |
| 4 | %%% |
| 5 | %%% (c) 2015 Straylight/Edgeware |
| 6 | %%% |
| 7 | |
| 8 | %%%----- Licensing notice --------------------------------------------------- |
| 9 | %%% |
| 10 | %%% This file is part of the Simple Object Definition system. |
| 11 | %%% |
| 12 | %%% SOD is free software; you can redistribute it and/or modify |
| 13 | %%% it under the terms of the GNU General Public License as published by |
| 14 | %%% the Free Software Foundation; either version 2 of the License, or |
| 15 | %%% (at your option) any later version. |
| 16 | %%% |
| 17 | %%% SOD is distributed in the hope that it will be useful, |
| 18 | %%% but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 19 | %%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 20 | %%% GNU General Public License for more details. |
| 21 | %%% |
| 22 | %%% You should have received a copy of the GNU General Public License |
| 23 | %%% along with SOD; if not, write to the Free Software Foundation, |
| 24 | %%% Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
| 25 | |
| 26 | \chapter{The runtime library} \label{ch:runtime} |
| 27 | |
| 28 | This chapter describes the runtime support macros and functions provided by |
| 29 | the Sod library. The common structure of object instances and classes is |
| 30 | described in \xref{ch:structures}. |
| 31 | |
| 32 | %%%-------------------------------------------------------------------------- |
| 33 | \section{Keyword argument support} \label{sec:runtime.keywords} |
| 34 | |
| 35 | This section describes the types, macros, and functions exposed in the |
| 36 | @|<sod/keyword.h>| header file which provides support for defining and |
| 37 | calling functions which make use of keyword arguments; see |
| 38 | \xref{sec:concepts.keywords}. |
| 39 | |
| 40 | |
| 41 | \subsection{Type definitions} \label{sec:sec:runtime.keywords.types} |
| 42 | |
| 43 | The header file defines two simple structure types, and a function type which |
| 44 | will be described later. |
| 45 | |
| 46 | \begin{describe}{ty}[struct kwval] |
| 47 | {struct kwval \{ \\ \ind |
| 48 | const char *kw; \\ |
| 49 | const void *val; \-\\ |
| 50 | \};} |
| 51 | |
| 52 | The @|kwval| structure describes a keyword argument name/value pair. The |
| 53 | @|kw| member points to the name, as a null-terminated string. The @|val| |
| 54 | member always contains the \emph{address} of the value. (This somewhat |
| 55 | inconvenient arrangement makes the size of a @|kwval| object independent of |
| 56 | the actual argument type.) |
| 57 | \end{describe} |
| 58 | |
| 59 | \begin{describe}{ty}[struct kwtab] |
| 60 | {struct kwtab \{ \\ \ind |
| 61 | const struct kwval *v; \\ |
| 62 | size_t n; \-\\ |
| 63 | \};} |
| 64 | |
| 65 | The @|kwtab| structure describes a list of keyword arguments, represented |
| 66 | as a vector of @|kwval| structures. The @|v| member points to the start of |
| 67 | the vector; the @|n| member contains the number of elements in the vector. |
| 68 | \end{describe} |
| 69 | |
| 70 | |
| 71 | \subsection{Calling functions with keyword arguments} |
| 72 | \label{sec:runtime.keywords.calling} |
| 73 | |
| 74 | Functions which accept keyword arguments are ordinary C functions with |
| 75 | variable-length argument tails. Hence, they can be called using ordinary C |
| 76 | (of the right kind) and all will be well. However, argument lists must |
| 77 | follow certain rules (which will be described in full below); failure to do |
| 78 | this will result in \emph{undefined behaviour}. |
| 79 | |
| 80 | The header file provides integration with some C compilers in the form of |
| 81 | macros which can be used to help the compiler diagnose errors in calls to |
| 82 | keyword-accepting functions; but such support is rather limited at the |
| 83 | moment. Some additional macros are provided for use in calls to such |
| 84 | functions, and it is recommended that, where possible, these are used. In |
| 85 | particular, it's all too easy to forget the trailing null terminator which |
| 86 | marks the end of a list of keyword arguments. |
| 87 | |
| 88 | That said, the underlying machinery is presented first, and the convenience |
| 89 | macros are described later. |
| 90 | |
| 91 | \subsubsection{Keyword argument mechanism} |
| 92 | The argument tail, following the mandatory arguments, consists of a sequence |
| 93 | of zero or more alternating keyword names, as pointers to null-terminated |
| 94 | strings (with type @|const char~*|), and their argument values. This |
| 95 | sequence is finally terminated by a null pointer (again with type @|const |
| 96 | char~*|) in place of a keyword name. |
| 97 | |
| 98 | Each function may define for itself which keyword names it accepts, |
| 99 | and what types the corresponding argument values should have. |
| 100 | There are also (currently) three special keyword names. |
| 101 | \begin{description} \let\makelabel\code |
| 102 | |
| 103 | \item[kw.valist] This special keyword is followed by a pointer to a |
| 104 | variable-length argument tail cursor object, of type @|va_list~*|. This |
| 105 | cursor object will be modified as the function extracts successive |
| 106 | arguments from the tail. The argument tail should consist of alternating |
| 107 | keyword names and argument values, as described above, including the first |
| 108 | keyword name. (This is therefore different from the convention used when |
| 109 | calling keyword argument parser functions: see the description of the |
| 110 | \descref{mac}{KWSET_PARSEFN}[macro] for more details about these.) The |
| 111 | argument tail may itself contain the special keywords. |
| 112 | |
| 113 | \item[kw.tab] This special keyword is followed by \emph{two} argument values: |
| 114 | a pointer to the base of a vector of @|kwval| structures, and the number of |
| 115 | elements in this vector (as a @|size_t|). Each element of the vector |
| 116 | describes a single keyword argument: the @|kw| member points to the |
| 117 | keyword's name, and the @|val| member points to the value. |
| 118 | |
| 119 | The vector may contain special keywords. The @|val| pointer for a |
| 120 | @|kw.valist| argument should contain the address of an object of type |
| 121 | @|va_list~*| (and not point directly to the cursor object, since @|val| is |
| 122 | has type @|const void~*| but the cursor will be modified as its argument |
| 123 | tail is traversed). The @|val| pointer for a @|kw.tab| argument should |
| 124 | contain the address of a @|kwtab| structure which itself contains the base |
| 125 | address and length of the argument vector to be processed. |
| 126 | |
| 127 | \item[kw.unknown] This keyword is never accepted by any function. If it is |
| 128 | encountered, the @|kw_unknown| function is called to report the situation |
| 129 | as an error; see below. |
| 130 | |
| 131 | \end{description} |
| 132 | It is possible to construct a circular structure of indirect argument lists |
| 133 | (in a number of ways). Don't try to pass such a structure to a function: the |
| 134 | result will be unbounded recursion or some other bad outcome. |
| 135 | |
| 136 | \subsubsection{Argument list structuring macros} |
| 137 | The following macros are intended to help with constructing keyword argument |
| 138 | lists. Their use is not essential, but may help prevent errors. |
| 139 | |
| 140 | \begin{describe}{mac}[KWARGS]{KWARGS(@<body>)} |
| 141 | The @<body> encloses a sequence of keyword arguments expressed as calls to |
| 142 | argument consists of a sequence of calls to the keyword-argument macros |
| 143 | described below, one after another without any separation. |
| 144 | |
| 145 | If there are no keyword arguments, use @|NO_KWARGS| (below) instead. |
| 146 | \end{describe} |
| 147 | |
| 148 | \begin{describe}{mac}{NO_KWARGS} |
| 149 | A marker, to be written instead of a @|KWARGS| invocation, to indicate that |
| 150 | no keyword arguments are to be passed to a function. |
| 151 | |
| 152 | Using this macro instead of @|KWARGS| if there are no arguments does two |
| 153 | things: |
| 154 | \begin{itemize} |
| 155 | |
| 156 | \item C89 doesn't permit empty macro arguments for some reason, so |
| 157 | @|NO_KWARGS| is necessary when using a C89 compiler. |
| 158 | |
| 159 | \item Omitting the null terminator is a common mistake, so @|<keyword.h>| |
| 160 | tries to get the compiler to warn if you miss it. However, the |
| 161 | \descref{mac}{KWTAIL}[macro] introduces an extra real argument |
| 162 | @|kwfirst_|, because it's not possible to scan a variable-length argument |
| 163 | tail if there are no mandatory arguments. If you use @|KWARGS()|, with |
| 164 | an empty argument list, then the null terminator is passed as @|kwfirst_| |
| 165 | and the variable-length tail ends up empty, which might trigger a |
| 166 | compiler warning about the missing terminator. @|NO_KWARGS| passes |
| 167 | \emph{two} null terminators: a real one to indicate that there are no |
| 168 | keyword arguments, and a dummy one to placate the compiler. |
| 169 | |
| 170 | (Sod method entry functions don't have this extra argument, so |
| 171 | @|KWARGS()| would work fine for sending Sod messages with keyword |
| 172 | arguments if you're using C99 or later, but it's probably best to use the |
| 173 | version which always works.) |
| 174 | |
| 175 | \end{itemize} |
| 176 | \end{describe} |
| 177 | |
| 178 | The following keyword-argument macros can be used within the @|KWARGS| |
| 179 | @<body> argument. |
| 180 | |
| 181 | \begin{describe}{mac}[K]{K(@<name>, @<value>)} |
| 182 | Passes a keyword @<name> and its corresponding @<value>, as a pair of |
| 183 | arguments. The @<name> should be a single identifier (not a quoted |
| 184 | string). The @<value> may be any C expression of the appropriate type. |
| 185 | \end{describe} |
| 186 | |
| 187 | \begin{describe}{mac}[K_VALIST]{K_VALIST(@<ap>)} |
| 188 | Passes an indirect variable-length argument tail. The argument @<ap> |
| 189 | should be an lvalue of type @|va_list|, which will be passed by reference. |
| 190 | \end{describe} |
| 191 | |
| 192 | \begin{describe}{mac}[K_TAB]{K_TAB(@<v>, @<n>)} |
| 193 | Passes a vector of keyword arguments. The argument @<v> should be the base |
| 194 | address of the vector, and @<n> should be the number of elements in the |
| 195 | vector. |
| 196 | \end{describe} |
| 197 | |
| 198 | |
| 199 | \subsection{Defining functions with keyword arguments} |
| 200 | \label{sec:runtime.keywords.defining} |
| 201 | |
| 202 | \subsubsection{Keyword sets} |
| 203 | A \emph{keyword set} defines the collection of keyword arguments accepted by |
| 204 | a particular function. The same keyword set may be used by several |
| 205 | functions. (If your function currently accepts no keyword arguments, but you |
| 206 | plan to add some later, do not define a keyword set; instead, use the |
| 207 | @|KWPARSE_EMPTY| macro described below.) |
| 208 | |
| 209 | Each keyword set has a name, which is a C identifier. It's good to choose |
| 210 | meaningful and distinctive names for keyword sets. Keyword set names are |
| 211 | meaningful at runtime: they are used as part of the @|kw_unknown| protocol |
| 212 | (\xref{sec:runtime.keywords.unknown}), and may be examined by handler |
| 213 | functions, or reported to a user in error messages. For a keyword set which |
| 214 | is used only by a single function, it is recommended that the set be given |
| 215 | the same name as the function. |
| 216 | |
| 217 | The keyword arguments for a keyword set named @<set> are described by a `list |
| 218 | macro' named @|@<set>{}_KWSET|. This macro takes a single argument, |
| 219 | conventionally named @`_'. It should expand to a sequence of one or more |
| 220 | list items of the form |
| 221 | \begin{prog} |
| 222 | _(@<type>, @<name>, @<default>) |
| 223 | \end{prog} |
| 224 | with no separation between them. For example: |
| 225 | \begin{prog} |
| 226 | \#define example_KWSET(_) \macsl \\ \ind |
| 227 | _(int, x, 0) \macsl \\ |
| 228 | _(const char *, y, NULL) |
| 229 | \end{prog} |
| 230 | |
| 231 | Each @<name> should be a distinct C identifier; they will be used to name |
| 232 | structure members. An argument @<name> should not end with the suffix |
| 233 | @`_suppliedp' (for reasons which will soon become apparent). |
| 234 | |
| 235 | Each @<type> should be a C @<type-name> such that |
| 236 | \begin{prog} |
| 237 | @<type> @<name> ; |
| 238 | \end{prog} |
| 239 | is a valid declaration: so it may consist of declaration specifiers and |
| 240 | (possibly qualified) pointer declarator markers, but not array or function |
| 241 | markers (since they would have to be placed after the @<name>). This is the |
| 242 | same requirement made by the standard \man{va_arg}{3} macro. |
| 243 | |
| 244 | Each @<default> should be an initializer expression or brace-enclosed list, |
| 245 | suitable for use in an aggregate initializer for a variable with automatic |
| 246 | storage duration. (In C89, aggregate initializers may contain only constant |
| 247 | expressions; this restriction was lifted in C99.) |
| 248 | |
| 249 | \subsubsection{Function declaration markers} |
| 250 | The following marker macros are intended to be used in both declarations and |
| 251 | definitions of functions which accept keyword arguments. |
| 252 | |
| 253 | \begin{describe}{mac}{KWTAIL} |
| 254 | The @|KWTAIL| is expected to be used at the end of function parameter type |
| 255 | list to indicate that the function accepts keyword arguments; if there are |
| 256 | preceding mandatory arguments then the @|KWTAIL| marker should be separated |
| 257 | from them with a comma @`,'. (It is permitted for a function parameter |
| 258 | type list to contain only a @|KWTAIL| marker.) |
| 259 | |
| 260 | Specifically, the macro declares a mandatory argument @|const char |
| 261 | *kwfirst_| (to collect the first keyword name), and a variable-length |
| 262 | argument tail. |
| 263 | |
| 264 | The \descref{mac}{KWPARSE}[macro] assumes that the enclosing function's |
| 265 | argument list ends with a @|KWTAIL| marker. |
| 266 | \end{describe} |
| 267 | |
| 268 | \begin{describe}{mac}{KWCALL} |
| 269 | The @|KWCALL| macro acts as a declaration specifier for functions which |
| 270 | accept keyword arguments. Its effect is to arrange for the compiler to |
| 271 | check, as far as is possible, that calls to the function are well-formed |
| 272 | according to the keyword-argument rules. The exact checking performed |
| 273 | depends on the compiler's abilities (and how well supported the compiler |
| 274 | is): it may check that every other argument is a string; it may check that |
| 275 | the list is terminated with a null pointer; it may not do anything at all. |
| 276 | Again, this marker should be included in a function's definition and in any |
| 277 | declarations. |
| 278 | \end{describe} |
| 279 | |
| 280 | \subsubsection{Auxiliary definitions} |
| 281 | The following macros define data types and functions used for collecting |
| 282 | keyword arguments. |
| 283 | |
| 284 | \begin{describe}{mac}[KWSET_STRUCT]{KWSET_STRUCT(@<set>);} |
| 285 | The @|KWSET_STRUCT| macro defines a \emph{keyword structure} named @|struct |
| 286 | @<set>{}_kwargs|. For each argument defined in the keyword set, this |
| 287 | structure contains two members: one has exactly the @<name> and @<type> |
| 288 | listed in the keyword set definition; the other is a 1-bit-wide bitfield of |
| 289 | type @|unsigned int| named @|@<name>{}_suppliedp|. |
| 290 | \end{describe} |
| 291 | |
| 292 | \begin{describe}{mac}[KWDECL] |
| 293 | {@<declaration-specifiers> KWDECL(@<set>, @<kw>);} |
| 294 | The macro declares and initializes a keyword argument structure variable |
| 295 | named @<kw> for the named keyword @<set>. The optional |
| 296 | @<declaration-specifiers> may provide additional storage-class specifiers, |
| 297 | qualifiers, or other declaration specifiers. The @`_suppliedp' flags are |
| 298 | initialized to zero; the other members are initialized with the |
| 299 | corresponding defaults from the keyword-set definition. |
| 300 | \end{describe} |
| 301 | |
| 302 | \begin{describe}{mac}[KWSET_PARSEFN] |
| 303 | {@<declaration-specifiers> KWSET_PARSEFN(@<set>)} |
| 304 | |
| 305 | The macro @|KWSET_PARSEFN| defines a keyword argument \emph{parser |
| 306 | function} |
| 307 | \begin{prog} |
| 308 | void @<set>{}_kwparse% |
| 309 | (\=struct @<set>{}_kwargs *@<kw>, |
| 310 | const char *@<kwfirst>, va_list *@<ap>, \+\\ |
| 311 | const struct kwval *@<v>, size_t @<n>); |
| 312 | \end{prog} |
| 313 | The macro call can (and usually will) be preceded by storage class |
| 314 | specifiers such as @|static|, for example to adjust the linkage of the |
| 315 | name.\footnote{% |
| 316 | I don't recommend declaring parser functions @|inline|: parser functions |
| 317 | are somewhat large, and modern compilers are pretty good at figuring out |
| 318 | whether to inline static functions.} % |
| 319 | |
| 320 | The function's behaviour is as follows. It parses keyword arguments from a |
| 321 | variable-length argument tail, and/or a vector of @|kwval| structures. |
| 322 | When a keyword argument is recognized, for some keyword @<name>, the |
| 323 | keyword argument structure pointed to by @<kw> is updated: the flag |
| 324 | @|@<name>{}_suppliedp| is set to 1; and the argument value is stored (by |
| 325 | simple assignment) in the @<name> member. |
| 326 | |
| 327 | Hence, if the @`_suppliedp' members are initialized to zero, the caller can |
| 328 | determine which keyword arguments were supplied. It is not possible to |
| 329 | discover whether two or more arguments have the same keyword: in this case, |
| 330 | the value from the last such argument is left in the keyword argument |
| 331 | structure, and any values from earlier arguments are lost. (For this |
| 332 | purpose, the argument vector @<v> is scanned \emph{after} the |
| 333 | variable-length argument tail captured in @<ap>.) |
| 334 | |
| 335 | The variable-argument tail is read from the list described by @|*@<ap>|. |
| 336 | The argument tail is expected to consist of alternating keyword strings (as |
| 337 | ordinary null-terminated strings) and the corresponding values, terminated |
| 338 | by a null pointer of type @|const char~*| in place of a keyword; except |
| 339 | that the first keyword (or terminating null pointer, if no arguments are |
| 340 | provided) is expected to have been extracted already and provided as the |
| 341 | @<kwfirst> argument; the first argument retrieved using the @|va_list| |
| 342 | cursor object should then be the value corresponding to the keyword named |
| 343 | by @<kwfirst>.\footnote{% |
| 344 | This slightly unusual convention makes it possible for a function to |
| 345 | collect the first keyword as a separate mandatory argument, which is |
| 346 | essential if there are no other mandatory arguments. It also means that |
| 347 | the compiler will emit a diagnostic if you attempt to call a function |
| 348 | which expects keyword arguments, but don't supply any and forget the null |
| 349 | pointer which terminates the (empty) list.} % |
| 350 | If @<kwfirst> is a null pointer, then @<ap> need not be a valid pointer; |
| 351 | otherwise, the cursor object @|*@<ap>| will be modified as the function |
| 352 | extracts successive arguments from the tail. |
| 353 | |
| 354 | The keyword vector is read from the vector of @|kwval| structures starting |
| 355 | at address @<v> and containing the following @<n> items. If @<n> is zero |
| 356 | then @<v> need not be a valid pointer. |
| 357 | |
| 358 | The function also handles the special @|kw.valist| and @|kw.tab| arguments |
| 359 | described above (\xref{sec:runtime.keywords.calling}). If an unrecognized |
| 360 | keyword argument is encountered, then \descref{fun}{kw_unknown} is called. |
| 361 | \end{describe} |
| 362 | |
| 363 | \subsubsection{Parsing keywords} |
| 364 | The following macros make use of the definitions described above to actually |
| 365 | make a function's keyword arguments available to it. |
| 366 | |
| 367 | \begin{describe}{mac}[KW_PARSE]{KW_PARSE(@<set>, @<kw>, @<kwfirst>);} |
| 368 | The @|KW_PARSE| macro invokes a keyword argument parsing function. The |
| 369 | @<set> argument should name a keyword set; @<kw> should be an lvalue of |
| 370 | type @|struct @<set>{}_kwargs|; and @<kwfirst> should be the name of the |
| 371 | enclosing function's last mandatory argument, which must have type @|const |
| 372 | char~*|. |
| 373 | |
| 374 | It calls the function @|@<set>{}_kwparse| with five arguments: the address |
| 375 | of the keyword argument structure @<kw>; the string pointer @<kwfirst>; the |
| 376 | address of a temporary argument-tail cursor object of type @|va_list|, |
| 377 | constructed on the assumption that @<kwfirst> is the enclosing function's |
| 378 | final keyword argument; a null pointer; and the value zero (signifying an |
| 379 | empty keyword-argument vector). |
| 380 | |
| 381 | If the variable @<kw> was declared using \descref{mac}{KWDECL} and the |
| 382 | function @|@<set>{}_kwparse| has been defined using |
| 383 | \descref{mac}{KWSET_PARSEFN} then the effect is to parse the keyword |
| 384 | arguments passed to the function and set the members of @<kw> |
| 385 | appropriately. |
| 386 | \end{describe} |
| 387 | |
| 388 | \begin{describe}{mac}[KWPARSE]{KWPARSE(@<set>);} |
| 389 | The macro @|KWPARSE| (note the lack of underscore) combines |
| 390 | \descref{mac}{KWDECL} and \descref{mac}{KW_PARSE}. It declares and |
| 391 | initializes a keyword argument structure variable with the fixed name |
| 392 | @|kw|, and parses the keyword arguments provided to the enclosing function, |
| 393 | storing the results in @|kw|. It assumes that the first keyword name is in |
| 394 | an argument named @|kwfirst_|, as set up by the |
| 395 | \descref{mac}{KWTAIL}[marker]. |
| 396 | |
| 397 | The macro expands both to a variable declaration and a statement: in C89, |
| 398 | declarations must precede statements, so under C89 rules this macro must |
| 399 | appear exactly between the declarations at the head of a brace-enclosed |
| 400 | block (typically the function body) and the statements at the end. This |
| 401 | restriction was lifted in C99, so the macro may appear anywhere in the |
| 402 | function body. However, it is recommended that callers avoid taking |
| 403 | actions which might require cleanup before attempting to parse their |
| 404 | keyword arguments, since keyword argument parsing functions invoke the |
| 405 | @|kw_unknown| handler (\xref{sec:runtime.keywords.unknown}) if they |
| 406 | encounter an unknown keyword, and the calling function will not get a |
| 407 | chance to tidy up after itself if this happens. |
| 408 | \end{describe} |
| 409 | |
| 410 | As mentioned above, it is not permitted to define an empty keyword set. |
| 411 | (Specifically, invoking \descref{mac}{KWSET_STRUCT} for an empty keyword set |
| 412 | would result in attempting to define a structure with no members, which C |
| 413 | doesn't allow.) On the other hand, keyword arguments are a useful extension |
| 414 | mechanism, and it's useful to be able to define a function which doesn't |
| 415 | currently accept any keywords, but which might in the future be extended to |
| 416 | allow keyword arguments. |
| 417 | |
| 418 | \begin{describe}{mac}[KW_PARSE_EMPTY]{KW_PARSE_EMPTY(@<set>, @<kwfirst>);} |
| 419 | This is an analogue to \descref{mac}{KW_PARSE} which checks the keyword |
| 420 | argument list for a function which accepts no keyword arguments. |
| 421 | |
| 422 | It calls the \descref{fun}{kw_parseempty}[function] with five arguments: |
| 423 | the @<set> name, as a string; the string pointer @<kwfirst>; the address of |
| 424 | a temporary argument-tail cursor object of type @|va_list|, constructed on |
| 425 | the assumption that @<kwfirst> is the enclosing function's final keyword |
| 426 | argument; a null pointer; and the value zero (signifying an empty |
| 427 | keyword-argument vector). |
| 428 | |
| 429 | The effect is to check that the argument tail contains no keyword arguments |
| 430 | other than the special predefined ones. |
| 431 | \end{describe} |
| 432 | |
| 433 | \begin{describe}{mac}[KWPARSE_EMPTY]{KWPARSE_EMPTY(@<set>);} |
| 434 | This is an analogue to \descref{mac}{KWPARSE} which checks that the |
| 435 | enclosing function has been passed no keyword arguments other than the |
| 436 | special predefined ones. It assumes that the first keyword name is in an |
| 437 | argument named @|kwfirst_|, as set up by the \descref{mac}{KWTAIL}[marker]. |
| 438 | \end{describe} |
| 439 | |
| 440 | \begin{describe}{fun}[kw_parseempty] |
| 441 | {void kw_parseempty% |
| 442 | (\=const char *@<set>, |
| 443 | const char *@<kwfirst>, va_list *@<ap>, \+\\ |
| 444 | const struct kwval *@<v>, size_t @<n>);} |
| 445 | This function checks an keyword argument list to make sure that contains no |
| 446 | keyword arguments (other than the special ones described in |
| 447 | \xref{sec:runtime.keywords.calling}). |
| 448 | |
| 449 | The @<set> argument should point to a null-terminated string: this will be |
| 450 | reported as the keyword set name to \descref{fun}{kw_unknown}, though it |
| 451 | need not (and likely will not) refer to any defined keyword set. The |
| 452 | remaining arguments are as for the keyword parsing functions defined by the |
| 453 | \descref{mac}{KWSET_PARSEFN}[macro]. |
| 454 | \end{describe} |
| 455 | |
| 456 | \subsection{Function wrappers} \label{sec:runtime.keywords.wrappers} |
| 457 | |
| 458 | Most users will not need the hairy machinery involving argument vectors. |
| 459 | Their main use is in defining \emph{wrapper functions}. Suppose there is a |
| 460 | function @<f> which accepts some keyword arguments, and we want to write a |
| 461 | function @<g> which accepts the same keywords recognized by @<f> and some |
| 462 | additional ones. Unfortunately @<f> may behave differently depending on |
| 463 | whether or not a particular keyword argument is supplied at all, but it's not |
| 464 | possible to synthesize a valid @|va_list| other than by simply capturing a |
| 465 | live argument tail, and it's not possible to decide at runtime whether or not |
| 466 | to include some arguments in a function call. It's still possible to write |
| 467 | @<g>, by building a vector of keyword arguments, collected one-by-one |
| 468 | depending on the corresponding @`_suppliedp' flags. |
| 469 | |
| 470 | A few macros are provided to make this task easier. |
| 471 | |
| 472 | \begin{describe}{mac}[KW_COUNT]{KW_COUNT(@<set>)} |
| 473 | Returns the number of keywords defined in a keyword set named @<set>. |
| 474 | \end{describe} |
| 475 | |
| 476 | \begin{describe}{mac}[KW_COPY] |
| 477 | {KW_COPY(@<fromset>, @<toset>, @<kw>, @<v>, @<n>);} |
| 478 | |
| 479 | The macro @|KW_COPY| populates a vector of @|kwval| structures from a |
| 480 | keyword-argument structure. |
| 481 | |
| 482 | The @<fromset> and @<toset> arguments should be the names of keyword sets; |
| 483 | @<kw> should be an lvalue of type @|@<fromset>{}_kwargs|; @<v> should be |
| 484 | the base address of a sufficiently large vector of @|struct kwval| objects; |
| 485 | and @<n> should be an lvalue of some appropriate integer type. The |
| 486 | @<toset> must be a subset of @<fromset>: i.e., for every keyword defined in |
| 487 | @<toset> there is a keyword defined in @<fromset> with the same name and |
| 488 | type. |
| 489 | |
| 490 | Successive elements of @<v>, starting at index @<n>, are filled in to refer |
| 491 | to the keyword arguments defined in @<toset> whose @`_suppliedp' flag is |
| 492 | set in the argument structure pointed to by @<kw>; for each such argument, |
| 493 | a pointer to the keyword name is stored in the corresponding vector |
| 494 | element's @|kw| member, and a pointer to the argument value, held in the |
| 495 | keyword argument structure, is stored in the vector element's @|val| |
| 496 | member. |
| 497 | |
| 498 | At the end of this, the index @<n> is advanced so as to contain the index |
| 499 | of the first unused element of @<v>. Hence, at most @|KW_COUNT(@<toset>)| |
| 500 | elements of @<v> will be used. |
| 501 | \end{describe} |
| 502 | |
| 503 | |
| 504 | \subsection{Handling unknown-keyword errors} |
| 505 | \label{sec:runtime.keywords.unknown} |
| 506 | |
| 507 | When parsing a variable-length argument tail, it is not possible to continue |
| 508 | after encountering an unknown keyword name. This is because it is necessary |
| 509 | to know the (promoted) type of the following argument value in order to skip |
| 510 | past it; but the only clue provided as to the type is the keyword name, which |
| 511 | in this case is meaningless. |
| 512 | |
| 513 | In this situation, the parser functions generated by |
| 514 | \descref{mac}{KWSET_PARSEFN} (and the \descref{fun}{kw_parseempty}[function]) |
| 515 | call @|kw_unknown|. |
| 516 | |
| 517 | \begin{describe}{fun}[kw_unknown] |
| 518 | {void kw_unknown(const char *@<set>, const char *@<kw>);} |
| 519 | |
| 520 | This is a function of two arguments: @<set> points to the name of the |
| 521 | keyword set expected by the caller, as a null-terminated string; and @<kw> |
| 522 | is the unknown keyword which was encountered. All that @|kw_unknown| does |
| 523 | is invoke the function whose address is stored in the global variable |
| 524 | \descref{var}{kw_unkhook} with the same arguments. |
| 525 | |
| 526 | This function never returns to its caller: if the @|kw_unkhook| function |
| 527 | returns (which it shouldn't) then @|kw_unknown| writes a fatal error |
| 528 | message to the standard error stream and calls \man{abort}{3}. |
| 529 | \end{describe} |
| 530 | |
| 531 | \begin{describe}{ty}[kw_unkhookfn] |
| 532 | {typedef void kw_unkhookfn(const char *@<set>, const char *@<kw>);} |
| 533 | |
| 534 | The @|kw_unkhookfn| type is the type of unknown-keyword handler functions. |
| 535 | A handler function is given two arguments, both of which are pointers to |
| 536 | null-terminated strings: @<set> is the name of the keyword set expected; |
| 537 | and @<kw> is the name of the offending unknown keyword. |
| 538 | \end{describe} |
| 539 | |
| 540 | \begin{describe}{var}[kw_unkhook]{kw_unkhookfn *kw_unkhook} |
| 541 | This variable\footnote{% |
| 542 | Having a single global hook variable is obviously inadequate for a modern |
| 543 | library, but dealing with multiple threads isn't currently possible |
| 544 | without writing (moderately complex) system-specific code which would be |
| 545 | out of place in this library. The author's intention is that the hook |
| 546 | variable @|kw_unkhook| be `owned' by some external library which can make |
| 547 | its functionality available to client programs in a safer and more |
| 548 | convenient way. On Unix-like platforms (including Cygwin) that library |
| 549 | will be (a later version of) \textbf{mLib}; other platforms will likely |
| 550 | need different arrangements. The author is willing to coordinate any |
| 551 | such efforts.} % |
| 552 | holds the current unknown-keyword handler function. It will be invoked by |
| 553 | \descref{fun}{kw_unknown}. The function may take whatever action seems |
| 554 | appropriate, but should not return to its caller. |
| 555 | |
| 556 | Initially, this variable points to the |
| 557 | \descref{fun}{kw_defunknown}[function]. |
| 558 | \end{describe} |
| 559 | |
| 560 | \begin{describe}{fun}[kw_defunknown] |
| 561 | {void kw_defunknown(const char *@<set>, const char *@<kw>);} |
| 562 | This function simply writes a message to standard error, to the effect that |
| 563 | the keyword named by @<kw> is not known in the keyword set @<set>, and |
| 564 | calls \man{abort}{3}. |
| 565 | |
| 566 | This function is the default value of the \descref{var}{kw_unkhook}[hook |
| 567 | variable]. |
| 568 | \end{describe} |
| 569 | |
| 570 | As an example of the kind of special effect which can be achieved using this |
| 571 | hook, the following hacking answers whether a function recognizes a |
| 572 | particular keyword argument. |
| 573 | |
| 574 | \begin{prog} |
| 575 | \#define KWARGS_TEST(k, val) KWARGS(K(k, val) K(kw.unknown, 0)) |
| 576 | \\+ |
| 577 | static jmp_buf kw_test_jmp; |
| 578 | \\+ |
| 579 | static void kw_test_unknown(const char *set, const char *kw) \\ |
| 580 | \{ \\ \ind |
| 581 | if (strcmp(kw, "kw.unknown")) longjmp(kw_test_jmp, 1); \\ |
| 582 | else longjmp(kw_test_jmp, 2); \-\\ |
| 583 | \} \\+ |
| 584 | |
| 585 | \#define KW_TEST(flag, set, call) do \{ \macsl \\ \ind |
| 586 | kw_unkhookfn *oldunk = kw_unkhook; \macsl \\ |
| 587 | kw_unkhook = kw_test_unknown; \macsl \\ |
| 588 | switch (setjmp(kw_test_jmp)) \{ \macsl \\ \ind |
| 589 | case 0: call; abort(); \macsl \\ |
| 590 | case 1: flag = 1; break; \macsl \\ |
| 591 | case 2: flag = 0; break; \macsl \\ |
| 592 | default: abort(); \macsl\-\\ |
| 593 | \} \macsl \\ |
| 594 | kw_unkhook = oldunk; \macsl\-\\ |
| 595 | \} while (0) \\+ |
| 596 | |
| 597 | @/* Example of use */ \\ |
| 598 | int f; \\ |
| 599 | KW_TEST(f, somefunc(1, "two", 3, KWARGS_TEST("shiny", 68.7))); \\ |
| 600 | /\=* \comment{now @|f| is nonzero if @|somefunc| accepts the |
| 601 | @|shiny| keyword} \+\\ |
| 602 | {}* \comment{(which we hope wants a @|double| argument)} \\ |
| 603 | {}*/ |
| 604 | \end{prog} |
| 605 | |
| 606 | %%%-------------------------------------------------------------------------- |
| 607 | \section{Object system support} \label{sec:runtime.object} |
| 608 | |
| 609 | This section describes the macros and functions exposed in the @|<sod/sod.h>| |
| 610 | header file which provide assistance for working with Sod classes and |
| 611 | objects. |
| 612 | |
| 613 | The runtime support functionality defined here generally expects that |
| 614 | instances and classes inherit from the standard @|SodObject| root object. |
| 615 | While the translator can (at some effort) support alternative roots, they |
| 616 | will require different run-time support machinery. |
| 617 | |
| 618 | \begin{describe}{feat}{SOD_RECKLESS} |
| 619 | Some of Sod's macros include runtime checking by default. This checking |
| 620 | can be disabled if you value performance more than early diagnosis of |
| 621 | problems. Define @|SOD_RECKLESS| to a nonzero value before including |
| 622 | @|<sod/sod.h>| to inhibit the runtime checking. |
| 623 | \end{describe} |
| 624 | |
| 625 | |
| 626 | \subsection{Layout utilities} \label{sec:runtime.object.layout} |
| 627 | |
| 628 | The following macros are useful in finding one's way around an instance |
| 629 | layout structure, given various levels of information about what kind of |
| 630 | object one is dealing with, or for computing the tables which are used for |
| 631 | this kind of navigation. |
| 632 | |
| 633 | These macros are mostly intended for use in code generated by the Sod |
| 634 | translator. Others may find them useful for special effects, but they can be |
| 635 | tricky to understand and use correctly and can't really be recommended for |
| 636 | general use. |
| 637 | |
| 638 | \begin{describe}{mac}[SOD_OFFSETDIFF] |
| 639 | {ptrdiff_t SOD_OFFSETDIFF(@<type>, @<member>_1, @<member>_2);} |
| 640 | Returns the signed offset between two members of a structure or union type. |
| 641 | |
| 642 | Given a structure or union type @<type>, and two member names @<member>_1 |
| 643 | and @<member>_2, then @|SOD_OFFSETDIFF| gives the difference, in bytes, |
| 644 | between the addresses of objects @|$x$.@<member>_1| and @|$x$.@<member>_2| |
| 645 | for any object $x$ of type @<type>. |
| 646 | |
| 647 | This macro is used internally when generating vtables and is not expected |
| 648 | to be very useful elsewhere. |
| 649 | \end{describe} |
| 650 | |
| 651 | \begin{describe}{mac}[SOD_ILAYOUT] |
| 652 | {@<cls>{}__ilayout *SOD_ILAYOUT(@<cls>, @<chead>, const void *@<obj>);} |
| 653 | Recovers the instance layout base address from a pointer to one of its |
| 654 | instance chains. |
| 655 | |
| 656 | Specifically, given a class name @<cls>, the nickname @<chead> of the least |
| 657 | specific class in one of @<cls>'s superclass chains, and a pointer @<obj> |
| 658 | to the instance storage for the chain containing @<chead> within a direct |
| 659 | instance of @<cls> (i.e., not an instance of any proper subclass), |
| 660 | @|SOD_ILAYOUT| returns the a pointer to the layout structure containing |
| 661 | @<obj>. |
| 662 | |
| 663 | This macro is used internally in effective method bodies and is not |
| 664 | expected to be very useful elsewhere since it's unusual to have such |
| 665 | specific knowledge about the dynamic type of an instance. The |
| 666 | @|SOD_INSTBASE| macro (described below) is more suited to general use. |
| 667 | \end{describe} |
| 668 | |
| 669 | \begin{describe}{mac}[SOD_INSTBASE]{void *SOD_INSTBASE(const @<cls> *@<obj>)} |
| 670 | Finds the base address of an instance's layout. |
| 671 | |
| 672 | Given a pointer @<obj> to an instance, @|SOD_INSTBASE| returns the base |
| 673 | address of the storage allocated to @<obj>. This is useful if you want to |
| 674 | free a dynamically allocated instance, for example. |
| 675 | |
| 676 | This macro needs to look up an offset in @<obj>'s vtable to do its work. |
| 677 | Compare @|SOD_ILAYOUT| above, which is faster but requires precise |
| 678 | knowledge of the instance's dynamic class. |
| 679 | \end{describe} |
| 680 | |
| 681 | |
| 682 | \subsection{Classes} \label{sec:runtime.object.class} |
| 683 | |
| 684 | The following macros and functions query the runtime relationships between |
| 685 | instances and classes. |
| 686 | |
| 687 | \begin{describe}{mac}[SOD_CLASSOF] |
| 688 | {const SodClass *SOD_CLASSOF(const @<cls> *@<obj>);} |
| 689 | Returns the class object describing an instance's dynamic class. |
| 690 | |
| 691 | Given a pointer @<obj> to an instance, @|SOD_CLASSOF| returns a pointer to |
| 692 | @<obj>'s dynamic class, which (assuming @<obj> is typed correctly in the |
| 693 | first place) will be a subclass of @<cls>. (If you wanted the class object |
| 694 | for @<cls> itself, it's called @|@<cls>{}__class|.) |
| 695 | \end{describe} |
| 696 | |
| 697 | \begin{describe}{fun}[sod_subclassp] |
| 698 | {int sod_subclassp(const SodClass *@<sub>, const SodClass *@<super>);} |
| 699 | |
| 700 | Decide whether one class @<sub> is actually a subclass of another class |
| 701 | @<super>. |
| 702 | |
| 703 | The @<sod_subclassp> function returns nonzero if and only if |
| 704 | @<sub> is a subclass of @<super>. |
| 705 | |
| 706 | This involves a run-time trawl through the class structures: while some |
| 707 | effort has been made to make it perform well it's still not very fast. |
| 708 | \end{describe} |
| 709 | |
| 710 | |
| 711 | \subsection{Conversions} \label{sec:runtime.object.conversions} |
| 712 | |
| 713 | The following macros and functions are used to convert instance pointers of |
| 714 | some (static) type into instance pointers of other static types to the same |
| 715 | instance. |
| 716 | |
| 717 | \begin{describe}{mac}[SOD_XCHAIN] |
| 718 | {void *SOD_XCHAIN(@<chead>, const @<cls> *@<obj>);} |
| 719 | Performs a `cross-chain upcast'. |
| 720 | |
| 721 | Given a pointer @<obj> to an instance of a class of type @<cls> and the |
| 722 | nickname @<chead> of the least specific class in one of @<cls>'s superclass |
| 723 | chains which does not contain @<cls> itself, @|SOD_XCHAIN| returns the |
| 724 | address of that chain's storage within the instance layout as a raw |
| 725 | @|void~*| pointer. (Note that @<cls> is not mentioned explicitly.) |
| 726 | |
| 727 | This macro is used by the generated @|@<cls>{}__CONV_@<c>| conversion |
| 728 | macros, which you are encouraged to use instead where possible. |
| 729 | \end{describe} |
| 730 | |
| 731 | \begin{describe*} |
| 732 | {\dhead{mac}[SOD_CONVERT] |
| 733 | {@<cls> *SOD_CONVERT(@<cls>, const void *@<obj>);} |
| 734 | \dhead{fun}[sod_convert] |
| 735 | {void *sod_convert(const SodClass *@<cls>, const void *@<obj>);}} |
| 736 | Perform general conversions (up-, down-, and cross-casts) on instance |
| 737 | pointers. |
| 738 | |
| 739 | Given a class @<cls> and a pointer @<obj> to an instance, return an |
| 740 | appropriately converted pointer to @<obj> if @<obj> is indeed an instance |
| 741 | of (some subclass of) @<cls>; otherwise return a null pointer. |
| 742 | |
| 743 | The @|SOD_CONVERT| macro expects @<cls> to be a class name; the |
| 744 | @|sod_convert| function expects a pointer to a class object instead. |
| 745 | |
| 746 | This involves a run-time trawl through the class structures: while some |
| 747 | effort has been made to make it perform well it's still not very fast. For |
| 748 | upcasts (where @<cls> is a superclass of the static type of @<obj>) the |
| 749 | automatically defined conversion macros should be used instead, because |
| 750 | they're much faster and can't fail. |
| 751 | |
| 752 | When the target class is known statically, it's slightly more convenient to |
| 753 | use the @|SOD_CONVERT| macro than the @|sod_convert| function, since the |
| 754 | class object name is longer and uglier, and the macro returns a pointer of |
| 755 | the correct type. |
| 756 | \end{describe*} |
| 757 | |
| 758 | |
| 759 | \subsection{Instance lifecycle} |
| 760 | \label{sec:runtime.object.lifecycle} |
| 761 | |
| 762 | The following macros and functions manage the standard steps along an |
| 763 | instance's lifecycle. |
| 764 | |
| 765 | \subsubsection{Low-level operations} |
| 766 | The following macros and functions are agnostic with respect to storage |
| 767 | allocation strategies. They don't concern themselves with allocation or |
| 768 | deallocation, and applications are free to use any suitable mechanism. |
| 769 | |
| 770 | \begin{describe*} |
| 771 | {\dhead{mac}[SOD_INIT] |
| 772 | {@<cls> *SOD_INIT(@<cls>, void *@<p>, @<keywords>);} |
| 773 | \dhead{fun}[sod_init] |
| 774 | {void *sod_init(const SodClass *@<cls>, void *@<p>, \dots);} |
| 775 | \dhead{fun}[sod_initv] |
| 776 | {void *sod_initv(const SodClass *@<cls>, void *@<p>, va_list @<ap>);}} |
| 777 | Imprints and initializes an instance of a class @<cls> in the storage |
| 778 | starting at address~@<p>. |
| 779 | |
| 780 | The direct class for the new instance is specified as a class name to |
| 781 | @|SOD_INIT|, or a pointer to a class object to the functions. |
| 782 | |
| 783 | Keyword arguments for the initialization message may be provided. The |
| 784 | @|SOD_INIT| macro expects a single preprocessor-time argument which is |
| 785 | a use of one of \descref*{mac}{KWARGS} or \descref{mac}{NO_KWARGS}; the |
| 786 | @|sod_init| function expects the keywords as a variable-length argument |
| 787 | tail; and @|sod_initv| expects the keywords to be passed indirectly, |
| 788 | through the captured argument-tail cursor @<ap>. |
| 789 | |
| 790 | The return value is an instance pointer for the class @<cls>; the |
| 791 | @|SOD_INIT| macro will have converted it to the correct type, so it should |
| 792 | probably be used where possible. In fact, this is guaranteed to be equal |
| 793 | to @<p> by the layout rules described in |
| 794 | \xref{sec:structures.layout.instance}. |
| 795 | \end{describe*} |
| 796 | |
| 797 | \begin{describe}{fun}[sod_teardown]{int sod_teardown(void *@<p>);} |
| 798 | Tears down an instance of a class, releasing any resources it holds. |
| 799 | |
| 800 | This function is a very thin wrapper around sending the |
| 801 | \descref*{msg}{obj.teardown} message. See the description of that message |
| 802 | (\autopageref{msg:obj.teardown}) and \xref{sec:concepts.lifecycle.death} |
| 803 | for details. |
| 804 | \end{describe} |
| 805 | |
| 806 | \subsubsection{Automatic storage duration} |
| 807 | The following macro constructs an instance with automatic storage duration. |
| 808 | |
| 809 | \begin{describe}{mac}[SOD_DECL]{SOD_DECL(@<cls>, @<var>, @<keywords>);} |
| 810 | Declares and initializes an instance with automatic storage duration. |
| 811 | |
| 812 | Given a class name @<cls> and an identifier @<var>, @|SOD_DECL| declares |
| 813 | @<var> to be a pointer to an instance of @<cls>. The instance is |
| 814 | initialized in the sense that its vtable and class pointers have been set |
| 815 | up, and slots for which initializers are defined are set to the appropriate |
| 816 | initial values. |
| 817 | |
| 818 | Keyword arguments for the initialization message may be provided. The |
| 819 | macro expects a single preprocessor-time argument which is a use of one of |
| 820 | \descref*{mac}{KWARGS} or \descref{mac}{NO_KWARGS}. |
| 821 | |
| 822 | The instance has automatic storage duration: pointers to it will become |
| 823 | invalid when control exits the scope of the declaration. If necessary, the |
| 824 | instance should be torn down before this happens, using the |
| 825 | \descref{fun}{sod_teardown}[function]. It may be appropriate to @|assert| |
| 826 | that the object is ready for deallocation at this time. |
| 827 | |
| 828 | By default, this macro will abort the program if the size allocated for the |
| 829 | instance doesn't match the size required by the class object; set |
| 830 | \descref{feat}{SOD_RECKLESS} to inhibit this check. |
| 831 | \end{describe} |
| 832 | |
| 833 | \subsubsection{Dynamic allocation} |
| 834 | The following macros and functions deal with objects allocated from the |
| 835 | standard C heap. They don't work in freestanding implementations where |
| 836 | @|malloc| and @|free| are not available. |
| 837 | |
| 838 | \begin{describe*} |
| 839 | {\dhead{mac}[SOD_MAKE]{@<cls> *SOD_MAKE(@<cls>, @<keywords>);} |
| 840 | \dhead{fun}[sod_make]{void *sod_make(const SodClass *@<cls>, \dots);} |
| 841 | \dhead{fun}[sod_makev] |
| 842 | {void *sod_makev(const SodClass *@<cls>, va_list @<ap>);}} |
| 843 | Constructs and returns a pointer to a new instance of @<cls>. |
| 844 | |
| 845 | The direct class for the new instance is specified as a class name to |
| 846 | @|SOD_MAKE|, or a class object to the functions. |
| 847 | |
| 848 | Keyword arguments for the initialization message may be provided. The |
| 849 | @|SOD_MAKE| macro expects a single preprocessor-time argument which is |
| 850 | a use of one of \descref*{mac}{KWARGS} or \descref{mac}{NO_KWARGS}; the |
| 851 | @|sod_make| function expects the keywords as a variable-length argument |
| 852 | tail; and @|sod_makev| expects the keywords to be passed indirectly, |
| 853 | through the captured argument-tail cursor @<ap>. |
| 854 | |
| 855 | Storage for the new instance will have been allocated using the standard |
| 856 | @|malloc| function. The easiest way to destroy the instance, when it is no |
| 857 | longer needed, is probably to call the |
| 858 | \descref{fun}{sod_destroy}[function]. |
| 859 | |
| 860 | The return value is an instance pointer for the class @<cls>; the |
| 861 | @|SOD_MAKE| macro will have converted it to the correct type, so it should |
| 862 | probably be used where possible. |
| 863 | \end{describe*} |
| 864 | |
| 865 | \begin{describe}{fun}[sod_destroy]{int sod_destroy(void *@<p>);} |
| 866 | Tears down and frees an instance allocated using @|malloc|. |
| 867 | |
| 868 | The pointer @<p> should be an instance pointer, i.e., a pointer to any of |
| 869 | an instance's chains. The instance is torn down, by sending it the |
| 870 | \descref{msg}{obj.teardown}[message]. If the instance reports itself ready |
| 871 | for deallocation, then its storage is released using @|free|. The return |
| 872 | value is the value returned by the @|obj.teardown| message. |
| 873 | \end{describe} |
| 874 | |
| 875 | %%%----- That's all, folks -------------------------------------------------- |
| 876 | |
| 877 | %%% Local variables: |
| 878 | %%% mode: LaTeX |
| 879 | %%% TeX-master: "sod.tex" |
| 880 | %%% TeX-PDF-mode: t |
| 881 | %%% End: |