home *** CD-ROM | disk | FTP | other *** search
/ World of Shareware - Software Farm 2 / wosw_2.zip / wosw_2 / CPROG / FORMGE.ZIP / READ.ME < prev    next >
Text File  |  1989-04-20  |  26KB  |  538 lines

  1. /*=========================================================================*/
  2.                  Formgen   -- a C language form generator
  3. /*=========================================================================*/
  4.  
  5.                                  Overview
  6.  
  7.  Formgen is a tool which lets you interactively create a data entry form
  8.  for use with C software applications. It generates three C functions for
  9.  you automatically:
  10.  
  11.              (1) a display-the-form function
  12.              (2) a fill-the-form function
  13.              (3) an edit-the-form function (for data entry)
  14.  
  15.  You may then incorporate these functions into your own programs, edit
  16.  them, chain them, add special features, etc..
  17.  
  18.  To help convert "old" screens to C, a simple screen capture program has
  19.  been included (capture.com).  This is a pop-up utility (written in
  20.  Pascal--source available) which allows you to run another program and
  21.  "capture" its screens to a text file.  You can then edit the text file and
  22.  isolate the individual screens.  If you feed Formgen a text file
  23.  containing a captured screen (limit: 20 lines), it will accept that as its
  24.  working form and allow you to add fields, etc.. (saving time and effort!)
  25.  
  26.  Note that Formgen's work files are simple ASCII text files, which permits
  27.  you to edit them yourself (or feed Formgen a captured screen, as described
  28.  above).  Beware, however-- if you edit a form which contains field
  29.  information, you must not disturb the line sequence.  The first 20 lines,
  30.  for example, represent the text of the form itself.  This is followed by
  31.  color, parameter, and field variable information.  Take a look at the
  32.  "saveform" function in Formgen for a rundown of the actual sequence the
  33.  data file must adhere to.  Position is important!
  34.  
  35.  
  36.                                  Ownership
  37.  
  38.  Formgen and its associated support files (iolib and ioed) have been
  39.  contributed to the PUBLIC DOMAIN by their author (John Queern -- that's
  40.  me).  You may use them for whatever you like.  But please don't sell them
  41.  to others, since they're free.  This is also an excuse for not doing a
  42.  better job documenting the programs.  Oh, well. Figuring out what you can
  43.  get away with is half the fun, right?
  44.  
  45.  
  46.                               Files Included
  47.  
  48.  The archive or diskette which you have received should contain the
  49.  following files:
  50.  
  51.     CAPTURE.COM - the screen capture utility
  52.  
  53.     DOSTEST.C   - a "short" demo screen (uses iolib, but not ioed)
  54.     DOSTEST.PRJ
  55.  
  56.     DOTEST.C    - a slightly longer demo screen (same as STEST, but
  57.     DOTEST.PRJ    adds an ioed edit box--which costs another 9K);
  58.                   illustrates one example of each standard data type (char,
  59.                   int, float, string, and ed)
  60.  
  61.     FORMGEN.C   - formgen source (also uses iolib and ioed)
  62.     FORMGEN.PRJ
  63.  
  64.     IOED.C      - ioed source (the "editor-in-a-box" add-on to iolib)
  65.     IOED.H
  66.  
  67.     IOLIB.C     - iolib source (the "get" functions, buffered screen
  68.     IOLIB.H       routines, etc. -- more later...)
  69.  
  70.     STEST.C     - STEST screen generated by Formgen
  71.     STEST.FRM   - STEST Formgen work file (try "formgen stest" to play
  72.                   with it yourself)
  73.  
  74.     TEST.C      - TEST screen code generated by Formgen
  75.     TEST.FRM    - TEST Formgen work file
  76.  
  77.  
  78.                              Compiling Formgen
  79.  
  80.  To compile Formgen, use the Turbo C project file included.  This will
  81.  cause iolib and ioed to be linked into the Formgen executable.  If you
  82.  wish to use another C compiler (no guarantees...) just be sure to link
  83.  with iolib and ioed, since they are required by Formgen.  This version of
  84.  Formgen is rather PC-specific (for performance reasons), but could be
  85.  fairly easily modified (or watered down?) for other systems.
  86.  
  87.  
  88.                          Support File Assumptions
  89.  
  90.  The functions which Formgen creates assume the use of iolib.obj for simple
  91.  data entry routines and screen buffering, and ioed.obj for the
  92.  "editor-in-a-box"  (if used).  It should be relatively easy to change the
  93.  program to use your choice of libraries (if you don't like mine). The
  94.  public domain distribution file includes source for all three modules
  95.  (formgen, iolib and ioed) so that you can customize them as you wish.
  96.  TEST and STEST illustrate simple forms, and DOTEST/DOSTEST illustrate
  97.  simple programs which use the forms.
  98.  
  99.  
  100.                             Full Screen Editor
  101.  
  102.   Formgen's built-in editor lets you compose your form by moving the cursor
  103.   around the screen using PC cursor keys and WordStar-like commands (this
  104.   is actually the "editor-in-a-box", which is included in the "ioed"
  105.   module, and which you can include as a data field on your own forms):
  106.  
  107.   ╔═════════════════════════════════════════════════════════════════════╗
  108.   ║     EDIT COMMANDS:                                                  ║
  109.   ║                             F1 - show this help screen              ║
  110.   ║                             Home - goto line 1, column 1            ║
  111.   ║           ^e                PgUp, ^r - goto top                     ║
  112.   ║                             PgDn, ^c - goto bottom                  ║
  113.   ║            ^                End, ^w  - save changes, exit           ║
  114.   ║            |                Ins, ^v  - toggle insert mode           ║
  115.   ║            |                Del, ^g  - delete one character         ║
  116.   ║    ^s <----o----> ^d        Tab, ^i  - goto next tab position       ║
  117.   ║            |                ^y  -  delete line                      ║
  118.   ║            |                ^z  -  blank everything                 ║
  119.   ║            v                ^t  -  delete word right                ║
  120.   ║                             ^a/^f  -  advance word left/right       ║
  121.   ║           ^x                ^qs/^qd - goto beginning/end of line    ║
  122.   ║                             ^n  -  insert line                      ║
  123.   ║     Cursor Movement         ^b/^u, F7/F8 - generate/erase a box     ║
  124.   ║    (or use cursor keys)     F6 - change box character set           ║
  125.   ║                             F9/F10 - horiz/vert line draw/erase     ║
  126.   ║    Note: ^ = hold Ctrl                                              ║
  127.   ╚═════════════════════════════════════════════════════════════════════╝
  128.  
  129.  
  130.                                Function Keys
  131.  
  132.   Function keys F1 through F10 also perform specific tasks, as outlined at
  133.   the bottom of your entry screen:
  134.  
  135.                                 End/
  136.    F1      F2     F3     F4      F5     F6      F7      F8      F9     F10
  137.   =====  =====  ====== ======  ======  =====   =====   =====   =====  =====
  138.   Help | Field| Color | Parms | DONE | SelBx | MkBox | ClrBx | HLine | VLin
  139.  
  140.   F1 - will display the editor help screen (shown above)
  141.  
  142.   F2 - will (a) create a data field at the current cursor position, or
  143.             (b) edit the data field that's already at that position
  144.  
  145.        You will be presented with a pop-up form (created by Formgen,
  146.        incidentally) to fill in the field specifics:
  147.  
  148.     ╓─────────────────────────────────────────────────────────────────────╖
  149.     ║    Variable Name:  customer_name                                    ║
  150.     ║    Field Width:    30            Decimals:                          ║
  151.     ║    Data Type:      s                                                ║
  152.     ║    Display Command:  gotoxy(#X,#Y); cprintf(\"%-#Ws\",#N);          ║
  153.     ║    Entry Command(*): rcode = getstring(#X,#Y,&col,#N,#W);           ║
  154.     ║                                                                     ║
  155.     ║    (*) leave blank if no entry allowed                              ║
  156.     ║    Special Sequences: #X, #Y -- insert screen row, column           ║
  157.     ║                       #N     -- insert variable name                ║
  158.     ║                       #W, #D -- insert width, decimals              ║
  159.     ╙─────────────────────────────────────────────────────────────────────╜
  160.  
  161.        Standard data types included are:
  162.  
  163.             c   - char
  164.             i   - int
  165.             f   - float
  166.             s   - string
  167.             ed  - edit buffer (the editor-in-a-box)
  168.  
  169.        You can add your own standard data types in Formgen, or simply enter
  170.        them as you create your forms.  If a data type is standard (or
  171.        already used on this form), Formgen will automatically fill in the
  172.        Display and Entry command templates for you.  Otherwise, you'll have
  173.        to enter them yourself (more later..)
  174.  
  175.   F3 - will bring up a "color selection" form. Formgen's color capabilities
  176.        are somewhat primitive (in an effort to make more compact screens).
  177.        You may choose a background color (or NOCLEAR, indicating that this
  178.        form should "pop up" over the existing screen as an additional
  179.        "window"), a form color (assuming you have a box around your form--
  180.        otherwise, this may not look good), and color combos for fill and
  181.        edit (normally the same). The color selection form looks like this
  182.        (and was also created using a (previous) version of Formgen):
  183.  
  184.     ╔═══════════════════════════════════════════════════════════════════╗
  185.     ║ SCREEN  (for initial screen clear, or NOCLEAR to avoid clearing)  ║
  186.     ║ Foreground:  NOCLEAR             Background:                      ║
  187.     ╠═══════════════════════════════════════════════════════════════════╣
  188.     ║ FORM                                                              ║
  189.     ║ Foreground:  WHITE               Background:  BLUE                ║
  190.     ╠═══════════════════════════════════════════════════════════════════╣
  191.     ║ FIELD FILL                                                        ║
  192.     ║ Foreground:  BLUE                Background:  LIGHTGRAY           ║
  193.     ╠═══════════════════════════════════════════════════════════════════╣
  194.     ║ FIELD EDIT   BLUE                                                 ║
  195.     ║ Foreground:                      Background:  LIGHTGRAY           ║
  196.     ║           NOTE: use CAPITAL LETTERS for color names               ║
  197.     ╚═══════════════════════════════════════════════════════════════════╝
  198.  
  199.        You can use any of the color names which are declared in Borland's
  200.        conio.h header file.  Notice that all color names are upper case
  201.        (since they represent constant definitions).  Also: don't try to use
  202.        "light" colors for the background, since that will cause blinking.
  203.        Experiment!
  204.  
  205.   F4 - will bring up a "parameter" form. This is where you specify the
  206.        names of the three C functions which will be generated, and their
  207.        header information. You will also specify the video buffer number
  208.        to use (0..9), in case you want to reserve a specific buffer for
  209.        this screen so that you can avoid rewriting it over and over (talk
  210.        about fast-- once the screen is loaded, just use restorescreen(n),
  211.        and in a split second it'll be there...)
  212.  
  213.  ╔══════════════════════════════════════════════════════════════════════════╗
  214.  ║   FUNCTION NAMES                                                         ║
  215.  ║     (omit parameter list for Display fncn, (void) will be assumed)       ║
  216.  ║   Display:  displayme                                                    ║
  217.  ║   Fill:     fillme(struct MYREC *m)                                      ║
  218.  ║   Edit:     editme(struct MYREC *m)                                      ║
  219.  ╠══════════════════════════════════════════════════════════════════════════╣
  220.  ║   Screen Buffer to use:                                                  ║
  221.  ║   (0-9)     0                                                            ║
  222.  ╠══════════════════════════════════════════════════════════════════════════╣
  223.  ║   EXTRA LINES (added to top and/or bottom of fill and edit functions)    ║
  224.  ║   First:                                                                 ║
  225.  ║   Last:                                                                  ║
  226.  ╠══════════════════════════════════════════════════════════════════════════╣
  227.  ║   EXTRA LINES (added to the end of the display function)                 ║
  228.  ║   1:                                                                     ║
  229.  ║   2:                                                                     ║
  230.  ║                                                                          ║
  231.  ╚══════════════════════════════════════════════════════════════════════════╝
  232.  
  233.  
  234.   F5 - DONE. (You may also use End or ctrl-W for this). Formgen will ask
  235.        you whether you wish to generate code now (with options to send the
  236.        output to the Screen, Printer or File), allow you to resume editing
  237.        if you wish, or quit and save your workfile.
  238.  
  239.   F6 - Select Box Type.  This lets you choose which set of box characters
  240.        to use when drawing boxes and lines.  You can mix different kinds
  241.        of boxes if you like. Your box selection will remain current for
  242.        this session only--or until you change it by pressing F6 again:
  243.  
  244.                    ╔══════════════════════════════════╗
  245.                    ║  Box Character Selection:        ║
  246.                    ║                                  ║
  247.                    ║               ┌───┐              ║
  248.                    ║  a. single    │╔═══╗             ║
  249.                    ║  b. double    └║╒═══╕            ║
  250.                    ║  c. sing/doub  ╚│╓───╖           ║
  251.                    ║  d. doub/sing   ╘║+---+          ║
  252.                    ║  e. ascii        ╙|░░░░░         ║
  253.                    ║  f. half1         +░▒▒▒▒▒        ║
  254.                    ║  g. half2           ▒▓▓▓▓▓       ║
  255.                    ║  h. half3            ▓█████      ║
  256.                    ║  i. solid             █████      ║
  257.                    ║                                  ║
  258.                    ║  Selection (a-i)?                ║
  259.                    ║                                  ║
  260.                    ╚══════════════════════════════════╝
  261.  
  262.  
  263.   F7 -  Make box. (Ctrl-B can also be used)  This command will draw boxes
  264.         for you, using the box char set selected via F6 (which defaults to
  265.         single line boxes).  To draw a box, move the cursor to the upper
  266.         left hand corner position and press F7.  An "<in box>" flag should
  267.         appear on the status line (toward the bottom of the screen).  Now
  268.         move the cursor to the lower right hand corner position and press
  269.         F7 again.  Formgen should draw a box using the corners you have
  270.         specified.  Note that this is a "dumb" box, and will not worry
  271.         about making pretty intersections with other lines or boxes.
  272.  
  273.   F8 -  Clear box. (Ctrl-U can also be used).  Use this when you don't like
  274.         the box produced above. Once again, move the cursor to the upper
  275.         left hand corner and press F8 (or ctrl-U).  Now move the cursor to
  276.         the lower right hand corner and press F8 again.  The box will be
  277.         replaced with blanks so that you can try again.
  278.  
  279.   F9 -  Horizontal line.  I borrowed this idea from an old public domain
  280.         CP/M dBase utility called Zip (remember that?)  Move your cursor
  281.         to the leftmost position of a horizontal line which you'd like to
  282.         draw, and press F9.  Formgen will draw a line, and (hopefully) make
  283.         the appropriate intersections with existing boxes and lines.  Want
  284.         to cut the line short? Position the cursor to the leftmost position
  285.         that you want to clear, and press F9 again. Formgen should erase
  286.         everything from this position to the right, and fix up any
  287.         connections needed.
  288.  
  289.   F10 - Vertical line.  This works like F9, but does a vertical line. Move
  290.         the cursor to the top of a desired line and press F10.  To clip the
  291.         line off at some point, move the cursor to the first position to be
  292.         removed and press F10 again.
  293.  
  294.         Experiment with F7-F10 a bit, and you'll quickly learn how to
  295.         create complex box forms (anything like complex life forms?) to
  296.         your liking.  You may also find some combinations that don't work
  297.         right. If so, drop me a line (try CompuServe 70120,107 or call my
  298.         humble local BBS at 618-277-1162), and I'll try to fix 'em.
  299.  
  300.  
  301.                           More About Data Fields
  302.  
  303.  Data entry "field" types have been generalized so that you can add new
  304.  field types easily. A data field description structure is used to describe
  305.  each "standard" data format and provide default "get" and "say" command
  306.  templates for the display and edit screens:
  307.  
  308.         struct FIELDTYPE {
  309.             char    descr[20];          e.g., "i" for integer
  310.             char    *saycommand;        default display command template
  311.             char    *getcommand;        default edit command template
  312.         }
  313.  
  314.   Special codes which may be used in "say" and "get" command templates:
  315.  
  316.                 #X, #Y  - insert screen coordinates here
  317.                 #N      - insert variable name here
  318.                 #W      - insert width here
  319.                 #D      - insert decimals here
  320.  
  321.   Note: X and Y are integer values which are automatically generated for
  322.   you based on screen position. The rest are all strings, and may actually
  323.   be used for anything useful. For example, our "ed" field type (the
  324.   editor-in-a-box) uses #D to represent the number of lines in the edit
  325.   window.
  326.  
  327.   Sample "standard" data types with their default "say" and "get"
  328.   templates:
  329.  
  330.     "c",    "gotoxy(#X,#Y); cprintf(\"%c\",#N);",         /* char     */
  331.             "rcode = getachar(#X,#Y,&#N);",
  332.  
  333.     "s",    "gotoxy(#X,#Y); cprintf(\"%-#Ws\",#N);",      /* string   */
  334.             "rcode = getstring(#X,#Y,&col,#N,#W);",
  335.  
  336.     "i",    "gotoxy(#X,#Y); cprintf(\"%#Wd\",#N);",       /* integer  */
  337.             "rcode = getint(#X,#Y,&#N,#W);",
  338.  
  339.     "f",    "gotoxy(#X,#Y); cprintf(\"%#W.#Dd\",#N);",    /* float    */
  340.             "rcode = getfloat(#X,#Y,&#N,#W,#D);",
  341.  
  342.     "ed",   "redraw((char *)#N,#X,#Y,#W,#D);",            /* box editor */
  343.             "rcode=edit((char*)#N,#X,#Y,&xp,&yp,#W,#D);",
  344.  
  345.  
  346.   When you create an actual entry field on a screen, formgen keeps track of
  347.   it in a VARTYPE record (which you will fill in when you create the
  348.   variable):
  349.  
  350.         struct VARTYPE {
  351.             char    type[21];       data type (may match FIELDTYPE entry)
  352.             char    name[31];       name of this one
  353.             char    width[7];       width of field
  354.             char    decimals[7];    decimals (or lines, if "ed")
  355.             char    saycomm[46];    actual say command for this var
  356.             char    getcomm[46];    actual get command for this var
  357.             int     x,y;            position on screen (where token placed)
  358.             int     flagnum;        flag number on screen
  359.         }
  360.  
  361.   The presence of a data entry field is marked on the form using a graphic
  362.   icon which signifies the anchor point for the entry field (normally, the
  363.   left side or upper left hand corner), followed by the field table index
  364.   value for the entry.  The field table is kept updated to reflect current
  365.   screen positions.
  366.  
  367.  
  368.               APPENDIX: Functions included in iolib and ioed:
  369.  
  370. /*=========================================================================*/
  371.         iolib.c   -- library of i/o functions for use from Turbo C
  372. /*=========================================================================*/
  373.  
  374. char *strdel(char st[],int start,int count);
  375.     Deletes <count> characters beginning at <start> position in st.
  376.  
  377. int nonblank (char *st);
  378.     Returns TRUE if st is not empty or blank, FALSE otherwise.
  379.  
  380. void stub(void);
  381.     Makes a sound (warble) to indicate error or missing function (stub).
  382.  
  383. void binit(int buff);
  384.     Initializes video buffers 0-buff. Buff identifies how many buffers to
  385.     allocate (maximum currently 10).  This will be called automatically by
  386.     the other iolib functions if needed.
  387.  
  388. void savescreen(int i);
  389.     Copy the current (actual) screen contents to buffer i.  Each screen is
  390.     saved as a 4000-character block consisting of attribute bytes and
  391.     character information in the same format as they appear on the physical
  392.     (CGA) screen.
  393.  
  394. void restorescreen(int i);
  395.     Copy the contents of buffer i to the physical screen. If you have saved
  396.     a previous screen, this will restore it.  Or if you have built a form
  397.     in buffer i (using Formgen-generated code), this will display it
  398.     immediately.
  399.  
  400. void copyscreen(int i,int j);
  401.     Copy a screen image from buffer i to buffer j.
  402.  
  403. void bclear(int b);
  404.     Clear buffer b in preparation for a sequence of bwrite statements. This
  405.     will set all of the attribute bytes to the current bfore and bback
  406.     (foreground and background) colors, and blank all of the character
  407.     information.
  408.  
  409. void bwrite(int b,int x,int y,char st[]);
  410.     Write string st[] to buffer b, starting at position (x,y).
  411.  
  412. void border(int color);
  413.     Set CGA border color (this is a holdover from the old days).
  414.  
  415. void pad(char st[],int len);
  416.     Pad string st with blanks until its length matches <len>. This is used
  417.     to expand entry fields to their full width before displaying them on
  418.     the form.
  419.  
  420. void trim(char st[]);
  421.     Trim trailing blanks (and \n's) off of string st.  This is the inverse
  422.     of pad.  It's also useful when reading string information using fgets.
  423.  
  424. void lcase(char st[]);
  425.     Convert all characters in string st to lower case.
  426.  
  427. int getstring(int x,int y,int *c,char st[],int len);
  428.     This is the generic "get a string" function, which includes internal
  429.     WordStar-like line editing commands, etc.. Positions the cursor in
  430.     a field which begins at coordinates (x,y) on the screen, but in column
  431.     c. If c=0, the cursor will be positioned at the beginning of the field.
  432.     Getstring updates the value of c so that the calling program knows what
  433.     column the user was in when exiting (this allows ioed to build a
  434.     full-screen editor around calls to getstring). String st[] is the
  435.     buffer which contains any initial value--and in which to return any
  436.     changes.  len defines the allowable width of the entry field.
  437.  
  438. int getint(int x,int y,int *i,int w);
  439.     Integer entry routine. Calls getstring, but converts the result to an
  440.     integer. The entry field should begin at coordinates (x,y), the initial
  441.     value should be in *i (which will also receive the returned value), and
  442.     the field width should be in w.
  443.  
  444. int getachar(int x,int y,char *ch);
  445.     This routine gets a single character.
  446.  
  447. int getfloat(int x,int y,float *f,int w,int d);
  448.     This routine gets a float using a format of %w.df
  449.  
  450.  
  451.               /* iolib public definitions and declarations */
  452.  
  453. #define TRUE  1
  454. #define FALSE 0
  455.  
  456. typedef unsigned char vscreen[4000];
  457. typedef vscreen  *vptr;
  458.  
  459. extern vptr     sbuff[10];          /* screen buffers */
  460. extern char     monochrome;         /* mono/cga flag */
  461. extern char     insert;             /* insert/overwrite mode flag */
  462. extern int      insertx,inserty;    /* location of insert/overwrite message */
  463. extern int      colx,coly;          /* location of column info, if present */
  464. extern int      trimblanks;         /* make true for getstring to trim blanks */
  465. extern int      colons;             /* make true for getstring to use colons */
  466. extern int      nobeep;             /* make true to suppress end-field beep */
  467. extern int      bfore,bback;        /* buffer foreground, background colors */
  468.  
  469.  
  470.                                Return Values
  471.  
  472.  The following return values are used by each of the "get" routines,
  473.  and (to some extent) by edit(). They are based on the keystroke which the
  474.  user employed to exit the get function:
  475.  
  476.     0:    CR, original entry changed
  477.     1:    CR, original entry unchanged
  478.     2:    Esc
  479.     3:    up arrow, ctrl-e
  480.     4:    left arrow, ctrl-s
  481.     5:    right arrow, ctrl-d
  482.     6:    down arrow, ctrl-x
  483.     7:    ctrl-w
  484.     8:    End
  485.     9:    PgUp, ctrl-r
  486.    10:    PgDn, ctrl-c
  487.    11-20: F1..F10
  488.    21:    ctrl-y
  489.    22:    ctrl-z
  490.    23:    ctrl-n
  491.    24:    Home
  492.    25:    ctrl-b
  493.    26:    ctrl-u
  494.  
  495.  
  496. /*=========================================================================*/
  497.             ioed.c   -- the "editor in a box" addition to iolib
  498. /*=========================================================================*/
  499.  
  500. void do_help (void);
  501.  
  502.     This routine displays the help screen illustrated above.
  503.  
  504. void redraw (char *edscreen,int sx,int sy, int wid, int lines);
  505.  
  506.     This routine redraws the edit buffer--or displays it initially.
  507.     edscreen should be a pointer to your buffer, (sx,sy) are the screen
  508.     coordinates of the upper left hand corner of the edit box, wid is the
  509.     width of the box, and lines is the number of lines in the box.
  510.     Be sure your buffer contains at least (wid+1)*lines bytes.
  511.  
  512. int  edit (char *edscreen,int sx,int sy, int *px, int *py, int wid,
  513.    int lines);
  514.  
  515.     This is the editor-in-a-box. Parameters are the same as redraw,
  516.     except for the addition of px and py, which identify the current
  517.     relative position (x,y) within the edit box. These values are updated
  518.     and returned to the calling program, allowing you to process special
  519.     keys outside of edit(), then return to the same position to continue
  520.     editing.  Formgen uses this capability in main().
  521.  
  522.  
  523.                                 Conclusion?
  524.  
  525.     That's about it.  At least enough to get you started.  If you have any
  526.     neat ideas for improving this tool, let me know.  And if you enhance it
  527.     yourself, please keep it in the public domain.
  528.  
  529.     Interested in other free tools? I am. Let's exchange info. I'm working
  530.     on a template-driven code generator and a Jackson-style front end as
  531.     part of another project (we have a working version, but are trying to
  532.     make it better).  Your ideas are welcome!
  533.  
  534.  
  535.     John Queern, Belleville IL
  536.     CIS 70120,107
  537.     BBS: 618-277-1162
  538.