/* 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 2 * 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ /* 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; /* ------------------------------------------------------------------------ */ /* * definitions. * * os_time() should act like Unix time(), returning the number of seconds * elapsed since January 1, 1970 at midnight UTC. * * The original Unix 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 X 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 Mac OS (OS X and later), 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 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]; *. sprintf(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 attribute - by default, map this to bold-face */ #ifndef OS_ATTR_EM # define OS_ATTR_EM OS_ATTR_BOLD #endif /* HTML 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 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