glk-main-function.sgml \
glk-api-conventions.sgml \
glk-character-encoding.sgml \
+ glk-normalization.sgml \
glk-output.sgml \
glk-line-input.sgml \
glk-windows.sgml \
expand_content_files = \
glk-main-function.sgml \
glk-api-conventions.sgml \
+ glk-normalization.sgml \
glk-output.sgml \
glk-line-input.sgml \
glk-window-arrangement.sgml \
The Glk spec does not require that resources be stored in a Blorb file. It says only that the library knows how to load them and use them, when you so request. However, Blorb is the recommended way to supply portable resources. Most Glk libraries will support Blorb, using the interface defined in this section.
</para>
<para>
+The quick summary: resources are identified by type (image, sound, etc) and by an index number.
+<note><para>
+But not by name.
+This is for historical reasons; Infocom's Z-machine architecture used this scheme.
+</para></note>
+</para>
+<para>
For the complete Blorb specification and tools for Blorb file manipulation, see:
<ulink role="online-location" url="http://www.eblong.com/zarf/blorb/">http://www.eblong.com/zarf/blorb/</ulink>
</para>
<xi:include href="xml/glk-line-input.sgml"/>
<xi:include href="xml/glk-character-input.xml"/>
<xi:include href="xml/glk-case.xml"/>
+ <xi:include href="xml/glk-normalize.xml"/>
+ <xi:include href="xml/glk-normalization.sgml"/>
</chapter>
<!-- Chapter 3. Windows -->
<xi:include href="xml/glk-accepting-hyperlinks.xml"/>
<xi:include href="xml/glk-hyperlinks-testing.xml"/>
</chapter>
+
+ <!-- Chapter 10. The System Clock -->
+ <chapter>
+ <title>The System Clock</title>
+ <xi:include href="xml/glk-clock.xml"/>
+ <xi:include href="xml/glk-clock-conversions.xml"/>
+ <xi:include href="xml/glk-clock-testing.xml"/>
+ </chapter>
- <!-- Chapter 10. Porting, Adapting and Other Messy Bits -->
+ <!-- Chapter 11. Porting, Adapting and Other Messy Bits -->
<xi:include href="glk-porting.sgml"/>
- <!-- Chapter 11. Appendices -->
+ <!-- Appendices -->
<appendix>
<title>The Dispatch Layer</title>
<xi:include href="dispatch.sgml"/>
chimara_error_quark
ChimaraResourceLoadFunc
ChimaraResourceType
+ChimaraGlkWindowType
chimara_glk_new
chimara_glk_set_interactive
chimara_glk_get_interactive
chimara_glk_feed_line_input
chimara_glk_is_char_input_pending
chimara_glk_is_line_input_pending
+chimara_glk_get_num_tag_names
+chimara_glk_get_tag
+chimara_glk_get_tag_names
+chimara_glk_update_style
chimara_glk_set_resource_load_callback
<SUBSECTION Standard>
CHIMARA_GLK
gestalt_Version
gestalt_Unicode
GLK_MODULE_UNICODE
+gestalt_UnicodeNorm
+GLK_MODULE_UNICODE_NORM
gestalt_CharOutput
gestalt_CharOutput_CannotPrint
gestalt_CharOutput_ApproxPrint
gestalt_CharOutput_ExactPrint
gestalt_LineInput
+gestalt_LineInputEcho
+GLK_MODULE_LINE_ECHO
+gestalt_LineTerminators
+GLK_MODULE_LINE_TERMINATORS
+gestalt_LineTerminatorKey
gestalt_CharInput
gestalt_MouseInput
gestalt_Timer
glk_buffer_to_title_case_uni
</SECTION>
+<SECTION>
+<FILE>glk-normalize</FILE>
+<TITLE>Unicode String Normalization</TITLE>
+glk_buffer_canon_decompose_uni
+glk_buffer_canon_normalize_uni
+</SECTION>
+
<SECTION>
<FILE>glk-window-opening</FILE>
<TITLE>Window Opening, Closing, and Constraints</TITLE>
winmethod_Below
winmethod_Fixed
winmethod_Proportional
+winmethod_Border
+winmethod_NoBorder
glk_window_close
<SUBSECTION Private>
winmethod_DirMask
winmethod_DivisionMask
+winmethod_BorderMask
</SECTION>
<SECTION>
glk_request_line_event
glk_request_line_event_uni
glk_cancel_line_event
+glk_set_echo_line_event
+glk_set_terminators_line_event
</SECTION>
<SECTION>
GLK_MODULE_HYPERLINKS
</SECTION>
+<SECTION>
+<FILE>glk-clock</FILE>
+<TITLE>The System Clock</TITLE>
+glktimeval_t
+glk_current_time
+glk_current_simple_time
+</SECTION>
+
+<SECTION>
+<FILE>glk-clock-conversions</FILE>
+<TITLE>Time and Date Conversions</TITLE>
+glkdate_t
+glk_time_to_date_utc
+glk_time_to_date_local
+glk_simple_time_to_date_utc
+glk_simple_time_to_date_local
+glk_date_to_time_utc
+glk_date_to_time_local
+glk_date_to_simple_time_utc
+glk_date_to_simple_time_local
+</SECTION>
+
+<SECTION>
+<FILE>glk-clock-testing</FILE>
+<TITLE>Testing for Clock Capabilities</TITLE>
+gestalt_DateTime
+GLK_MODULE_DATETIME
+</SECTION>
+
<SECTION>
<FILE>dispatch-interrogating</FILE>
<TITLE>Interrogating the Interface</TITLE>
gidispatch_count_classes
+gidispatch_get_class
gidispatch_count_intconst
gidispatch_get_intconst
gidispatch_intconst_t
garglk_unput_string
garglk_unput_string_uni
garglk_set_zcolors
+garglk_set_zcolors_stream
garglk_set_reversevideo
+garglk_set_reversevideo_stream
<SUBSECTION Constants>
zcolor_Current
zcolor_Default
-zcolor_Black
-zcolor_Red
-zcolor_Green
-zcolor_Yellow
-zcolor_Blue
-zcolor_Magenta
-zcolor_Cyan
-zcolor_White
-zcolor_LightGrey
-zcolor_MediumGrey
-zcolor_DarkGrey
+zcolor_Cursor
+zcolor_Transparent
keycode_Erase
+keycode_MouseWheelUp
+keycode_MouseWheelDown
<SUBSECTION Private>
zcolor_NUMCOLORS
</SECTION>
<note><para>
An earlier version of Glk had gestalt selectors <code>gestalt_FunctionNameToID</code> and <code>gestalt_FunctionIDToName</code>, but these have been withdrawn.
</para></note>
-They are defined and used only in the dispatch layer.
+They are defined and used only by the dispatch layer.
+</para>
+<para>
+Call selectors 0x1200 to 0x12FF are reserved for extension projects by Carlos Sanchez.
+The same is true of gestalt selector 0x1200.
+These are not documented here.
</para>
</refsect1>
</refentry>
The <filename class="headerfile">glk.h</filename> header file is the same on all platforms, with the sole exception of the typedef of #glui32 and #glsi32. These will always be defined as 32-bit unsigned and signed integer types, which may be <quote><type>long</type></quote> or <quote><type>int</type></quote> or some other C definition.
</para>
<para>
-Note that all constants are #defines, and all functions are actual function declarations (as opposed to macros.)
+Note that all constants are #defines. All functions are currently actual function declarations (as opposed to macros), but this may change in future Glk revisions. As in the standard C library, if Glk function is defined by a macro, an actual function of the same name will also be available.
</para>
-<note><para>
-There are a few places where macros would be more efficient — glk_gestalt() and glk_gestalt_ext(), for example — but they are not likely to be CPU bottlenecks, and clarity seems more important.
-</para></note>
<para>
-%FALSE is 0; %TRUE is 1. %NULL is also 0.
+Functions that return or generate boolean values will produce only 0 (%FALSE) or 1 (%TRUE). Functions that accept boolean arguments will accept any value, with zero indicating %FALSE and nonzero indicating %TRUE.
</para>
<para>
-As stated above, it is illegal to pass %NULL to a function which is expecting a valid object reference, unless the function definition says otherwise.
+%NULL (when used in this document) refers to the C null pointer. As stated above, it is illegal to pass %NULL to a function which is expecting a valid object reference, unless the function definition says otherwise.
</para>
<para>
-Some functions have pointer arguments, acting as <quote>variable</quote> or <quote>reference</quote> arguments; the function's intent is to return some value in the space pointed to by the argument. Unless the function says otherwise, it is legal to pass a %NULL pointer to indicate that you do not care about that value.
+Some functions have pointer arguments, acting as <quote>variable</quote> or <quote>reference</quote> arguments; the function's intent is to return some value in the space pointed to by the argument. Unless the function says otherwise, it is legal to pass %NULL to indicate that you do not care about that value.
</para>
</refsect1>
</refentry>
<refsect1>
<title>Description</title>
<para>
-The way windows are displayed is, of course, entirely up to the Glk library; it depends on what is natural for the player's machine. The borders between windows may be black lines, 3-D bars, rows of <quote><computeroutput>#</computeroutput></quote> characters; there may even be no borders at all.
+The way windows are displayed is, of course, entirely up to the Glk library; it depends on what is natural for the player's machine. The borders between windows may be black lines, 3-D bars, rows of <quote><computeroutput>#</computeroutput></quote> characters; there may even be no borders at all.
+The library may not support the Border/NoBorder hint, in which case <emphasis>every</emphasis> pair of windows will have a visible border — or no border — between them.
</para>
<note><para>
-This is an important possibility to keep in mind.
+The Border/NoBorder was introduced in Glk 0.7.1.
+Prior to that, all games used the Border hint, and this remains the default.
+However, as noted, not all implementations display window borders.
+Therefore, for existing implementations, <quote>Border</quote> may be understood as <quote>your normal style of window display</quote>; <quote>NoBorder</quote> may be understood as <quote>suppress any interwindow borders you may have</quote>.
</para></note>
<para>
-There may be other decorations as well. A text buffer window will often have a scroll bar. The library (or player) may prefer wide margins around each text window. And so on.
+There may be decorations within the windows as well. A text buffer window will often have a scroll bar. The library (or player) may prefer wide margins around each text window. And so on.
</para>
<para>
The library is reponsible for handling these decorations, margins, spaces, and borders. You should never worry about them. You are guaranteed that if you request a fixed size of two rows, your text grid window will have room for two rows of characters — if there is enough total space. Any margins or borders will be allowed for already. If there <emphasis>isn't</emphasis> enough total space (as in stages 4 and 5 of <link linkend="chimara-Figure-Squeezing-Window">this figure</link>), you lose, of course.
]>
<referenceinfo>
<title>Glk API Specification</title>
-<subtitle>API version 0.7.0</subtitle>
+<subtitle>API version 0.7.2</subtitle>
<author>
<personname>
<firstname>Andrew</firstname>
<email>erkyrath@eblong.com</email>
</author>
<copyright>
- <year>1998–2004</year>
+ <year>1998–2011</year>
<holder>Andrew Plotkin</holder>
</copyright>
<legalnotice>
-You have permission to display, download, and print this document, provided that you do so for personal, non-commercial use only. You may not modify or distribute this document without the author's written permission.
+<para>
+This specification is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License: <ulink href="http://creativecommons.org/licenses/by-nc-sa/3.0">http://creativecommons.org/licenses/by-nc-sa/3.0</ulink>
+</para>
+<para>
+The API <emphasis>described</emphasis> by this document is an idea, not an expression of an idea, and is therefore not copyrightable.
+Anyone is free to write programs that use the Glk API or libraries that implement it.
+</para>
</legalnotice>
<releaseinfo>
The authors of the Chimara library have adapted this document to better fit the format of a GtkDoc reference manual. They have also added notes specific to Chimara's implementation of the Glk API. The original API specification and further Glk information can be found at: <ulink url="http://www.eblong.com/zarf/glk/">http://www.eblong.com/zarf/glk/</ulink>
<chapter id="chimara-Introduction"><title>Introduction</title>
<sect1 id="chimara-What-Glk-Is"><title>What Glk Is</title>
<para>
-Glk is an attempt to define a portable API (programming interface) for applications with text UIs (user interfaces.)
+Glk defines a portable API (programming interface) for applications with text UIs (user interfaces.)
+It was primarily designed for interactive fiction, but it should be suitable for many interactive text utilities, particularly those based on a command line.
</para>
<para>
-Rather than go into a detailed explanation of what that means, let me give examples from the world of text adventures. TADS and Infocom's Z-machine have nearly identical interface capabilities; each allows a program to...
+Rather than go into a detailed explanation of what that means, let me give examples from the world of text adventures. TADS, Glulx, and Infocom's Z-machine have nearly identical interface capabilities; each allows a program to...
<itemizedlist>
<listitem><para>print an indefinite stream of text into an output buffer, with some style control</para></listitem>
<listitem><para>input a line of text</para></listitem>
and so on. However, the implementation of these capabilities vary widely between platforms and operating systems. Furthermore, this variance is transparent to the program (the adventure game.) The game does not care whether output is displayed via a character terminal emulator or a GUI window; nor whether input uses Mac-style mouse editing or EMACS-style control key editing.
</para>
<para>
-On the third hand, the user is likely to care deeply about these interface decisions. This is why there are Mac-native interpreters on Macintoshes, pen-controlled interpreters on Newtons and PalmOS PDAs, and so on — and (ultimately) why there Macintoshes and Palms and X-windows platforms in the first place.
+On the third hand, the user is likely to care deeply about these interface decisions. This is why there are Mac-native interpreters on Macintoshes, stylus and touch-screen interpreters on mobile devices, and so on — and (ultimately) why there are Macintoshes and iPads and terminal window apps in the first place.
</para>
<para>
On the <emphasis>fourth</emphasis> hand, TADS and Inform are not alone; there is historically a large number of text adventure systems. Most are obsolete or effectively dead; but it is inevitable that more will appear. Users want each living system ported to all the platforms in use. Users also prefer these ports to use the same interface, as much as possible.
--- /dev/null
+<?xml version="1.0"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
+]>
+<refentry id="chimara-A-Note-on-Unicode-Case-Folding-and-Normalization">
+<refmeta>
+<refentrytitle>A Note on Unicode Case-Folding and Normalization</refentrytitle>
+<manvolnum>3</manvolnum>
+<refmiscinfo>CHIMARA Library</refmiscinfo>
+</refmeta>
+<refnamediv>
+<refname>A Note on Unicode Case-Folding and Normalization</refname>
+<refpurpose>How to handle line input</refpurpose>
+</refnamediv>
+<refsect1>
+<title>Description</title>
+<para>
+With all of these Unicode transformations hovering about, an author might reasonably ask about the right way to handle line input.
+Our recommendation is: call glk_buffer_to_lower_case_uni(), followed by glk_buffer_canon_normalize_uni(), and then parse the result.
+The parsing process should of course match against strings that have been put through the same process.
+</para>
+<para>
+The Unicode spec (chapter 3.13) gives a different, three-step process: decomposition, case-folding, and decomposition again.
+Our recommendation comes through a series of practical compromises:
+</para>
+<itemizedlist>
+ <listitem><para>
+ The initial decomposition is only necessary because of a historical error in the Unicode spec: character 0x0345 (COMBINING GREEK YPOGEGRAMMENI) behaves inconsistently.
+ We ignore this case, and skip this step.
+ </para></listitem>
+ <listitem><para>
+ Case-folding is a slightly different operation from lower-casing.
+ (Case-folding splits some combined characters, so that, for example, <quote>ß</quote> can match both <quote>ss</quote> and <quote>SS</quote>.)
+ However, Glk does not currently offer a case-folding function.
+ We substitute glk_buffer_to_lower_case_uni().
+ </para></listitem>
+ <listitem><para>
+ I'm not sure why the spec recommends decomposition (glk_buffer_canon_decompose_uni()) rather than glk_buffer_canon_normalize_uni().
+ However, composed characters are the norm in source code, and therefore in compiled Inform game files.
+ If we specified decomposition, the compiler would have to do extra work; also, the standard Inform dictionary table (with its fixed word length) would store fewer useful characters.
+ Therefore, we substitute glk_buffer_canon_normalize_uni().
+ </para></listitem>
+</itemizedlist>
+<note><para>
+ We may revisit these recommendations in future versions of the spec.
+</para></note>
+</refsect1>
+</refentry>
\ No newline at end of file
This is the real nuisance, because Glk provides a limited set of stream and file functions. And yet there are all these beautiful ANSI stdio calls, which have all these clever tricks — <function>ungetc()</function>, fast macro <function>fgetc()</function>, formatted <function>fprintf()</function>, not to mention the joys of direct pathname manipulation. Why bother with the Glk calls?
</para>
<para>
-The problem is, the stdio library really isn't always the best choice. PalmOS and Newton simply don't use stdio. The Mac has a stdio library built on top of its native file API, but it's a large extra library which porters may not wish to link in.
+The problem is, the stdio library really isn't always the best choice, particularly on mobile OSes.
</para>
<para>
There's also the problem of hooking into the Glk API. Window output goes through Glk streams.
chimara-glk.c chimara-glk.h chimara-glk-private.h \
chimara-if.c chimara-if.h \
chimara-marshallers.c chimara-marshallers.h \
+ datetime.c \
dispatch.c \
event.c event.h \
fileref.c fileref.h \
* <note><para>
* Unicode has some strange case cases. For example, a combined character
* that looks like <quote>ss</quote> might properly be upper-cased into
- * <emphasis>two</emphasis> characters <quote>S</quote>. Title-casing is even
+ * <emphasis>two</emphasis> <quote>S</quote> characters. Title-casing is even
* stranger; <quote>ss</quote> (at the beginning of a word) might be
* title-cased into a different combined character that looks like
* <quote>Ss</quote>. The glk_buffer_to_title_case_uni() function is actually
* otherwise.
*
* See glk_buffer_to_lower_case_uni(). The <code>title_case</code> function has
- * an additional (boolean) flag. Its basic function is to change the first
- * character of the buffer to upper-case, and leave the rest of the buffer
- * unchanged. If @lowerrest is true, it changes all the non-first characters to
- * lower-case (instead of leaving them alone.)
+ * an additional (boolean) flag. If the flag is zero, the function changes the
+ * first character of the buffer to upper-case, and leaves the rest of the
+ * buffer unchanged. If the flag is nonzero, it changes the first character to
+ * upper-case and the rest to lower-case.
*
* <note><para>
* Earlier drafts of this spec had a separate function which title-cased the
return numchars;
}
+/**
+ * glk_buffer_canon_decompose_uni:
+ * @buf: A character array in UCS-4.
+ * @len: Available length of @buf.
+ * @numchars: Number of characters in @buf.
+ *
+ * This transforms a string into its canonical decomposition
+ * (<quote>Normalization Form D</quote>). Effectively, this takes apart
+ * multipart characters into their individual parts. For example, it would
+ * convert <quote>è</quote> (character 0xE8, an accented
+ * <quote>e</quote>) into the two-character string containing <quote>e</quote>
+ * followed by Unicode character 0x0300 (COMBINING GRAVE ACCENT). If a single
+ * character has multiple accent marks, they are also rearranged into a standard
+ * order.
+ *
+ * Returns: The number of characters in @buf after decomposition.
+ */
+glui32
+glk_buffer_canon_decompose_uni(glui32 *buf, glui32 len, glui32 numchars)
+{
+ g_return_val_if_fail(buf != NULL && (len > 0 || numchars > 0), 0);
+ g_return_val_if_fail(numchars <= len, 0);
+
+ /* TODO: Implement this */
+ return numchars;
+}
+
+/**
+ * glk_buffer_canon_normalize_uni:
+ * @buf: A character array in UCS-4.
+ * @len: Available length of @buf.
+ * @numchars: Number of characters in @buf.
+ *
+ * This transforms a string into its canonical decomposition and recomposition
+ * (<quote>Normalization Form C</quote>). Effectively, this takes apart
+ * multipart characters, and then puts them back together in a standard way. For
+ * example, this would convert the two-character string containing
+ * <quote>e</quote> followed by Unicode character 0x0300 (COMBINING GRAVE
+ * ACCENT) into the one-character string <quote>è</quote> (character
+ * 0xE8, an accented <quote>e</quote>).
+ *
+ * The <code>canon_normalize</code> function includes decomposition as part of
+ * its implementation. You never have to call both functions on the same string.
+ *
+ * Both of these functions are idempotent.
+ *
+ * These functions provide two length arguments because a string of Unicode
+ * characters may expand when it is transformed. The @len argument is the
+ * available length of the buffer; @numchars is the number of characters in the
+ * buffer initially. (So @numchars must be less than or equal to @len. The
+ * contents of the buffer after @numchars do not affect the operation.)
+ *
+ * The functions return the number of characters after transformation. If this
+ * is greater than @len, the characters in the array will be safely truncated at
+ * @len, but the true count will be returned. (The contents of the buffer after
+ * the returned count are undefined.)
+ *
+ * <note><para>
+ * The Unicode spec also defines stronger forms of these functions, called
+ * <quote>compatibility decomposition and recomposition</quote>
+ * (<quote>Normalization Form KD</quote> and <quote>Normalization Form
+ * KC</quote>.) These do all of the accent-mangling described above, but they
+ * also transform many other obscure Unicode characters into more familiar
+ * forms. For example, they split ligatures apart into separate letters. They
+ * also convert Unicode display variations such as script letters, circled
+ * letters, and half-width letters into their common forms.
+ * </para></note>
+ *
+ * <note><para>
+ * The Glk spec does not currently provide these stronger transformations.
+ * Glk's expected use of Unicode normalization is for line input, and an OS
+ * facility for line input will generally not produce these alternate
+ * character forms (unless the user goes out of his way to type them).
+ * Therefore, the need for these transformations does not seem to be worth the
+ * extra data table space.
+ * </para></note>
+ *
+ * Returns: the number of characters in @buf after normalization.
+ */
+glui32
+glk_buffer_canon_normalize_uni(glui32 *buf, glui32 len, glui32 numchars)
+{
+ g_return_val_if_fail(buf != NULL && (len > 0 || numchars > 0), 0);
+ g_return_val_if_fail(numchars <= len, 0);
+
+ /* TODO: Implement this */
+ return numchars;
+}
--- /dev/null
+#include <glib.h>
+#include "glk.h"
+
+/**
+ * glk_current_time:
+ * @time: pointer to a #glktimeval_t structure.
+ *
+ * The current Unix time is stored in the structure @time. (The argument may not
+ * be %NULL.) This is the number of seconds since the beginning of 1970 (UTC).
+ *
+ * The first two values in the structure should be considered a single
+ * <emphasis>signed</emphasis> 64-bit number. This allows the #glktimeval_t to
+ * store a reasonable range of values in the future and past. The @high_sec
+ * value will remain zero until sometime in 2106. If your computer is running in
+ * 1969, perhaps due to an unexpected solar flare, then @high_sec will be
+ * negative.
+ *
+ * The third value in the structure represents a fraction of a second, in
+ * microseconds (from 0 to 999999). The resolution of the glk_current_time()
+ * call is platform-dependent; the @microsec value may not be updated
+ * continuously.
+ */
+void
+glk_current_time(glktimeval_t *time)
+{
+ g_return_if_fail(time != NULL);
+}
+
+/**
+ * glk_current_simple_time:
+ * @factor: Factor by which to divide the time value.
+ *
+ * If dealing with 64-bit values is awkward, you can also get the current time
+ * as a lower-resolution 32-bit value. This is simply the Unix time divided by
+ * the @factor argument (which must not be zero). For example, if factor is 60,
+ * the result will be the number of minutes since 1970 (rounded towards negative
+ * infinity). If factor is 1, you will get the Unix time directly, but the value
+ * will be truncated starting some time in 2038.
+ *
+ * Returns: Unix time divided by @factor, truncated to 32 bits.
+ */
+glsi32
+glk_current_simple_time(glui32 factor)
+{
+ g_return_val_if_fail(factor != 0, -1);
+
+ return -1;
+}
+
+/**
+ * glk_time_to_date_utc:
+ * @time: A #glktimeval_t structure as returned by glk_current_time().
+ * @date: An empty #glkdate_t structure to fill in.
+ *
+ * Convert the given timestamp (as returned by glk_current_time()) to a
+ * broken-out structure. This function returns a date and time in universal time
+ * (GMT).
+ *
+ * <note><para>
+ * The seconds value may be 60 because of a leap second.
+ * </para></note>
+ */
+void
+glk_time_to_date_utc(glktimeval_t *time, glkdate_t *date)
+{
+ g_return_if_fail(time != NULL);
+ g_return_if_fail(date != NULL);
+}
+
+/**
+ * glk_time_to_date_local:
+ * @time: A #glktimeval_t structure as returned by glk_current_time().
+ * @date: An empty #glkdate_t structure to fill in.
+ *
+ * Does the same thing as glk_time_to_date_utc(), but this function returns
+ * local time.
+ */
+void
+glk_time_to_date_local(glktimeval_t *time, glkdate_t *date)
+{
+ g_return_if_fail(time != NULL);
+ g_return_if_fail(date != NULL);
+}
+
+/**
+ * glk_simple_time_to_date_utc:
+ * @time: Timestamp as returned by glk_current_simple_time().
+ * @factor: Factor by which to multiply @time in order to get seconds.
+ * @date: An empty #glkdate_t structure to fill in.
+ *
+ * Convert the given timestamp (as returned by glk_current_simple_time()) to a
+ * broken-out structure in universal time. The @time argument is multiplied by
+ * @factor to produce a Unix timestamp.
+ *
+ * Since the resolution of glk_simple_time_to_date_utc() and
+ * glk_simple_time_to_date_local() is no better than seconds, they will return
+ * zero for the microseconds value.
+ */
+void
+glk_simple_time_to_date_utc(glsi32 time, glui32 factor, glkdate_t *date)
+{
+ g_return_if_fail(factor != 0);
+ g_return_if_fail(date != NULL);
+}
+
+/**
+ * glk_simple_time_to_date_local:
+ * @time: Timestamp as returned by glk_current_simple_time().
+ * @factor: Factor by which to multiply @time in order to get seconds.
+ * @date: An empty #glkdate_t structure to fill in.
+ *
+ * Does the same thing as glk_simple_time_to_date_utc(), but fills in the @date
+ * structure in local time.
+ */
+void
+glk_simple_time_to_date_local(glsi32 time, glui32 factor, glkdate_t *date)
+{
+ g_return_if_fail(factor != 0);
+ g_return_if_fail(date != NULL);
+}
+
+/**
+ * glk_date_to_time_utc:
+ * @date: A date in the form of a #glkdate_t structure.
+ * @time: An empty #glktimeval_t structure to fill in.
+ *
+ * Convert the broken-out structure (interpreted as universal time) to a
+ * timestamp. The weekday value in @date is ignored. The other values need not
+ * be in their normal ranges; they will be normalized.
+ *
+ * If the time cannot be represented by the platform's time library, this may
+ * return -1 for the seconds value. (I.e., the @high_sec and @low_sec fields
+ * both $FFFFFFFF. The microseconds field is undefined in this case.)
+ */
+void
+glk_date_to_time_utc(glkdate_t *date, glktimeval_t *time)
+{
+ g_return_if_fail(date != NULL);
+ g_return_if_fail(time != NULL);
+}
+
+/**
+ * glk_date_to_time_local:
+ * @date: A date in the form of a #glkdate_t structure.
+ * @time: An empty #glktimeval_t structure to fill in.
+ *
+ * Does the same thing as glk_date_to_time_utc(), but interprets the broken-out
+ * structure as local time.
+ *
+ * The glk_date_to_time_local() function may not be smart about Daylight Saving
+ * Time conversions.
+ * <note><para>
+ * If implemented with the mktime() libc function, it should use the negative
+ * @tm_isdst flag to <quote>attempt to divine whether summer time is in
+ * effect</quote>.
+ * </para></note>
+ */
+void
+glk_date_to_time_local(glkdate_t *date, glktimeval_t *time)
+{
+ g_return_if_fail(date != NULL);
+ g_return_if_fail(time != NULL);
+}
+
+/**
+ * glk_date_to_simple_time_utc:
+ * @date: A date in the form of a #glkdate_t structure.
+ * @factor: Factor by which to divide the time value.
+ *
+ * Convert the broken-out structure (interpreted as universal time) to a
+ * timestamp divided by @factor. The weekday value in @date is ignored. The
+ * other values need not be in their normal ranges; they will be normalized.
+ *
+ * If the time cannot be represented by the platform's time library, this may
+ * return -1.
+ *
+ * Returns: a timestamp divided by @factor, and truncated to 32 bits, or -1 on
+ * error.
+ */
+glsi32
+glk_date_to_simple_time_utc(glkdate_t *date, glui32 factor)
+{
+ g_return_val_if_fail(date != NULL, -1);
+ g_return_val_if_fail(factor != 0, -1);
+
+ return -1;
+}
+
+/**
+ * glk_date_to_simple_time_local:
+ * @date: A date in the form of a #glkdate_t structure.
+ * @factor: Factor by which to divide the time value.
+ *
+ * Does the same thing as glk_date_to_simple_time_utc(), but interprets the
+ * broken-out structure as local time.
+ *
+ * Returns: a timestamp divided by @factor, and truncated to 32 bits, or -1 on
+ * error.
+ */
+glsi32
+glk_date_to_simple_time_local(glkdate_t *date, glui32 factor)
+{
+ g_return_val_if_fail(date != NULL, -1);
+ g_return_val_if_fail(factor != 0, -1);
+
+ return -1;
+}
*
* When you create one of these objects, it is always possible that the creation
* will fail (due to lack of memory, or some other OS error.) When this happens,
- * the allocation function will return %NULL (0) instead of a valid pointer. You
+ * the allocation function will return %NULL instead of a valid pointer. You
* should always test for this possibility.
*
* %NULL is never the identifier of any object (window, stream, file reference,
* functions act on whole strings, since the length of the string may change.
*/
+/**
+ * SECTION:glk-normalize
+ * @short_description: Combining characters
+ * @include: libchimara/glk.h
+ *
+ * Comparing Unicode strings is difficult, because there can be several ways to
+ * represent a piece of text as a Unicode string. For example, the one-character
+ * string <quote>è</quote> (an accented <quote>e</quote>) will be
+ * displayed the same as the two-character string containing <quote>e</quote>
+ * followed by Unicode character 0x0300 (COMBINING GRAVE ACCENT). These strings
+ * should be considered equal.
+ *
+ * Therefore, a Glk program that accepts line input should convert its text to a
+ * normalized form before parsing it. These functions offer those conversions.
+ * The algorithms are defined by the Unicode spec (chapter 3.7) and <ulink
+ * url="http://www.unicode.org/reports/tr15/">Unicode Standard Annex
+ * #15</ulink>.
+ */
+
/**
* SECTION:glk-window-opening
* @short_description: Creating new windows and closing them
* <para>
* Every window has an output stream associated with it. This is created
* automatically, with %filemode_Write, when you open the window. You get it
- * with glk_window_get_stream().
+ * with glk_window_get_stream(). Window streams always have rock value 0.
*
* A window stream cannot be closed with glk_stream_close(). It is closed
* automatically when you close its window with glk_window_close().
* create a fileref for a nonexistent file, and then open it in write mode to
* create a new file.
*
- * You always provide a usage argument when you create a fileref. The usage is a
- * mask of constants (see below) to indicate the file type and the mode (text or
- * binary.) These values are used when you create a new file, and also to filter
- * file lists when the player is selecting a file to load.
+ * You always provide a usage argument when you create a fileref. The usage
+ * indicates the file type and the mode (text or binary.) It must be the
+ * logical-or of a file-type constant and a mode constant. These values are used
+ * when you create a new file, and also to filter file lists when the player is
+ * selecting a file to load.
*
* In general, you should use text mode if the player expects to read the file
* with a platform-native text editor; you should use binary mode if the file is
* Before calling Glk hyperlink functions, you should use the gestalt selectors
* %gestalt_Hyperlinks and %gestalt_HyperlinkInput.
*/
+
+/**
+ * SECTION:glk-clock
+ * @short_description: Getting the current time from the system clock
+ * @include: libchimara/glk.h
+ *
+ * You can get the current time, either as a Unix timestamp (seconds since 1970)
+ * or as a broken-out structure of time elements (year, month, day, hour,
+ * minute, second).
+ *
+ * The system clock is not guaranteed to line up with timer events (see <link
+ * linkend="chimara-Timer-Events">Timer Events</link>). Timer events may be
+ * delivered late according to the system clock.
+ */
+
+/**
+ * SECTION:glk-clock-conversions
+ * @short_description: Converting from timestamps to date structures and back
+ * @include: libchimara/glk.h
+ *
+ */
+
+/**
+ * SECTION:glk-clock-testing
+ * @short_description: Checking whether the library supports the clock functions
+ * @include: libchimara/glk.h
+ *
+ * Before calling Glk date and time functions, you should use the following
+ * gestalt selector.
+ */
/**
* SECTION:dispatch-interrogating
/**
* GLK_MODULE_UNICODE:
*
- * If this preprocessor symbol is defined, so are all the Unicode functions and
+ * If this preprocessor symbol is defined, so are the core Unicode functions and
* constants (see %gestalt_Unicode). If not, not.
*/
* functions and constants described in this section. If not, not.
*/
+/**
+ * GLK_MODULE_UNICODE_NORM:
+ *
+ * If this preprocessor symbol is defined, so are the Unicode normalization
+ * functions (see %gestalt_UnicodeNorm). If not, not.
+ */
+
+/**
+ * GLK_MODULE_DATETIME:
+ *
+ * If you are writing a C program, you can perform a preprocessor test for the
+ * existence of %GLK_MODULE_DATETIME. If this is defined, so are all the
+ * functions and data types described in this section.
+ */
+
/**
* winid_t:
*
* So the version number 78.2.11 would be encoded as 0x004E020B.
* </para></note>
*
- * The current Glk specification version is 0.7.0, so this selector will return
- * 0x00000700.
+ * The current Glk specification version is 0.7.2, so this selector will return
+ * 0x00000702.
*
* |[
* glui32 res;
*
* <note><para>
* Make sure you do not get confused by signed byte values. If you set a
- * <quote><type>char</type></quote> variable <code>ch</code> to 0xFE, the
- * small-thorn character (þ), and then call
+ * <quote><type>signed char</type></quote> variable <code>ch</code> to 0xFE,
+ * the small-thorn character (þ), it will wind up as -2. (The same is
+ * true of a <quote><type>char</type></quote> variable, if your compiler
+ * treats <quote><type>char</type></quote> as signed!) If you then call
* |[ res = glk_gestalt(gestalt_CharOutput, ch); ]|
* then (by the definition of C/C++) <code>ch</code> will be sign-extended to
- * 0xFFFFFFFE, which is not a legitimate character, even in Unicode. You
+ * 0xFFFFFFFE, which is not a legitimate character, even in Unicode. You
* should write
* |[ res = glk_gestalt(gestalt_CharOutput, (unsigned char)ch); ]|
* instead.
*
* You can test whether the library supports timer events:
* |[ res = glk_gestalt(gestalt_Timer, 0); ]|
- * This returns 1 if timer events are supported, and 0 if they are not.
+ * This returns %TRUE (1) if timer events are supported, and %FALSE (0) if they
+ * are not.
*/
/**
* gestalt_DrawImage:
*
* This selector returns 1 if images can be drawn in windows of the given type.
- * If it returns 0, glk_image_draw() will fail and return %FALSE. You should
+ * If it returns 0, glk_image_draw() will fail and return %FALSE (0). You should
* test %wintype_Graphics and %wintype_TextBuffer separately, since libraries
* may implement both, neither, or only one.
*/
*
* The basic text functions will be available in every Glk library. The Unicode
* functions may or may not be available. Before calling them, you should use
- * the following gestalt selector:
+ * the %gestalt_Unicode and %gestalt_UnicodeNorm gestalt selectors.
+ *
* |[
* glui32 res;
* res = glk_gestalt(gestalt_Unicode, 0);
* ]|
- *
- * This returns 1 if the Unicode functions are available. If it returns 0, you
- * should not try to call them. They may print nothing, print gibberish, or
+ * This returns 1 if the core Unicode functions are available. If it returns 0,
+ * you should not try to call them. They may print nothing, print gibberish, or
* cause a run-time error. The Unicode functions include
* glk_buffer_to_lower_case_uni(), glk_buffer_to_upper_case_uni(),
* glk_buffer_to_title_case_uni(), glk_put_char_uni(), glk_put_string_uni(),
* errors.
*
* To avoid this, you can perform a preprocessor test for the existence of
- * #GLK_MODULE_UNICODE.
+ * %GLK_MODULE_UNICODE.
*/
-
+
+/**
+ * gestalt_UnicodeNorm:
+ *
+ * |[
+ * glui32 res;
+ * res = glk_gestalt(gestalt_UnicodeNorm, 0);
+ * ]|
+ * This code returns 1 if the Unicode normalization functions are available. If
+ * it returns 0, you should not try to call them. The Unicode normalization
+ * functions include glk_buffer_canon_decompose_uni() and
+ * glk_buffer_canon_normalize_uni().
+ *
+ * The equivalent preprocessor test for these functions is
+ * %GLK_MODULE_UNICODE_NORM.
+ */
+
+/**
+ * gestalt_LineInputEcho:
+ *
+ * |[
+ * res = glk_gestalt(gestalt_LineInputEcho, 0);
+ * ]|
+ *
+ * This returns 1 if glk_set_echo_line_event() is supported, and 0 if it is not.
+ * <note><para>
+ * Remember that if it is not supported, the behavior is always the default,
+ * which is line echoing <emphasis>enabled</emphasis>.
+ * </para></note>
+ */
+
+/**
+ * gestalt_LineTerminators:
+ *
+ * |[
+ * res = glk_gestalt(gestalt_LineTerminators, 0);
+ * ]|
+ *
+ * This returns 1 if glk_set_terminators_line_event() is supported, and 0 if it
+ * is not.
+ */
+
+/**
+ * gestalt_LineTerminatorKey:
+ *
+ * |[
+ * res = glk_gestalt(gestalt_LineTerminatorKey, ch);
+ * ]|
+ *
+ * This returns 1 if the keycode @ch can be passed to
+ * glk_set_terminators_line_event(). If it returns 0, that keycode will be
+ * ignored as a line terminator. Printable characters and %keycode_Return will
+ * always return 0.
+ */
+
+/**
+ * gestalt_DateTime:
+ *
+ * |[
+ * res = glk_gestalt(gestalt_DateTime, 0);
+ * ]|
+ *
+ * This returns 1 if the overall suite of system clock functions, as described
+ * in this chapter, is available.
+ *
+ * If this selector returns 0, you should not try to call these functions. They
+ * may have no effect, or they may cause a run-time error.
+ *
+ * <note><para>
+ * Glk timer events are covered by a different selector. See %gestalt_Timer.
+ * </para></note>
+ */
+
/**
* evtype_None:
*
* A full line of input completed in a window. See <link
* linkend="chimara-Line-Input-Events">Line Input Events</link>.
*
- * If a window has a pending request for line input, and the player hits
- * <keycap>enter</keycap> in that window (or whatever action is appropriate to
- * enter his input), glk_select() will return an event whose type is
- * %evtype_LineInput. Once this happens, the request is complete; it is no
- * longer pending. You must call glk_request_line_event() if you want another
+ * If a window has a pending request for line input, the player can generally
+ * hit the <keycap>enter</keycap> key (in that window) to complete line input.
+ * The details will depend on the platform's native user interface.
+ *
+ * When line input is completed, glk_select() will return an event whose type is
+ * %evtype_LineInput. Once this happens, the request is complete; it is no
+ * longer pending. You must call glk_request_line_event() if you want another
* line of text from that window.
- *
- * In the event structure, @win tells what window the event came from. @val1
- * tells how many characters were entered. @val2 will be 0. The characters
- * themselves are stored in the buffer specified in the original
- * glk_request_line_event() or glk_request_line_event_uni() call.
*
- * <note><para>There is no null terminator stored in the buffer.</para></note>
+ * In the event structure, @win tells what window the event came from. @val1
+ * tells how many characters were entered. @val2 will be 0 unless input was
+ * ended by a special terminator key, in which case @val2 will be the keycode
+ * (one of the values passed to glk_set_terminators_line_event()).
+ *
+ * The characters themselves are stored in the buffer specified in the original
+ * glk_request_line_event() or glk_request_line_event_uni() call.
+ *
+ * <note><para>
+ * There is no null terminator or newline stored in the buffer.
+ * </para></note>
*
* It is illegal to print anything to a window which has line input pending.
*
* result.
* </para></note>
*
- * When the player finishes his line of input, the library will display the
- * input text at the end of the buffer text (if it wasn't there already.) It
- * will be followed by a newline, so that the next text you print will start a
- * new line (paragraph) after the input.
+ * By default, when the player finishes his line of input, the library will
+ * display the input text at the end of the buffer text (if it wasn't there
+ * already.) It will be followed by a newline, so that the next text you print
+ * will start a new line (paragraph) after the input.
*
* If you call glk_cancel_line_event(), the same thing happens; whatever text
* the user was composing is visible at the end of the buffer text, followed by
* a newline.
+ *
+ * However, this default behavior can be changed with the
+ * glk_set_echo_line_event() call. If the default echoing is disabled, the
+ * library will <emphasis>not</emphasis> display the input text (plus newline)
+ * after input is either completed or cancelled. The buffer will end with
+ * whatever prompt you displayed before requesting input. If you want the
+ * traditional input behavior, it is then your responsibility to print the text,
+ * using the Input text style, followed by a newline (in the original style).
*/
/**
*
* When you print, the characters of the output are laid into the array in
* order, left to right and top to bottom. When the cursor reaches the end of a
- * line, it goes to the beginning of the next line. The library makes no attempt
- * to wrap lines at word breaks.
+ * line, or if a newline (0x0A) is printed, the cursor goes to the beginning of
+ * the next line. The library makes <emphasis>no</emphasis> attempt to wrap
+ * lines at word breaks. If the cursor reaches the end of the last line, further
+ * printing has no effect on the window until the cursor is moved.
*
* <note><para>
* Note that printing fancy characters may cause the cursor to advance more
* When the player finishes his line of input, it will remain visible in the
* window, and the output cursor will be positioned at the beginning of the
* <emphasis>next</emphasis> row. Again, if you glk_cancel_line_event(), the
- * same thing happens.
+ * same thing happens. The glk_set_echo_line_event() call has no effect in grid
+ * windows.
*/
/**
* linkend="chimara-Graphics-in-Graphics-Windows">Graphics in Graphics
* Windows</link>.
*
- * When a text grid window is resized smaller, the bottom or right area is
+ * When a graphics window is resized smaller, the bottom or right area is
* thrown away, but the remaining area stays unchanged. When it is resized
* larger, the new bottom or right area is filled with the background color.
*
* When calling glk_window_open() with this @method, the new window will be
* a given proportion of the old window's size. (See glk_window_open()).
*/
-
+
+/**
+ * winmethod_Border:
+ *
+ * When calling glk_window_open() with this @method, it specifies that there
+ * should be a visible window border between the new window and its sibling.
+ * (This is a hint to the library.)
+ */
+
+/**
+ * winmethod_NoBorder:
+ *
+ * When calling glk_window_open() with this @method, it specifies that there
+ * should not be a visible window border between the new window and its sibling.
+ * (This is a hint to the library; you might specify NoBorder between two
+ * graphics windows that should form a single image.)
+ */
+
/**
* fileusage_Data:
*
* existed in the destination, instead of replacing it.
*
* <note><para>
- * Corresponds to mode <code>"a"</code> in the stdio library, using fopen().
+ * Confusingly, %filemode_WriteAppend cannot be mode <code>"a"</code>, because
+ * the stdio spec says that when you open a file with mode <code>"a"</code>,
+ * then fseek() doesn't work. So we have to use mode <code>"r+"</code> for
+ * appending. Then we run into the <emphasis>other</emphasis> stdio problem,
+ * which is that <code>"r+"</code> never creates a new file. So
+ * %filemode_WriteAppend has to <emphasis>first</emphasis> open the file with
+ * <code>"a"</code>, close it, reopen with <code>"r+"</code>, and then fseek()
+ * to the end of the file. For %filemode_ReadWrite, the process is the same,
+ * except without the fseek() — we begin at the beginning of the file.
* </para></note>
*/
*
* <warning><para>Margin images are not implemented yet.</para></warning>
*/
+
+/**
+ * glktimeval_t:
+ *
+ */
/*---------- TYPES, FUNCTIONS AND CONSTANTS FROM GI_DISPA.H ------------------*/
* This structure simply contains a string and a value. The string is a
* symbolic name of the value, and can be re-exported to anyone interested in
* using Glk constants.
+ *
+ * <note><para>
+ * In the current <filename>gi_dispa.c</filename> library, these structures
+ * are static and immutable, and will never be deallocated. However, it is
+ * safer to assume that the structure may be reused in future
+ * gidispatch_get_intconst() calls.
+ * </para></note>
*/
/**
* 1</alt></inlineequation>, where N is the value returned by
* gidispatch_count_functions().
*
+ * <note><para>
+ * Again, it is safest to assume that the structure is only valid until the
+ * next gidispatch_get_function() or gidispatch_get_function_by_id() call.
+ * </para></note>
+ *
* Returns: A #gidispatch_function_t structure describing the function.
*/
* Returns a structure describing the Glk function with selector @id. If there
* is no such function in the library, this returns %NULL.
*
+ * <note><para>
+ * Again, it is safest to assume that the structure is only valid until the
+ * next gidispatch_get_function() or gidispatch_get_function_by_id() call.
+ * </para></note>
+ *
* Returns: a #gidispatch_function_t structure, or %NULL.
*/
* the list of arguments, and @numargs is the length of the list.
*
* The arguments are all stored as #gluniversal_t objects.
- * </para><refsect3 id="chimara-Basic-Types"><title>Basic Types</title><para>
+ * </para><refsect3 id="chimara-Basic-Dispatch-Types"><title>Basic Dispatch
+ * Types</title><para>
* Numeric arguments are passed in the obvious way — one argument per
* #gluniversal_t, with the @uint or @sint field set to the numeric value.
* Characters and strings are also passed in this way — #char<!---->s in
* <code>#glui32*</code>, <code>#winid_t*</code>, and so on — takes
* <emphasis>one or two</emphasis> #gluniversal_t objects. The first is a flag
* indicating whether the reference argument is %NULL or not. The @ptrflag field
- * of this #gluniversal_t should be %FALSE if the reference is %NULL, and %TRUE
- * otherwise. If %FALSE, that is the end of the argument; you should not use a
- * #gluniversal_t to explicitly store the %NULL reference. If the flag is %TRUE,
- * you must then put a #gluniversal_t storing the base type of the reference.
+ * of this #gluniversal_t should be %FALSE (0) if the reference is %NULL, and
+ * %TRUE (1) otherwise. If %FALSE, that is the end of the argument; you should
+ * not use a #gluniversal_t to explicitly store the %NULL reference. If the flag
+ * is %TRUE, you must then put a #gluniversal_t storing the base type of the
+ * reference.
*
* For example, consider a hypothetical function, with selector
* <code>0xABCD</code>:
* </para></note></listitem>
* </varlistentry>
* </variablelist>
- * Any type code can be prefixed with one or more of the following characters
- * (order does not matter):
+ * Any type code can be prefixed with one or more of the following characters:
* <variablelist>
* <varlistentry>
* <term><code>&</code></term>
* </varlistentry>
* </variablelist>
*
+ * The order of these characters and prefixes is not completely arbitrary. Here
+ * is a formal grammar for the prototype strings.
+ *
+ * <note><para>Thanks to Neil Cerutti for working this out.</para></note>
+ *
+ * <productionset>
+ * <production id="prototype">
+ * <lhs>prototype</lhs>
+ * <rhs>ArgCount [ <nonterminal def="#arg_list">arg_list</nonterminal> ]
+ * ':' [ <nonterminal def="#arg">arg</nonterminal> ] EOL</rhs>
+ * </production>
+ * <production id="arg_list">
+ * <lhs>arg_list</lhs>
+ * <rhs><nonterminal def="#arg">arg</nonterminal> { <nonterminal
+ * def="#arg">arg</nonterminal> }</rhs>
+ * </production>
+ * <production id="arg">
+ * <lhs>arg</lhs>
+ * <rhs>TypeName | <nonterminal def="#ref_type">ref_type</nonterminal>
+ * </rhs>
+ * </production>
+ * <production id="ref_type">
+ * <lhs>ref_type</lhs>
+ * <rhs>RefType [ '+' ] <nonterminal
+ * def="#target_type">target_type</nonterminal></rhs>
+ * </production>
+ * <production id="target_type">
+ * <lhs>target_type</lhs>
+ * <rhs>TypeName | <nonterminal def="#array">array</nonterminal> |
+ * <nonterminal def="#struct">struct</nonterminal></rhs>
+ * </production>
+ * <production id="array">
+ * <lhs>array</lhs>
+ * <rhs>'#' [ '!' ] TypeName</rhs>
+ * </production>
+ * <production id="struct">
+ * <lhs>struct</lhs>
+ * <rhs>'[' ArgCount [ <nonterminal def="#arg_list">arg_list</nonterminal>
+ * ] ']'</rhs>
+ * </production>
+ * </productionset>
+ * <constraintdef id="TypeName">
+ * <para>TypeName is <code>I[us]<!---->|C[nus]<!---->|S|U|F|Q[a-z]</code>
+ * </para>
+ * </constraintdef>
+ * <constraintdef id="ArgCount">
+ * <para>ArgCount is <code>\d+</code></para>
+ * </constraintdef>
+ * <constraintdef id="RefType">
+ * <para>RefType is <code>&|<|></code></para>
+ * </constraintdef>
+ * <constraintdef id="EOL">
+ * <para>EOL is end of input</para>
+ * </constraintdef>
+ *
* Returns: A string which encodes the prototype of the specified Glk function.
*/
/**
* giblorb_result_t:
* @chunknum: The chunk number (for use in giblorb_unload_chunk(), etc.)
- * @data: A union containing a pointer to the data @ptr (if you used
- * %giblorb_method_Memory) and the position in the file @startpos (if you used
- * %giblorb_method_FilePos)
* @length: The length of the data
* @chunktype: The type of the chunk.
*
* Holds information about a chunk loaded from a Blorb file, and the method of
- * accessing the chunk data. See giblorb_load_chunk_by_type() and
+ * accessing the chunk data. @data is a union of @ptr, a pointer to the data (if
+ * you used %giblorb_method_Memory) and @startpos, the position in the file (if
+ * you used %giblorb_method_FilePos). See giblorb_load_chunk_by_type() and
* giblorb_load_chunk_by_number().
*/
+#include <config.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <gtk/gtk.h>
#include <glib/gstdio.h>
+#include <glib/gi18n-lib.h>
#include "fileref.h"
#include "magic.h"
#include "chimara-glk-private.h"
* open the file.
*
* <note><para>
- * It is possible that the prompt or file tool will have a
- * <quote>cancel</quote> option. If the player chooses this,
- * glk_fileref_create_by_prompt() will return %NULL. This is a major reason
- * why you should make sure the return value is valid before you use it.
+ * It is likely that the prompt or file tool will have a <quote>cancel</quote>
+ * option. If the player chooses this, glk_fileref_create_by_prompt() will
+ * return %NULL. This is a major reason why you should make sure the return
+ * value is valid before you use it.
* </para></note>
*
* Returns: A new fileref, or #NULL if the fileref creation failed or the
* @fref: A refrence to the file to delete.
*
* Deletes the file referred to by @fref. It does not destroy @fref itself.
+ *
+ * You should only call this with a fileref that refers to an existing file.
*/
void
glk_fileref_delete_file(frefid_t fref)
{
VALID_FILEREF(fref, return);
if( glk_fileref_does_file_exist(fref) )
+ {
if(g_unlink(fref->filename) == -1)
IO_WARNING( "Error deleting file", fref->filename, g_strerror(errno) );
+ }
+ else
+ {
+ ILLEGAL(_("Tried to delete a fileref that does not refer to an existing file."));
+ }
+
}
/**
/* Version of the Glk specification implemented by this library */
#define MAJOR_VERSION 0
#define MINOR_VERSION 7
-#define SUB_VERSION 0
+#define SUB_VERSION 2
/**
* glk_gestalt:
case gestalt_Sound:
case gestalt_SoundVolume:
case gestalt_SoundNotify:
+ case gestalt_SoundMusic:
#ifdef GSTREAMER_SOUND
return 1;
#else
#endif
/* Unsupported capabilities */
- case gestalt_SoundMusic:
+ case gestalt_DateTime:
+ case gestalt_LineInputEcho:
+ case gestalt_LineTerminatorKey:
+ case gestalt_LineTerminators:
+ case gestalt_UnicodeNorm:
/* Selector not supported */
default:
return 0;
* all. So you can call it often.
*
* <note><para>
- * In a virtual machine interpreter, once per opcode is appropriate. In a
- * program with lots of computation, pick a comparable rate.
+ * In a virtual machine interpreter, once per opcode is appropriate. A more
+ * parsimonious approach would be once per branch and function call opcode;
+ * this guarantees it will be called inside loops. In a program with lots of
+ * computation, pick a comparable rate.
* </para></note>
*
* glk_tick() does not try to update the screen, or check for player input, or
* @height: Pointer to a location at which to store the image's height.
*
* This gets information about the image resource with the given identifier. It
- * returns %TRUE if there is such an image, and %FALSE if not. You can also pass
- * pointers to width and height variables; if the image exists, the variables
- * will be filled in with the width and height of the image, in pixels. (You can
- * pass %NULL for either width or height if you don't care about that
- * information.)
+ * returns %TRUE (1) if there is such an image, and %FALSE (0) if not. You can
+ * also pass pointers to width and height variables; if the image exists, the
+ * variables will be filled in with the width and height of the image, in
+ * pixels. (You can pass %NULL for either width or height if you don't care
+ * about that information.)
*
* <note><para>
* You should always use this function to measure the size of images when you
* <type>glui32</type> values instead of an array of characters, and the values
* may be any valid Unicode code points.
*
- * The result will be in Unicode Normalization Form C. This basically means that
- * composite characters will be single characters where possible, instead of
- * sequences of base and combining marks. See
- * <ulink url="http://www.unicode.org/reports/tr15/">Unicode Standard Annex
- * #15</ulink> for the details.
+ * If possible, the library should return fully composed Unicode characters,
+ * rather than strings of base and composition characters.
+ *
+ * <note><para>
+ * Fully-composed characters are the norm for Unicode text, so an
+ * implementation that ignores this issue will probably produce the right
+ * result. However, the game may not want to rely on that. Another factor is
+ * that case-folding can (occasionally) produce non-normalized text.
+ * Therefore, to cover all its bases, a game should call
+ * glk_buffer_to_lower_case_uni(), followed by
+ * glk_buffer_canon_normalize_uni(), before parsing.
+ * </para></note>
+ *
+ * <note><para>
+ * Earlier versions of this spec said that line input must always be in
+ * Unicode Normalization Form C. However, this has not been universally
+ * implemented. It is also somewhat redundant, for the results noted above.
+ * Therefore, we now merely recommend that line input be fully composed. The
+ * game is ultimately responsible for all case-folding and normalization. See
+ * <link linkend="chimara-Unicode-String-Normalization">Unicode String
+ * Normalization</link>.
+ * </para></note>
*/
void
glk_request_line_event_uni(winid_t win, glui32 *buf, glui32 maxlen, glui32 initlen)
WARNING("Could not cancel pending input request: unknown input request");
}
}
+
+/**
+ * glk_set_echo_line_event:
+ * @win: The window in which to change the echoing behavior.
+ * @val: Zero to turn off echoing, nonzero for normal echoing.
+ *
+ * Normally, after line input is completed or cancelled in a buffer window, the
+ * library ensures that the complete input line (or its latest state, after
+ * cancelling) is displayed at the end of the buffer, followed by a newline.
+ * This call allows you to suppress this behavior. If the @val argument is zero,
+ * all <emphasis>subsequent</emphasis> line input requests in the given window
+ * will leave the buffer unchanged after the input is completed or cancelled;
+ * the player's input will not be printed. If @val is nonzero, subsequent input
+ * requests will have the normal printing behavior.
+ *
+ * <note><para>
+ * Note that this feature is unrelated to the window's echo stream.
+ * </para></note>
+ *
+ * If you turn off line input echoing, you can reproduce the standard input
+ * behavior by following each line input event (or line input cancellation) by
+ * printing the input line, in the Input style, followed by a newline in the
+ * original style.
+ *
+ * The glk_set_echo_line_event() does not affect a pending line input request.
+ * It also has no effect in non-buffer windows.
+ * <note><para>
+ * In a grid window, the game can overwrite the input area at will, so there
+ * is no need for this distinction.
+ * </para></note>
+ *
+ * Not all libraries support this feature. You can test for it with
+ * %gestalt_LineInputEcho.
+ */
+void
+glk_set_echo_line_event(winid_t win, glui32 val)
+{
+ VALID_WINDOW(win, return);
+}
+
+/**
+ * glk_set_terminators_line_event:
+ * @win: The window for which to set the line input terminator keys.
+ * @keycodes: An array of <code>keycode_</code> constants, of length @count.
+ * @count: The array length of @keycodes.
+ *
+ * It is possible to request that other keystrokes complete line input as well.
+ * (This allows a game to intercept function keys or other special keys during
+ * line input.) To do this, call glk_set_terminators_line_event(), and pass an
+ * array of @count keycodes. These must all be special keycodes (see <link
+ * linkend="chimara-Character-Input">Character Input</link>). Do not include
+ * regular printable characters in the array, nor %keycode_Return (which
+ * represents the default <keycap>enter</keycap> key and will always be
+ * recognized). To return to the default behavior, pass a %NULL or empty array.
+ *
+ * The glk_set_terminators_line_event() affects <emphasis>subsequent</emphasis>
+ * line input requests in the given window. It does not affect a pending line
+ * input request.
+ *
+ * <note><para>
+ * This distinction makes life easier for interpreters that set up UI
+ * callbacks only at the start of input.
+ * </para></note>
+ *
+ * A library may not support this feature; if it does, it may not support all
+ * special keys as terminators. (Some keystrokes are reserved for OS or
+ * interpreter control.) You can test for this with %gestalt_LineTerminators and
+ * %gestalt_LineTerminatorKey.
+ */
+void
+glk_set_terminators_line_event(winid_t win, glui32 *keycodes, glui32 count)
+{
+ VALID_WINDOW(win, return);
+}
\ No newline at end of file
* @str: A stream.
*
* Retrieves the stream @str's rock value. See <link
- * linkend="chimara-Rocks">Rocks</link>.
+ * linkend="chimara-Rocks">Rocks</link>. Window streams always have rock 0; all
+ * other streams return whatever rock you created them with.
*
* Returns: A rock value.
*/
* Opens a stream which reads to or writes from a disk file. If @fmode is
* %filemode_Read, the file must already exist; for the other modes, an empty
* file is created if none exists. If @fmode is %filemode_Write, and the file
- * already exists, it is truncated down to zero length (an empty file). If
- * @fmode is %filemode_WriteAppend, the file mark is set to the end of the
- * file.
+ * already exists, it is truncated down to zero length (an empty file); the
+ * other modes do not truncate. If @fmode is %filemode_WriteAppend, the file
+ * mark is set to the end of the file.
+ *
+ * <note><para>
+ * Note, again, that this doesn't match stdio's fopen() call very well. See
+ * <link linkend="filemode-WriteAppend">the file mode constants</link>.
+ * </para></note>
+ *
+ * If the filemode requires the file to exist, but the file does not exist,
+ * glk_stream_open_file() returns %NULL.
+ *
+ * The file may be read or written in text or binary mode; this is determined
+ * by the @fileref argument. Similarly, platform-dependent attributes such as
+ * file type are determined by @fileref. See <link
+ * linkend="chimara-File-References">File References</link>.
*
* When writing in binary mode, Unicode values (characters greater than 255)
* cannot be written to the file. If you try, they will be stored as 0x3F
* glk_get_char_stream_uni:
* @str: An input stream.
*
- * Reads one character from the stream @str. The result will be between 0 and
- * 0x7FFFFFFF. If the end of the stream has been reached, the result will be -1.
+ * Reads one character from the stream @str. If the end of the stream has been
+ * reached, the result will be -1.
*
* Returns: A value between 0 and 0x7FFFFFFF, or -1 on end of stream.
*/
* good for much anyhow.
* </para></note>
*
+ * glk_stream_get_position() on a window stream will always return zero.
+ *
+ * <note><para>
+ * It might make more sense to return the number of characters written to the
+ * window, but existing libraries do not support this and it's not really
+ * worth adding the feature.
+ * </para></note>
+ *
* Returns: position of the read/write mark in @str.
*/
glui32
return str->mark;
case STREAM_TYPE_FILE:
return ftell(str->file_pointer);
+ case STREAM_TYPE_WINDOW:
+ return 0;
default:
ILLEGAL_PARAM("Seeking illegal on stream type: %u", str->type);
return 0;
*
* Again, in Latin-1 streams, characters are bytes. In Unicode streams,
* characters are 32-bit words, or four bytes each.
+ *
+ * A window stream doesn't have a movable mark, so calling
+ * glk_stream_set_position() has no effect.
*/
void
glk_stream_set_position(strid_t str, glsi32 pos, glui32 seekmode)
WARNING("Seek failed on file stream");
break;
}
+ case STREAM_TYPE_WINDOW:
+ break; /* Quietly do nothing */
default:
ILLEGAL_PARAM("Seeking illegal on stream type: %u", str->type);
return;
* colors are reversed.</para></listitem>
* </varlistentry>
* </variablelist>
+ * Signed values, such as the %stylehint_Weight value, are cast to
+ * <type>glui32</type>. They may be cast to <type>glsi32</type> to be dealt with
+ * in a more natural context.
*
* Returns: TRUE upon successul retrieval, otherwise FALSE.
*/
* This prevents the user from being locked out by overly enthusiastic timer
* events. Unfortunately, it also means that your timer can be locked out on
* slower machines, if the player pounds too enthusiastically on the keyboard.
- * Sorry. If you want a real-time operating system, talk to Wind River.
+ * Sorry.
* </para></note>
*
* <note><para>
* @method: Position of the new window and method of size computation. One of
* %winmethod_Above, %winmethod_Below, %winmethod_Left, or %winmethod_Right
* OR'ed with %winmethod_Fixed or %winmethod_Proportional. If @wintype is
- * %wintype_Blank, then %winmethod_Fixed is not allowed.
+ * %wintype_Blank, then %winmethod_Fixed is not allowed. May also be OR'ed with
+ * %winmethod_Border or %winmethod_NoBorder.
* @size: Size of the new window, in percentage points if @method is
* %winmethod_Proportional, otherwise in characters if @wintype is
* %wintype_TextBuffer or %wintype_TextGrid, or pixels if @wintype is
*
* If any windows exist, new windows must be created by splitting existing
* ones. @split is the window you want to split; this <emphasis>must
- * not</emphasis> be zero. @method is a mask of constants to specify the
- * direction and the split method (see below). @size is the size of the split.
- * @wintype is the type of window you're creating, and @rock is the rock.
+ * not</emphasis> be zero. @method specifies the direction and the split method
+ * (see below). @size is the size of the split. @wintype is the type of window
+ * you're creating, and @rock is the rock.
+ *
+ * The method argument must be the logical-or of a direction constant
+ * (%winmethod_Above, %winmethod_Below, %winmethod_Left, %winmethod_Right) and a
+ * split-method constant (%winmethod_Fixed, %winmethod_Proportional).
*
* Remember that it is possible that the library will be unable to create a new
* window, in which case glk_window_open() will return %NULL.
* <varlistentry>
* <term>Text grid</term>
* <listitem><para>
- * This will clear the window, filling all positions with blanks. The window
- * cursor is moved to the top left corner (position 0,0).
+ * This will clear the window, filling all positions with blanks (in the
+ * normal style). The window cursor is moved to the top left corner (position
+ * 0,0).
* </para></listitem>
* </varlistentry>
* <varlistentry>
* glk_set_window:
* @win: A window, or %NULL.
*
- * Sets the current stream to @win's window stream. It is exactly equivalent to
- * |[ glk_stream_set_current(glk_window_get_stream(win)) ]|
+ * Sets the current stream to @win's window stream. If @win is %NULL, it is
+ * equivalent to
+ * |[ glk_stream_set_current(NULL); ]|
+ * If @win is not %NULL, it is equivalent to
+ * |[ glk_stream_set_current(glk_window_get_stream(win)); ]|
* See <link linkend="chimara-Streams">Streams</link>.
- *
- * <note><title>Chimara</title>
- * <para>
- * Although this is not mentioned in the specification, @win may also be
- * %NULL, in which case the current stream is also set to %NULL.
- * </para></note>
*/
void
glk_set_window(winid_t win)
* Whatever constraint you set, glk_window_get_size() will tell you the actual
* window size you got.
*
- * Note that you can resize windows, but you can't flip or rotate them. You
- * can't move A above D, or change O2 to a vertical split where A is left or
- * right of D.
+ * Note that you can resize windows, and alter the Border/NoBorder flag. But you
+ * can't flip or rotate them. You can't move A above D, or change O2 to a
+ * vertical split where A is left or right of D.
* <note><para>
* To get this effect you could close one of the windows, and re-split the
* other one with glk_window_open().