Porting WWIV 4.23 to FreeBSD UNIX
Robert N. M. Watson
In January, 2007, I spent a weekend porting WWIV 4.23, based on a source
license from 1995, to FreeBSD 6.2.
These notes describe what's involved in doing this.
As the WWIV 4.x source code is not open source, I cannot redistribute the
patches, but I can provide supplemental DOS and BIOS compatibility source
that anyone wanting to replicate this can use.
I ported the basic WWIV structure, including the communications and display
libraries, user system, message bases, g-files, e-mail, transfers, and so on.
I made no attempt to deal with external programs, such as doors, WWIV
networking, external events, and external transfer protocols.
By the end of the weekend, I was able to log in locally and via FreeBSD's
synthetic NULL modem device driver, read e-mail, messages, and so on.
This port is hardly complete, but as proof of concepts go, it's not shabby.
Premature Optimism
Discovered while perusing posts from my BBS message boards using the FreeBSD
port of WWIV:
47/50: Port to UNIX
Name: Star Gazer #1 @3101
Date: Sat Nov 19 22:21:27 1994
I'm currently in the process of porting WWIV to Unix so I can switch to a free 
implementation of BSD (eg., FreeBSD 2.0 when released.)  If anyone out there 
has experience with Unix/C (and BSD style socket access) and is interested in 
helping out, please let me know.  Email rwatson@sidwell.edu, or autoreply to 
this mail and I can email you source and access information.
Thanks..
                       陳陳様様様- Star Gazer -様様様陳陳
I meant well, but never got much further than that e-mail.  However, this does
illustrate an early interest in FreeBSD!
Screenshots
No software port is complete without the a few screenshots.  These images
were captured using ksnapshot running on FreeBSD 7.x, with WWIV 4.23 running
over the synthetic null modem device (nmdm).  Click to view the full-size
capture.
WWIV 4.23
WWIV is written in relatively portable Borland C code, but relies on the
availability of a variety of system functions and libraries present in the MS
DOS and Borland C programming environments.  These include DOS APIs for file
system access, BIOS functions for screen management, and direct hardware I/O
for serial port access.  To get WWIV running on FreeBSD, I had to provide
support routines to emulate these services based on natively available
services, such as POSIX I/O routines, ncurses, etc.  There are also some C
language differences that must be adapted to, and in some cases papered over.
Why not just use WWIV 5.0, the open source C++ offspring of WWIV 4?  Well, I
have a WWIV 4.23 install already, and am, at heart, a C programmer, not a C++
programmer.  However, you can learn more about WWIV 5 on its sourceforget.net web
page.
New Files (DOS, BIOS compatibility)
New files created during the port, under a BSD license:
- borland.h - Functions and definitions from
  Borland C not found in most UNIX environments
- cons.h - Abstracted ncurses interface to resemble
  functions implemented by video BIOS
- dos.h - Functions and definitions for DOS library
  calls
- emul.h - General functions for setting up the DOS
  and BIOS emulation environment
- my_bios.c - Implementation of some BIOS and
  hardware functionality
- my_borland.c - Implementation of Borland
  library functions
- my_com.c - Implementation of WWIV communications
  API using UNIX ttys
- my_cons.c - Implementation of simple BIOS video
  functions using ncurses
- my_dos.c - DOS library functions wrapped around
  POSIX, mostly file access
- my_emul.c - Infrastructure and setup for emulation environment
Porting WWIV to UNIX in 10 Easy Steps
  - -1. Rename all source files to be all lower-case. 
- 
    This is UNIX. 
- 0. Create a makefile 
- 
    The shipped makefiles are not useful as a starting point, create new
      ones. 
- 1. C language changes 
- 
    
     
    - Remove all "#pragma hdrstop" statements; these are a Borland C
      compiler performance optimization and to not apply with gcc.  Likewise
      other #pragma statements.
- Rename WWIV 'yn()' function to 'yesno()' to avoid collision with then
      yn(3) floating point function.
- #define far, interrupt, and huge to nothing, since they don't apply.
      
- #define farmalloc() and farfree() to POSIX equivilents.
- Remove references to farcoreleft(), which returns the amount of free
      memory available in the Borland C runtime environment.  This was purely
      advisory.
- Eliminate or otherwise ignore all code relating to overlays, which
      are not required.
- Fix certain printfs, sprintfs, etc.  For example, gcc doesn't like
      format strings specifying decimal points for longs.
- Cast arguments to time(3) to (time_t *), not (long *).  Similar
      time_t related changes elsewhere.
- Provide our own OFFOF() macros to replace use of FP_OFF(), since far
      pointers don't exist in UNIX-land.  This sort of expression comes in
      handy: #define OFFOF(x) ((uintptr_t)(&u.x) - (uintptr_t)(&u))
- Replace dubious casts of data structure types to pointer casts.  For
      example, replace: "&(type)variable" with: "(type *)&variable".
      
- Replace "random(x)" with "(random() % x)".  Initialize the random
      number generator with srandomdev() rather than randomize().
