home *** CD-ROM | disk | FTP | other *** search
- // Program: OOED.CPP
- // Progammer: Bruce Ide
- // Date: 3-25-91
- // Language: Turbo C++
- // OS: PC MOS 4.0
- //
- // Description: This is an object oriented data editor which allows the
- // user to edit various data strings in the spirit of DBASE's
- // PIC clause. This set of functions uses such nifty object
- // oriented features such as late binding and multiple
- // inheritance. These classes do not go all the way to
- // forms, though a form editing function or class would
- // be easily created from these classes (I'm working on an
- // interrupt driven system similiar to others on the market.
- // I'll include a form class there, along with some window
- // and button routines.)
-
- // If you're going to compile this file to an OBJ file and just link it
- // (Which will save a lot of time) include the following:
- //#include <dos.h>
- //#include <conio.h>
- //#include <stdio.h>
- //#include <stdlib.h>
- //#include <string.h>
- //#include "useful.hpp"
- //#include "useful.cpp"
- //#include "ooed.hpp"
-
- void KEYSTROKE::GETKEY()
- {
- union SCAN thang;
- union REGS r;
-
- r.h.ah = 0;
- thang.c = int86(0x16, &r, &r) ;
- if (thang.ch[0] == 0)
- {
- special = 1;
- lastkey = thang.ch[1];
- }
- else
- {
- special = 0;
- lastkey = thang.ch[0];
- }
- }
-
-
- // First constructor for ED -- sets up to edit at wherever the cursor
- // is.
-
- ED::ED()
- {
- row = wherey();
- col = wherex();
- }
-
- // Second constructor for ED -- Sets up to edit at a specified row/column
- // (somewhat more useful).
-
- ED::ED(int r,
- int c)
- {
- row = r;
- col = c;
- }
-
-
- // First constructor for EDSTR -- as ed, it sets up to edit the string
- // wherever the cursor is. This will only be useful if you are using
- // the new command to create a new variable of this class at a pointer.
- // Note that this constructor calls ED's constructor to do some
- // dirty work.
-
- EDSTR :: EDSTR(char *str,
- int len) : ED()
- {
- data = str;
- datalen = len;
- curx = wherex();
- cury = wherey();
- loc = 0;
- }
-
- // Second constructor for EDSTR -- Sets up to edit the string
- // at a specified row and column. As the with the first constructor,
- // this one calls ED to do some dirty work.
-
- EDSTR :: EDSTR(int urow, int ucol, char *str, int len) :
- ED(urow, ucol)
- {
- data = str;
- datalen = len;
- curx = ucol;
- cury = urow;
- loc = 0;
- }
-
- // RIGHT -- Moves the cursor 1 space right, and makes sure the location
- // of the cursor and the location in the array are correct. Returns a
- // value so that it can be called recursively if desired.
-
- int EDSTR :: RIGHT()
- {
- loc++;
- if (loc >= datalen - 1)
- {
- loc --;
- return 0;
- }
- curx++;
- gotoxy(curx, cury);
- return 1;
- }
-
- // LEFT moves the cursor left 1 space. See RIGHT
-
- int EDSTR :: LEFT()
- {
- loc--;
- if (loc < 0)
- {
- loc++;
- return 0;
- }
- curx--;
- gotoxy(curx, cury);
- return 1;
- }
-
- // DEL removes a character at the cursor and moves everything beyond the
- // cursor 1 space left. This returns a value in case I should ever need
- // it to, really.
-
- int EDSTR :: DEL()
- {
- register int i;
- int tmpx = curx;
- if (loc > strlen(data)) return 0;
- i = loc;
- while(data[i])
- {
- data[i] = data[i + 1];
- putchar(data[i + 1]);
- i++;
- }
- curx = tmpx;
- gotoxy(curx, cury);
- return 1;
- }
-
- // BKSP is a LEFT plus a DEL. Should you not be able to LEFT, it will
- // NOT DEL.
-
- int EDSTR :: BKSP()
- {
- if (LEFT()) return DEL(); // Now that IS clever :-)
- }
-
- // INS inserts a space at the cursor (DOES NOT GO INTO INSERT MODE!!!)
- // and moves everything right of the cursor 1 space right. Note that this
- // does not work if the field is full (Even if it is just full of spaces.)
-
- // If you prefer to make the insert key go into insert mode, derive a class
- // from this one or a later one and set up a boolean flag insertmode and
- // modify NORMAL and GET so that hitting insert toggles insertmode and
- // whenever insertmode is on, have NORMAL call INS before entering the
- // character. (This probably is not a good idea unless you are building a
- // text editor)
-
- int EDSTR :: INS()
- {
- register int i;
- if (datalen == strlen(data)) return 0; // Don't want to push any data off
- // the side of the field
- if (loc > strlen(data)) return 0;
- i = strlen(data);
- curx = startcol() + i;
- gotoxy(curx, cury);
- while(i != loc)
- {
- data[i] = data[i - 1];
- i --;
- curx--;
- putchar(data[i]);
- gotoxy(curx, cury);
- }
- data[loc] = ' ';
- putchar(data[loc]);
- gotoxy(curx, cury);
- return 1;
- }
-
- // HOME moves the cursor to the first character in the field to edit
-
- int EDSTR :: HOME()
- {
- loc = 0;
- curx = startcol();
- gotoxy(curx, cury);
- return 1;
- }
-
- // END moves the cursor to the last character in the field to edit. Note
- // that if the field is 9 spaces long and there are only 4 spaces filled,
- // END will only move out to 4.
-
- int EDSTR :: END()
- {
- loc = strlen(data);
- curx = startcol() + loc;
- gotoxy(curx, cury);
- return 1;
- }
-
- // Currently, NORMAL will insert any ascii character that is not a movement
- // key -- it will get all control characters and high ascii etc. Revise the
- // function later (in later classes) to be more discriminating (Like, get
- // only numbers or something.) (This is done in EDFANCY)
-
- int EDSTR :: NORMAL()
- {
- register int i = strlen(data);
- while (i < loc)
- {
- data[i] = ' ';
- ++i;
- }
- data[loc] = lastkey;
- putchar(lastkey);
- gotoxy(curx, cury);
- RIGHT();
- return 1;
- }
-
- // get is the driver for all the other functions. It is the function you
- // should modify if you want to change keystrokes to do other things. It
- // mainly consists of a case statement which checks to see what the key
- // pressed should do.
-
- void * EDSTR :: get()
- {
- curx = startcol();
- cury = startrow();
- loc = 0;
- gotoxy(curx, cury);
- while (!INFINITY)
- {
- GETKEY();
- if (special)
- {
- switch(lastkey)
- {
- case LEFTARROW :
- LEFT();
- break;
- case RIGHTARROW :
- RIGHT();
- break;
- case ENDKEY :
- END();
- break;
- case HOMEKEY :
- HOME();
- break;
- case INSERTKEY :
- INS();
- break;
- case DELETEKEY :
- DEL();
- break;
- }
- }
- else
- {
- switch(lastkey)
- {
- case BACKSPACE :
- BKSP();
- break;
- case RETURN :
- return (void *) data;
- default :
- NORMAL();
- break;
- }
- }
- }
- }
-
-
- // EDFANCY - The first (and ONLY) constructor for this class. We have
- // dropped the capability to edit at the cursor row/col, as this class
- // will probably be more concerned with forms. Note that we call EDSTR
- // (Which calls ED) to do some of our dirty work for us.)
-
- // Please note that the mask will be stored in the returned string,
- // so if you give the computer a mask of " / / " and the user types
- // 032691 the returned string will be "03/26/91".
-
- EDFANCY :: EDFANCY(int urow,
- int ucol,
- char *umask,
- char *udata,
- int ulen) : EDSTR (urow,
- ucol,
- udata,
- ulen)
- {
- ERR = 0;
- mask = new char[strlen(umask)];
- if (!mask)
- {
- ERR = 1;
- return;
- }
- strcpy(mask, umask);
- }
-
- // ~EDFANCY -- We need a destructor now to delete the memory we allocated
- // to store mask.
-
- EDFANCY :: ~EDFANCY()
- {
- delete mask;
- }
-
- // onmask returns a 1 if we are on a character we can't type over,
- // or a 0 if we can put a char in this space in the array.
-
- int EDFANCY :: onmask()
- {
- if (ISKNOWN()) return 0;
- return 1;
- }
-
- // onmask is also overloaded to act as mentioned above for any space
- // in the array.
-
- int EDFANCY :: onmask(int where)
- {
- if (ISKNOWN(where)) return 0;
- return 1;
- }
-
- // ISKNOWN returns a 1 if the character in the mask at the passed location
- // is one that we can type on (In this case, a space or a null) in the
- // data field. If it is not, the functions keep the user from typing
- // a character in that space. This function is of more use in later classes,
- // but is placed here to allow late binding to get and other functions.
-
- int EDFANCY :: ISKNOWN(int where)
- {
- if (where > strlen(mask)) return 1;
- if (!mask[where]) return 1;
- if (mask[where] == ' ') return 1;
- return 0;
- }
-
- // ISKNOWN is also overloaded to perform as mentioned above for the
- // current location in the data array.
-
- int EDFANCY :: ISKNOWN()
- {
- if (loc > strlen(mask)) return 1;
- if (!mask[loc]) return 1;
- if (mask[loc] == ' ') return 1;
- return 0;
- }
-
- // INS behaves more or less as INS in the previous class, but because
- // it affects (potentially) every character in the array, and because
- // we don't want it blundering over a mask characters, so we have to
- // redefine it in this class.
-
- int EDFANCY :: INS()
- {
- register int cur, prev;
- if (datalen == strlen(data)) return 0;
- if (loc > strlen(data)) return 0;
- cur = strlen(data);
- if (onmask(cur)) cur++;
- if (cur >= datalen - 1) return 0;
- curx = startcol() + cur;
- gotoxy(curx, cury);
- prev = cur;
- do
- {
- prev--;
- } while (onmask(prev));
- while(cur != loc && prev >= loc)
- {
- data[cur] = data[prev];
- putchar(data[cur]);
- do
- {
- cur--;
- curx--;
- } while(onmask(cur));
- do
- {
- prev--;
- } while(onmask(prev));
- gotoxy(curx, cury);
- }
- data[loc] = ' ';
- putchar(data[loc]);
- gotoxy(curx, cury);
- return 1;
- }
-
- // What we said for INS also goes for DEL.
-
- int EDFANCY :: DEL()
- {
- register int cur, prev;
- int tmpx = curx;
- if (loc > strlen(data)) return 0;
- cur = loc;
- if (onmask(cur)) return 0;
- prev = cur;
- do
- {
- prev++;
- } while (onmask(prev));
- while (data[cur])
- {
- data[cur] = data[prev];
- putchar(data[prev]);
- do
- {
- cur++;
- curx++;
- } while (onmask(cur));
- do
- {
- prev++;
- } while(onmask(prev));
- gotoxy(curx, cury);
- }
- curx = tmpx;
- gotoxy(curx, cury);
- return 1;
- }
-
- // NORMAL also behaves slightly differently, so we redefine it. It now
- // skips over mask characters, as INS and DEL do.
-
- int EDFANCY :: NORMAL()
- {
- register int i = strlen(data);
- while (i < loc)
- {
- data[i] = ' ';
- ++i;
- }
- if (onmask()) return 0;
- data[loc] = lastkey;
- putchar(lastkey);
- gotoxy(curx, cury);
- do
- {
- if (!RIGHT()) return 1;
- } while (onmask());
- return 1;
- }
-
- // DISPLAY displays the mask without the user having to edit it. This
- // is good if you want to enter forms or something and don't feel like
- // deriving a form class or if you feel like building a data entry
- // function for one screen.
-
- void EDFANCY :: DISPLAY()
- {
- register int i = 0;
- int tmpx = startcol();
- gotoxy(tmpx, startrow());
- printf("%s", data);
- gotoxy(tmpx, startrow());
- while(mask[i])
- {
- if (!ISKNOWN(i))
- {
- gotoxy(tmpx, startrow());
- putchar(mask[i]);
- }
- i++;
- tmpx++;
- }
- gotoxy(startcol(), startrow());
- }
-
- // get's behavior changes here and there, so we redefine it too.
- // Overall it is the same function. Carry on...
-
- void * EDFANCY::get()
- {
- int retval = 0;
- int i;
- i = 0;
- if (ERR) return NULL;
- curx = startcol();
- cury = startrow();
- loc = 0;
- DISPLAY();
- gotoxy(curx, cury);
- while (onmask()) RIGHT();
- while (!INFINITY)
- {
- GETKEY();
- if (special)
- {
- switch(lastkey)
- {
- case LEFTARROW :
- do
- {
- retval = LEFT();
- } while(onmask() && retval);
- break;
- case RIGHTARROW :
- do
- {
- retval = RIGHT();
- } while(onmask() && retval);
- break;
- case ENDKEY :
- END();
- break;
- case HOMEKEY :
- HOME();
- break;
- case INSERTKEY :
- INS();
- break;
- case DELETEKEY :
- DEL();
- break;
- }
- }
- else
- {
- switch(lastkey)
- {
- case BACKSPACE :
- do
- {
- retval = LEFT();
- } while (onmask() && retval);
- if (retval) DEL();
- break;
- case RETURN :
- i = 0;
- while(mask[i])
- {
- if(!ISKNOWN(i))
- {
- data[i] = mask[i];
- }
- i++;
- }
- return (void *) data;
- default :
- NORMAL();
- break;
- }
- }
- }
- }
-
-
- // The constructor EDPIC does ABSOLUTELY NOTHING! It allows EDFANCY
- // to do ALL its dirty work for it. Since there is not a lot of difference
- // between EDPIC and EDFANCY, we can get away with this, and it saves
- // a XXXX of a lot of programming time.
-
- EDPIC :: EDPIC(int urow,
- int ucol,
- char *umask,
- char *udata,
- int ulen) : EDFANCY(urow,
- ucol,
- umask,
- udata,
- ulen)
- {
- // No operations.
- // (Don't want you guys to thing *I* made a mistake :-)
- }
-
- // ISKNOWN's behavior changes. I have some more values to look out
- // for. Apart from that, it's the same function. Also is late bound
- // to onmask -- ie onmask is EDFANCY's function, but it is called with
- // THIS ISKNOWN for THIS class! Isn't that neat?
-
- int EDPIC :: ISKNOWN(int where)
- {
- char known[] = {"# Aa+XH"};
- register int i;
- if (where > strlen(mask)) return ' ';
- if (!mask[where]) return ' ';
- for(i=0; i < strlen(known); ++i)
- {
- if (mask[where] == known[i]) return (int) known[i];
- }
- return 0;
- }
-
- // ISKNOWN (again) is overloaded to work with the current array location,
- // too.
-
- int EDPIC :: ISKNOWN()
- {
- return ISKNOWN(loc);
- }
-
- // ISGOOD is a new function which verifies that the keystroke can indeed
- // go in to the data array. ISGOOD is called by NORMAL. If it isn't good,
- // the keystroke does not show up on the screen or in the array. If it
- // is, it does.
-
- int EDPIC :: ISGOOD(int where)
- {
- switch(ISKNOWN(where))
- {
- case 0 :
- return 0;
- case ' ' :
- return 1;
- case '#' :
- if (is_in(lastkey, "0123456789.")) return 1;
- return 0;
- case 'A' :
- if (is_in(lastkey, "ABCDEFGHIJKLMNOPQRSTUVWXYZ")) return 1;
- return 0;
- case 'a' :
- if (is_in(lastkey, "abcdefghijklmnopqrstuvwxyz")) return 1;
- return 0;
- case '+' :
- if (is_in(lastkey, "0123456789+-/*^,")) return 1;
- return 0;
- case 'X' :
- if (lastkey < 32 || lastkey > 126) return 0;
- return 1;
- case 'H' :
- if (is_in(lastkey, "0123456789AaBbCcDdEeFf")) return 1;
- return 0;
- }
- return 0;
- }
-
- // ISGOOD is overloaded to work at the current array location, too.
-
- int EDPIC :: ISGOOD()
- {
- return ISGOOD(loc);
- }
-
- // NORMAL (of course) changes its behavior a bit, so that new behavior
- // must be redefined.
-
- int EDPIC :: NORMAL()
- {
- register int i = strlen(data);
- while (i < loc)
- {
- data[i] = ' ';
- ++i;
- }
- if (onmask()) return 0;
- if (!ISGOOD()) return 0;
- data[loc] = lastkey;
- putchar(lastkey);
- gotoxy(curx, cury);
- do
- {
- if (!RIGHT()) return 1;
- } while (onmask());
- return 1;
- }
-