STANDARD FOR NOSTUB COMMENT AND OTHER EXPORTED STATIC DATA EXTENSIONS Specification Version 1.01 This is the second version valid as a standard. Copyright (C) 2002-2004, Kevin Kofler. All rights reserved. Portions are the copyright of the authors of the specific proposals incorporated into this draft: Thibaut Barthélémy, Gregory Dietsche, Lionel Debroux. You are allowed to copy, modify and/or excerpt this document IF AND ONLY IF: A. you are copying this document VERBATIM, with NO modifications whatsoever OR B. 1. your modified version cannot be confused with this standard AND 2. your modified version does not try to set a new standard without the permission of the 4 authors of this document. DEFINITIONS: Through the rest of this document: * "shell" shall refer to any program (not necessarily a "program" as defined below!) for the TI-89/92+/Voyage 200 wanting to extract data from an extension header as defined by this standard * "program" shall refer to any assembly or compiled program for the TI-89/92+/Voyage 200 containing an extension header as defined by this standard * "should" is used for some recommendations of this standard. This does NOT mean that those recommendations are optional. If you want to fully conform to the standard, you MUST follow all those recommendations. A shell or program not implementing "should" recommendations is only partially conforming or not conforming at all. I. Basic Format The following data should be right at the beginning of the program: move.l (a7),(a7) ;intentionally stupid instruction bra.w end_of_extension_data ;Do NOT jump directly to _main here in tipatch.lib - it might require ;a long jump, and only a bra.w is allowed here. ;However, do NOT use this to locate end_of_extension_data - a program ;IS entitled to jump directly to _main here if a bra.w is enough. dc.w $2e76, $5c7b, $4e74, $4e72, $4afc, 0 ;The first 5 words are all illegal instructions on the ;Motorola 68000, the last 0 is to allow shells to use ;longword checks for everything. ; See following paragraphs for a detailed description of that data: dc.l standard_revision dc.w num_extensions dc.w type_of_extension_1 dc.w offset_of_extension_1 dc.w type_of_extension_2 dc.w offset_of_extension_2 ;... end_of_extension_data: II. Identification of extension data by a shell A shell MUST do the following checks before concluding that a program has extension data: * check that the first instruction is "move.l (a7),(a7)" * check that the second instruction is a "bra.w" * check that the following bytes are "dc.w $2e76, $5c7b, $4e74, $4e72, $4afc, 0" Sample code: unsigned long *fptr=/* pointer to the beginning of the program */, *sigptr; unsigned short *extptr; if (*fptr!=0x2e976000UL) { sigptr=(short *)fptr+3; // sigptr is 6 bytes beyond fptr if ((*(sigptr++)!=0x2e765c7bUL) && (*(sigptr++)!=0x4e744e72UL) && (*(sigptr++)!=0x4afc0000UL)) { if (*(sigptr++)>0x01000000UL) // standard_revision > 1.0.0.0 printf("WARNING: Program uses newer standard revision than shell."); extptr=sigptr; // start of the extensions (now points to num_extensions) // handle the extensions (for example, display the comment) } } III. Detailed description 1. standard_revision This is the revision of the standard which the program follows. While this standard is designed to be backwards- and forwards-compatible once it is out of draft stage, shell authors expressed desire to be able to check whether their shell is current enough to read all data extensions used for the program in question. This revision entry allows such checks. It is a numeric revision number as defined in section III.10. The revision for this version of the standard is 1.1.0.0 (0x01010000). Programs should define this to be the lowest possible release revision supporting all features they use. "Release revision" means that the revision needs to be AT LEAST 1.0.0.0 (0x01000000). Do NOT declare conformance to a draft revision. A revision of 0.3.0.0 (0x00030000) is NOT valid. 2. num_extensions This is the number of extensions effectively present. For example, 1 for comment only. It can be interpreted as signed or unsigned, but values below 1 or above 16384 are NOT ALLOWED. A shell should reject invalid values smoothly (i.e. not crash), but a program should not use them. 3. type_of_extension This has the following values: 0x0=comment (null-terminated string) 0x1=program name (null-terminated string) 0x2=program version (null-terminated string) 0x3=program version (structure of 4 unsigned chars, can be read as an unsigned long integer) 0x4=16×16 icon (ICON structure, in other words: a 16×16 black&white sprite) 0x5=16×16 grayscale icon (array of 2 ICON structures: dark plane first, light plane last) 0x6=crash protection or low stack condition incompatibility flags (unsigned long integer bitfield) 0x7=program author(s) (null-terminated string) 0x8-0x7fff=reserved for future versions of the standard 0x8000-0x80ff=reserved for unregistered extensions for shells by the TI-Chess Team 0x8100-0x81ff=reserved for unregistered extensions for shells by Thibaut Barthélémy 0x8200-0x82ff=reserved for unregistered extensions for the DB92 debugger 0x8300-0xffff=reserved for shells asking for a range for their unregistered extensions DO NOT just pick a range, ASK US for one 4. offset_of_extension This is the offset to the actual extension data FROM THE BEGINNING of the CONTENTS of the program (i.e. byte 0 is the first byte AFTER the 2 file size bytes, which are NOT counted), as an UNSIGNED short integer (because it might be >32 KB). The extension data might be in any format which can be read with an offset alone, for example: * a null-terminated string * a structure such as BITMAP * a fixed-length number * variable length stuff, but this must in most cases be immediately prefixed by its length (since you CANNOT store the length in the extension header) The expected format is of course specified by the shell (or for standard-defined extensions, by this standard), not by the program. 5. Ordering of Extensions Extensions should be ordered in ASCENDING numerical order of their type. The type should be taken as an UNSIGNED short integer, so standard-defined extensions should come BEFORE shell-specific ones. If this order is violated by a program, a shell might either ignore the problem and treat the extension as valid (preferred, but programs must NOT rely on this), or simply ignore the misordered extensions. It must NOT, however, crash when confronted with misordered extensions. 6. Multiple Extensions with the same Type ID This is allowed ONLY when it makes sense for the specific type of extensions. All the current standard-defined extensions (comments, program names, ICON structure icons and program versions) MUST be unique. However, it is of course valid to specify the version both as a string and as a number, and/or to specify both a black&white and a grayscale icon. For shell-specific extensions, it is up to the shell to specify if multiple extensions of the same type are allowed. If this rule is violated by a program, a shell might either ignore the duplicates and just treat the first extension with the duplicate type ID (preferred, but programs must NOT rely on this), or ignore all extensions with the duplicate type ID including the first one, and it may or may not ignore all subsequent extensions (not ignoring them is preferred, but programs must NOT rely on this). It must NOT, however, crash when confronted with duplicate extensions. 7. Omitted Extensions ALL extensions defined above are OPTIONAL. A program is NOT forced to implement all extensions just because it implements one of them! Shells should look for the presence of specific extensions, not just assume that if the extension header is present, the specific extension they are looking for is present too. 8. A Few Notes about Icons While allowing arbitrary-size icons was a nice idea, the fact that specifying multiple size icons in a program takes lots of space and the fact that there are no scaling routines which can scale icons from an arbitrary size to another arbitrary size available made us decide for fixed-size icons instead. As for the size to choose, this is a difficult decision since there is no way to please everyone. Shells are (and/or will be) drawing icons at different sizes. We (Kevin Kofler and Gregory Dietsche) selected 16×16 because: * that's what AMS defines for the ICON structure. * there is no standard AMS structure available to describe other fixed-size sprites. * they are a good compromise between detail level and required byte space. * there are multiple routines to draw 16×16 sprites available (probably more than for any other sprite size): DrawIcon, Sprite16, ExtGraph Sprite16 routines and routines provided by various other graphical libraries. * there are routines to scale 16×16 sprites to any arbitrary size available in ExtGraph (ScaleSprite16_OR, ScaleSprite16_AND, ScaleSprite16_XOR). For the order of the planes in grayscale icons, I (Kevin Kofler) went for dark plane first to make life easier for black&white shell authors (see below). Moreover, shell authors wishing to implement program icon drawing in their shells should follow the guidelines below: * In order to allow programs to save size by not providing both a black&white icon and a grayscale icon unless it is really needed: - grayscale shells should draw black&white icons by drawing the same icon in both planes if (and only if) no grayscale icon is available. - black&white shells should draw grayscale icons by drawing only the dark plane (the first one) if (and only if) no black&white icon is available. * Shells displaying icons at sizes other than 16×16 should scale the icon provided by the program to the desired size using ScaleSprite16_OR from ExtGraph or a custom scaling routine. 9. Strings Null-terminated strings are not limited in size by the standard. Shell authors should make sure they either use clipped string drawing routines or truncate the strings to a length known not to overflow the screen area or some buffer. Program authors should be aware of the fact that comments might be truncated by shells if they are too long and try to make the comments as short as possible to avoid truncation. The reason no fixed size limit is set by the standard is that since each shell uses the screen in a different way, the maximum size which each one can display varies very much. 10. Numeric Version Number (standard_revision, extension type 0x3) The numeric version number is a 4-byte entry corresponding to the following structure: typedef struct VERSION { unsigned char major; unsigned char minor; unsigned char revision; unsigned char subrev; } VERSION; It should be placed at an EVEN address (in assembly, use an "EVEN" or ".even" directive, in C, use "__attribute__((aligned(2)))"), in order to allow shells to read it in as an unsigned long integer. However, it is a good idea for shells to either use byte-by-byte reading or to check for the address being even before reading the data in order to avoid crashes. Programs should NOT rely on the shell handling unaligned version number entries though. The preferred format for displaying those entries is the format used for IP numbers: VERSION *version; printf("%d.%d.%d.%d",(short)(version->major),(short)(version->minor),(short)(version->revision), (short)(version->subrev)); Those fields should contain the following entries: * major: The major version number. Can be any value from 0 to 255. * minor: The minor version number. This are usually the next 1 or 2 digits after the dot. Can be any value from 0 to 255. If your program does not use minor versions, it should be 0. * revision: The revision version number. This should be used only when both major and minor numbers are significant. Can be any value from 0 to 255. If your program does not use revisions, it should be 0. * subrev: The subrevision version number. This should be used only when all 3 of major and minor numbers and the revision are significant. Can be any value from 0 to 255. If your program does not use subrevisions, it should be 0. Newer versions should have HIGHER version numbers than older ones when read as an unsigned long. In other words, one of the following sentences should apply: * The major version number of the newer version is greater than the major version number of the older version. * The major version number is the same for both versions, and the minor version number of the newer version is greater than the minor version number of the older version. * The major and minor version numbers are the same for both versions, and the revision number of the newer version is greater than the revision number of the older version. * The major and minor version numbers and the revision are the same for both versions, and the subrevision number of the newer version is greater than the subrevision number of the older version. Some examples: * good examples: 3 -> 3.0.0.0 3.0 -> 3.0.0.0 3.0.0 -> 3.0.0.0 3.0.0.0 -> 3.0.0.0 3.1 -> 3.1.0.0 3.1.0 -> 3.1.0.0 3.11 -> 3.11.0.0 if the previous version was 3.10 (3.10.0.0), 3.1.1.0 if it was 3.1 3.1.1 -> 3.1.1.0 3.2.1-tigcc1 -> 3.2.1.1 0.94 beta 18 -> 0.94.18.0 0.94 release -> 0.94.255.0 0.94 SP4 -> 0.94.255.4 0.94 b18 r1 -> 0.94.18.1 2.71.F3i -> 2.71.3.9 4.00.950 -> 4.0.9.50 (The revision number is too long, so you need to split it up into revision and subrev.) 4.00.1111 -> 4.0.11.11 (Same as above.) * bad examples (do NOT do this): 3.11 -> 3.0.11.0 (use minor, not revision: 3.11.0.0) 3.1.1 -> 3.1.0.1 (use revision, not subrev: 3.1.1.0) 2.95.3 -> 2.9.5.3 (do not split up the minor version: 2.95.3.0) 3.11->3.11.0.0, followed by 3.2->3.2.0.0 (always INCREMENT version numbers, use 3.1.1.0 for 3.11 here) 11. Crash Protection or Low Stack Condition Incompatibility Flags (extension type 0x6) Those flags allow programs to protect themselves from being run from a shell with crash protection mechanisms which would actually make them crash or otherwise fail to work. The flags currently defined are: bit 0 (0x00000001): incompatible with automatic handle freeing. For the purpose of this flag, automatic handle freeing is assumed to keep handles associated to files or home screen history handles untouched. Define this if your program is a TSR. bit 1 (0x00000002): incompatible with trap restoring. Define this if your program is a TSR which hooks (or might hook, for example by including h220xTSR) trap vectors. bit 2 (0x00000004): incompatible with vector table (except traps) restoring. Define this if your program is a TSR which hooks (or might hook) non-trap vectors, such as interrupts or hardware exceptions. bit 3 (0x00000008): incompatible with EV_hook restoring. Define this if your program is an event hook TSR. bit 4 (0x00000010): see below. In presence of those flags, a shell should either refuse the execution of the program or disable the parts of its crash protection which the program is incompatible with. Whether a shell accepts to run a program which sets flags other than those defined above (which might be defined by future releases of this standard) is up to the shell. Bit 4 allows programs to specify that they need more stack space than typically available with a shell running, in order to protect themselves from being run from a shell which uses up significant parts of the stack (more than about 128 bytes). A shell such as the TICT Explorer which leaves (practically) all the stack space available can happily ignore this flag. There is no such flag for low RAM conditions because they can also very easily happen when a program is run directly from AMS (not from a shell), and because there are better methods to handle low RAM conditions. (Programs should test each of their memory allocations for success, it is more reliable than just checking the amount of free RAM because the RAM might be fragmented by locked handles.) 12. Comment (type 0x0) vs. Program Name (type 0x1) Since the Comment field and the Program Name field serve similar purposes, the differences between them shall be clarified by the following guidelines: * A "program name", if specified, should ONLY contain the program name. It MUST NOT contain items such as version numbers (use the "version string" and/or "version number" fields instead), authorship information (use the "author(s)" field instead) etc. * A "comment", if specified, must contain a description which should be shown by shells in their description area (usually the status bar). For example, this can be any combination of program name, version number and authorship information (e.g. "AutoClBr 2.22 by Kevin Kofler"), or it can be a short (1-line) description of the program's purpose (e.g. "Automatic parentheses closer"). * If "comment" is missing, the shell must look for "program name" instead. If the program name is present, it must be shown in place of the missing comment. Consequently, programs should not set "program name" and "comment" to identical strings, setting "program name" only saves memory. Kevin Kofler, Thibaut Barthélémy, Gregory Dietsche, Lionel Debroux