- Modern compilers and systems pad structures for alignment reasons;
      Borland C did not.  As WWIV interchangeably uses on-disk and in-memory
      data structure layouts, it's easiest simply to mark all WWIV data
      Structures as __packed in order to eliminate binary incompatibility.
      In particular, look in instmsg.h, net.h, and vardec.h.  This is
      important because the source code for INIT.EXE was not distributed to
      WWIV source licensees, and so there is no way to initialize new BBS
      configuration files without writing a new initialization tool.
- Implement Borland C string functions that don't exist in POSIX/C99:
      gcvt(), itoa(), ltoa(), stricmp(), strupr(), ultoa().
- Implement Borland C non-portable I/O functions getch(), getche().
      
 
- 2. Adjust include files 
- 
    Search for and remove inclusions of: alloc.h conio.h dos.h io.h mem.h;
      In some cases, replace paths, for example sys\stat.h to sys/stat.h. 
- 3. Disable everything relating to printers 
- 
    Search for and #ifdef out references to stdprn and sysconfig_printer.
      Probably this should be replaced with syslog(3) calls. 
- 4. Disable all external programs 
- 
    Do so by hook or by crook; I disabled various shell points, execution
      points, external chat programs, network callouts, external programs,
      etc, using ifdefs. 
- 5. Build a serial port compatibility library 
- 
    
     
    - Rename many functions in com.c to begin with wwiv_ or #ifdef out
      entirely (such as setbeep(), dtr(), etc).
- Implement check_comport(), async_isr(), outcomch(), peek1c(),
      get1c(), comhit(), dump(), set_baud(), initport(), closeport(), dtr(),
      rts(), cdet(), empty() in terms of UNIX ttys.  Implement ring buffer,
      etc, to allow peaking and so on.
 
- 6. Build a BIOS and console compatibility library 
- 
    
     
    - Implement several parallel instances of various functions that invoke
      DOS or BIOS interrupts, including geninterrupt().
- Implement interrupt 0x10 (video BIOS) functions in terms of ncurses,
      including 0x2 (setxy), 0x3 (getxy), 0x6 (scrollup), 0x7 (scrolldown),
      0x9 (putchar), 0xf (getwidth).
- Implement keyboard interrupt 06 function 0x1 (check for key
      hit).
- Implement DOS interrupt routines 0x6 (console I/O), 0x33 (ctrl-break
      handling).
- Implement setbeep() in terms of ncurses.
- Provide peek() and peekb() for video mode, keyboard status, and
      numlock state (sysop available to chat).
 
- 7. Build a DOS compatibility library 
- 
    
     
    - Search through for references to function name and constant conflicts
      between DOS and POSIX.  For example, chdir() to dos_chdir(), mkdir() to
      dos_mkdir(), and open() to dos_open().
- Define _osmajor, _osminor.
- Define struct ftime, struct date, struct time, struct dostime, struct
      ffblk, struct dfree, struct SREGS, struct DWORDREGS, struct WORDREGS,
      struct BYTEREGS, struct REGS.
- Define _S_IWRITE to S_IWUSR, _S_IREAD to S_URUSR.
- Define O_BINARY to 0.
- Define MAXDRIVE, MAXPATH, MAXDIR, MAXFILE, MAXEXT, DRIVE, DIRECTORY,
      FILENAME, EXTENSION, WILDCARDS.
- Define compatibility flags for dos_open() which will be mapped to
      similar UNIX semantics: SH_COMPAT, SH_DENYRW, SH_DENYWR, SH_DENYRD,
      SH_DENYNO.
- Create wrapper geninterrupt(), getvect(), int86(), int86x(),
      setvect().
- Implement DOS library calls: _chmod(), chsize(), delay(),
      dostounix(), filelength(), findfirst(), findnext(), fnsplit(),
      getcurdir(), getdate(), getdfree(), getftime(), getdisk(), gettime(),
      searchpath(), setdisk(), setftime(), unixtodos(), dos_chdir(),
      dos_mkdir(), dos_open().  Also dos_init() to initialize the DOS
      run-time environment.  Among other things, the library calls simulate
      multiple drives pointed at various UNIX paths, and the fact that DOS
      programs have several different simultaneous working directories (one
      per drive).
- Implement interrupt 21h function 0x2a (get time).
 
- 8. Add MT_UNIX to utility.c, comment out various things that can't
    work. 
- 10. Fix lots of random compiling things that aren't meaningful anymore,
    such as attempts to manipulate stack pointers in extrn.c. 
- 
    
    Since we're not implementing external programs or overlays, these can
    basically be ignored. 
Known Issues
There are so many issues it's almost silly to enumerate them, but here are
a few:
- My understanding of ncurses, especially scrolling, is poor, so the
  console login is of limited utility.
- Right now there's no way to set that the sysop is local, so chatting
  doesn't work.
- I did test multi-instance execution, but not much.
- Not being able to run external programs, such as the daily external event
  and networking, is quite a problem.
- You must have an existing WWIV configuration since INIT.EXE source isn't
  available.  It would be easy enough to create one, but I haven't since I
  already have a configuration.
- There are a number of Y2K bugs in WWIV 4.23.
- Certain activities, such as reading the display using direct memory
  access, don't work.  As such, activities that may re-draw the prompt and
  current input, which include requesting help in some contexts, fail.
- Input during the waiting-for-caller screen is unreliable.
Copyright 2007 Robert N. M. Watson