scummvm/engines/glk/tads/os_glk.h
2022-10-23 22:46:19 +02:00

3224 lines
146 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/* TADS OS interface file type definitions
*
* Defines certain datatypes used in the TADS operating system interface
*/
#ifndef GLK_TADS_OS_GLK
#define GLK_TADS_OS_GLK
#include "common/scummsys.h"
#include "glk/tads/os_frob_tads.h"
namespace Glk {
namespace TADS {
#define TADS_RUNTIME_VERSION "2.5.17"
#define OS_SYSTEM_NAME "ScummVM Glk"
#define OSPATHCHAR '/'
#define OSPATHALT ""
#define OSPATHURL "/"
#define OSPATHSEP ':'
#define OS_NEWLINE_SEQ "\n"
#define DBG_OFF
/* maximum width (in characters) of a line of text */
#define OS_MAXWIDTH 255
/* round a size to worst-case alignment boundary */
#define osrndsz(s) (((s)+3) & ~3)
/* round a pointer to worst-case alignment boundary */
#define osrndpt(p) ((uchar *)((((unsigned long)(p)) + 3) & ~3))
/* read unaligned portable unsigned 2-byte value, returning int */
#define osrp2(p) READ_LE_UINT16(p)
/* read unaligned portable signed 2-byte value, returning int */
#define osrp2s(p) READ_LE_INT16(p)
/* write int to unaligned portable 2-byte value */
#define oswp2(p, i) WRITE_LE_UINT16(p, i)
#define oswp2s(p, i) WRITE_LE_INT16(p, i)
/* read unaligned portable 4-byte value, returning unsigned long */
#define osrp4(p) READ_LE_UINT32(p)
#define osrp4s(p) READ_LE_INT32(p)
#define oswp4(p, l) WRITE_LE_UINT32(p, l)
#define oswp4s(p, l) WRITE_LE_INT32(p, l)
/* ------------------------------------------------------------------------ */
typedef int32 int32_t;
typedef uint32 uint32_t;
/* ------------------------------------------------------------------------ */
/*
* <time.h> definitions.
*
* os_time() should act like Unix time(), returning the number of seconds
* elapsed since January 1, 1970 at midnight UTC.
*
* The original Unix <time.h> package defined time_t as a 32-bit signed
* int, and many subsequent C compilers on other platforms followed suit.
* A signed 32-bit time_t has the well-known year-2038 problem; some later
* C compilers tried to improve matters by using an unsigned 32-bit time_t
* instead, but for many purposes this is even worse since it can't
* represent any date before 1/1/1970. *Most* modern compilers solve the
* problem once and for all (for 300 billion years in either direction of
* 1/1/1970, anyway - enough to represent literally all of eternity in most
* current cosmological models) by defining time_t as a signed 64-bit int.
* But some compilers stubbornly stick to the old 32-bit time_t even in
* newer versions, for the sake of compatibility with older code that might
* be lax about mixing time_t's with ordinary int's. E.g., MSVC2003 does
* this. Fortunately, some of these compilers (such as MSVC2003 again)
* also define a parallel, transitional set of 64-bit time functions that
* you can use by replacing all references to the standard time_t and
* related names with the corresponding 64-bit names.
*
* We'd really like to use a 64-bit time_t wherever we can - the TADS
* release cycle can be a bit slow, and we don't want 2038 to sneak up on
* us and catch us unawares. So for those compilers that offer a choice of
* 32 or 64 bits, we'd like to select the 64 bit version. To facilitate
* this, we define covers here for the time.h types and functions that we
* use. On platforms where the regular time_t is already 64 bits, or where
* there's no 64-bit option at all, you can simply do nothing - the
* defaults defined here use the standard time_t typedef and functions, so
* that's what you'll get if you don't define these in the OS-specific
* headers for your platform. For compilers that provide both a 32-bit
* time_t and a 64-bit other_time_t, the OS headers should #define these
* macros in terms of those compiler-specific 64-bit names.
*/
#ifndef os_time_t
# define os_time_t int64
# define os_gmtime(t) gmtime(t)
# define os_localtime(t) localtime(t)
# define os_time(t) time(t)
#endif
/*
* Initialize the time zone. This routine is meant to take care of any
* work that needs to be done prior to calling localtime() and other
* time-zone-dependent routines in the run-time library. For DOS and
* Windows, we need to call the run-time library routine tzset() to set up
* the time zone from the environment; most systems shouldn't need to do
* anything in this routine. It's sufficient to call this once during the
* process lifetime, since it's meant to perform static initialization that
* lasts as long as the process is running.
*/
#ifndef os_tzset
void os_tzset(void);
#endif
/*
* Higher-precision time. This retrieves the same time information as
* os_time() (i.e., the elapsed time since the standard Unix Epoch, January
* 1, 1970 at midnight UTC), but retrieves it with the highest precision
* available on the local system, up to nanosecond precision. If less
* precision is available, that's fine; just return the time to the best
* precision available, but expressed in terms of the number of
* nanoseconds. For example, if you can retrieve milliseconds, you can
* convert that to nanoseconds by multiplying by 1,000,000.
*
* On return, fills in '*seconds' with the number of whole seconds since
* the Epoch, and fills in '*nanoseconds' with the fractional portion,
* expressed in nanosceconds. Note that '*nanoseconds' is merely the
* fractional portion of the time, so 0 <= *nanoseconds < 1000000000.
*/
void os_time_ns(os_time_t *seconds, long *nanoseconds);
/*
* Get the local time zone name, as a location name in the IANA zoneinfo
* database. For example, locations using US Pacific Time should return
* "America/Los_Angeles".
*
* Returns true if successful, false if not. If the local operating system
* doesn't have a way to obtain this information, or if it's not available
* in the local machine's configuration, this returns false.
*
* The zoneinfo database is also known as the Olson or TZ (timezone)
* database; it's widely used on Unix systems as the definitive source of
* local time zone settings. See http://www.iana.org/time-zones for more
* information.
*
* On many Unix systems, the TZ environment variable contains the zoneinfo
* zone name when its first character is ':'. Windows uses a proprietary
* list of time zone names that can be mapped to zoneinfo names via a
* hand-coded list (such a list is maintained in the Unicode CLDR; our
* Windows implementation uses the CLDR list to generate the mapping).
* macOS uses zoneinfo keys directly; /etc/localtime is a link to the
* zoneinfo file for the local zone as set via the system preferences.
*
* os_tzset() must be invoked at some point before this routine is called.
*/
int os_get_zoneinfo_key(char *buf, size_t buflen);
/*
* Get a description of the local time zone. Fills in '*info' with the
* available information. Returns true on success, false on failure.
*
* See osstzprs.h/.c for a portable implementation of a parser for
* POSIX-style TZ strings. That can serve as a full implementation of this
* function for systems that use the POSIX TZ environment variable syntax
* to specify the timezone. (That routine simply parses a string from any
* source, so it can be used to parse the TZ syntax even on systems where
* the string comes from somewhere other than the TZ environment variable.)
*
* os_tzset() must be invoked at some point before this routine is called.
*
* The following two structures are used for the return information:
*
* os_tzrule_t - Timezone Rule structure. This describes a rule for an
* annual transition between daylight savings time and standard time in a
* time zone. Most timezones that have recurring standard/daylight changes
* require two of these rules, one for switching to daylight time in the
* spring and one for switching to standard time in the fall.
*
* os_tzinfo_t - Timezone Information structure. This describes a
* timezone's clock settings, name(s), and rules for recurring annual
* changes between standard time and daylight time, if applicable.
*/
struct os_tzrule_t {
/*
* Day of year, 1-365, NEVER counting Feb 29; set to 0 if not used.
* Corresponds to the "J" format in Unix TZ strings. (Called "Julian
* day" in the POSIX docs, thus the "J", even though it's a bit of a
* misnomer.)(Because of the invariance of the mapping from J-number to
* date, this is just an obtuse way of specifying a month/day date.
* But even so, we'll let the OS layer relay this back to us in
* J-number format and count on the portable caller to work out the
* date, rather than foisting that work on each platform
* implementation.)
*/
int jday;
/*
* Day of year, 1-366, counting Feb 29 on leap years; set to 0 if not
* used; ignored if 'jday' is nonzero. This corresponds to the Julian
* day sans "J" in TZ strings (almost - that TZ format uses 0-365 as
* its range, so bump it up by one when parsing a TZ string). This
* format is even more obtuse than the J-day format, in that it doesn't
* even have an invariant month/day mapping (not after day 59, anyway -
* day 60 is either February 29 or March 1, depending on the leapness
* of the year, and every day after that is similarly conditional). As
* far as I can tell, no one uses this option, so I'm not sure why it
* exists. The zoneinfo source format doesn't have a way to represent
* it, which says to me that no one has ever used it in a statutory DST
* start/end date definition in the whole history of time zones around
* the world, since the whole history of time zones around the world is
* exactly what the zoneinfo database captures in exhaustive and
* painstaking detail. If anyone had ever used it in defining a time
* zone, zoneinfo would have an option for it. My guess is that it's a
* fossilized bug from some early C RTL that's been retained out of an
* abundance of caution vis-a-vis compatibility, and was entirely
* replaced in practice by the J-number format as soon as someone
* noticed the fiddly leap year behavior. But for the sake of
* completeness...
*/
int yday;
/*
* The month (1-12), week of the month, and day of the week (1-7 for
* Sunday to Saturday). Week 1 is the first week in which 'day'
* occurs, week 2 is the second, etc.; week 5 is the last occurrence of
* 'day' in the month. These fields are used for "second Sunday in
* March" types of rules. Set these to zero if they're not used;
* they're ignored in any case if 'jday' or 'yday' are non-zero.
*/
int month;
int week;
int day;
/* time of day, in seconds after midnight (e.g., 2AM is 120 == 2*60*60) */
int time;
};
struct os_tzinfo_t {
/*
* The local offset from GMT, in seconds, for standard time and
* daylight time in this zone. These values are positive for zones
* east of GMT and negative for zones west: New York standard time
* (EST) is 5 hours west of GMT, so its offset is -5*60*60.
*
* Set both of these fields (if possible) regardless of whether
* standard or daylight time is currently in effect in the zone. The
* caller will select which offset to use based on the start/end rules,
* or based on the 'is_dst' flag if no rules are available.
*
* If it's only possible to determine the current wall clock offset, be
* it standard or daylight time, and it's not possible to determine the
* time difference between the two, simply set both of these to the
* current offset. This information isn't available from the standard
* C library, and many OS APIs also lack it.
*/
int32_t std_ofs;
int32_t dst_ofs;
/*
* The abbreviations for the local zone's standard time and daylight
* time, respectively, when displaying date/time values. E.g., "EST"
* and "EDT" for US Eastern Time. If the zone doesn't observe daylight
* time (it's on standard time year round), set dst_abbr to an empty
* string.
*
* As with std_ofs and dst_ofs, you can set both of these to the same
* string if it's only possible to determine the one that's currently
* in effect.
*/
char std_abbr[16];
char dst_abbr[16];
/*
* The ongoing rules for switching between daylight and standard time
* in this zone, if available. 'dst_start' is the date when daylight
* savings starts, 'dst_end' is the date when standard time resumes.
* Set all fields to 0 if the start/stop dates aren't available, or the
* zone is on standard time year round.
*/
struct os_tzrule_t dst_start;
struct os_tzrule_t dst_end;
/*
* True -> the zone is CURRENTLY on daylight savings time; false means
* it's currently on standard time.
*
* This is only used if the start/end rules aren't specified. In the
* absence of start/end rules, there's no way to know when the current
* standard/daylight phase ends, so we'll have to assume that the
* current mode is in effect permanently. In this case, the caller
* will use only be able to use the offset and abbreviation for the
* current mode and will have to ignore the other one.
*/
int is_dst;
};
int os_get_timezone_info(struct os_tzinfo_t *info);
/*
* Get the current system high-precision timer. This function returns a
* value giving the wall-clock ("real") time in milliseconds, relative to
* any arbitrary zero point. It doesn't matter what this value is relative
* to -- the only important thing is that the values returned by two
* different calls should differ by the number of actual milliseconds that
* have elapsed between the two calls. This might be the number of
* milliseconds since the computer was booted, since the current user
* logged in, since midnight of the previous night, since the program
* started running, since 1-1-1970, etc - it doesn't matter what the epoch
* is, so the implementation can use whatever's convenient on the local
* system.
*
* True millisecond precision isn't required. Each implementation should
* simply use the best precision available on the system. If your system
* doesn't have any kind of high-precision clock, you can simply use the
* time() function and multiply the result by 1000 (but see the note below
* about exceeding 32-bit precision).
*
* However, it *is* required that the return value be in *units* of
* milliseconds, even if your system clock doesn't have that much
* precision; so on a system that uses its own internal clock units, this
* routine must multiply the clock units by the appropriate factor to yield
* milliseconds for the return value.
*
* It is also required that the values returned by this function be
* monotonically increasing. In other words, each subsequent call must
* return a value that is equal to or greater than the value returned from
* the last call. On some systems, you must be careful of two special
* situations.
*
* First, the system clock may "roll over" to zero at some point; for
* example, on some systems, the internal clock is reset to zero at
* midnight every night. If this happens, you should make sure that you
* apply a bias after a roll-over to make sure that the value returned from
* this return continues to increase despite the reset of the system clock.
*
* Second, a 32-bit signed number can only hold about twenty-three days
* worth of milliseconds. While it seems unlikely that a TADS game would
* run for 23 days without a break, it's certainly reasonable to expect
* that the computer itself may run this long without being rebooted. So,
* if your system uses some large type (a 64-bit number, for example) for
* its high-precision timer, you may want to store a zero point the very
* first time this function is called, and then always subtract this zero
* point from the large value returned by the system clock. If you're
* using time(0)*1000, you should use this technique, since the result of
* time(0)*1000 will almost certainly not fit in 32 bits in most cases.
*/
long os_get_sys_clock_ms();
/* ------------------------------------------------------------------------ */
/*
* Hardware Configuration. Define the following functions appropriately
* for your hardware. For efficiency, these functions should be defined
* as macros if possible.
*
* Note that these hardware definitions are independent of the OS, at
* least to the extent that your OS can run on multiple types of
* hardware. So, rather than combining these definitions into your
* osxxx.h header file, we recommend that you put these definitions in a
* separate h_yyy.h header file, which can be configured into os.h with
* an appropriate "_M_yyy" preprocessor symbol. Refer to os.h for
* details of configuring the hardware include file.
*/
/*
* Round a size up to worst-case alignment boundary. For example, on a
* platform where the largest type must be aligned on a 4-byte boundary,
* this should round the value up to the next higher mutliple of 4 and
* return the result.
*/
/* size_t osrndsz(size_t siz); */
/*
* Round a pointer up to worst-case alignment boundary.
*/
/* void *osrndpt(void *ptr); */
/*
* Read an unaligned portable unsigned 2-byte value, returning an int
* value. The portable representation has the least significant byte
* first, so the value 0x1234 is represented as the byte 0x34, followed
* by the byte 0x12.
*
* The source value must be treated as unsigned, but the result is
* signed. This is significant on 32- and 64-bit platforms, because it
* means that the source value should never be sign-extended to 32-bits.
* For example, if the source value is 0xffff, the result is 65535, not
* -1.
*/
/* int osrp2(unsigned char *p); */
/*
* Read an unaligned portable signed 2-byte value, returning int. This
* differs from osrp2() in that this function treats the source value as
* signed, and returns a signed result; hence, on 32- and 64-bit
* platforms, the result must be sign-extended to the int size. For
* example, if the source value is 0xffff, the result is -1.
*/
/* int osrp2s(unsigned char *p); */
/*
* Write unsigned int to unaligned portable 2-byte value. The portable
* representation stores the low-order byte first in memory, so
* oswp2(0x1234) should result in storing a byte value 0x34 in the first
* byte, and 0x12 in the second byte.
*/
/* void oswp2(unsigned char *p, unsigned int i); */
/*
* Write signed int to unaligned portable 2-byte value. Negative values
* must be stored in two's complement notation. E.g., -1 is stored as
* FF.FF, -32768 is stored as 00.80 (little-endian).
*
* Virtually all modern hardware uses two's complement notation as the
* native representation, which makes this routine a trivial synonym of
* osrp2() (i.e., #define oswp2s(p,i) oswp2(p,i)). We distinguish the
* signed version on the extremely off chance that TADS is ever ported to
* wacky hardware with a different representation for negative integers
* (one's complement, sign bit, etc).
*/
/* void oswp2s(unsigned char *p, int i); */
/*
* Read an unaligned unsigned portable 4-byte value, returning long. The
* underlying value should be considered signed, and the result is signed.
* The portable representation stores the bytes starting with the least
* significant: the value 0x12345678 is stored with 0x78 in the first byte,
* 0x56 in the second byte, 0x34 in the third byte, and 0x12 in the fourth
* byte.
*/
/* unsigned long osrp4(unsigned char *p); */
/*
* Read an unaligned signed portable 4-byte value, returning long.
*/
/* long osrp4s(unsigned char *p); */
/*
* Write an unsigned long to an unaligned portable 4-byte value. The
* portable representation stores the low-order byte first in memory, so
* 0x12345678 is written to memory as 0x78, 0x56, 0x34, 0x12.
*/
/* void oswp4(unsigned char *p, unsigned long l); */
/*
* Write a signed long, using little-endian byte order and two's complement
* notation for negative numbers. This is a trivial synonym for oswp4()
* for all platforms with native two's complement arithmetic (which is
* virtually all modern platforms). See oswp2s() for more discussion.
*/
/* void oswp4s(unsigned char *p, long l); */
/*
* For convenience and readability, the 1-byte integer (signed and
* unsigned) equivalents of the above.
*/
#define osrp1(p) (*(unsigned char *)(p))
#define osrp1s(p) (*(signed char *)(p))
#define oswp1(p, b) (*(unsigned char *)(p) = (b))
#define oswp1s(p, b) (*(signed char *)(p) = (b))
/* ------------------------------------------------------------------------ */
/*
* varargs va_copy() extension.
*
* On some compilers, va_list is a reference type. This means that if a
* va_list value is passed to a function that uses va_arg() to step through
* the referenced arguments, the caller's copy of the va_list might be
* updated on return. This is problematic in cases where the caller needs
* to use the va_list again in another function call, since the va_list is
* no longer pointing to the first argument for the second call. C99 has a
* solution in the form of the va_copy() macro. Unfortunately, this isn't
* typically available in pre-C99 compilers, and isn't standard in *any*
* C++ version. We thus virtualize it here in a macro.
*
* os_va_copy() has identical semantics to C99 va_copy(). A matching call
* to os_va_copy_end() must be made for each call to os_va_copy() before
* the calling function returns; this has identical semantics to C99
* va_end().
*
* Because our semantics are identical to the C99 version, we provide a
* default definition here for compilers that define va_copy(). Platform
* headers must provide suitable definitions only if their compilers don't
* have va_copy(). We also provide a definition for GCC compilers that
* define the private __va_copy macro, which also has the same semantics.
*/
#ifdef va_copy
# define os_va_copy(dst, src) va_copy(dst, src)
# define os_va_copy_end(dst) va_end(dst)
#else
# if defined(__GNUC__) && defined(__va_copy)
# define os_va_copy(dst, src) __va_copy(dst, src)
# define os_va_copy_end(dst) va_end(dst)
# endif
#endif
/* ------------------------------------------------------------------------ */
/*
* Platform Identifiers. You must define the following macros in your
* osxxx.h header file:
*
* OS_SYSTEM_NAME - a string giving the system identifier. This string
* must contain only characters that are valid in a TADS identifier:
* letters, numbers, and underscores; and must start with a letter or
* underscore. For example, on MS-DOS, this string is "MSDOS".
*
* OS_SYSTEM_LDESC - a string giving the system descriptive name. This
* is used in messages displayed to the user. For example, on MS-DOS,
* this string is "MS-DOS".
*/
/* ------------------------------------------------------------------------ */
/*
* Message Linking Configuration. You should #define ERR_LINK_MESSAGES
* in your osxxx.h header file if you want error messages linked into
* the application. Leave this symbol undefined if you want an external
* message file.
*/
/* ------------------------------------------------------------------------ */
/*
* Program Exit Codes. These values are used for the argument to exit()
* to conform to local conventions. Define the following values in your
* OS-specific header:
*
* OSEXSUCC - successful completion. Usually defined to 0.
*. OSEXFAIL - failure. Usually defined to 1.
*/
/* ------------------------------------------------------------------------ */
/*
* Basic memory management interface. These functions are merely
* documented here, but no prototypes are defined, because most
* platforms #define macros for these functions and types, mapping them
* to malloc or other system interfaces.
*/
/*
* Theoretical maximum osmalloc() size. This may be less than the
* capacity of the argument to osmalloc() on some systems. For example,
* on segmented architectures (such as 16-bit x86), memory is divided into
* segments, so a single memory allocation can allocate only a subset of
* the total addressable memory in the system. This value thus specifies
* the maximum amount of memory that can be allocated in one chunk.
*
* Note that this is an architectural maximum for the hardware and
* operating system. It doesn't have anything to do with the total amount
* of memory actually available at run-time.
*
* #define OSMALMAX to a constant long value with theoretical maximum
* osmalloc() argument value. For a platform with a flat (unsegmented)
* 32-bit memory space, this is usually 0xffffffff; for 16-bit platforms,
* this is usually 0xffff.
*/
/* #define OSMALMAX 0xffffffff */
/*
* Allocate a block of memory of the given size in bytes. The actual
* allocation may be larger, but may be no smaller. The block returned
* should be worst-case aligned (i.e., suitably aligned for any type).
* Return null if the given amount of memory is not available.
*/
/* void *osmalloc(size_t siz); */
/*
* Free memory previously allocated with osmalloc().
*/
/* void osfree(void *block); */
/*
* Reallocate memory previously allocated with osmalloc() or
* osrealloc(), changing the block's size to the given number of bytes.
* If necessary, a new block at a different address can be allocated, in
* which case the data from the original block is copied (the lesser of
* the old block size and the new size is copied) to the new block, and
* the original block is freed. If the new size is less than the old
* size, this need not do anything at all, since the returned block can
* be larger than the new requested size. If the block cannot be
* enlarged to the requested size, return null.
*/
/* void *osrealloc(void *block, size_t siz); */
/* ------------------------------------------------------------------------ */
/*
* Basic file I/O interface. These functions are merely documented here,
* but no prototypes are defined, because most platforms #define macros for
* these functions and types, mapping them to stdio or other system I/O
* interfaces.
*
* When writing a file, writes might or might not be buffered in
* application memory; this is up to the OS implementation, which can
* perform buffering according to local conventions and what's most
* efficient. However, it shouldn't make any difference to the caller
* whether writes are buffered or not - the OS implementation must take
* care that any buffering is invisible to the app. (Porters: note that
* the basic C stdio package has the proper behavior here, so you'll get
* the correct semantics if you use a simple stdio implementation.)
*
* Write buffering might be visible to *other* apps, though. In
* particular, another process might not see data written to a file (with
* osfwb(), os_fprint(), etc) immediately, since the write functions might
* hold the written bytes in an internal memory buffer rather than sending
* them to the OS. Any internal buffers are guaranteed to be flushed to
* the OS upon calling osfcls() or osfflush(). Note that it's never
* *necessary* to call osfflush(), because buffered data will always be
* flushed on closing the file with osfcls(). However, if you want other
* apps to be able to see updates immediately, you can use osfflush() to
* ensure that buffers are flushed to a file before you close it.
*
* You can also use osfflush() to check for buffered write errors. When
* you use osfwb() or other write functions to write data, they will return
* a success indication even if the data was only copied into a buffer.
* This means that a write that appeared to succeed might actually fail
* later, when the buffer is flushed. The only way to know for sure is to
* explicitly flush buffers using osfflush(), and check the result code.
* If the original write function and a subsequent osfflush() *both* return
* success indications, then the write has definitely succeeded.
*/
/*
* Define the following values in your OS header to indicate local
* file/path syntax conventions:
*
* OSFNMAX - integer indicating maximum length of a filename
*
* OSPATHCHAR - character giving the normal path separator character
*. OSPATHALT - string giving other path separator characters
*. OSPATHURL - string giving path separator characters for URL conversions
*. OSPATHSEP - directory separator for PATH-style environment variables
*. OSPATHPWD - string giving the special path representing the current
*. working directory; for Unix or Windows, this is "."
*
* OSPATHURL is a little different: this specifies the characters that
* should be converted to URL-style separators when converting a path from
* local notation to URL notation. This is usually the same as the union
* of OSPATHCHAR and OSPATHALT, but need not be; for example, on DOS, the
* colon (':') is a path separator for most purposes, but is NOT a path
* character for URL conversions.
*/
/*
* Define the type osfildef as the appropriate file handle structure for
* your osfxxx functions. This type is always used as a pointer, but
* the value is always obtained from an osfopxxx call, and is never
* synthesized by portable code, so you can use essentially any type
* here that you want.
*
* For platforms that use C stdio functions to implement the osfxxx
* functions, osfildef can simply be defined as FILE.
*/
/* typedef FILE osfildef; */
/*
* File types.
*
* These are symbols of the form OSFTxxxx defining various content types,
* somewhat aking to MIME types. These were mainly designed for the old
* Mac OS (versions up to OS 9), where the file system stored a type tag
* with each file's metadata. The type tags were used for things like
* filtering file selector dialogs and setting file-to-app associations in
* the desktop shell.
*
* Our OSFTxxx symbols are abstract file types that we define, for types
* used within the TADS family of applications. They give us a common,
* cross-platform reference point for each type we use. Each port where
* file types are meaningful then maps our abstract type IDs to the
* corresponding port-specific type IDs. In practice, this has never been
* used anywhere other than the old Mac OS ports; in fact, it's not even
* used in the modern macOS since Apple decided to stop
* fighting the tide and start using filename suffixes for this sort of
* tagging, like everyone else always has.
*
* For the list of file types, see osifctyp.h
*/
/*
* Local newline convention.
*
* Because of the pernicious NIH ("Not Invented Here") cultures of the
* major technology vendors, basically every platform out there has its own
* unique way of expressing newlines in text files. Unix uses LF (ASCII
* 10); Mac uses CR (ASCII 13); DOS and Windows use CR-LF pairs. In the
* past there were heaven-only-knows how many other conventions in use, but
* fortunately these three have the market pretty well locked up at this
* point. But we do still have to worry about these three.
*
* Our strategy on input is to be open to just about anything whenever
* possible. So, when we're reading something that we believe to be a text
* file, we'll treat all of these as line endings: CR, LF, CR-LF, and
* LF-CR. It's pretty safe to do this; if we have a CR and LF occurring
* adjacently, it's almost certain that they're intended to be taken
* together as a single newline sequence. Likewise, if there's a lone CR
* or LF, it's rare for it to mean anything other than a newline.
*
* On output, though, we can't be as loose. The problem is that other
* applications on our big three platforms *don't* tend to aim for the same
* flexibility we do on input: other apps usually expect exactly the local
* conventions on input, and don't always work well if they don't get it.
* So it's important that when we're writing a text file, we write newlines
* in the local convention. This means that we sometimes need to know what
* the local convention actually is. That's where this definition comes
* in.
*
* Each port must define OS_NEWLINE_SEQ as an ASCII string giving the local
* newline sequence to write on output. For example, DOS defines it as
* "\r\n" (CR-LF). Always define it as a STRING (not a character
* constant), even if it's only one character long.
*
* (Note that some compilers use wacky mappings for \r and \n. Some older
* Mac compilers, for example, defined \n as CR and \r as LF, because of
* the Mac convention where newline is represented as CR in a text file.
* If there's any such variability on your platform, you can always use the
* octal codes to be unambiguous: \012 for LF and \015 for CR.)
*/
/* #define OS_NEWLINE_SEQ "\r\n" */
/* ------------------------------------------------------------------------ */
/*
* File "stat()" information - mode, size, time stamps
*/
/*
* Get a file's mode and attribute flags. This retrieves information on
* the given file equivalent to the st_mode member of the 'struct stat'
* data returned by the Unix stat() family of functions, as well as some
* extra system-specific attributes. On success, fills in *mode (if mode
* is non-null) with the mode information as a bitwise combination of
* OSFMODE_xxx values, fills in *attr (if attr is non-null) with a
* combination of OSFATTR_xxx attribute flags, and returns true; on
* failure, simply returns false. Failure can occur if the file doesn't
* exist, can't be accessed due to permissions, etc.
*
* Note that 'mode' and/or 'attr' can be null if the caller doesn't need
* that information. Implementations must check these parameters for null
* pointers and skip returning the corresponding information if null.
*
* If the file in 'fname' is a symbolic link, the behavior depends upon
* 'follow_links'. If 'follow_links' is true, the function should resolve
* the link reference (and if that points to another link, the function
* resolves that link as well, and so on) and return information on the
* object the link points to. Otherwise, the function returns information
* on the link itself. This only applies for symbolic links (not for hard
* links), and only if the underlying OS and file system support this
* distinction; if the OS transparently resolves links and doesn't allow
* retrieving information about the link itself, 'follow_links' can be
* ignored. Likewise, hard links (on systems that support them) are
* generally indistinguishable from regular files, so this function isn't
* expected to do anything special with them.
*
* The '*mode' value returned is a bitwise combination of OSFMODE_xxx flag.
* Many of the flags are mutually exclusive; for example, "file" and
* "directory" should never be combined. It's also possible for '*mode' to
* be zero for a valid file; this means that the file is of some special
* type on the local system that doesn't fit any of the OSFMODE_xxx types.
* (If any ports do encounter such cases, we can add OSFMODE_xxx types to
* accommodate new types. The list below isn't meant to be final; it's
* just what we've encountered so far on the platforms where TADS has
* already been ported.)
*
* The OSFMODE_xxx values are left for the OS to define so that they can be
* mapped directly to the OS API's equivalent constants, if desired. This
* makes the routine easy to write, since you can simply set *mode directly
* to the mode information the OS returns from its stat() or equivalent.
* However, note that these MUST be defined as bit flags - that is, each
* value must be exactly a power of 2. Windows and Unix-like systems
* follow this practice, as do most "stat()" functions in C run-time
* libraries, so this usually works automatically if you map these
* constants to OS or C library values. However, if a port defines its own
* values for these, take care that they're all powers of 2.
*
* Obviously, a given OS might not have all of the file types listed here.
* If any OSFMODE_xxx values aren't applicable on the local OS, you can
* simply define them as zero since they'll never be returned.
*
* Notes on attribute flags:
*
* OSFATTR_HIDDEN means that the file is conventionally hidden by default
* in user interface views or listings, but is still fully accessible to
* the user. Hidden files are also usually excluded by default from
* wildcard patterns in commands ("rm *.*"). On Unix, a hidden file is one
* whose name starts with "."; on Windows, it's a file with the HIDDEN bit
* in its file attributes. On systems where this concept exists, the user
* can still manipulate these files as normal by naming them explicitly,
* and can typically make them appear in UI views or directory listings via
* a preference setting or command flag (e.g., "ls -a" on Unix). The
* "hidden" flag is explicitly NOT a security or permissions mechanism, and
* it doesn't protect the file against intentional access by a user; it's
* merely a convenience designed to reduce clutter by excluding files
* maintained by the OS or by an application (such as preference files,
* indices, caches, etc) from casual folder browsing, where a user is
* typically only concerned with her own document files. On systems where
* there's no such naming convention or attribute metadata, this flag will
* never appear.
*
* OSFATTR_SYSTEM is similar to 'hidden', but means that the file is
* specially marked as an operating system file. This is mostly a
* DOS/Windows concept, where it corresponds to the SYSTEM bit in the file
* attributes; this flag will probably never appear on other systems. The
* distinction between 'system' and 'hidden' is somewhat murky even on
* Windows; most 'system' file are also marked as 'hidden', and in
* practical terms in the user interface, 'system' files are treated the
* same as 'hidden'.
*
* OSFATTR_READ means that the file is readable by this process.
*
* OSFATTR_WRITE means that the file is writable by this process.
*/
/* int osfmode(const char *fname, int follow_links, */
/* unsigned long *mode, unsigned long *attr); */
/* file mode/type constants */
/* #define OSFMODE_FILE - regular file */
/* #define OSFMODE_DIR - directory */
/* #define OSFMODE_BLK - block-mode device */
/* #define OSFMODE_CHAR - character-mode device */
/* #define OSFMODE_PIPE - pipe/FIFO/other character-oriented IPC */
/* #define OSFMODE_SOCKET - network socket */
/* #define OSFMODE_LINK - symbolic link */
/* file attribute constants */
/* #define OSFATTR_HIDDEN - hidden file */
/* #define OSFATTR_SYSTEM - system file */
/* #define OSFATTR_READ - the file is readable by this process */
/* #define OSFATTR_WRITE - the file is writable by this process */
struct os_file_stat_t {
/*
* Size of the file, in bytes. For platforms lacking 64-bit types, we
* split this into high and low 32-bit portions. Platforms where the
* native stat() or equivalent only returns a 32-bit file size can
* simply set sizehi to zero, since sizelo can hold the entire size
* value.
*/
uint32_t sizelo;
uint32_t sizehi;
/*
* Creation time, modification time, and last access time. If the file
* system doesn't keep information on one or more of these, use
* (os_time_t)0 to indicate that the timestamp isn't available. It's
* fine to return any subset of these. Per the standard C stat(),
* these should be expressed as seconds after the Unix Epoch.
*/
os_time_t cre_time;
os_time_t mod_time;
os_time_t acc_time;
/* file mode, using the same flags as returned from osfmode() */
unsigned long mode;
/* file attributes, using the same flags as returned from osfmode() */
unsigned long attrs;
};
/*
* Get stat() information. This fills in the portable os_file_stat
* structure with the requested file information. Returns true on success,
* false on failure (file not found, permissions error, etc).
*
* 'follow_links' has the same meaning as for osfmode().
*/
int os_file_stat(const char *fname, int follow_links, os_file_stat_t *s);
/*
* Manually resolve a symbolic link. If the local OS and file system
* support symbolic links, and the given filename is a symbolic link (in
* which case osfmode(fname, FALSE, &m, &a) will set OSFMODE_LINK in the
* mode bits), this fills in 'target' with the name of the link target
* (i.e., the object that the link in 'fname' points to). This should
* return a fully qualified file system path. Returns true on success,
* false on failure.
*
* This should only resolve a single level of indirection. If the link
* target of 'fname' is itself a link to a second target, this should only
* resolve the single reference from 'fname' to its direct direct. Callers
* that wish to resolve the final target of a chain of link references must
* iterate until the returned path doesn't refer to a link.
*/
int os_resolve_symlink(const char *fname, char *target, size_t target_size);
/* ------------------------------------------------------------------------ */
/*
* Get a list of root directories. If 'buf' is non-null, fills in 'buf'
* with a list of strings giving the root directories for the local,
* file-oriented devices on the system. The strings are each null
* terminated and are arranged consecutively in the buffer, with an extra
* null terminator after the last string to mark the end of the list.
*
* The return value is the length of the buffer required to hold the
* results. If the caller's buffer is null or is too short, the routine
* should return the full length required, and leaves the contents of the
* buffer undefined; the caller shouldn't expect any contents to be filled
* in if the return value is greater than buflen. Both 'buflen' and the
* return value include the null terminators, including the extra null
* terminator at the end of the list. If an error occurs, or the system
* has no concept of a root directory, returns zero.
*
* Each result string should be expressed using the syntax for the root
* directory on a device. For example, on Windows, "C:\" represents the
* root directory on the C: drive.
*
* "Local" means a device is mounted locally, as opposed to being merely
* visible on the network via some remote node syntax; e.g., on Windows
* this wouldn't include any UNC-style \\SERVER\SHARE names, and on VMS it
* excludes any SERVER:: nodes. It's up to each system how to treat
* virtual local devices, i.e., those that look synctactically like local
* devices but are actually mounted network devices, such as Windows mapped
* network drives; we recommend including them if it would take extra work
* to filter them out, and excluding them if it would take extra work to
* include them. "File-oriented" means that the returned devices are
* accessed via file systems, not as character devices or raw block
* devices; so this would exclude /dev/xxx devices on Unix and things like
* CON: and LPT1: on Windows.
*
* Examples ("." represents a null byte):
*
* Windows: C:\.D:\.E:\..
*
* Unix example: /..
*/
size_t os_get_root_dirs(char *buf, size_t buflen);
/* ------------------------------------------------------------------------ */
/*
* Open a directory. This begins an enumeration of a directory's contents.
* 'dirname' is a relative or absolute path to a directory. On success,
* returns true, and 'handle' is set to a port-defined handle value that's
* used in subsequent calls to os_read_dir() and os_close_dir(). Returns
* false on failure.
*
* If the routine succeeds, the caller must eventually call os_close_dir()
* to release the resources associated with the handle.
*/
/* typedef <local system type> osdirhdl_t; */
int os_open_dir(const char *dirname, /*OUT*/osdirhdl_t *handle);
/*
* Read the next file in a directory. 'handle' is a handle value obtained
* from a call to os_open_dir(). On success, returns true and fills in
* 'fname' with the next filename; the handle is also internally updated so
* that the next call to this function will retrieve the next file, and so
* on until all files have been retrieved. If an error occurs, or there
* are no more files in the directory, returns false.
*
* The filename returned is the root filename only, without the path. The
* caller can build the full path by calling os_build_full_path() or
* os_combine_paths() with the original directory name and the returned
* filename as parameters.
*
* This routine lists all objects in the directory that are visible to the
* corresponding native API, and is non-recursive. The listing should thus
* include subdirectory objects, but not the contents of subdirectories.
* Implementations are encouraged to simply return all objects returned
* from the corresponding native directory scan API; there's no need to do
* any filtering, except perhaps in cases where it's difficult or
* impossible to represent an object in terms of the osifc APIs (e.g., it
* might be reasonable to exclude files without names). System relative
* links, such as the Unix/DOS "." and "..", specifically should be
* included in the listing. For unusual objects that don't fit into the
* os_file_stat() taxonomy or that otherwise might create confusion for a
* caller, err on the side of full disclosure (i.e., just return everything
* unfiltered); if necessary, we can extend the os_file_stat() taxonomy or
* add new osifc APIs to create a portable abstraction to handle whatever
* is unusual or potentially confusing about the native object. For
* example, Unix implementations should feel free to return symbolic link
* objects, including dangling links, since we have the portable
* os_resolve_symlink() that lets the caller examine the meaning of the
* link object.
*/
int os_read_dir(osdirhdl_t handle, char *fname, size_t fname_size);
/*
* Close a directory handle. This releases the resources associated with a
* directory search started with os_open_dir(). Every successful call to
* os_open_dir() must have a matching call to os_close_dir(). As usual for
* open/close protocols, the handle is invalid after calling this function,
* so no more calls to os_read_dir() may be made with the handle.
*/
void os_close_dir(osdirhdl_t handle);
/* ------------------------------------------------------------------------ */
/*
* NB - this routine is DEPRECATED as of TADS 2.5.16/3.1.1. Callers should
* use os_open_dir(), os_read_dir(), os_close_dir() instead.
*
* Find the first file matching a given pattern. The returned context
* pointer is a pointer to whatever system-dependent context structure is
* needed to continue the search with the next file, and is opaque to the
* caller. The caller must pass the context pointer to the next-file
* routine. The caller can optionally cancel a search by calling the
* close-search routine with the context pointer. If the return value is
* null, it indicates that no matching files were found. If a file was
* found, outbuf will be filled in with its name, and isdir will be set to
* true if the match is a directory, false if it's a file. If pattern is
* null, all files in the given directory should be returned; otherwise,
* pattern is a string containing '*' and '?' as wildcard characters, but
* not containing any directory separators, and all files in the given
* directory matching the pattern should be returned.
*
* Important: because this routine may allocate memory for the returned
* context structure, the caller must either call os_find_next_file until
* that routine returns null, or call os_find_close() to cancel the search,
* to ensure that the os code has a chance to release the allocated memory.
*
* 'outbuf' should be set on output to the name of the matching file,
* without any path information.
*
* 'outpathbuf' should be set on output to full path of the matching file.
* If possible, 'outpathbuf' should use the same relative or absolute
* notation that the search criteria used on input. For example, if dir =
* "resfiles", and the file found is "MyPic.jpg", outpathbuf should be set
* to "resfiles/MyPic.jpg" (or appropriate syntax for the local platform).
* Similarly, if dir = "/home/tads/resfiles", outpath buf should be
* "/home/tads/resfiles/MyPic.jpg". The result should always conform to
* correct local conventions, which may require some amount of manipulation
* of the filename; for example, on the Mac, if dir = "resfiles", the
* result should be ":resfiles:MyPic.jpg" (note the added leading colon) to
* conform to Macintosh relative path notation.
*
* Note that 'outpathbuf' may be null, in which case the caller is not
* interested in the full path information.
*/
/*
* Note the following possible ways this function may be called:
*
* dir = "", pattern = filename - in this case, pattern is the name of a
* file or directory in the current directory. filename *might* be a
* relative path specified by the user (on a command line, for example);
* for instance, on Unix, it could be something like "resfiles/jpegs".
*
* dir = path, pattern = filname - same as above, but this time the
* filename or directory pattern is relative to the given path, rather
* than to the current directory. For example, we could have dir =
* "/games/mygame" and pattern = "resfiles/jpegs".
*
* dir = path, pattern = 0 (NULL) - this should search for all files in
* the given path. The path might be absolute or it might be relative.
*
* dir = path, pattern = "*" - this should have the same result as when
* pattern = 0.
*
* dir = path, pattern = "*.ext" - this should search for all files in
* the given path whose names end with ".ext".
*
* dir = path, pattern = "abc*" - this should search for all files in
* the given path whose names start with "abc".
*
* All of these combinations are possible because callers, for
* portability, must generally not manipulate filenames directly;
* instead, callers obtain paths and search strings from external
* sources, such as from the user, and present them to this routine with
* minimal manipulation.
*/
void *os_find_first_file(const char *dir,
char *outbuf, size_t outbufsiz, int *isdir,
char *outpathbuf, size_t outpathbufsiz);
/*
* Implementation notes for porting os_find_first_file:
*
* The algorithm for this routine should go something like this:
*
* - If 'path' is null, create a variable real_path and initialize it
* with the current directory. Otherwise, copy path to real_path.
*
* - If 'pattern' contains any directory separators ("/" on Unix, for
* example), change real_path so that it reflects the additional leading
* subdirectories in the path in 'pattern', and remove the leading path
* information from 'pattern'. For example, on Unix, if real_path
* starts out as "./subdir", and pattern is "resfiles/jpegs", change
* real_path to "./subdir/resfiles", and change pattern to "jpegs".
* Take care to add and remove path separators as needed to keep the
* path strings well-formed.
*
* - Begin a search using appropriate OS API's for all files in
* real_path.
*
* - Check each file found. Skip any files that don't match 'pattern',
* treating "*" as a wildcard that matches any string of zero or more
* characters, and "?" as a wildcard that matches any single character
* (or matches nothing at the end of a string). For example:
*
*. "*" matches anything
*. "abc?" matches "abc", "abcd", "abce", "abcf", but not "abcde"
*. "abc???" matches "abc", "abcd", "abcde", "abcdef", but not "abcdefg"
*. "?xyz" matches "wxyz", "axyz", but not "xyz" or "abcxyz"
*
* - Return the first file that matches, if any, by filling in 'outbuf'
* and 'isdir' with appropriate information. Before returning, allocate
* a context structure (which is entirely for your own use, and opaque
* to the caller) and fill it in with the information necessary for
* os_find_next_file to get the next matching file. If no file matches,
* return null.
*/
/*
* Find the next matching file, continuing a search started with
* os_find_first_file(). Returns null if no more files were found, in
* which case the search will have been automatically closed (i.e.,
* there's no need to call os_find_close() after this routine returns
* null). Returns a non-null context pointer, which is to be passed to
* this function again to get the next file, if a file was found.
*
* 'outbuf' and 'outpathbuf' are filled in with the filename (without
* path) and full path (relative or absolute, as appropriate),
* respectively, in the same manner as they do for os_find_first_file().
*
* Implementation note: if os_find_first_file() allocated memory for the
* search context, this routine must free the memory if it returs null,
* because this indicates that the search is finished and the caller
* need not call os_find_close().
*/
void *os_find_next_file(void *ctx, char *outbuf, size_t outbufsiz,
int *isdir, char *outpathbuf, size_t outpathbufsiz);
/*
* Cancel a search. The context pointer returned by the last call to
* os_find_first_file() or os_find_next_file() is the parameter. There
* is no need to call this function if find-first or find-next returned
* null, since they will have automatically closed the search.
*
* Implementation note: if os_find_first_file() allocated memory for the
* search context, this routine should release the memory.
*/
void os_find_close(void *ctx);
/*
* Special filename classification
*/
enum os_specfile_t
{
/* not a special file */
OS_SPECFILE_NONE,
/*
* current directory link - this is a file like the "." file on Unix
* or DOS, which is a special link that simply refers to itself
*/
OS_SPECFILE_SELF,
/*
* parent directory link - this is a file like the ".." file on Unix
* or DOS, which is a special link that refers to the parent
* directory
*/
OS_SPECFILE_PARENT
};
/*
* Determine if the given filename refers to a special file. Returns the
* appropriate enum value if so, or OS_SPECFILE_NONE if not. The given
* filename must be a root name - it must not contain a path prefix. The
* purpose here is to classify the results from os_find_first_file() and
* os_find_next_file() to identify the special relative links, so callers
* can avoid infinite recursion when traversing a directory tree.
*/
enum os_specfile_t os_is_special_file(const char *fname);
/* ------------------------------------------------------------------------ */
/*
* Convert string to all-lowercase.
*/
char *os_strlwr(char *s);
/* ------------------------------------------------------------------------ */
/*
* Character classifications for quote characters. os_squote() returns
* true if its argument is any type of single-quote character;
* os_dquote() returns true if its argument is any type of double-quote
* character; and os_qmatch(a, b) returns true if a and b are matching
* open- and close-quote characters.
*
* These functions allow systems with extended character codes with
* weird quote characters (such as the Mac) to match the weird
* characters, so that users can use the extended quotes in input.
*
* These are usually implemented as macros. The most common
* implementation simply returns true for the standard ASCII quote
* characters:
*
* #define os_squote(c) ((c) == '\'')
*. #define os_dquote(c) ((c) == '"')
*. #define os_qmatch(a, b) ((a) == (b))
*
* These functions take int arguments to allow for the possibility of
* Unicode input.
*/
/* int os_squote(int c); */
/* int os_dquote(int c); */
/* int os_qmatch(int a, int b); */
/* ------------------------------------------------------------------------ */
/*
* Special file and directory locations
*/
/*
* Get the full filename (including directory path) to the executable
* file, given the argv[0] parameter passed into the main program. This
* fills in the buffer with a null-terminated string that can be used in
* osfoprb(), for example, to open the executable file.
*
* Returns non-zero on success. If it's not possible to determine the
* name of the executable file, returns zero.
*
* Some operating systems might not provide access to the executable file
* information, so non-trivial implementation of this routine is optional;
* if the necessary information is not available, simply implement this to
* return zero. If the information is not available, callers should offer
* gracefully degraded functionality if possible.
*/
int os_get_exe_filename(char *buf, size_t buflen, const char *argv0);
/*
* Get a special directory path. Returns the selected path, in a format
* suitable for use with os_build_full_path(). The main program's argv[0]
* parameter is provided so that the system code can choose to make the
* special paths relative to the program install directory, but this is
* entirely up to the system implementation, so the argv[0] parameter can
* be ignored if it is not needed.
*
* The 'id' parameter selects which special path is requested; this is one
* of the constants defined below. If the id is not understood, there is
* no way of signalling an error to the caller; this routine can fail with
* an assert() in such cases, because it indicates that the OS layer code
* is out of date with respect to the calling code.
*
* This routine can be implemented using one of the strategies below, or a
* combination of these. These are merely suggestions, though, and systems
* are free to ignore these and implement this routine using whatever
* scheme is the best fit to local conventions.
*
* - Relative to argv[0]. Some systems use this approach because it keeps
* all of the TADS files together in a single install directory tree, and
* doesn't require any extra configuration information to find the install
* directory. Since we base the path name on the executable that's
* actually running, we don't need any environment variables or parameter
* files or registry entries to know where to look for related files.
*
* - Environment variables or local equivalent. On some systems, it is
* conventional to set some form of global system parameter (environment
* variables on Unix, for example) for this sort of install configuration
* data. In these cases, this routine can look up the appropriate
* configuration variables in the system environment.
*
* - Hard-coded paths. Some systems have universal conventions for the
* installation configuration of compiler-like tools, so the paths to our
* component files can be hard-coded based on these conventions.
*
* - Hard-coded default paths with environment variable overrides. Let the
* user set environment variables if they want, but use the standard system
* paths as hard-coded defaults if the variables aren't set. This is often
* the best choice; users who expect the standard system conventions won't
* have to fuss with any manual settings or even be aware of them, while
* users who need custom settings aren't stuck with the defaults.
*/
void os_get_special_path(char *buf, size_t buflen,
const char *argv0, int id);
/*
* TADS 3 system resource path. This path is used to load system
* resources, such as character mapping files and error message files.
*/
#define OS_GSP_T3_RES 1
/*
* TADS 3 compiler - system headers. This is the #include path for the
* header files included with the compiler.
*/
#define OS_GSP_T3_INC 2
/*
* TADS 3 compiler - system library source code. This is the path to the
* library source files that the compiler includes in every compilation by
* default (such as _main.t).
*/
#define OS_GSP_T3_LIB 3
/*
* TADS 3 compiler - user library path list. This is a list of directory
* paths, separated by the OSPATHSEP character, that should be searched for
* user library files. The TADS 3 compiler uses this as an additional set
* of locations to search after the list of "-Fs" options and before the
* OS_GSP_T3_LIB directory.
*
* This path list is intended for the user's use, so no default value is
* needed. The value should be user-configurable using local conventions;
* on Unix, for example, this might be handled with an environment
* variable.
*/
#define OS_GSP_T3_USER_LIBS 4
/*
* TADS 3 interpreter - application data path. This is the directory where
* we should store things like option settings: data that we want to store
* in a file, global to all games. Depending on local system conventions,
* this can be a global shared directory for all users, or can be a
* user-specific directory.
*/
#define OS_GSP_T3_APP_DATA 5
/*
* TADS 3 interpreter - system configuration files. This is used for files
* that affect all games, and generally all users on the system, so it
* should be in a central location. On Windows, for example, we simply
* store these files in the install directory containing the intepreter
* binary.
*/
#define OS_GSP_T3_SYSCONFIG 6
/*
* System log files. This is the directory for system-level status, debug,
* and error logging files. (Note that we're NOT talking about in-game
* transcript logging per the SCRIPT command. SCRIPT logs are usually sent
* to files selected by the user via a save-file dialog, so these don't
* need a special location.)
*/
#define OS_GSP_LOGFILE 7
/*
* Seek to the resource file embedded in the current executable file,
* given the main program's argv[0].
*
* On platforms where the executable file format allows additional
* information to be attached to an executable, this function can be used
* to find the extra information within the executable.
*
* The 'typ' argument gives a resource type to find. This is an arbitrary
* string that the caller uses to identify what type of object to find.
* The "TGAM" type, for example, is used by convention to indicate a TADS
* compiled GAM file.
*/
osfildef *os_exeseek(const char *argv0, const char *typ);
/* ------------------------------------------------------------------------ */
/*
* Load a string resource. Given a string ID number, load the string
* into the given buffer.
*
* Returns zero on success, non-zero if an error occurs (for example,
* the buffer is too small, or the requested resource isn't present).
*
* Whenever possible, implementations should use an operating system
* mechanism for loading the string from a user-modifiable resource
* store; this will make localization of these strings easier, since the
* resource store can be modified without the need to recompile the
* application. For example, on the Macintosh, the normal system string
* resource mechanism should be used to load the string from the
* application's resource fork.
*
* When no operating system mechanism exists, the resources can be
* stored as an array of strings in a static variable; this isn't ideal,
* because it makes it much more difficult to localize the application.
*
* Resource ID's are application-defined. For example, for TADS 2,
* "res.h" defines the resource ID's.
*/
int os_get_str_rsc(int id, char *buf, size_t buflen);
/* ------------------------------------------------------------------------ */
/*
* Get a suitable seed for a random number generator; should use the system
* clock or some other source of an unpredictable and changing seed value.
*/
void os_rand(long *val);
/*
* Generate random bytes for use in seeding a PRNG (pseudo-random number
* generator). This is an extended version of os_rand() for PRNGs that use
* large seed vectors containing many bytes, rather than the simple 32-bit
* seed that os_rand() assumes.
*
* As with os_rand(), this function isn't meant to be used directly as a
* random number source for ongoing use - instead, this is intended mostly
* for seeding a PRNG, which will then be used as the primary source of
* random numbers. The big problem with using this routine directly as a
* randomness source is that some implementations might rely heavily on
* environmental randomness, such as the real-time clock or OS usage
* statistics. Such sources tend to provide reasonable entropy from one
* run to the next, but not within a single session, as the underlying data
* sources don't change rapidly enough.
*
* Ideally, this routine should generate *truly* random bytes obtained from
* hardware sources. Not all systems can provide that, though, so true
* randomness isn't guaranteed. Here are the suggested implementation
* options, in descending order of desirability:
*
* 1. Use a hardware source of true randomness, such as a /dev/rand type
* of device. However, note that this call should return reasonably
* quickly, so always use a non-blocking source. Some Unix /dev/rand
* devices, for example, can block indefinitely to allow sufficient entropy
* to accumulate.
*
* 2. Use a cryptographic random number source provided by the OS. Some
* systems provide this as an API service. If going this route, be sure
* that the OS generator is itself "seeded" with some kind of true
* randomness source, as it defeats the whole purpose if you always return
* a fixed pseudo-random sequence each time the program runs.
*
* 3. Use whatever true random sources are available locally to seed a
* software pseudo-random number generator, then generate bytes from your
* PRNG. Some commonly available sources of true randomness are a
* high-resolution timer, the system clock, the current process ID,
* logged-in user ID, environment variables, uninitialized pages of memory,
* the IP address; each of these sources might give you a few bits of
* entropy at best, so the best bet is to use an ensemble. You could, for
* example, concatenate a bunch of this type of information together and
* calculate an MD5 or SHA1 hash to mix the bits more thoroughly. For the
* PRNG, use a cryptographic generator. (You could use the ISAAC generator
* from TADS 3, as that's a crypto PRNG, but it's probably better to use a
* different generator here since TADS 3 is going to turn around and use
* this function's output to seed ISAAC - seeding one ISAAC instance with
* another ISAAC's output seems likely to magnify any weaknesses in the
* ISAAC algorithm.) Note that this option is basically the DIY version of
* option 2. Option 2 is better because the OS probably has access to
* better sources of true randomness than an application does.
*/
void os_gen_rand_bytes(unsigned char *buf, size_t len);
/* ------------------------------------------------------------------------ */
/*
* Display routines.
*
* Our display model is a simple stdio-style character stream.
*
* In addition, we provide an optional "status line," which is a
* non-scrolling area where a line of text can be displayed. If the status
* line is supported, text should only be displayed in this area when
* os_status() is used to enter status-line mode (mode 1); while in status
* line mode, text is written to the status line area, otherwise (mode 0)
* it's written to the normal main text area. The status line is normally
* shown in a different color to set it off from the rest of the text.
*
* The OS layer can provide its own formatting (word wrapping in
* particular) if it wants, in which case it should also provide pagination
* using os_more_prompt().
*/
/*
* OS_MAXWIDTH - the maximum width of a line of text. Most platforms use
* 135 for this, but you can use more or less as appropriate. If you use
* OS-level line wrapping, then the true width of a text line is
* irrelevant, and the portable code will use this merely for setting its
* internal buffer sizes.
*
* This must be defined in the os_xxx.h header file for each platform.
*/
/*#define OS_MAXWIDTH 135 - example only: define for real in os_xxx.h header*/
/*
* Print a string on the console. These routines come in two varieties:
*
* os_printz - write a NULL-TERMINATED string
*. os_print - write a COUNTED-LENGTH string, which may not end with a null
*
* These two routines are identical except that os_printz() takes a string
* which is terminated by a null byte, and os_print() instead takes an
* explicit length, and a string that may not end with a null byte.
*
* os_printz(str) may be implemented as simply os_print(str, strlen(str)).
*
* The string is written in one of three ways, depending on the status mode
* set by os_status():
*
* status mode == 0 -> write to main text window
*. status mode == 1 -> write to status line
*. anything else -> do not display the text at all
*
* Implementations are free to omit any status line support, in which case
* they should simply suppress all output when the status mode is anything
* other than zero.
*
* The following special characters must be recognized in the displayed
* text:
*
* '\n' - newline: end the current line and move the cursor to the start of
* the next line. If the status line is supported, and the current status
* mode is 1 (i.e., displaying in the status line), then two special rules
* apply to newline handling: newlines preceding any other text should be
* ignored, and a newline following any other text should set the status
* mode to 2, so that all subsequent output is suppressed until the status
* mode is changed with an explicit call by the client program to
* os_status().
*
* '\r' - carriage return: end the current line and move the cursor back to
* the beginning of the current line. Subsequent output is expected to
* overwrite the text previously on this same line. The implementation
* may, if desired, IMMEDIATELY clear the previous text when the '\r' is
* written, rather than waiting for subsequent text to be displayed.
*
* All other characters may be assumed to be ordinary printing characters.
* The routine need not check for any other special characters.
*
*/
void os_printz(const char *str);
void os_print(const char *str, size_t len);
/*
* Print to the debugger console. These routines are for interactive
* debugger builds only: they display the given text to a separate window
* within the debugger UI (separate from the main game command window)
* where the debugger displays status information specific to the debugging
* session (such as compiler/build output, breakpoint status messages,
* etc). For example, TADS Workbench on Windows displays these messages in
* its "Debug Log" window.
*
* These routines only need to be implemented for interactive debugger
* builds, such as TADS Workbench on Windows. These can be omitted for
* regular interpreter builds.
*/
void os_dbg_printf(const char *fmt, ...);
void os_dbg_vprintf(const char *fmt, va_list args);
/*
* Allocating sprintf and vsprintf. These work like the regular C library
* sprintf and vsprintf funtions, but they allocate a return buffer that's
* big enough to hold the result, rather than formatting into a caller's
* buffer. This protects against buffer overruns and ensures that the
* result isn't truncated.
*
* On return, '*bufptr' is filled in with a pointer to a buffer allocated
* with osmalloc(). This buffer contains the formatted string result. The
* caller is responsible for freeing the buffer by calling osfree().
* *bufptr can be null on return if an error occurs.
*
* The return value is the number of bytes written to the allocated buffer,
* not including the null terminator. If an error occurs, the return value
* is -1 and *bufptr is undefined.
*
* Many modern C libraries provide equivalents of these, usually called
* asprintf() and vasprintf(), respectively.
*/
/* int os_asprintf(char **bufptr, const char *fmt, ...); */
int os_vasprintf(char **bufptr, const char *fmt, va_list ap);
/*
* Set the status line mode. There are three possible settings:
*
* 0 -> main text mode. In this mode, all subsequent text written with
* os_print() and os_printz() is to be displayed to the main text area.
* This is the normal mode that should be in effect initially. This mode
* stays in effect until an explicit call to os_status().
*
* 1 -> statusline mode. In this mode, text written with os_print() and
* os_printz() is written to the status line, which is usually rendered as
* a one-line area across the top of the terminal screen or application
* window. In statusline mode, leading newlines ('\n' characters) are to
* be ignored, and any newline following any other character must change
* the mode to 2, as though os_status(2) had been called.
*
* 2 -> suppress mode. In this mode, all text written with os_print() and
* os_printz() must simply be ignored, and not displayed at all. This mode
* stays in effect until an explicit call to os_status().
*/
void os_status(int stat);
/* get the status line mode */
int os_get_status();
/*
* Set the score value. This displays the given score and turn counts on
* the status line. In most cases, these values are displayed at the right
* edge of the status line, in the format "score/turns", but the format is
* up to the implementation to determine. In most cases, this can simply
* be implemented as follows:
*
*. void os_score(int score, int turncount)
*. {
*. char buf[40];
*. Common::sprintf_s(buf, "%d/%d", score, turncount);
*. os_strsc(buf);
*. }
*/
void os_score(int score, int turncount);
/* display a string in the score area in the status line */
void os_strsc(const char *p);
/* clear the screen */
void oscls(void);
/* redraw the screen */
void os_redraw(void);
/* flush any buffered display output */
void os_flush(void);
/*
* Update the display - process any pending drawing immediately. This
* only needs to be implemented for operating systems that use
* event-driven drawing based on window invalidations; the Windows and
* Macintosh GUI's both use this method for drawing window contents.
*
* The purpose of this routine is to refresh the display prior to a
* potentially long-running computation, to avoid the appearance that the
* application is frozen during the computation delay.
*
* Platforms that don't need to process events in the main thread in order
* to draw their window contents do not need to do anything here. In
* particular, text-mode implementations generally don't need to implement
* this routine.
*
* This routine doesn't absolutely need a non-empty implementation on any
* platform, but it will provide better visual feedback if implemented for
* those platforms that do use event-driven drawing.
*/
void os_update_display();
/* ------------------------------------------------------------------------ */
/*
* Set text attributes. Text subsequently displayed through os_print() and
* os_printz() are to be displayed with the given attributes.
*
* 'attr' is a (bitwise-OR'd) combination of OS_ATTR_xxx values. A value
* of zero indicates normal text, with no extra attributes.
*/
void os_set_text_attr(int attr);
/* attribute code: bold-face */
#define OS_ATTR_BOLD 0x0001
/* attribute code: italic */
#define OS_ATTR_ITALIC 0x0002
/*
* Abstract attribute codes. Each platform can choose a custom rendering
* for these by #defining them before this point, in the OS-specific header
* (osdos.h, osmac.h, etc). We provide *default* definitions in case the
* platform doesn't define these.
*
* For compatibility with past versions, we treat HILITE, EM, and BOLD as
* equivalent. Platforms that can display multiple kinds of text
* attributes (boldface and italic, say) should feel free to use more
* conventional HTML mappings, such as EM->italic and STRONG->bold.
*/
/*
* "Highlighted" text, as appropriate to the local platform. On most
* text-mode platforms, the only kind of rendering variation possible is a
* brighter or intensified color. If actual bold-face is available, that
* can be used instead. This is the attribute used for text enclosed in a
* TADS2 "\( \)" sequence.
*/
#ifndef OS_ATTR_HILITE
# define OS_ATTR_HILITE OS_ATTR_BOLD
#endif
/* HTML <em> attribute - by default, map this to bold-face */
#ifndef OS_ATTR_EM
# define OS_ATTR_EM OS_ATTR_BOLD
#endif
/* HTML <strong> attribute - by default, this has no effect */
#ifndef OS_ATTR_STRONG
# define OS_ATTR_STRONG 0
#endif
/* ------------------------------------------------------------------------ */
/*
* Colors.
*
* There are two ways of encoding a color. First, a specific color can be
* specified as an RGB (red-green-blue) value, with discreet levels for
* each component's intensity, ranging from 0 to 255. Second, a color can
* be "parameterized," which doesn't specify a color in absolute terms but
* rather specified one of a number of pre-defined *types* of colors;
* these pre-defined types can be chosen by the OS implementation, or, on
* some systems, selected by the user via a preferences mechanism.
*
* The os_color_t type encodes a color in 32 bits. The high-order 8 bits
* of a color value give the parameterized color identifier, or are set to
* zero to indicate an RGB color. An RGB color is encoded in the
* low-order 24 bits, via the following formula:
*
* (R << 16) + (G << 8) + B
*
* R specifies the intensity of the red component of the color, G green,
* and B blue. Each of R, G, and B must be in the range 0-255.
*/
typedef unsigned long os_color_t;
/* encode an R, G, B triplet into an os_color_t value */
#define os_rgb_color(r, g, b) (((r) << 16) + ((g) << 8) + (b))
/*
* Determine if a color is given as an RGB value or as a parameterized
* color value. Returns true if the color is given as a parameterized
* color (one of the OS_COLOR_xxx values), false if it's given as an
* absolute RGB value.
*/
#define os_color_is_param(color) (((color) & 0xFF000000) != 0)
/* get the red/green/blue components of an os_color_t value */
#define os_color_get_r(color) ((int)(((color) >> 16) & 0xFF))
#define os_color_get_g(color) ((int)(((color) >> 8) & 0xFF))
#define os_color_get_b(color) ((int)((color) & 0xFF))
/*
* Parameterized color codes. These are os_color_t values that indicate
* colors by type, rather than by absolute RGB values.
*/
/*
* "transparent" - applicable to backgrounds only, this specifies that the
* current screen background color should be used
*/
#define OS_COLOR_P_TRANSPARENT ((os_color_t)0x01000000)
/* "normal text" color (as set via user preferences, if applicable) */
#define OS_COLOR_P_TEXT ((os_color_t)0x02000000)
/* normal text background color (from user preferences) */
#define OS_COLOR_P_TEXTBG ((os_color_t)0x03000000)
/* "status line" text color (as set via user preferences, if applicable) */
#define OS_COLOR_P_STATUSLINE ((os_color_t)0x04000000)
/* status line background color (from user preferences) */
#define OS_COLOR_P_STATUSBG ((os_color_t)0x05000000)
/* input text color (as set via user preferences, if applicable) */
#define OS_COLOR_P_INPUT ((os_color_t)0x06000000)
/*
* Set the text foreground and background colors. This sets the text
* color for subsequent os_printf() and os_vprintf() calls.
*
* The background color can be OS_COLOR_TRANSPARENT, in which case the
* background color is "inherited" from the current screen background.
* Note that if the platform is capable of keeping old text for
* "scrollback," then the transparency should be a permanent attribute of
* the character - in other words, it should not be mapped to the current
* screen color in the scrollback buffer, because doing so would keep the
* current screen color even if the screen color changes in the future.
*
* Text color support is optional. If the platform doesn't support text
* colors, this can simply do nothing. If the platform supports text
* colors, but the requested color or attributes cannot be displayed, the
* implementation should use the best available approximation.
*/
void os_set_text_color(os_color_t fg, os_color_t bg);
/*
* Set the screen background color. This sets the text color for the
* background of the screen. If possible, this should immediately redraw
* the main text area with this background color. The color is given as an
* OS_COLOR_xxx value.
*
* If the platform is capable of redisplaying the existing text, then any
* existing text that was originally displayed with 'transparent'
* background color should be redisplayed with the new screen background
* color. In other words, the 'transparent' background color of previously
* drawn text should be a permanent attribute of the character - the color
* should not be mapped on display to the then-current background color,
* because doing so would lose the transparency and thus retain the old
* screen color on a screen color change.
*/
void os_set_screen_color(os_color_t color);
/* ------------------------------------------------------------------------ */
/*
* os_plain() - Use plain ascii mode for the display. If possible and
* necessary, turn off any text formatting effects, such as cursor
* positioning, highlighting, or coloring. If this routine is called,
* the terminal should be treated as a simple text stream; users might
* wish to use this mode for things like text-to-speech converters.
*
* Purely graphical implementations that cannot offer a textual mode
* (such as Mac OS or Windows) can ignore this setting.
*
* If this routine is to be called, it must be called BEFORE os_init().
* The implementation should set a flag so that os_init() will know to
* set up the terminal for plain text output.
*/
#ifndef os_plain
/*
* some platforms (e.g. Mac OS) define this to be a null macro, so don't
* define a prototype in those cases
*/
void os_plain(void);
#endif
/*
* Set the game title. The output layer calls this routine when a game
* sets its title (via an HTML <title> tag, for example). If it's
* convenient to do so, the OS layer can use this string to set a window
* caption, or whatever else makes sense on each system. Most
* character-mode implementations will provide an empty implementation,
* since there's not usually any standard way to show the current
* application title on a character-mode display.
*/
void os_set_title(const char *title);
/*
* Show the system-specific MORE prompt, and wait for the user to respond.
* Before returning, remove the MORE prompt from the screen.
*
* This routine is only used and only needs to be implemented when the OS
* layer takes responsibility for pagination; this will be the case on
* most systems that use proportionally-spaced (variable-pitch) fonts or
* variable-sized windows, since on such platforms the OS layer must do
* most of the formatting work, leaving the standard output layer unable
* to guess where pagination should occur.
*
* If the portable output formatter handles the MORE prompt, which is the
* usual case for character-mode or terminal-style implementations, this
* routine is not used and you don't need to provide an implementation.
* Note that HTML TADS provides an implementation of this routine, because
* the HTML renderer handles line breaking and thus must handle
* pagination.
*/
void os_more_prompt();
/*
* Interpreter Class Configuration.
*
* If this is a TEXT-ONLY interpreter: DO NOT define USE_HTML.
*
* If this is a MULTIMEDIA (HTML TADS) intepreter: #define USE_HTML
*
* (This really should be called something like OS_USE_HTML - the USE_ name
* is for historical reasons. This purpose of this macro is to configure
* the tads 2 VM-level output formatter's line breaking and MORE mode
* behavior. In HTML mode, the VM-level formatter knows that it's feeding
* its output to a page layout engine, so the VM-level output is just a
* text stream. In plain-text mode, the VM formatter *is* the page layout
* engine, so it needs to do all of the word wrapping and MORE prompting
* itself. The tads 3 output layer does NOT use this macro for its
* equivalent configuration, but instead has different .cpp files for the
* different modes, and you simply link in the one for the configuration
* you want.)
*/
/* #define USE_HTML */
/*
* Enter HTML mode. This is only used when the run-time is compiled
* with the USE_HTML flag defined. This call instructs the renderer
* that HTML sequences should be parsed; until this call is made, the
* renderer should not interpret output as HTML. Non-HTML
* implementations do not need to define this routine, since the
* run-time will not call it if USE_HTML is not defined.
*/
void os_start_html(void);
/* exit HTML mode */
void os_end_html(void);
/*
* Global variables with the height and width (in character cells - rows
* and columns) of the main text display area into which os_printf
* displays. The height and width are given in text lines and character
* columns, respectively. The portable code can use these values to
* format text for display via os_printf(); for example, the caller can
* use the width to determine where to put line breaks.
*
* These values are only needed for systems where os_printf() doesn't
* perform its own word-wrap formatting. On systems such as the Mac,
* where os_printf() performs word wrapping, these sizes aren't really
* important because the portable code doesn't need to perform any real
* formatting.
*
* These variables reflect the size of the "main text area," which is the
* area of the screen excluding the status line and any "banner" windows
* (as created with the os_banner_xxx() interfaces).
*
* The OS code must initialize these variables during start-up, and must
* adjust them whenever the display size is changed by user action or
* other external events (for example, if we're running inside a terminal
* window, and the user resizes the window, the OS code must recalculate
* the layout and adjust these accordingly).
*/
extern int G_os_pagelength;
extern int G_os_linewidth;
/*
* Global flag that tells the output formatter whether to count lines
* that it's displaying against the total on the screen so far. If this
* variable is true, lines are counted, and the screen is paused with a
* [More] message when it's full. When not in MORE mode, lines aren't
* counted. This variable should be set to false when displaying text
* that doesn't count against the current page, such as status line
* information.
*
* This flag should not be modified by OS code. Instead, the output
* formatter will set this flag according to its current state; the OS
* code can use this flag to determine whether or not to display a MORE
* prompt during os_printf()-type operations. Note that this flag is
* normally interesting to the OS code only when the OS code itself is
* handling the MORE prompt.
*/
extern int G_os_moremode;
/*
* Global buffer containing the name of the byte-code file (the "game
* file") loaded into the VM. This is used only where applicable, which
* generally means in TADS Interpreter builds. In other application
* builds, this is simply left empty. The application is responsible for
* setting this during start-up (or wherever else the byte-code filename
* becomes known or changes).
*/
extern char G_os_gamename[OSFNMAX];
/*
* Set non-stop mode. This tells the OS layer that it should disable any
* MORE prompting it would normally do.
*
* This routine is needed only when the OS layer handles MORE prompting; on
* character-mode platforms, where the prompting is handled in the portable
* console layer, this can be a dummy implementation.
*/
void os_nonstop_mode(int flag);
/*
* Update progress display with current info, if appropriate. This can
* be used to provide a status display during compilation. Most
* command-line implementations will just ignore this notification; this
* can be used for GUI compiler implementations to provide regular
* display updates during compilation to show the progress so far.
*/
/* void os_progress(const char *fname, unsigned long linenum); */
/*
* Set busy cursor. If 'flag' is true, provide a visual representation
* that the system or application is busy doing work. If 'flag' is
* false, remove any visual "busy" indication and show normal status.
*
* We provide a prototype here if your osxxx.h header file does not
* #define a macro for os_csr_busy. On many systems, this function has
* no effect at all, so the osxxx.h header file simply #define's it to
* do an empty macro.
*/
#ifndef os_csr_busy
void os_csr_busy(int flag);
#endif
/* ------------------------------------------------------------------------ */
/*
* User Input Routines
*/
/*
* Ask the user for a filename, using a system-dependent dialog or other
* mechanism. Returns one of the OS_AFE_xxx status codes (see below).
*
* prompt_type is the type of prompt to provide -- this is one of the
* OS_AFP_xxx codes (see below). The OS implementation doesn't need to
* pay any attention to this parameter, but it can be used if desired to
* determine the type of dialog to present if the system provides
* different types of dialogs for different types of operations.
*
* file_type is one of the OSFTxxx codes for system file type. The OS
* implementation is free to ignore this information, but can use it to
* filter the list of files displayed if desired; this can also be used
* to apply a default suffix on systems that use suffixes to indicate
* file type. If OSFTUNK is specified, it means that no filtering
* should be performed, and no default suffix should be applied.
*/
int os_askfile(const char *prompt, char *fname_buf, int fname_buf_len,
int prompt_type, os_filetype_t file_type);
/*
* os_askfile status codes
*/
/* success */
#define OS_AFE_SUCCESS 0
/*
* Generic failure - this is largely provided for compatibility with
* past versions, in which only zero and non-zero error codes were
* meaningful; since TRUE is defined as 1 on most platforms, we assume
* that 1 is probably the generic non-zero error code that most OS
* implementations have traditionally used. In addition, this can be
* used to indicate any other error for which there is no more specific
* error code.
*/
#define OS_AFE_FAILURE 1
/* user cancelled */
#define OS_AFE_CANCEL 2
/*
* os_askfile prompt types
*
* Important note: do not change these values when porting TADS. These
* values can be used by games, so they must be the same on all
* platforms.
*/
#define OS_AFP_OPEN 1 /* choose an existing file to open for reading */
#define OS_AFP_SAVE 2 /* choose a filename for saving to a file */
/*
* Read a string of input. Fills in the buffer with a null-terminated
* string containing a line of text read from the standard input. The
* returned string should NOT contain a trailing newline sequence. On
* success, returns 'buf'; on failure, including end of file, returns a
* null pointer.
*/
unsigned char *os_gets(unsigned char *buf, size_t bufl);
/*
* Read a string of input with an optional timeout. This behaves like
* os_gets(), in that it allows the user to edit a line of text (ideally
* using the same editing keys that os_gets() does), showing the line of
* text under construction during editing. This routine differs from
* os_gets() in that it returns if the given timeout interval expires
* before the user presses Return (or the local equivalent).
*
* If the user presses Return before the timeout expires, we store the
* command line in the given buffer, just as os_gets() would, and we return
* OS_EVT_LINE. We also update the display in the same manner that
* os_gets() would, by moving the cursor to a new line and scrolling the
* displayed text as needed.
*
* If a timeout occurs before the user presses Return, we store the command
* line so far in the given buffer, statically store the cursor position,
* insert mode, buffer text, and anything else relevant to the editing
* state, and we return OS_EVT_TIMEOUT.
*
* If the implementation does not support the timeout operation, this
* routine should simply return OS_EVT_NOTIMEOUT immediately when called;
* the routine should not allow the user to perform any editing if the
* timeout is not supported. Callers must use the ordinary os_gets()
* routine, which has no timeout capabilities, if the timeout is not
* supported.
*
* When we return OS_EVT_TIMEOUT, the caller is responsible for doing one
* of two things.
*
* The first possibility is that the caller performs some work that doesn't
* require any display operations (in other words, the caller doesn't
* invoke os_printf, os_getc, or anything else that would update the
* display), and then calls os_gets_timeout() again. In this case, we will
* use the editing state that we statically stored before we returned
* OS_EVT_TIMEOUT to continue editing where we left off. This allows the
* caller to perform some computation in the middle of user command editing
* without interrupting the user - the extra computation is transparent to
* the user, because we act as though we were still in the midst of the
* original editing.
*
* The second possibility is that the caller wants to update the display.
* In this case, the caller must call os_gets_cancel() BEFORE making any
* display changes. Then, the caller must do any post-input work of its
* own, such as updating the display mode (for example, closing HTML font
* tags that were opened at the start of the input). The caller is now
* free to do any display work it wants.
*
* If we have information stored from a previous call that was interrupted
* by a timeout, and os_gets_cancel(TRUE) was never called, we will resume
* editing where we left off when the cancelled call returned; this means
* that we'll restore the cursor position, insertion state, and anything
* else relevant. Note that if os_gets_cancel(FALSE) was called, we must
* re-display the command line under construction, but if os_gets_cancel()
* was never called, we will not have to make any changes to the display at
* all.
*
* Note that when resuming an interrupted editing session (interrupted via
* os_gets_cancel()), the caller must re-display the prompt prior to
* invoking this routine.
*
* Note that we can return OS_EVT_EOF in addition to the other codes
* mentioned above. OS_EVT_EOF indicates that an error occurred reading,
* which usually indicates that the application is being terminated or that
* some hardware error occurred reading the keyboard.
*
* If 'use_timeout' is false, the timeout should be ignored. Without a
* timeout, the function behaves the same as os_gets(), except that it will
* resume editing of a previously-interrupted command line if appropriate.
* (This difference is why the timeout is optional: a caller might not need
* a timeout, but might still want to resume a previous input that did time
* out, in which case the caller would invoke this routine with
* use_timeout==FALSE. The regular os_gets() would not satisfy this need,
* because it cannot resume an interrupted input.)
*
* Note that a zero timeout has the same meaning as for os_get_event(): if
* input is available IMMEDIATELY, return the input, otherwise return
* immediately with the OS_EVT_TIMEOUT result code.
*/
int os_gets_timeout(unsigned char *buf, size_t bufl,
unsigned long timeout_in_milliseconds, int use_timeout);
/*
* Cancel an interrupted editing session. This MUST be called if any
* output is to be displayed after a call to os_gets_timeout() returns
* OS_EVT_TIMEOUT.
*
* 'reset' indicates whether or not we will forget the input state saved
* by os_gets_timeout() when it last returned. If 'reset' is true, we'll
* clear the input state, so that the next call to os_gets_timeout() will
* start with an empty input buffer. If 'reset' is false, we will retain
* the previous input state, if any; this means that the next call to
* os_gets_timeout() will re-display the same input buffer that was under
* construction when it last returned.
*
* This routine need not be called if os_gets_timeout() is to be called
* again with no other output operations between the previous
* os_gets_timeout() call and the next one.
*
* Note that this routine needs only a trivial implementation when
* os_gets_timeout() is not supported (i.e., the function always returns
* OS_EVT_NOTIMEOUT).
*/
void os_gets_cancel(int reset);
/*
* Read a character from the keyboard. For extended keystrokes, this
* function returns zero, and then returns the CMD_xxx code for the
* extended keystroke on the next call. For example, if the user presses
* the up-arrow key, the first call to os_getc() should return 0, and the
* next call should return CMD_UP. Refer to the CMD_xxx codes below.
*
* os_getc() should return a high-level, translated command code for
* command editing. This means that, where a functional interpretation of
* a key and the raw key-cap interpretation both exist as CMD_xxx codes,
* the functional interpretation should be returned. For example, on Unix,
* Ctrl-E is conventionally used in command editing to move to the end of
* the line, following Emacs key bindings. Hence, os_getc() should return
* CMD_END for this keystroke, rather than a single 0x05 character (ASCII
* Ctrl-E), because CMD_END is the high-level command code for the
* operation.
*
* The translation ability of this function allows for system-dependent key
* mappings to functional meanings.
*/
int os_getc(void);
/*
* Read a character from the keyboard, following the same protocol as
* os_getc() for CMD_xxx codes (i.e., when an extended keystroke is
* encountered, os_getc_raw() returns zero, then returns the CMD_xxx code
* on the subsequent call).
*
* This function differs from os_getc() in that this function returns the
* low-level, untranslated key code whenever possible. This means that,
* when a functional interpretation of a key and the raw key-cap
* interpretation both exist as CMD_xxx codes, this function returns the
* key-cap interpretation. For the Unix Ctrl-E example in the comments
* describing os_getc() above, this function should return 5 (the ASCII
* code for Ctrl-E), because the ASCII control character interpretation is
* the low-level key code.
*
* This function should return all control keys using their ASCII control
* codes, whenever possible. Similarly, this function should return ASCII
* 27 for the Escape key, if possible.
*
* For keys for which there is no portable ASCII representation, this
* should return the CMD_xxx sequence. So, this function acts exactly the
* same as os_getc() for arrow keys, function keys, and other special keys
* that have no ASCII representation. This function returns a
* non-translated version ONLY when an ASCII representation exists - in
* practice, this means that this function and os_getc() vary only for CTRL
* keys and Escape.
*/
int os_getc_raw(void);
/* wait for a character to become available from the keyboard */
void os_waitc(void);
/*
* Constants for os_getc() when returning commands. When used for
* command line editing, special keys (arrows, END, etc.) should cause
* os_getc() to return 0, and return the appropriate CMD_ value on the
* NEXT call. Hence, os_getc() must keep the appropriate information
* around statically for the next call when a command key is issued.
*
* The comments indicate which CMD_xxx codes are "translated" codes and
* which are "raw"; the difference is that, when a particular keystroke
* could be interpreted as two different CMD_xxx codes, one translated
* and the other raw, os_getc() should always return the translated
* version of the key, and os_getc_raw() should return the raw version.
*/
#define CMD_UP 1 /* move up/up arrow (translated) */
#define CMD_DOWN 2 /* move down/down arrow (translated) */
#define CMD_RIGHT 3 /* move right/right arrow (translated) */
#define CMD_LEFT 4 /* move left/left arrow (translated) */
#define CMD_END 5 /* move cursor to end of line (translated) */
#define CMD_HOME 6 /* move cursor to start of line (translated) */
#define CMD_DEOL 7 /* delete to end of line (translated) */
#define CMD_KILL 8 /* delete entire line (translated) */
#define CMD_DEL 9 /* delete current character (translated) */
#define CMD_SCR 10 /* toggle scrollback mode (translated) */
#define CMD_PGUP 11 /* page up (translated) */
#define CMD_PGDN 12 /* page down (translated) */
#define CMD_TOP 13 /* top of file (translated) */
#define CMD_BOT 14 /* bottom of file (translated) */
#define CMD_F1 15 /* function key F1 (raw) */
#define CMD_F2 16 /* function key F2 (raw) */
#define CMD_F3 17 /* function key F3 (raw) */
#define CMD_F4 18 /* function key F4 (raw) */
#define CMD_F5 19 /* function key F5 (raw) */
#define CMD_F6 20 /* function key F6 (raw) */
#define CMD_F7 21 /* function key F7 (raw) */
#define CMD_F8 22 /* function key F8 (raw) */
#define CMD_F9 23 /* function key F9 (raw) */
#define CMD_F10 24 /* function key F10 (raw) */
#define CMD_CHOME 25 /* control-home (raw) */
#define CMD_TAB 26 /* tab (translated) */
#define CMD_SF2 27 /* shift-F2 (raw) */
/* not used (obsolete) - 28 */
#define CMD_WORD_LEFT 29 /* word left (ctrl-left on dos) (translated) */
#define CMD_WORD_RIGHT 30 /* word right (ctrl-right on dos) (translated) */
#define CMD_WORDKILL 31 /* delete word right (translated) */
#define CMD_EOF 32 /* end-of-file (raw) */
#define CMD_BREAK 33 /* break (Ctrl-C or local equivalent) (translated) */
#define CMD_INS 34 /* insert key (raw) */
/*
* ALT-keys - add alphabetical code to CMD_ALT: ALT-A == CMD_ALT + 0,
* ALT-B == CMD_ALT + 1, ALT-C == CMD_ALT + 2, etc
*
* These keys are all raw (untranslated).
*/
#define CMD_ALT 128 /* start of ALT keys */
/* ------------------------------------------------------------------------ */
/*
* Event information structure for os_get_event. The appropriate union
* member should be filled in, depending on the type of event that
* occurs.
*/
union os_event_info_t
{
/*
* OS_EVT_KEY - this returns the one or two characters of the
* keystroke. If the key is an extended key, so that os_getc() would
* return a two-character sequence for the keystroke, the first
* character should be zero and the second the extended key code.
* Otherwise, the first character should simply be the ASCII key code.
*
* The key code here is the "raw" keycode, equivalent to the codes
* returned by os_getc_raw(). Note in particular that this means that
* CTRL and Escape keys are presented as one-byte ASCII control
* characters, not as two-byte CMD_xxx sequences.
*
* For multi-byte character sets (Shift-JIS, for example), note that
* os_get_event() must NOT return a complete two-byte character here.
* The two bytes here are exclusively used to represent special
* CMD_xxx keys (such as arrow keys and function keys). For a
* keystroke that is represented in a multi-byte character set using
* more than one byte, os_get_event() must return a series of events.
* Return an ordinary OS_EVT_KEY for the first byte of the sequence,
* putting the byte in key[0]; then, return the second byte as a
* separate OS_EVT_KEY as the next event; and so on for any additional
* bytes. This will allow callers that are not multibyte-aware to
* treat multi-byte characters as though they were sequences of
* one-byte characters.
*/
int key[2];
/*
* OS_EVT_HREF - this returns the text of the HREF as a
* null-terminated string.
*/
char href[256];
/* command ID (for OS_EVT_COMMAND) */
int cmd_id;
};
typedef union os_event_info_t os_event_info_t;
/*
* Event types for os_get_event
*/
/* invalid/no event */
#define OS_EVT_NONE 0x0000
/* OS_EVT_KEY - user typed a key on the keyboard */
#define OS_EVT_KEY 0x0001
/* OS_EVT_TIMEOUT - no event occurred before the timeout elapsed */
#define OS_EVT_TIMEOUT 0x0002
/*
* OS_EVT_HREF - user clicked on a <A HREF> link. This only applies to
* the HTML-enabled run-time.
*/
#define OS_EVT_HREF 0x0003
/*
* OS_EVT_NOTIMEOUT - caller requested a timeout, but timeout is not
* supported by this version of the run-time
*/
#define OS_EVT_NOTIMEOUT 0x0004
/*
* OS_EVT_EOF - an error occurred reading the event. This generally
* means that the application is quitting or we can no longer read from
* the keyboard or terminal.
*/
#define OS_EVT_EOF 0x0005
/*
* OS_EVT_LINE - user entered a line of text on the keyboard. This event
* is not returned from os_get_event(), but rather from os_gets_timeout().
*/
#define OS_EVT_LINE 0x0006
/*
* Get an input event. The event types are shown above. If use_timeout is
* false, this routine should simply wait until one of the events it
* recognizes occurs, then return the appropriate information on the event.
* If use_timeout is true, this routine should return OS_EVT_TIMEOUT after
* the given number of milliseconds elapses if no event occurs first.
*
* This function is not obligated to obey the timeout. If a timeout is
* specified and it is not possible to obey the timeout, the function
* should simply return OS_EVT_NOTIMEOUT. The trivial implementation thus
* checks for a timeout, returns an error if specified, and otherwise
* simply waits for the user to press a key.
*
* A timeout value of 0 does *not* mean that there's no timeout (i.e., it
* doesn't mean we should wait indefinitely) - that's specified by passing
* FALSE for use_timeout. A zero timeout also doesn't meant that the
* function should unconditionally return OS_EVT_TIMEOUT. Instead, a zero
* timeout specifically means that IF an event is available IMMEDIATELY,
* without blocking the thread, we should return that event; otherwise we
* should immediately return a timeout event.
*/
int os_get_event(unsigned long timeout_in_milliseconds, int use_timeout,
os_event_info_t *info);
/* ------------------------------------------------------------------------ */
/*
* Extended os_get_event() codes.
*
* THESE ARE NOT USED in the basic osifc implementation - these are only
* used if the interpreter supports the "extended" interface defined in
* osifcext.h.
*/
/*
* System menu command event. Some interpreters (such as HTML TADS for
* Windows) provide menu commands for common system-level game verbs -
* SAVE, RESTORE, UNDO, QUIT. By default, these commands are returned as
* literal command strings ("save", "restore", etc) via os_gets(), as
* though the user had typed the commands at the keyboard. The extended OS
* interface allows the program to receive these commands via
* os_get_event(). When a command is enabled for os_get_event() via the
* extended OS interface, and the player selects the command via a menu (or
* toolbar button, etc) during a call to os_get_event(), os_get_event()
* returns this event code, with the menu ID stored in the cmd_id field of
* the event structure.
*/
#define OS_EVT_COMMAND 0x0100
/* command IDs for OS_EVT_COMMAND */
#define OS_CMD_NONE 0x0000 /* invalid command ID, for internal use */
#define OS_CMD_SAVE 0x0001 /* save game */
#define OS_CMD_RESTORE 0x0002 /* restore game */
#define OS_CMD_UNDO 0x0003 /* undo last turn */
#define OS_CMD_QUIT 0x0004 /* quit game */
#define OS_CMD_CLOSE 0x0005 /* close the game window */
#define OS_CMD_HELP 0x0006 /* show game help */
/* highest command ID used in this version of the interface */
#define OS_CMD_LAST 0x0006
/* ------------------------------------------------------------------------ */
/*
* Ask for input through a dialog.
*
* 'prompt' is a text string to display as a prompting message. For
* graphical systems, this message should be displayed in the dialog;
* for text systems, this should be displayed on the terminal after a
* newline.
*
* 'standard_button_set' is one of the OS_INDLG_xxx values defined
* below, or zero. If this value is zero, no standard button set is to
* be used; the custom set of buttons defined in 'buttons' is to be used
* instead. If this value is non-zero, the appropriate set of standard
* buttons, with labels translated to the local language if possible, is
* to be used.
*
* 'buttons' is an array of strings to use as button labels.
* 'button_count' gives the number of entries in the 'buttons' array.
* 'buttons' and 'button_count' are ignored if 'standard_button_set' is
* non-zero, since a standard set of buttons is used instead. If
* 'buttons' and 'button_count' are to be used, each entry contains the
* label of a button to show.
*/
/*
* An ampersand ('&') character in a label string indicates that the
* next character after the '&' is to be used as the short-cut key for
* the button, if supported. The '&' should NOT be displayed in the
* string; instead, the character should be highlighted according to
* local system conventions. On Windows, for example, the short-cut
* character should be shown underlined; on a text display, the response
* might be shown with the short-cut character enclosed in parentheses.
* If there is no local convention for displaying a short-cut character,
* then the '&' should simply be removed from the displayed text.
*
* The short-cut key specified by each '&' character should be used in
* processing responses. If the user presses the key corresponding to a
* button's short-cut, the effect should be the same as if the user
* clicked the button with the mouse. If local system conventions don't
* allow for short-cut keys, any short-cut keys can be ignored.
*
* 'default_index' is the 1-based index of the button to use as the
* default. If this value is zero, there is no default response. If
* the user performs the appropriate system-specific action to select
* the default response for the dialog, this is the response that is to
* be selected. On Windows, for example, pressing the "Return" key
* should select this item.
*
* 'cancel_index' is the 1-based index of the button to use as the
* cancel response. If this value is zero, there is no cancel response.
* This is the response to be used if the user cancels the dialog using
* the appropriate system-specific action. On Windows, for example,
* pressing the "Escape" key should select this item.
*/
/*
* icon_id is one of the OS_INDLG_ICON_xxx values defined below. If
* possible, an appropriate icon should be displayed in the dialog.
* This can be ignored in text mode, and also in GUI mode if there is no
* appropriate system icon.
*
* The return value is the 1-based index of the response selected. If
* an error occurs, return 0.
*/
int os_input_dialog(int icon_id, const char *prompt, int standard_button_set,
const char **buttons, int button_count,
int default_index, int cancel_index);
/*
* Standard button set ID's
*/
/* OK */
#define OS_INDLG_OK 1
/* OK, Cancel */
#define OS_INDLG_OKCANCEL 2
/* Yes, No */
#define OS_INDLG_YESNO 3
/* Yes, No, Cancel */
#define OS_INDLG_YESNOCANCEL 4
/*
* Dialog icons
*/
/* no icon */
#define OS_INDLG_ICON_NONE 0
/* warning */
#define OS_INDLG_ICON_WARNING 1
/* information */
#define OS_INDLG_ICON_INFO 2
/* question */
#define OS_INDLG_ICON_QUESTION 3
/* error */
#define OS_INDLG_ICON_ERROR 4
/*
* OBSOLETE - Get filename from startup parameter, if possible; returns
* true and fills in the buffer with the parameter filename on success,
* false if no parameter file could be found.
*
* (This was used until TADS 2.2.5 for the benefit of the Mac interpreter,
* and interpreters on systems with similar desktop shells, to allow the
* user to launch the terp by double-clicking on a saved game file. The
* terp would read the launch parameters, discover that a saved game had
* been used to invoke it, and would then stash away the saved game info
* for later retrieval from this function. This functionality was replaced
* in 2.2.5 with a command-line parameter: the terp now uses the desktop
* launch data to synthesize a suitable argv[] vectro to pass to os0main()
* or os0main2(). This function should now simply be stubbed out - it
* should simply return FALSE.)
*/
int os_paramfile(char *buf);
/*
* Initialize. This should be called during program startup to
* initialize the OS layer and check OS-specific command-line arguments.
*
* If 'prompt' and 'buf' are non-null, and there are no arguments on the
* given command line, the OS code can use the prompt to ask the user to
* supply a filename, then store the filename in 'buf' and set up
* argc/argv to give a one-argument command string. (This mechanism for
* prompting for a filename is obsolescent, and is retained for
* compatibility with a small number of existing implementations only;
* new implementations should ignore this mechanism and leave the
* argc/argv values unchanged.)
*/
int os_init(int *argc, char *argv[], const char *prompt,
char *buf, int bufsiz);
/*
* Termination functions. There are three main termination functions,
* described individually below; here's a brief overview of the
* relationship among the functions. The important thing to realize is
* that these functions have completely independent purposes; they should
* never call one another, and they should never do any of the work that's
* intended for the others.
*
* os_uninit() is meant to undo the effects of os_init(). On many
* systems, os_init() has some global effect, such as setting the terminal
* to some special input or output mode. os_uninit's purpose is to undo
* these global effects, returning the terminal mode (and whatever else)
* to the conditions they were in at program startup. Portable callers
* are meant to call this routine at some point before terminating if they
* ever called os_init(). Note that this routine DOES NOT terminate the
* program - it should simply undo anything that os_init() did and return,
* to let the caller do any additional termination work of its own.
*
* os_expause() optionally pauses before termination, to allow the user to
* acknowledge any text the program displays just before exiting. This
* doesn't have to do anything at all, but it's useful on systems where
* program termination will do something drastic like close the window:
* without a pause, the user wouldn't have a chance to read any text the
* program displayed after the last interactive input, because the window
* would abruptly disappear moments after the text was displayed. For
* systems where termination doesn't have such drastic effects, there's no
* need to do anything in this routine. Because it's up to this routine
* whether or not to pause, this routine must display a prompt if it's
* going to pause for user input - the portable caller obviously can't do
* so, because the caller doesn't know if the routine is going to pause or
* not (so if the caller displayed a prompt assuming the routine would
* pause, the prompt would show up even on systems where there actually is
* no pause, which would be confusing). This routine DOES NOT terminate
* the program; it simply pauses if necessary to allow the user to
* acknowledge the last bit of text the program displayed, then returns to
* allow the caller to carry on with its own termination work.
*
* os_term() is meant to perform the same function as the C standard
* library routine exit(): this actually terminates the program, exiting
* to the operating system. This routine is not meant to return to its
* caller, because it's supposed to exit the program directly. For many
* systems, this routine can simply call exit(); the portable code calls
* this routine instead of calling exit() directly, because some systems
* have their own OS-specific way of terminating rather than using exit().
* This routine MUST NOT undo the effects of os_init(), because callers
* might not have ever called os_init(); callers are required to call
* os_uninit() if they ever called os_init(), before calling os_term(), so
* this routine can simply assume that any global modes set by os_init()
* have already been undone by the time this is called.
*/
/*
* Uninitialize. This is called prior to progam termination to reverse
* the effect of any changes made in os_init(). For example, if
* os_init() put the terminal in raw mode, this should restore the
* previous terminal mode. This routine should not terminate the
* program (so don't call exit() here) - the caller might have more
* processing to perform after this routine returns.
*/
void os_uninit(void);
/*
* Pause prior to exit, if desired. This is meant to be called by
* portable code just before the program is to be terminated; it can be
* implemented to show a prompt and wait for user acknowledgment before
* proceeding. This is useful for implementations that are using
* something like a character-mode terminal window running on a graphical
* operating system: this gives the implementation a chance to pause
* before exiting, so that the window doesn't just disappear
* unceremoniously.
*
* This is allowed to do nothing at all. For regular character-mode
* systems, this routine usually doesn't do anything, because when the
* program exits, the terminal will simply return to the OS command
* prompt; none of the text displayed just before the program exited will
* be lost, so there's no need for any interactive pause. Likewise, for
* graphical systems where the window will remain open, even after the
* program exits, until the user explicitly closes the window, there's no
* need to do anything here.
*
* If this is implemented to pause, then this routine MUST show some kind
* of prompt to let the user know we're waiting. In the simple case of a
* text-mode terminal window on a graphical OS, this should simply print
* out some prompt text ("Press a key to exit...") and then wait for the
* user to acknowledge the prompt (by pressing a key, for example). For
* graphical systems, the prompt could be placed in the window's title
* bar, or status-bar, or wherever is appropriate for the OS.
*/
void os_expause(void);
/*
* Terminate. This should exit the program with the given exit status.
* In general, this should be equivalent to the standard C library
* exit() function, but we define this interface to allow the OS code to
* do any necessary pre-termination cleanup.
*/
void os_term(int status);
/*
* Install/uninstall the break handler. If possible, the OS code should
* set (if 'install' is true) or clear (if 'install' is false) a signal
* handler for keyboard break signals (control-C, etc, depending on
* local convention). The OS code should set its own handler routine,
* which should note that a break occurred with an internal flag; the
* portable code uses os_break() from time to time to poll this flag.
*/
void os_instbrk(int install);
/*
* Check for user break ("control-C", etc) - returns true if a break is
* pending, false if not. If this returns true, it should "consume" the
* pending break (probably by simply clearing the OS code's internal
* break-pending flag).
*/
bool os_break(void);
/*
* Sleep for a given interval. This should simply pause for the given
* number of milliseconds, then return. On multi-tasking systems, this
* should use a system API to suspend the current process for the desired
* delay; on single-tasking systems, this can simply sit in a wait loop
* until the desired interval has elapsed.
*/
void os_sleep_ms(long delay_in_milliseconds);
/*
* Yield CPU; returns TRUE if user requested an interrupt (a "control-C"
* type of operation to abort the entire program), FALSE to continue.
* Portable code should call this routine from time to time during lengthy
* computations that don't involve any UI operations; if practical, this
* routine should be invoked roughly every 10 to 100 milliseconds.
*
* The purpose of this routine is to support "cooperative multitasking"
* systems, such as pre-X MacOS, where it's necessary for each running
* program to call the operating system explicitly in order to yield the
* CPU from time to time to other concurrently running programs. On
* cooperative multitasking systems, a program can only lose control of
* the CPU by making specific system calls, usually related to GUI events;
* a program can never lose control of the CPU asynchronously. So, a
* program that performs lengthy computations without any UI interaction
* can cause the rest of the system to freeze up until the computations
* are finished; but if a compute-intensive program explicitly yields the
* CPU from time to time, it allows other programs to remain responsive.
* Yielding the CPU at least every 100 milliseconds or so will generally
* allow the UI to remain responsive; yielding more frequently than every
* 10 ms or so will probably start adding noticeable overhead.
*
* On single-tasking systems (such as MS-DOS), there's only one program
* running at a time, so there's no need to yield the CPU; on virtually
* every modern system, the OS automatically schedules CPU time without
* the running programs having any say in the matter, so again there's no
* need for a program to yield the CPU. For systems where this routine
* isn't needed, the system header should simply #define os_yield to
* something like "((void)0)" - this will allow the compiler to completely
* ignore calls to this routine for systems where they aren't needed.
*
* Note that this routine is NOT meant to provide scheduling hinting to
* modern systems with true multitasking, so a trivial implementation is
* fine for any modern system.
*/
#ifndef os_yield
int os_yield(void);
#endif
/*
* Set the default saved-game extension. This routine will NOT be called
* when we're using the standard saved game extension; this routine will be
* invoked only if we're running as a stand-alone game, and the game author
* specified a non-standard saved-game extension when creating the
* stand-alone game.
*
* This routine is not required if the system does not use the standard,
* semi-portable os0.c implementation. Even if the system uses the
* standard os0.c implementation, it can provide an empty routine here if
* the system code doesn't need to do anything special with this
* information.
*
* The extension is specified as a null-terminated string. The extension
* does NOT include the leading period.
*/
void os_set_save_ext(const char *ext);
/*
* Get the saved game extension previously set with os_set_save_ext().
* Returns null if no custom extension has been set.
*/
const char *os_get_save_ext();
/* ------------------------------------------------------------------------*/
/*
* Translate a character from the HTML 4 Unicode character set to the
* current character set used for display. Takes an HTML 4 character
* code and returns the appropriate local character code.
*
* The result buffer should be filled in with a null-terminated string
* that should be used to represent the character. Multi-character
* results are possible, which may be useful for certain approximations
* (such as using "(c)" for the copyright symbol).
*
* Note that we only define this prototype if this symbol isn't already
* defined as a macro, which may be the case on some platforms.
* Alternatively, if the function is already defined (for example, as an
* inline function), the defining code can define OS_XLAT_HTML4_DEFINED,
* in which case we'll also omit this prototype.
*
* Important: this routine provides the *default* mapping that is used
* when no external character mapping file is present, and for any named
* entities not defined in the mapping file. Any entities in the
* mapping file, if used, will override this routine.
*
* A trivial implementation of this routine (that simply returns a
* one-character result consisting of the original input character,
* truncated to eight bits if necessary) can be used if you want to
* require an external mapping file to be used for any game that
* includes HTML character entities. The DOS version implements this
* routine so that games will still look reasonable when played with no
* mapping file present, but other systems are not required to do this.
*/
#ifndef os_xlat_html4
# ifndef OS_XLAT_HTML4_DEFINED
void os_xlat_html4(unsigned int html4_char,
char *result, size_t result_buf_len);
# endif
#endif
/*
* Generate a filename for a character-set mapping file. This function
* should determine the current native character set in use, if
* possible, then generate a filename, according to system-specific
* conventions, that we should attempt to load to get a mapping between
* the current native character set and the internal character set
* identified by 'internal_id'.
*
* The internal character set ID is a string of up to 4 characters.
*
* On DOS, the native character set is a DOS code page. DOS code pages
* are identified by 3- or 4-digit identifiers; for example, code page
* 437 is the default US ASCII DOS code page. We generate the
* character-set mapping filename by appending the internal character
* set identifier to the DOS code page number, then appending ".TCP" to
* the result. So, to map between ISO Latin-1 (internal ID = "La1") and
* DOS code page 437, we would generate the filename "437La1.TCP".
*
* Note that this function should do only two things. First, determine
* the current native character set that's in use. Second, generate a
* filename based on the current native code page and the internal ID.
* This function is NOT responsible for figuring out the mapping or
* anything like that -- it's simply where we generate the correct
* filename based on local convention.
*
* 'filename' is a buffer of at least OSFNMAX characters.
*
* 'argv0' is the executable filename from the original command line.
* This parameter is provided so that the system code can look for
* mapping files in the original TADS executables directory, if desired.
*/
void os_gen_charmap_filename(char *filename, char *internal_id, char *argv0);
/*
* Receive notification that a character mapping file has been loaded.
* The caller doesn't require this routine to do anything at all; this
* is purely for the system-dependent code's use so that it can take
* care of any initialization that it must do after the caller has
* loaded a charater mapping file. 'id' is the character set ID, and
* 'ldesc' is the display name of the character set. 'sysinfo' is the
* extra system information string that is stored in the mapping file;
* the interpretation of this information is up to this routine.
*
* For reference, the Windows version uses the extra information as a
* code page identifier, and chooses its default font character set to
* match the code page. On DOS, the run-time requires the player to
* activate an appropriate code page using a DOS command (MODE CON CP
* SELECT) prior to starting the run-time, so this routine doesn't do
* anything at all on DOS.
*/
void os_advise_load_charmap(const char *id, const char *ldesc, const char *sysinfo);
/*
* Generate the name of the character set mapping table for Unicode
* characters to and from the given local character set. Fills in the
* buffer with the implementation-dependent name of the desired
* character set map. See below for the character set ID codes.
*
* For example, on Windows, the implementation would obtain the
* appropriate active code page (which is simply a Windows character set
* identifier number) from the operating system, and build the name of
* the Unicode mapping file for that code page, such as "CP1252". On
* Macintosh, the implementation would look up the current script system
* and return the name of the Unicode mapping for that script system,
* such as "ROMAN" or "CENTEURO".
*
* If it is not possible to determine the specific character set that is
* in use, this function should return "asc7dflt" (ASCII 7-bit default)
* as the character set identifier on an ASCII system, or an appropriate
* base character set name on a non-ASCII system. "asc7dflt" is the
* generic character set mapping for plain ASCII characters.
*
* The given buffer must be at least 32 bytes long; the implementation
* must limit the result it stores to 32 bytes. (We use a fixed-size
* buffer in this interface for simplicity, and because there seems no
* need for greater flexibility in the interface; a character set name
* doesn't carry very much information so shouldn't need to be very
* long. Note that this function doesn't generate a filename, but
* simply a mapping name; in practice, a map name will be used to
* construct a mapping file name.)
*
* Because this function obtains the Unicode mapping name, there is no
* need to specify the internal character set to be used: the internal
* character set is Unicode.
*/
/*
* Implementation note: when porting this routine, the convention that
* you use to name your mapping files is up to you. You should simply
* choose a convention for this implementation, and then use the same
* convention for packaging the mapping files for your OS release. In
* most cases, the best convention is to use the names that the Unicode
* consortium uses in their published cross-mapping listings, since
* these listings can be used as the basis of the mapping files that you
* include with your release. For example, on Windows, the convention
* is to use the code page number to construct the map name, as in
* CP1252 or CP1250.
*/
void os_get_charmap(char *mapname, int charmap_id);
/*
* Character map for the display (i.e., for the user interface). This
* is the character set which is used for input read from the keyboard,
* and for output displayed on the monitor or terminal.
*/
#define OS_CHARMAP_DISPLAY 1
/*
* Character map for mapping filename strings. This should identify the
* character set currently in use on the local system for filenames
* (i.e., for strings identifying objects in the local file system),
* providing a suitable name for use in opening a mapping file.
*
* On many platforms, the entire system uses only one character set at
* the OS level, so the file system character set is the same as the
* display character set. Some systems define a particular character
* set for file system use, though, because different users might be
* running applications on terminals that display different character
* sets.
*/
#define OS_CHARMAP_FILENAME 2
/*
* Default character map for file contents. On most systems, this will
* be the same as display. On some systems, it won't be possible to
* know in general what character set files use; in fact, this isn't
* possible anywhere, since a file might have been copied without
* translation from a different type of computer using a different
* character set. So, this isn't meant to provide a reliable choice of
* character set for any arbitrary file; it's simply meant to be a good
* guess that most files on this system are likely to use.
*/
#define OS_CHARMAP_FILECONTENTS 3
/*
* Default character map for the command line. This is the maping we use
* to interpret command line arguments passed to our main() or equivalent.
* On most systems, this will be the same as the display character set.
*/
#define OS_CHARMAP_CMDLINE 4
/* ------------------------------------------------------------------------ */
/*
* Get system information. 'code' is a SYSINFO_xxx code, which
* specifies what type of information to get. The 'param' argument's
* meaning depends on which code is selected. 'result' is a pointer to
* an integer that is to be filled in with the result value. If the
* code is not known, this function should return FALSE. If the code is
* known, the function should fill in *result and return TRUE.
*/
int os_get_sysinfo(int code, void *param, long *result);
/* determine if systemInfo is supported - os_get_sysinfo never gets this */
#define SYSINFO_SYSINFO 1
/* get interpreter version number - os_get_sysinfo never gets this */
#define SYSINFO_VERSION 2
/* get operating system name - os_get_sysinfo never gets this */
#define SYSINFO_OS_NAME 3
/*
* Can the system process HTML directives? returns 1 if so, 0 if not.
* Note that if this returns false, then all of the codes below from
* JPEG to LINKS are implicitly false as well, since TADS can only use
* images, sounds, and links through HTML.
*/
#define SYSINFO_HTML 4
/* can the system display JPEG's? 1 if yes, 0 if no */
#define SYSINFO_JPEG 5
/* can the system display PNG's? 1 if yes, 0 if no */
#define SYSINFO_PNG 6
/* can the system play WAV's? 1 if yes, 0 if no */
#define SYSINFO_WAV 7
/* can the system play MIDI's? 1 if yes, 0 if no */
#define SYSINFO_MIDI 8
/* can the system play MIDI and WAV's simultaneously? yes=1, no=0 */
#define SYSINFO_WAV_MIDI_OVL 9
/* can the system play multiple WAV's simultaneously? yes=1, no=0 */
#define SYSINFO_WAV_OVL 10
/*
* GENERAL NOTES ON PREFERENCE SETTINGS:
*
* Several of the selectors below refer to the preference settings. We're
* talking about user-settable options to control various aspects of the
* interpreter. The conventional GUI for this kind of thing is a dialog
* box reachable through a menu command named something like "Options" or
* "Preferences". A couple of general notes about these:
*
* 1. The entire existence of a preferences mechanism is optional -
* interpreter writers aren't required to implement anything along these
* lines. In some cases the local platforms might not have any suitable
* conventions for a preferences UI (e.g., character-mode console
* applications), and in other cases the terp developer might just want to
* omit a prefs mechanism because of the work involved to implement it, or
* to keep the UI simpler.
*
* 2. If a given SYSINFO_PREF_xxx selector refers to a preference item
* that's not implemented in the local interpreter, the terp should simply
* return a suitable default result. For example, if the interpreter
* doesn't have a preference item to allow the user to turn sounds off, the
* selector SYSINFO_PREF_SOUNDS should return 1 to indicate that the user
* has not in fact turned off sounds (because there's no way to do so).
*
* 3. The various SYSINFO_PREF_xxx selectors are purely queries - they're
* NOT a mechanism for enforcing the preferences. For example, if the
* interpreter provides a "Sounds On/Off" option, it's up to the terp to
* enforce it the Off setting by ignoring any sound playback requests. The
* game isn't under any obligation to query any of the preferences or to
* alter its behavior based on their settings - you should expect that the
* game will go on trying to play sounds even when "Sounds Off" is selected
* in the preferences. The purpose of these SYSINFO selectors is to let
* the game determine the current presentation status, but *only if it
* cares*. For example, the game might determine whether or not sounds are
* actually being heard just before playing a sound effect that's important
* to the progress of the game, so that it can provide a visual alternative
* if the effect won't be heard.
*/
/*
* Get image preference setting - 1 = images can be displayed, 0 = images
* are not being displayed because the user turned off images in the
* preferences. This is, of course, irrelevant if images can't be
* displayed at all.
*
* See the general notes on preferences queries above.
*/
#define SYSINFO_PREF_IMAGES 11
/*
* Get digitized sound effect (WAV) preference setting - 1 = sounds can be
* played, 0 = sounds are not being played because the user turned off
* sounds in the preferences.
*
* See the general notes on preferences queries above.
*/
#define SYSINFO_PREF_SOUNDS 12
/*
* Get music (MIDI) preference setting - 1 = music can be played, 0 = music
* is not being played because the user turned off music in the
* preferences.
*
* See the general notes on preferences queries above.
*/
#define SYSINFO_PREF_MUSIC 13
/*
* Get link display preference setting - 0 = links are not being displayed
* because the user set a preference item that suppresses all links (which
* doesn't actually hide them, but merely displays them and otherwise
* treats them as ordinary text). 1 = links are to be displayed normally.
* 2 = links can be displayed temporarily by the user by pressing a key or
* some similar action, but aren't being displayed at all times.
*
* See the general note on preferences queries above.
*/
#define SYSINFO_PREF_LINKS 14
/* can the system play MPEG sounds of any kind? */
#define SYSINFO_MPEG 15
/* can the system play MPEG audio 2.0 layer I/II/III sounds? */
#define SYSINFO_MPEG1 16
#define SYSINFO_MPEG2 17
#define SYSINFO_MPEG3 18
/*
* is the system *currently* in HTML mode? os_get_sysinfo never gets
* this code, since the portable output layer keeps track of this
*/
#define SYSINFO_HTML_MODE 19
/*
* Does the system allow following external URL links of the various
* types? These return true if the system is capable of following these
* types of hypertext links, false if not. Note that, if the system is
* capable of following these links, these should return true regardless
* of any current mode settings; in particular, these should not be
* sensitive to the current HTML mode or the current link display mode,
* since the question is not whether a link now displayed can be
* followed by the user, but rather whether the system has the
* capability to follow these types of links at all.
*/
#define SYSINFO_LINKS_HTTP 20
#define SYSINFO_LINKS_FTP 21
#define SYSINFO_LINKS_NEWS 22
#define SYSINFO_LINKS_MAILTO 23
#define SYSINFO_LINKS_TELNET 24
/* is PNG transparency supported? */
#define SYSINFO_PNG_TRANS 25
/* is PNG alpha blending supported? */
#define SYSINFO_PNG_ALPHA 26
/* is the Ogg Vorbis audio format supported? */
#define SYSINFO_OGG 27
/* can the system display MNG's? */
#define SYSINFO_MNG 28
/* can the system display MNG's with transparency? */
#define SYSINFO_MNG_TRANS 29
/* can the system display MNG's with alpha blending? */
#define SYSINFO_MNG_ALPHA 30
/* can we display highlighted text in its own appearance? */
#define SYSINFO_TEXT_HILITE 31
/*
* Can we display text colors? This returns a SYSINFO_TXC_xxx code
* indicating the level of color support.
*
* The os_xxx interfaces don't presently support anything beyond the ANSI
* colors; however, HTML-enabled interpreters generally support full RGB
* colors, so we call this out as a separate level.
*/
#define SYSINFO_TEXT_COLORS 32
/* no text color support */
#define SYSINFO_TXC_NONE 0
/* parameterized color names only (OS_COLOR_P_TEXT, etc) */
#define SYSINFO_TXC_PARAM 1
/*
* we support only the basic ANSI colors, foreground control only (white,
* black, blue, red, green, yellow, cyan, magenta)
*/
#define SYSINFO_TXC_ANSI_FG 2
/* ANSI colors, foreground and background */
#define SYSINFO_TXC_ANSI_FGBG 3
/* full RGB support */
#define SYSINFO_TXC_RGB 4
/* are the os_banner_xxx() interfaces supported? */
#define SYSINFO_BANNERS 33
/* Interpreter Class - this returns one of the SYSINFO_ICLASS_xxx codes */
#define SYSINFO_INTERP_CLASS 34
/*
* Interpreter class: Character-mode Text-Only. Interpreters of this class
* use a single, fixed-pitch font to display all text, and use the
* text-only HTML subset, and cannot display graphics.
*/
#define SYSINFO_ICLASS_TEXT 1
/*
* Interpreter class: Text-Only GUI. Interpreters of this class are
* traditional text-only interpreters running on graphical operating
* systems. These interpreters might use multiple fonts (for example, they
* might display highlighted text in boldface), and might use
* proportionally-spaced text for some windows. These interpreters support
* the text-only HTML subset, and cannot display graphics.
*
* Text-only GUI interpreters act essentially the same as character-mode
* text-only interpreters, from the perspective of the client program.
*/
#define SYSINFO_ICLASS_TEXTGUI 2
/*
* Interpreter class: HTML. Interpreters of this class can display
* graphics and sounds, can display multiple fonts and font sizes, can use
* proportional fonts, and support the full HTML TADS markup language for
* formatting.
*/
#define SYSINFO_ICLASS_HTML 3
/*
* Audio fade information.
*
* SYSINFO_AUDIO_FADE: basic fade-in and fade-out support. Interpreters
* that don't support audio fade at all should return 0. Interpreters that
* support fades should return a bitwise OR'd combination of
* SYSINFO_AUDIOFADE_xxx flags below indicating which formats can be used
* with fades.
*
* SYSINFO_AUDIO_CROSSFADE: cross-fades are supported (i.e., simultaneous
* play of overlapping tracks, one fading out while the other fades in).
* If cross-fades aren't supported, return 0. If they're supported, return
* a combination of SYSINFO_AUDIOFADE_xxx flags indicating which formats
* can be used with cross-fades.
*/
#define SYSINFO_AUDIO_FADE 35
#define SYSINFO_AUDIO_CROSSFADE 36
/*
* Specific audio fading features. These are bit flags that can be
* combined to indicate the fading capabilities of the interpreter.
*/
#define SYSINFO_AUDIOFADE_MPEG 0x0001 /* supported for MPEG audio */
#define SYSINFO_AUDIOFADE_OGG 0x0002 /* supported for Ogg Vorbis */
#define SYSINFO_AUDIOFADE_WAV 0x0004 /* supported for WAV */
#define SYSINFO_AUDIOFADE_MIDI 0x0008 /* supported for MIDI */
/* ------------------------------------------------------------------------ */
/*
* Integer division operators. For any compiler that follows ANSI C
* rules, no definitions are required for these routine, since the
* standard definitions below will work properly. However, if your
* compiler does not follow ANSI standards with respect to integer
* division of negative numbers, you must provide implementations of
* these routines that produce the correct results.
*
* Division must "truncate towards zero," which means that any
* fractional part is dropped from the result. If the result is
* positive, the result must be the largest integer less than the
* algebraic result: 11/3 yields 3. If the result is negative, the
* result must be the smallest integer less than the result: (-11)/3
* yields -3.
*
* The remainder must obey the relationship (a/b)*b + a%b == a, for any
* integers a and b (b != 0).
*
* If your compiler does not obey the ANSI rules for the division
* operators, make the following changes in your osxxx.h file
*
* - define the symbol OS_NON_ANSI_DIVIDE in the osxxx.h file
*
* - either define your own macros for os_divide_long() and
* os_remainder_long(), or put actual prototypes for these functions
* into your osxxx.h file and write appropriate implementations of these
* functions in one of your osxxx.c or .cpp files.
*/
/* long os_divide_long(long a, long b); // returns (a/b) with ANSI rules */
/* long os_remainder_long(long a, long b); // returns (a%b) with ANSI rules */
/* standard definitions for any ANSI compiler */
#ifndef OS_NON_ANSI_DIVIDE
#define os_divide_long(a, b) ((a) / (b))
#define os_remainder_long(a, b) ((a) % (b))
#endif
int memicmp(const char *s1, const char *s2, int len);
} // End of namespace TADS
} // End of namespace Glk
#endif