         ***********************************************************
                       Text data objects for Allegro.
                   By Chris La Mantia (lamantia@gte.net)
         Library conversion and makefile by Grzegorz Adam Hankiewicz
                               Version 1.2
         ***********************************************************

This code has been released to the public domain by its author. It may be
distributed and modified freely.

                               ************
                               INTRODUCTION
                               ************

If you have a program that deals with a large number of strings, you have a
few ways of getting those strings into a program. You can hardcode the
strings into your code; this allows easy creation of ragged arrays, saving
space at the expense of flexibility. You could put the strings in an
external file, reading them in at runtime; this, however, brings in the ugly
spectre of doing dynamic allocation to get ragged arrays, or reading a fixed
maximum number of strings at fixed sizes, wasting memory and reducing
flexibility. Here, I present another approach for users of the Allegro game
programming library, by Shawn Hargreaves: loadable text data objects.

                        ***************************
                        What is a text data object?
                        ***************************

A text data object is an Allegro datafile object. It can be stored in an
Allegro datafile and loaded as needed by the library. The actual data itself
is simply a block of zero-delimited strings (a utility for converting lists
of carriage-return delimited strings is included here). Allegro, with the
help of the loader routines in textdata.c, will allocate the memory
individually for each string, and will return a pointer to a table of string
pointers; thus, a dynamically-allocated ragged array.

                               ************
                               Installation
                               ************

To install the text data object library, simply unzip the archive into your
DJGPP directory. Make sure you preserve the directory structure when you do
this; otherwise, the makefile will not work. To preserve the directory 
structure with PKUNZIP, add the -d switch, as follows:

     pkunzip tdata120.zip -d

After unzipping the library, change to the allegro\addons\textdata directory 
and run make.

To use the library, you must link the tdata library with your executable and 
include <textdata.h> in your source code. If you are linking from the 
command line or a makefile, your command line should look something like 
this:

     gcc -o program.exe program.o -ltdata -lalleg

                     *********************************
                     What functions are included here?
                     *********************************

There are two functions and two macros involved. You will likely only use
the macros directly.

	install_textdata()

	This macro registers the text data type with Allegro; you must call it
   before loading any datafiles that include text data objects.

	strcount(data)

	This macro returns the number of strings in a text data object. Calling
   this macro on anything else will return funky results.

	void *load_textdata(PACKFILE *f, long size)

	This is the function that does the actual work of allocating the memory
	and loading the text data object. It returns a pointer to the beginning
   of the text data object. Normally, you will not call this function
   directly; it will be called by Allegro when your data file is loaded.

	void destroy_textdata(void *data)

	This function de-allocated the memory used by a text data object. Again,
	you should not call this function directly; Allegro will call it when you
	unload your data file.

                    ************************************
                    How do I prepare a text data object?
                    ************************************

For a simple text data object, simply use your favorite editor to create a
list of strings, one on each line. Then, run MAKETEXT filename.txt to create
a text data object file (.tdo).

Now, create a new object in your data file using Allegro's grabber. Select
Object from the grabber menu, then New, then Other. Enter the object type as
"TEXT", and name the object. Finally, grab your .TDO and you're all set.

For long text data objects, you can define labels for easy reference to the
strings in your code. This is useful when your strings represent messages,
for example, where you may want a separate text data object for each
language you support, loading the appropriate one at runtime.

To label your strings, first choose a character to act as a delimiter
between your labels and your strings. This character must not appear in any
of the strings that make up the TDO. (I like to use the tilde character (~);
it rarely appears in any of my strings.)

Now that you have your delimiter, simply enter the label followed by the
delimiter before the string you want to label. Thus, your text file might
look like this:


DISKFULL~Error: Out of disk space; cannot save file.
Please delete some files before continuing.
NOCREATE~Error: Cannot create %s.
OVERWRITE~File exists.  Overwrite?

(Note: Do not try to format this file up by indenting the strings that have
no labels; spaces at the beginning and end of the strings are saved in the
TDO!)

Now, to create the text data object, add the delimiter to your command line:
MAKETEXT DISKERR.TXT ~

This will create two files: a DISKERR.TDO containing the text data object,
and a DISKERR.H containing the labels.

                      ********************************
                      How do I use a text data object?
                      ********************************

Loading an Allegro datafile containing a text data object will automatically
build the text data object in memory. For easiest usage, you should assign
the address of the text data object's data member to a pointer to pointer to
char. This will allow you to treat the pointer as any other array of
strings.

Example

Here's an example, using the DISKERR.TDO we just created and imported into
DATAFILE.DAT.

#include <stdio.h>
#include <stdlib.h>
#include <allegro.h>
#include "textdata.h"
#include "diskerr.h"

int main(void)
{
   DATAFILE *data;
   char **message;
   char filename[13]="badfile.txt";

   allegro_init();
   install_textdata();
   data=load_datafile("datafile.dat");
   message=data[DISKERR]->dat;

   printf("%s\n%s\n",message[DISKFULL],message[DISKFULL+1]);
   printf(message[NOCREATE],filename);
   printf("\n");

   return(0);
}

                        ***************************
                        Limitations of MAKETEXT.EXE
                        ***************************

The line above that printed the NOCREATE message is an example of a
limitation of MAKETEXT: it does not allow for newline characters (or any
other escape sequences) to be stored in the TDO. If you must have newlines
in a string in your TDO, you must insert them by hand into the TDO file.

The other limitation of MAKETEXT.EXE is that it is limited to a maximum
string size of 4K. If you need exceedingly large strings in your program,
build the TDO by hand or modify MAKETEXT.C to allow a larger string size.

Putting TDO's to work: HANGMAN

I have put together a simple game to illustrate the use of text data
objects: HANGMAN. You've played the game hundreds of times as a child with
paper and pencil; the object, as always, is to guess a word before a gallows
can be drawn, with you dangling from it.

All of the strings in HANGMAN are contained in a text data object in an
Allegro datafile (with the obvious exception of the error messages warning
of a failure to load the datafile itself). Thus, the game is easily
translated to foreign languages: simply build a datafile for each language.
The game itself will not need to be re-compiled. (In this case, each
language's datafile must have the same number of words; if the message text
was moved to the beginning of wordlist.txt, and a little additional math was
added to determine the range of the word list, then any number of words
would work in each datafile.

                                 **********
                                 Conclusion
                                 **********

These routines are free for your use. There are no license requirements if
you want to use these routines; if you want to give me a credit somewhere,
though, I won't argue. On the other hand, if you use these routines, I am
not responsible if they wipe your hard drive, develop annoying habits, or
sleep with your wife.

If you have any suggestions for or comments about these routines, they are
welcome; please direct your comments and questions to Chris La Mantia
at lamantia@gte.net.

                                **************
                                Change History
                                **************

May 30, 1998: Version 1.2
- Fixed MAKETEXT to return a proper return code; it was returning random 
  values, making it unsuitable for use in makefiles.

May 19, 1998: Version 1.11
- Grzegorz Adam Hankiewicz converted textdata to a proper library, added an improved
  makefile, increased the string size handled by MAKETEXT, and re-organized the ZIP 
  file to install properly into the DJGPP tree.

May 17, 1998: Version 1.1 + Hangman
- Added sample game HANGMAN to the distribution.

December 6, 1997: Version 1.1
- First public release.
