home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 2 BBS
/
02-BBS.zip
/
dr2v41b1.zip
/
DOORS2.DOC
< prev
next >
Wrap
Text File
|
1994-10-02
|
52KB
|
1,186 lines
DOORS/2 -- Version 4.10
(C) 1994 Joel W. Downer
Based on source for OpenDoors 4.10, (C) 1991 - 1993, Brian Pirie
WHAT IS DOORS/2?
Doors/2 is a 32-bit, multithreaded OS/2 port of Brian Pirie's OpenDoors
4.10, which is widely acknowledged as the best door library available
for any language or BBS environment. Doors/2 is a C/C++ library
intended to be used with Borland C++ for OS/2. It includes features
such as:
* Fast, efficient OS/2 serial communications code -- no FOSSILs, .DLLs,
or other comm service packages required.
* Support for virtually any type of serial port through the OS/2
communications driver model.
* Multithreaded serial, keyboard, messaging, kernal, and video code for
top-flight performance with minimal CPU load.
* Support for a wide variety of dropfiles, such as DOOR.SYS,
DORINFOx.DEF, CHAIN.TXT, and RA 2.00 EXITINFO.BBS.
* The ability to run an OS/2 door from a BBS running in the OS/2 DOS box
(and they said it couldn't be done... <g>).
* An ultra-fast internode messaging/chat system with throughput suitable
for real-time interactive doors.
* Built-in support for blanked-screen "secure mode" *with* the ability
to save and restore the remote screen on demand.
* The rich graphics, dropfile, communications, and interface features of
OpenDoors 4.10 for DOS (exceptions and exclusions noted below).
* The ability to produce a *single-source* door portable to DOS and OS/2
with little more than a recompile!
* Coming soon: OpenDoors 5.00 compatibility and support for popular
non-Borland compilers!
If you're a seasoned door developer and customers have been asking for
OS/2 versions of your products, Doors/2 can help you meet this goal
*without* hundreds of hours porting and fussing with a new environment.
If you're a new door developer, OpenDoors for DOS and Doors/2
can allow you to focus on *your application* with minimal attention to
dropfiles, modems, or details of ANSI graphics. You can create an OS/2
door even if you know little about doors and OS/2!
SHAREWARE NOTICE
This library is distributed as copyrighted shareware. Although you are
permitted (and encouraged) to copy and distribute this library in its
original, unaltered archive form (with documentation and license
information), the library is *NOT* in the public domain.
You are allowed to evaluate this library for a period up to thirty days.
If you wish to use this library after that initial evaluation period,
*OR* if you wish to distribute a program developed with Doors/2 *at any
time* (during the evaluation period or afterwards), you must register.
Please see the section on licensing/registration for information on how
to register. Registered users of Doors/2 will receive a registered copy
of the library, a copy of the source code, and additional tools for OS/2
and DOS door programming that aren't available in the unregistered
version.
Thanks for evaluating Doors/2. Future development and support for this
product depends on you!
DISCLAIMER
Neither I nor any other individual or organization makes a warranty of
any kind regarding the usefulness, reliability, merchantability, or
fitness of this software and documentation for any purpose whatsoever.
While I have tested this library thoroughly, I cannot and will not make
any promises that programs developed with it will run well or safely on
your hardware or with your particular software configuration. You use
it at your own risk.
Your use of Doors/2 and/or any companion material constitutes your
acceptance of these terms.
REQUIREMENTS/LIMITATIONS
Doors/2 is a C/C++ library developed for the Borland C++ for OS/2
compiler. The version of the library (4.10 wide beta 1) does *not*
currently support other OS/2 compilers, such as CSet++ or Watcom C/C++.
I am feverishly working on providing support for popular OS/2 compilers
for wide beta 2.
Doors/2 is intended as a companion product to OpenDoors 4.10 by Brian
Pirie. It was originally ported from the source to OpenDoors 4.10.
From this point forward, this documentation will assume that you have
and are generally familiar with OpenDoors 4.10: it will focus almost
exclusively on differences between the two libraries and on techniques
for porting code. For reference on functions and data members that are
common to OD and Doors/2, please refer to the OpenDoors documentation.
If you need a copy of OpenDoors 4.10, see the section on support, below,
for information on how to obtain one.
Because the current version of Doors/2 is based on OpenDoors 4.10,
Doors/2 is *not* completely compatible with OpenDoors 5.00. Now that
OpenDoors 5.00 has been publicly released, 5.00 support is one of the
top two priorities (along with multicompiler support) that I'm working
on for wide beta 2. I can't make a promise about a specific release
date for wide beta 2. I *can* suggest that you not make extreme changes
in your code for backwards compatibility, and that you not spend money
purchasing Borland C for OS/2 (which is apparently generally inferior to
CSet++ and Watcomm) if you don't already have it.
Although Doors/2 is intended as an add-on to OpenDoors and must be
registered as such, complete compatibility between OD and Doors/2 is
*not* guaranteed. In particular, I make no guarantee that Doors/2 will
be compatible with future versions of OpenDoors.
Brian Pirie has been very gracious to allow me to distribute this add-on
to his OpenDoors library. However, he bears *NO* responsibility for the
support and maintenance of this product. In particular, he has no
obligation to make future changes to OpenDoors in ways that maintain
compatibility with Doors/2. All responsibility for supporting this
library -- insofar as such responsibility exists -- belongs to Joel W.
Downer.
QUICK START
If you already have a working door that uses OpenDoors 4.10, and you'd
like to recompile it and try it out with Doors/2 and BC-OS/2, this
section will give you a brief introduction to what you'll need to do.
Note: because there are a number of "under-the-hood" differences
between OD 4.10 and Doors/2, I strongly recommend that you read the next
few sections on functionality differences. If, for example, your door
uses any internal information about OpenDoors, if it uses RA and AVATAR
support, or if it uses control keys (several of which have been
appropriated by the library for use with the messaging system), you may
need to do more work than I describe in this section to get up and
running under OS/2. However, I understand the impulse to compile and
try things out instead of lingering on documentation.... <g>
These instructions will refer to the EZVOTE.C sample door included with
ODoors 4.10, but they should apply to a wide range of door projects.
1. Create a directory for your Doors/2 library and header files, and
copy the files to that directory. I'll assume from here that you're
using C:\SOURCE\DOORS2\, and that your OpenDoors library and header
files are in C:\SOURCE\ODOORS\.
2. Seek out the line where you include the OpenDoors header file.
That line probably looks something like this:
#include "c:\source\odoors\opendoor.h"
Replace that line with the following lines, substituting the correct
directories on your system:
#ifndef __OS2__
#include "c:\source\odoors\opendoor.h"
#else
#include "c:\source\doors2\opendoor.h"
#endif
This code will tell your compiler to use the Doors/2 version of
OPENDOOR.H if and only if you're compiling under OS/2. The __OS2__
macro is automatically defined by the BC-OS/2 compiler. Conditional
compilation -- which tells the compile to ignore or to use certain
code based on the state of various macros -- is extremely helpful
when you're writing source code that you want to compile under two or
more platforms.
3. If your main() function isn't already coded to receive command-line
arguments, modify it so that it will do so. In EZVOTE.C, that will
involve changing the line:
main()
to look like this:
int main(int ac, char *av[])
(Why? See 4., below.)
4. If you weren't using or processing command-line arguments before, add
the following prototype to your program:
void ProcessCmdLine(int ac, char *av[]);
and merge the contents of the file cmdline.c into your source file.
If you're already processing command-line arguments, refer to
cmdline.c for an example of how to support timing and use_port
parameters. Place a call to ProcessCmdLine(ac, av); near the
beginning of main (in EZVOTE, we'll do it at the very first line).
Bracket the new code with #ifdef __OS2__ ... #endif directives so
that it's "invisible" to your DOS compiler, like so:
void main(int ac, char *av[])
{
#ifdef __OS2__
ProcessCmdLine(ac, av);
#endif
/* And so forth.... */
The purpose of this extra code is to allow the user to indicate
whether a port or handle will be included in the BBS dropfile (i.e.,
whether the door is running under Maximus/2 or under a DOS-style BBS)
and to control the multitasking aggressiveness of the program.
If you prefer to use some other method (a config file, for example),
that will work just as well; the command-line method is outlined here
to provide for the quickest possible start.
5. You're now ready to compile! For EZVOTE.C, we can just compile from
the command line, like so:
BCC EZVOTE.C C:\SOURCE\DOORS2\DOORS2.LIB
If you're using a makefile, you'll need to create OS/2 versions of
each of the components. For example, I build Iron Ox/2 with a
makefile called OS2MAKE, which (vastly simplified and with many
source files reduced) looks something like this:
.autodepend
.path.c = C:\SOURCE\OX
.path.obj = C:\SOURCE\OS2OBJ
.path.exe = C:\SOURCE\OS2OUT
.c.obj:
bcc -c -Vo -v- -f -d -O2 -Od -G- -N -H- -DDEBUG -nC:\SOURCE\OS2OBJ $<
ironox.exe: ironox.obj badstuff.obj auctfunc.obj mailfunc.obj \
joingame.obj rungame.obj prospect.obj auction.obj makemap.obj \
(... and so forth ... )
tlink @os2resp
My linker response file, OS2RESP, looks something like this:
-c -s -Toe d:\bcos2\lib\c02 \source\os2obj\rungame +
\source\os2obj\ironox + \source\os2obj\draw_sqr +
\source\os2obj\lockfile +
\source\os2obj\(lots of other object files <g>) +
\source\os2obj\oxware, c:\source\os2out\ironox.EXE,,
c:\source\doors2\doors2.lib +
d:\bcos2\lib\c2mt.lib d:\bcos2\lib\c2mti.lib d:\bcos2\lib\os2.lib
In general, OS/2 text-mode makefiles are simpler than DOS makefiles
because memory models are not an issue.
Anyway, if you're using makefiles you can compile using a command
like this:
MAKE -fos2make
6. If you're using non-portable code in your project like direct memory
access or interrupt calls, the compiler will probably tell you about
it in a hurry. <g> EZVOTE.C doesn't, so it'll compile without error
on the standard warning level for BC-OS/2. (It will generate one
warning, because <stdio.h> was not included in the original source,
but you can safely ignore this warning.)
THE LIBRARY
The next section outlines the functionality differences between Doors/2
and OpenDoors. The section after that provides some information about
the design and internal workings of Doors/2. Because Doors/2 was
written to hide the details of OS/2 from the door developer, only the
first section is necessary reading for now. The material on design
philosophy is intended to give you an idea what to expect if you
purchase the source and to give you a feel for what's going on "under
the hood."
DOORS/2 VS. OPENDOORS 4.10 -- FUNCTIONALITY DIFFERENCES
The following known functionality differences exist between OD 4.10 and
this version of Doors/2. In some cases, the functionality differences
are based on additions or corrections to take advantage of the new
operating environment. In others, they're based on decisions of
convenience I made during the porting process (i.e., I stripped some
features that did not seem vital in order to simplify the recoding).
I am happy to provide suggestions on how to add any unsupported
features that exist in OD 4.10, and/or to correct discrepancies myself
for future versions.
Control structure changes:
I've added several new control members to the od_control structure to
handle specific features of the OS/2 BBS environment. You will
probably need to support at least two of them, od_control.use_port
and od_control.od_timing, with command-line parameters or
configuration options. For an example of command-line processing for
these options, see the cmdline.c file included in the standard
distribution package.
1. A new od_control member, od_control.od_timing, has been added to
control the multitasking aggressiveness of the library. Three values
are supported: TIMING_NICE, which is suitable for systems running
only native software, TIMING_NORMAL, which is a reasonable default
for most systems, and TIMING_NASTY, which is appropriate on systems
running DOS comm apps and misbehaved software. TIMING_NORMAL is the
default. Adjustments to this setting should be made before calling
od_init.
2. Another control member, od_control.use_port, controls whether the
library expects to find a comm port name or an open comm handle in
a found dropfile. The most popular OS/2 native BBS program,
Maximus/2, places a handle in its dropfiles, not a port name, so the
library expects a comm handle by default. Set use_port to TRUE if
you know that a valid port name will be included in the dropfile.
Adjustments to this setting should be made before calling od_init.
Sysops will need some means to select use_port to run Doors/2 doors
with OS/2 software that writes a port name to its dropfile, like
Lora. Using the /PORT parameter and Ray Gwinn's SIO drivers, sysops
who run *DOS BBS'es* under OS/2 can also run Doors/2 doors from the
OS/2 DOS box. (See the documentation for Iron Ox for OS/2 for
information on how to set up an OS/2 door from the DOS box. Sysops
will need OS2EXEC or a similar utility to accomplish this purpose.)
3. Another control member, od_infofile[], allows preselection of
dropfile. If you wish to allow users to specify dropfile name on the
command line, you can copy this name (8 x 3 only, not full path!) to
od_control.od_infofile. Use of this member is completely optional.
4. Variables for several thread ID's and semaphore handles are currently
in the od_control structure. These variables probably do not belong
in the od_control structure, and will be removed in an upcoming
version. In the meantime, I would strongly discourage you from using
or changing them in any way.
5. A flag, od_control.od_no_messages, allows you to disable multinode
messaging and chat. This flag is FALSE by default. Adjustments to
this setting should be made before calling od_init.
6. The variable od_control.od_max_nodes controls the highest node number
the messaging system should search for when it tries to send an
internode message. This value is unused when od_no_messages is TRUE;
otherwise, it defaults to 10. Adjustments to this setting should be
made before calling od_init.
7. Seven variables (fossil, od_no_fossil, od_accept_baud,
od_fifo_disable, force_address, force_irq, and lockbps) have been
added for compatibility with changes I have made to the DOS version
of the code to add internal async. None of these variables is used
under OS/2; you can remove them if you wish to save a few bytes. <g>
8. Four new function hooks have been added. All are optional:
void (*od_warnfunc)(char *str);
If you wish to control the formatting of warnings about keyboard
inactivity and remaining time, you can write your own function to
display the warning string, str, to the user. If you do not set this
parameter, the default behavior will be used.
void (*od_cbefore_status)(void);
void (*od_cafter_status)(void);
These hooks allow you to define functions that will be called
immediately before and after updating the status line.
void (*od_node_message)(tInternodeMsg *);
This function pointer will allow you to define a handler for received
internode messages. If max_nodes is greater than one and messaging
is not disabled, this pointer defaults to the od_show_message
function when not in chat and the chat_show_message function when in
chat. Source for od_show_message (the default function used to
display messages) is included in the standard shareware package as
smessage.c. If you wish to define a new handler for this function, I
recommend that you use this source as a model.
9. The pointer od_pipe_name controls the name format for the named pipes
used in internode messaging. The node number is appended to this
string to create a unique pipe name for each node. By default, the
pipe name is "\\PIPE\\ODPIPE".
If you wish to make internode messaging available in your door, you
should provide some means by which sysops can change this value. For
messaging to work across a LAN, the pipe name must contain the name of
the server, thus: "\\SERVER\\PIPE\\ODPIPE". Also, using a unique
name for your application might be advisable in case two different
doors using this library are running simultaneously. <g>
10. Support for the RA 2.00 EXITINFO.BBS format required that several
members of the od_control user variables be resized (e.g., strings
lengthened, unsigned ints converted to unsigned longs). Code that
relies on the size of these members may need to be changed.
11. The maximum string length handled safely by od_printf is now
controlled by the macro OD_MAX_STRING, defined in the source package.
Default is 1,024 bytes.
od_init function:
1. A function called od_srand is called from od_init. Use of od_srand
and od_random (exactly analogous to Borlands srand and random
functions) rather than the Borland equivalents is recommended. The
Borland OS/2 random number generator is broken.
od_kernal function:
1. Checks on carrier and time remaining have been moved to a separate
kernal thread. If od_kernal looks a little bare, that's why. <g>
2. The keyboard queue (input_buffer[], b_head, b_tail) is now protected
by a Mutex semaphore (a system semaphore that allows you to be sure
that another thread will not modify data you're using at the time).
Direct manipulation of the keyboard buffer or modem buffer is
*strongly* discouraged: you're best off letting the library do the
work for you. If you must manipulate the buffers directly, look
carefully at the way Mutex semaphores are used in the check_key
function source and do the same.
3. Several of the status line hotkey options have been removed because
status lines other than F1 and F9 are usually annoyingly blank with
dropfiles other than EXITINFO.BBS. If you like having the full range
of status lines, pasting in the code from the original source should
be a trivial matter.
od_exit function:
1. DOOR.SYS is not rewritten on exit. The DOOR.SYS standard indicates
that DOOR.SYS is not to be reread on door exit.
2. The value of "TRUE" for the term_call parameter is unsupported.
3. The od_control.od_noexit toggle is unsupported. The library
currently relies on DosExit(1, errorlevel) to terminate library
threads, so terminating library operation without exiting completely
is infeasible in this version. This will change in an upcoming
version.
od_video subsystem:
1. All OpenDoors video functions have been modified to use a cached
video write system. Lines 1-23 (the "client window area") are
maintained using a logical video buffer; od_printf, od_disp,
od_putch, and so forth have been modified to update this buffer
instead of addressing the screen directly. The library uses the
Borland video routines to maintain the status bar lines.
The most important consequence of this change is that you should use
avoid using Borland conio functions in your door code. Use the
following corresponding functions for each video operation:
For: Use:
--------------------------------------------------------
clrscr() od_clr_scr()
gettext() od_gettext() or od_save_screen()
puttext() od_restore_screen()
gotoxy() od_set_cursor()
wherex() od_wherex()
wherey() od_wherey()
gettextinfo() od_get_attrib() and others...
textattr() od_set_attrib()
2. You can now maintain a blank local client window (while keeping track
of the status of the remote screen) by calling od_blank_display(), and
restore the local screen with od_restore_display(). This option is
most useful for games in which the sysop may not want the unfair
advantage of watching other people play.
od_restore_display() requires no arguments. od_blank_display() takes
as argument a string that should be displayed on the local screen to
indicate that secure mode is on, thus:
od_blank_display("IRON OX 2.00 -- Game in Secure Mode!");
See "Using Secure Mode," below, for more details.
od_emu.c
1. The od_emu function itself now writes characters to be sent to the
modem to a cache for buffering to improve the performance of
od_send_file under OS/2.
If you call od_emu() outside of od_send_file and od_hotkey_menu, you
should call od_flush afterward to make sure the characters addressed
to the modem are sent promptly.
2. od_send_file now returns TRUE if a file was sent successfully and
FALSE if the send failed or was aborted. This change can be ignored,
but it was made to support code like the following:
if (od_send_file(datapath("ALPHANOT", buf)))
pause(); // Don't pause if this file isn't found....
3. I removed support for RA-specific control codes (which seemed of
fairly narrow interest) from the emulator to simplify the caching
code. If you need this support, let me know and we can give it a
try....
4. Avatar support is not currently available in the emulator. From the
research I did while doing the original port, I found virtually no
sysop demand for Avatar support, and eliminating the complex
sequence-handling greatly simplified the conversion. I am open to
re-adding Avatar support to an upcoming version if I find sufficient
demand.
DOORS/2: THE DESIGN
I began work on Doors/2 when I decided that I wanted to create an OS/2
version of my BBS game door, Iron Ox. Having already done considerable
work with the OpenDoors library source, I naturally concluded that
adapting that source would be the easiest way to develop a complete door
library for OS/2.
My design goal in porting OpenDoors was to try to encapsulate all
operating-system specific code in the door library. In other words,
your application source code shouldn't need to know whether it's going
to be linked to OpenDoors for DOS or to Doors/2.
Modifying OpenDoors so that it would compile cleanly under BC-OS/2, link
with program code, and run from a Maximus/2 BBS was a relatively minor
job. There were a number of small details, like eliminating direct
access to the hardware clock and adapting the dropfile code to read a
comm handle instead of the name of a comm port from a dropfile, but the
only serious change was isolating and modifying the communications code
and changing the FOSSIL interrupts into calls to the OS/2 device driver.
Easy enough.
Unfortunately, the resulting first try was a pig, and a very slow one at
that. <g> Performance was at best half what I'd learned to expect from
OpenDoors 4.10, and the emulator was even worse -- emulating a large
ANSI file took 4-10 times as long under this ported version as it did in
the original. CPU load was also higher than you'd get from a DOS door
written with OpenDoors running in the DOS box. This outcome wasn't a
surprise -- single-character I/O and polling just don't cut it under
OS/2 -- but it did indicate that the work had just begun.
So, let's make a boring story short: Doors/2 makes heavy use of caching
and multithreading to achieve performance comparable to what you can get
from DOS video and communications code. Input (through the keyboard or
the modem) is read by dedicated threads that block on input (put
themselves to sleep until something happens). Output is written to
memory buffers, and is flushed by low-priority output threads. The
result is door programs with excellent performance and less than 4% CPU
load on most systems.
Doors/2 programs will usually have seven threads of execution (fewer if
multinode messaging is disabled and/or the program is running in local
mode):
1. Main program thread:
This thread executes the code you write. It will call functions like
od_get_key() to get input from the keyboard and serial input threads,
and functions like od_send_file, od_printf, and od_disp to request
that data be displayed to the screen and sent out the modem.
2. Serial input thread:
This thread waits for characters to come in through the serial port.
When characters are received, it adds them to the input queue. Like
most good threads, it spends most of its time sleeping.
3. Keyboard input thread:
This thread waits for characters to come in through the keyboard
buffer so that it can add them to the input queue. Again, the rest
of the time, it sleeps.
4. Message thread:
This thread waits for messages to come in through the node's message
pipe. When a message is received, it adds the message to a queue
that will be checked next time your program waits for keyboard input
(i.e., calls od_get_key(TRUE)). This thread is not created if you
disabled multinode messaging.
5. Serial output thread:
This thread writes characters to the serial driver. It has a lower
priority than the other program threads, which allows the program to
buffer outgoing characters and send them out in blocks when a large
volume of data is being sent.
6. Video refresh thread:
Updating the text-mode video screen is a relatively expensive
activity under OS/2: the VIO16 functions are fairly slow and have
significant overhead. Therefore, all of the Doors/2 video functions
work by updating a virtual screen -- a memory buffer belonging to the
program. The video refresh thread uses idle time to repaint lines of
the display that have been changed.
7. Kernal thread:
This thread checks for timeout, user time remaining, and dropped
carrier. It, too, is a low-priority thread, and sleeps approximately
five seconds between checks.
This design may seem fairly Byzantine if you're unaccustomed to
multithreaded programming, but the underlying philosophy -- creating
threads for logically discrete activities and having them go to sleep
until something happens rather than having them poll -- provides
excellent performance with minimal CPU load.
NEW FEATURES
Doors/2 contains two substantial additions to the functionality of
OpenDoors 4.10: "Secure Mode" blank screen support, and multinode
messaging. Both of these features are entirely optional. You can avoid
using secure mode simply by not calling the functions that activate it.
You can disable multinode messaging by setting:
od_control.od_no_messages = TRUE;
However, both of these features do add useful functionality to the
library, so you may wish to consider using them.
USING SECURE MODE
When you activate secure mode, the local display is blanked except for
the status bar and a line that you specify across the middle of the
screen. The screen remains blank until you explicitly unblank it or
until the user exits the door. Secure mode would most often be used to
prevent an unfair sysop advantage in door games. If you don't wish to
use secure mode, you can skip over this section: secure mode is off by
default.
Blanking and unblanking the screen is very simple. You can blank it
with a call to:
od_blank_display(pszBlankLine);
where pszBlankLine is a string you want displayed centered on the blank
display (for example, "Iron Ox 2.00 -- Game in Secure Mode"). You can
unblank it at any time using:
od_restore_display();
While the screen is blanked with od_blank_display(), what *would have*
been displayed on the screen is stored in a memory buffer, so that
Doors/2 can keep track of the remote user's display. If you use the
function od_gettext() while the display is blanked, od_gettext will
capture the contents of the memory buffer (the "virtual display") and
not of the blank actual display. Why might you want to save the
contents of the "virtual display"? The most common reason is to allow
screen restore after sysop chat. (Screen restore after multiplayer chat
is handled automatically by the library assuming that enough memory is
available.)
Handling sysop chat is one of the few hairy things about secure mode.
Both OpenDoors and Doors/2 have the function pointers
od_control.od_cbefore_chat and od_control.od_cafter_chat that allow you
to run a custom function before and after sysop chat. At very least,
you need to use the od_cbefore_chat function to restore the display so
that the sysop will be able to see what he/she and the remote user are
typing. You need to use the od_cafter_chat function to reblank the
display if it was blanked before chat. You also may want to insert
logic to save and restore the remote screen if your application is a
fixed-screen rather than scrolling-screen program.
Here are sample pre-chat and post-chat functions that do as described:
char pszBlankStr[] = "IRON OX -- GAME IN SECURE MODE";
static boolean secure_mode; // Module status variables; shared by
static short savex; // save and restore functions.
static short savey;
static char * screenbuf;
void save_screen(void) // Pre-chat func; saves screen & secure state
{
saveattrib = cur_attrib;
savex = od_wherex();
savey = od_wherey();
if (screenbuf != NULL)
{
od_printf("\n\r\aCan't save screen! Buffer is in use!");
return;
}
if ((screenbuf = malloc(3680 * sizeof(char))) == NULL)
{
od_printf("\n\r\aInsufficient memory to save screen!");
return;
}
od_gettext(1, 1, 80, 23, screenbuf);
if (fScreenBlank)
{
secure_mode = TRUE;
od_restore_display();
}
else
secure_mode = FALSE;
clr_scr();
}
void restore_screen(void)
{
od_control.od_chat_disable = TRUE; // Re-entrancy protection... don't
od_control.od_shell_disable = TRUE; // want chat while redrawing!
if (screenbuf == NULL)
{
od_printf("\n\r\aError: unable to restore screen!");
od_control.od_chat_disable = FALSE;
od_control.od_shell_disable = FALSE;
return;
}
if ((secure_mode == TRUE) && (od_control.baud != 0))
od_blank_display(pszBlankStr);
od_restore_screen(screenbuf, savex, savey, 1, 1, 80, 25);
free(screenbuf);
screenbuf = NULL;
od_clear_keybuffer();
/* If sysop hits 's' during chat, will abort od_send_file. This is
common to OD 4.10 and Doors/2. */
_last_control_key = 0;
od_set_attrib(saveattrib);
od_control.od_chat_disable = FALSE;
od_control.od_shell_disable = FALSE;
}
THE MULTINODE MESSAGING MODULE
Doors/2 adds three built-in multinode-aware features to the
functionality of OpenDoors. At any time your program is waiting for
input, the user can request a list of other people currently in the
door, can send a message to one of those people, and can enter multinode
chat. Doors/2 automatically intercepts the following key commands:
Ctrl-O List people on the other nodes.
Ctrl-E Enter a message for a player on another node.
Ctrl-T Enter multinode chat.
Doors/2 automatically saves the screen before any of these functions and
restores the screen afterwards. If you have enabled the OpenDoors log
feature, Doors/2 will add a notice to the log when users activate these
options.
For the most part, these functions are completely automatic and clean up
after themselves. If you wish to disable messaging, you must do so
explicitly by setting od_control.od_no_messages to TRUE before calling
od_init(): messaging defaults to ON.
If you do decide to leave messaging active in your application, here are
some concerns you should be aware of:
1. The value od_control.od_max_nodes contains the highest node number
Doors/2 will look for. This value defaults to ten. If a user
attempts to enter the door on a node number *higher* than
od_control.od_max_nodes, and multinode messaging is enabled, the door
will display an error message and exit. Therefore, you will
definitely want to give sysops running your door some way
(command-line argument, config file option) to adjust this value.
(Sysops running fewer than ten nodes may also wish to adjust it to
improve performance.)
2. Somewhere in your program, you will probably want to display a menu
of multinode options so that users will know how to use them. I have
code like the following in Iron Ox/2 v. 1.12:
#ifdef __OS2__
if (od_control.od_max_nodes > 0)
{
clr_scr();
od_set_cursor(1, 19);
od_printf("`bright cyan`Iron Ox multinode messaging is "
"`bright white`ENABLED.");
od_set_cursor(3, 31);
od_printf("Commands`bright cyan`:");
od_set_cursor(5, 13);
od_printf("Press `bright white`Ctrl-O`bright cyan`"
" to list players currently in the game.");
od_set_cursor(6, 13);
od_printf("Press `bright white`Ctrl-E`bright cyan` to enter "
"a message for another node, and");
od_set_cursor(7, 13);
od_printf("Press `bright white`Ctrl-T`bright cyan` to enter "
"group chat!\n\r");
od_printf("`bright yellow`< Press a Key >");
od_get_key(TRUE);
}
#endif
3. You may also want to have your program send messages to other nodes
about common events -- someone entering or leaving the door, someone
being immortalized for the all-time record bowling score, and so
forth. See documentation on SendMessage(), below, for instructions
on doing this.
That's all there is to it!
DOORS/2 FUNCTION REFERENCE
For the most part, your Doors/2 door program will rely on the functions
included in OpenDoors to do its work. Please refer to the OpenDoors
documentation for information on these functions. This section includes
details on functions unique to Doors/2.
od_blank_display()
----------------------------------------------------------------------------
PURPOSE Activates blanked-screen secure mode.
FORMAT void od_blank_display(char *pszBlankStr);
DESCRIPTION This function blanks the local display and redirects screen
writes to a virtual video buffer. pszBlankStr is
displayed, centered, on the blank screen. See "Using
Secure Mode," above, for more details.
SEE ALSO od_restore_display(), od_gettext();
od_get_attrib()
----------------------------------------------------------------------------
PURPOSE Returns the current video attribute.
FORMAT int od_get_attrib(void);
DESCRIPTION Because all video attributes are virtualized, the Borland
run-time library gettextinfo call will not return correct
information about the current video attribute. This
function will return that information.
SEE ALSO od_gettext();
od_gettext()
----------------------------------------------------------------------------
PURPOSE Activates blanked-screen secure mode.
FORMAT void od_gettext(int lcol, int lrow, int rcol, int rrow,
void *buf);
DESCRIPTION This function allows you to save the contents of the
*user* display (what the library has transmitted to the
remote screen) regardless of the state of secure mode.
(The Borland library function gettext() will capture the
local screen, which is fine in standard mode but is
probably not what you want when the local screen is
blanked.)
EXAMPLE See the sample pre-chat and post-chat functions in "Using
Secure Mode" for an example of this function.
SEE ALSO od_blank_display(), od_restore_display();
od_random()
----------------------------------------------------------------------------
PURPOSE Returns a random number.
FORMAT int od_random(int max);
DESCRIPTION This function will return a random number between 0 and
max - 1. This function was necessary because the Borland
random number generator is broken: the Borland code
returns a small subset of the possible range of values in
a very tight periodicity, such that programs that rely on
normal pseudorandom periods can hang.
The library seeds the random number generator
automatically in od_init, so no preparatory work on your
part is required.
od_restore_display()
----------------------------------------------------------------------------
PURPOSE Deactivates blanked-screen secure mode.
FORMAT void od_restore_display(void);
DESCRIPTION This function unblanks a display that has been previously
blanked with od_blank_display(). See "Using Secure
Mode," above, for more details.
SEE ALSO od_blank_display();
od_wherex()
----------------------------------------------------------------------------
PURPOSE Returns the current cursor x position.
FORMAT int od_wherex(void);
DESCRIPTION Because the video display and cursor location are
virtualized, the Borland library call wherex() will
usually *not* return the correct cursor position.
(Virtualizing the cursor position reduces the number of
performance-reducing API calls and eliminates the
"dancing cursor" when in secure mode.) od_wherex() will
return the correct cursor location.
EXAMPLE See the sample pre-chat and post-chat functions in "Using
Secure Mode" for an example of this function.
SEE ALSO od_wherey();
od_wherey()
----------------------------------------------------------------------------
PURPOSE Returns the current cursor y position.
FORMAT int od_wherey(void);
DESCRIPTION Because the video display and cursor location are
virtualized, the Borland library call wherex() will
usually *not* return the correct cursor position.
od_wherey() will return the correct cursor location.
EXAMPLE See the sample pre-chat and post-chat functions in "Using
Secure Mode" for an example of this function.
SEE ALSO od_wherex();
SendMessage()
----------------------------------------------------------------------------
PURPOSE Transmits a message to some or all of the other nodes in
the door.
FORMAT int SendMessage(short dest_node, char *player, short event,
boolean from_player, char *format, ...);
RETURNS OK on success, ERROR on failure (macros defined in
Doors/2 version of OPENDOOR.H).
DESCRIPTION This function allows you to send a message and
accompanying information to other instances of the
program running on other BBS nodes. This message may be
a text note directed to a user, or it may be
notification of an event that is not displayed to the
user.
The parameter "dest_node" controls which nodes will
receive the message. This parameter may be any number
between 1 and the value contained in
od_control.od_max_nodes, or DEST_ALL_NODES, which
indicates that the message should be sent to all active
nodes.
The parameter "player" should include the name of the
person currently using the door. Usually, you will want
to use od_control.user_name for this parameter.
The "event" parameter is used by internal messaging
functions to transmit background information -- for
example, that a user is entering or exiting chat, or
entering or leaving the door. You should normally set it
to zero.
The "from_player" parameter distinguishes whether a
message was written by a player or sent by the door.
This parameter will often determine how a message is
displayed on the receiving end, thus distinguishing:
Received from Bob on Node 2: Hi!
from:
Bob has just died in game 6!
Because users are already able to enter messages using
the Ctrl-E hotkey, your code will usually set this value
to FALSE.
The remaining parameters correspond to the structure used
by printf() and od_printf().
EXAMPLE I use the following code if a new player decides not to
join Iron Ox:
if (ans == 'H')
{
od_printf("\n\r\nOh, well, if you change your mind, "
"you know where to find the launching pad.\n\r");
pause();
SendMessage(DEST_ALL_NODES, od_control.user_name, 0, FALSE,
"%s decided Ox looked too tough.", od_control.user_name,
od_control.od_node);
od_exit(10, FALSE);
}
To maintain compatibility with ODoors 4.10, you could use
conditional compilation so that SendMessage() will only
be called in your OS/2 version:
#ifdef __OS2__
SendMessage(DEST_ALL_NODES, od_control.user_name, 0, FALSE,
"%s decided Ox looked too tough.", od_control.user_name,
od_control.od_node);
#endif
REGISTRATION
Doors/2 is distributed as an add-on for OpenDoors. I created Doors/2 by
adding to and modifying Brian Pirie's source to support a new
environment.
For this reason, registration for Doors/2 is only available to people
who have a source registration for OpenDoors. I have included a copy of
the registration form for OpenDoors as ODSORDER.FRM. Remember: before
I can send you your registration for Doors/2, I am required by law to
verify that you have purchased a *full source registration* to
OpenDoors!
Registration for Doors/2 costs US$50.00. Registration entitles you to
use Doors/2 in any of your programs without royalties. You will also
receive complete source to the Doors/2 library. You may modify and
recompile this source in any way you like. (You may not distribute
modified versions of the library, except as part of executable door
programs, without my permission.) When new versions of Doors/2 become
available, you will be entitled to an updated version of the source (see
below for details).
EARLY REGISTRATION DISCOUNT: If you register your copy of Doors/2
before December 31, 1994, you will qualify for a discount of US$15.00
off the standard registration price of $50.00. In other words,
registration will only cost US$35.00!
PLACING YOUR ORDER AND UPDATING YOUR SOURCE
To order Doors/2, fill out the order form contained in REGISTER.FRM and
mail it, along with a check or money order for the correct amount, to:
Joel Downer, 4431 Parks Avenue #2, La Mesa, CA 91941-6166.
Please note: I require that checks or money orders be made in United
States funds drawn on United States banks. While I want to be as
accommodating as possible, checks that are not in U.S. funds or that are
drawn on foreign banks can cost US$10.00 or more for me to process, so I
will not accept them.
When I receive your registration and have verified that you are already
a registered owner of OpenDoors, I will send you a registration package
including (1) a library version of Doors/2 without the "unregistered
evaluation -- illegal to distribute" message, and (2) a complete copy of
the Doors/2 source code. You may choose to receive your registration in
any of the following ways:
(1) Fidonet crashmail: If you run a Fidonet BBS in North America, I
can transmit your registration package to you via Fido crashmail
file attachment. I am willing to crashmail orders outside of North
America, but to call outside North America I require an additional
fee of US$15.00 to cover long-distance charges.
(2) Conventional mail: If you prefer, I can transmit your registration
package on a 3-1/2" or 5-1/4" diskette (your choice) through
conventional mail. Sorry, but I'm unable to offer accelerated
shipping (next-day air, etc.) under any circumstances.
(3) BBS Login: If you have no Fidonet address but are in a hurry to get
your registration package, you can arrange to log into my BBS to
download your registration package. Please be sure to fill out the
required login information on the registration form (i.e., password,
date of birth)! When I receive your registration, I will create an
account for you so that you can pick up your package on one call.
Once you have received your registration package, you will be entitled
to receive updates to the library upon request, in any of the following
ways:
(1) On request, I will put the files on hold for you to pick up via a
Fidonet poll (you must be a nodelisted sysop),
(2) You may mail me a self-addressed, stamped envelope and diskette, or
(3) You may ask me to attach the files to a personal message to you on
my BBS (I ask that you already have an account on my BBS when you
make this request).
ADDITIONAL LICENSE INFO
You are allowed (and encouraged) to distribute unmodified copies of
the shareware version of Doors/2 so long as you distribute the complete
archive with all files intact. You may include unmodified, complete
archive versions of the shareware edition of Doors/2 in software
collections (e.g., CD-ROMs) so long as the documentation for the
collection clearly indicates that it contains shareware products and
that the purchase of the collection does not constitute a license for
the use of said products.
Distribution of the registered version of Doors/2 (the source to the
library and the registered version of the library) is strictly
prohibited. Distribution of programs developed with the unregistered
version of the library is also prohibited. Registered users may
distribute programs developed with modified versions of Doors/2, but may
*not* distribute modified versions of Doors/2 in reusable (library)
form.
Your registration is good for all future releases of Doors/2: you will
be entitled to obtain a new copy of the library source by any of the
means listed above.
Registrations are non-transferrable without my direct permission.
SUPPORT
I am committed to supporting and improving this product. Please feel
free to contact me with questions, problems, or suggestions.
I can be reached via the Internet as joel@dreamcty.jd.com. For those
with Internet access, this approach may provide the fastest and most
reliable method of asking questions, reporting problems, or providing
feedback except Fidonet crashmail.
I can be reached via crashmail or routed netmail at Fidonet 1:202/704
and 1:202/705, and at DoorNet 75:7619/7.
The support BBS for Doors/2, and for all other software by Joel Downer,
is The Dreaming City. The Dreaming City has two lines:
Node 1: USR Dual HST 14.4/ v.32 9600 (619) 462-8406
Node 2: ZyXEL 16.8 v.32bis (619) 462-7146
The latest shareware version of Doors/2 will always be available for
first-call download on this system and for FREQ as DOORS2 from 1:202/704
and 1:202/705. I will also have ODOORS41.ZIP available as long as
Doors/2 is based on it (Magic Name: OD4), and the latest version of
OpenDoors (Magic Name: ODOORS).
I monitor the Fidonet OPENDOORS echo for personal mail. I will attempt
to reply promptly to echo messages, email and netmail messages, and
messages in the DOORS2 support conference on my BBS.
FUTURE PLANS
I regularly update my door development tools as I develop versions of
Iron Ox and other doors. While I can't make guarantees about future
versions, here are some of the features I'm considering for future
versions of Doors/2:
* OpenDoors 5.00 compatibility
As of this writing (September, 1994), OpenDoors 5.00 has just been
publicly released. I am already working on converting this library
for 5.00 compatibility.
* Multicompiler support
As an adjunct to the 5.00 port, I am also working on converting this
library to support multiple compilers. Both 5.00 compatibility and
support for several popular compilers are targeted goals for wide
beta 2.
* "Reverse compatibility"
This version of Doors/2 includes a number of (optional) features that
don't appear in OpenDoors (e.g., internode messaging, secure mode). I
already have code to duplicate these features for DOS using OpenDoors
4.10; I am considering updating this code for OD 5.00, bundling it
into libraries, and making them available to registered Doors/2 users.
* Stronger Wildcat! Support
I am considering including support for the WC 3.x USERINFO.DAT file
and the WC 4.x USERREC.BIN files in future versions. These are the
dropfiles read back by Wildcat, so they are required for time banks
and other Wildcat utility doors.
Your feedback will help me decide which of these features (and which
features not listed here) will appear in future versions!