home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD2.mdf / c / library / dos / database / ooed / ooed.cpp next >
Encoding:
Text File  |  1991-03-27  |  15.3 KB  |  681 lines

  1. // Program:   OOED.CPP
  2. // Progammer: Bruce Ide
  3. // Date:      3-25-91
  4. // Language:  Turbo C++
  5. // OS:        PC MOS 4.0
  6. //
  7. // Description: This is an object oriented data editor which allows the
  8. //              user to edit various data strings in the spirit of DBASE's
  9. //              PIC clause. This set of functions uses such nifty object
  10. //              oriented features such as late binding and multiple
  11. //              inheritance. These classes do not go all the way to
  12. //              forms, though a form editing function or class would
  13. //              be easily created from these classes (I'm working on an
  14. //              interrupt driven system similiar to others on the market.
  15. //              I'll include a form class there, along with some window
  16. //              and button routines.)
  17.  
  18. // If you're going to compile this file to an OBJ file and just link it
  19. // (Which will save a lot of time) include the following:
  20. //#include <dos.h>
  21. //#include <conio.h>
  22. //#include <stdio.h>
  23. //#include <stdlib.h>
  24. //#include <string.h>
  25. //#include "useful.hpp"
  26. //#include "useful.cpp"
  27. //#include "ooed.hpp"
  28.  
  29. void KEYSTROKE::GETKEY()
  30. {
  31.  union SCAN thang;
  32.  union REGS r;
  33.  
  34.  r.h.ah = 0;
  35.  thang.c = int86(0x16, &r, &r) ;
  36.  if (thang.ch[0] == 0)
  37.     {
  38.      special = 1;
  39.      lastkey = thang.ch[1];
  40.     }
  41.   else
  42.     {
  43.      special = 0;
  44.      lastkey = thang.ch[0];
  45.     }
  46. }
  47.  
  48.  
  49. // First constructor for ED -- sets up to edit at wherever the cursor
  50. // is.
  51.  
  52. ED::ED()
  53. {
  54.  row = wherey();
  55.  col = wherex();
  56. }
  57.  
  58. // Second constructor for ED -- Sets up to edit at a specified row/column
  59. // (somewhat more useful).
  60.  
  61. ED::ED(int r,
  62.        int c)
  63. {
  64.  row = r;
  65.  col = c;
  66. }
  67.  
  68.  
  69. // First constructor for EDSTR -- as ed, it sets up to edit the string
  70. // wherever the cursor is. This will only be useful if you are using
  71. // the new command to create a new variable of this class at a pointer.
  72. // Note that this constructor calls ED's constructor to do some
  73. // dirty work.
  74.  
  75. EDSTR :: EDSTR(char *str,
  76.      int len) : ED()
  77. {
  78.  data = str;
  79.  datalen = len;
  80.  curx = wherex();
  81.  cury = wherey();
  82.  loc = 0;
  83. }
  84.  
  85. // Second constructor for EDSTR -- Sets up to edit the string
  86. // at a specified row and column. As the with the first constructor,
  87. // this one calls ED to do some dirty work.
  88.  
  89. EDSTR :: EDSTR(int urow, int ucol, char *str, int len) :
  90.      ED(urow, ucol)
  91. {
  92.  data = str;
  93.  datalen = len;
  94.  curx = ucol;
  95.  cury = urow;
  96.  loc = 0;
  97. }
  98.  
  99. // RIGHT -- Moves the cursor 1 space right, and makes sure the location
  100. // of the cursor and the location in the array are correct. Returns a
  101. // value so that it can be called recursively if desired.
  102.  
  103. int EDSTR :: RIGHT()
  104. {
  105.  loc++;
  106.  if (loc >= datalen - 1)
  107.    {
  108.     loc --;
  109.     return 0;
  110.    }
  111.  curx++;
  112.  gotoxy(curx, cury);
  113.  return 1;
  114. }
  115.  
  116. // LEFT moves the cursor left 1 space. See RIGHT
  117.  
  118. int EDSTR :: LEFT()
  119. {
  120.  loc--;
  121.  if (loc < 0)
  122.    {
  123.     loc++;
  124.     return 0;
  125.    }
  126.  curx--;
  127.  gotoxy(curx, cury);
  128.  return 1;
  129. }
  130.  
  131. // DEL removes a character at the cursor and moves everything beyond the
  132. // cursor 1 space left. This returns a value in case I should ever need
  133. // it to, really.
  134.  
  135. int EDSTR :: DEL()
  136. {
  137.  register int i;
  138.  int tmpx = curx;
  139.  if (loc > strlen(data)) return 0;
  140.  i = loc;
  141.  while(data[i])
  142.    {
  143.     data[i] = data[i + 1];
  144.     putchar(data[i + 1]);
  145.     i++;
  146.    }
  147.  curx = tmpx;
  148.  gotoxy(curx, cury);
  149.  return 1;
  150. }
  151.  
  152. // BKSP is a LEFT plus a DEL. Should you not be able to LEFT, it will
  153. // NOT DEL.
  154.  
  155. int EDSTR :: BKSP()
  156. {
  157.  if (LEFT()) return DEL();   // Now that IS clever :-)
  158. }
  159.  
  160. // INS inserts a space at the cursor (DOES NOT GO INTO INSERT MODE!!!)
  161. // and moves everything right of the cursor 1 space right. Note that this
  162. // does not work if the field is full (Even if it is just full of spaces.)
  163.  
  164. // If you prefer to make the insert key go into insert mode, derive a class
  165. // from this one or a later one and set up a boolean flag insertmode and
  166. // modify NORMAL and GET so that hitting insert toggles insertmode and
  167. // whenever insertmode is on, have NORMAL call INS before entering the
  168. // character. (This probably is not a good idea unless you are building a
  169. // text editor)
  170.  
  171. int EDSTR :: INS()
  172. {
  173.  register int i;
  174.  if (datalen == strlen(data)) return 0;  // Don't want to push any data off
  175.                                          // the side of the field
  176.  if (loc > strlen(data)) return 0;
  177.  i = strlen(data);
  178.  curx = startcol() + i;
  179.  gotoxy(curx, cury);
  180.  while(i != loc)
  181.    {
  182.     data[i] = data[i - 1];
  183.     i --;
  184.     curx--;
  185.     putchar(data[i]);
  186.     gotoxy(curx, cury);
  187.    }
  188.  data[loc] = ' ';
  189.  putchar(data[loc]);
  190.  gotoxy(curx, cury);
  191.  return 1;
  192. }
  193.  
  194. // HOME moves the cursor to the first character in the field to edit
  195.  
  196. int EDSTR :: HOME()
  197. {
  198.  loc = 0;
  199.  curx = startcol();
  200.  gotoxy(curx, cury);
  201.  return 1;
  202. }
  203.  
  204. // END moves the cursor to the last character in the field to edit. Note
  205. // that if the field is 9 spaces long and there are only 4 spaces filled,
  206. // END will only move out to 4.
  207.  
  208. int EDSTR :: END()
  209. {
  210.  loc = strlen(data);
  211.  curx = startcol() + loc;
  212.  gotoxy(curx, cury);
  213.  return 1;
  214. }
  215.  
  216. // Currently, NORMAL will insert any ascii character that is not a movement
  217. // key -- it will get all control characters and high ascii etc. Revise the
  218. // function later (in later classes) to be more discriminating (Like, get
  219. // only numbers or something.) (This is done in EDFANCY)
  220.  
  221. int EDSTR :: NORMAL()
  222. {
  223.  register int i = strlen(data);
  224.  while (i < loc)
  225.    {
  226.     data[i] = ' ';
  227.     ++i;
  228.    }
  229.  data[loc] = lastkey;
  230.  putchar(lastkey);
  231.  gotoxy(curx, cury);
  232.  RIGHT();
  233.  return 1;
  234. }
  235.  
  236. // get is the driver for all the other functions. It is the function you
  237. // should modify if you want to change keystrokes to do other things. It
  238. // mainly consists of a case statement which checks to see what the key
  239. // pressed should do.
  240.  
  241. void * EDSTR :: get()
  242. {
  243.  curx = startcol();
  244.  cury = startrow();
  245.  loc = 0;
  246.  gotoxy(curx, cury);
  247.  while (!INFINITY)
  248.    {
  249.     GETKEY();
  250.     if (special)
  251.       {
  252.        switch(lastkey)
  253.      {
  254.           case LEFTARROW :
  255.                LEFT();
  256.                break;
  257.           case RIGHTARROW :
  258.                RIGHT();
  259.                break;
  260.       case ENDKEY :
  261.                END();
  262.                break;
  263.           case HOMEKEY :
  264.                HOME();
  265.                break;
  266.           case INSERTKEY :
  267.                INS();
  268.                break;
  269.           case DELETEKEY :
  270.                DEL();
  271.                break;
  272.         }
  273.       }
  274.     else
  275.       {
  276.        switch(lastkey)
  277.         {
  278.          case BACKSPACE :
  279.               BKSP();
  280.               break;
  281.          case RETURN :
  282.               return (void *) data;
  283.          default :
  284.               NORMAL();
  285.               break;
  286.         }
  287.       }
  288.    }
  289. }
  290.  
  291.  
  292. // EDFANCY - The first (and ONLY) constructor for this class. We have
  293. // dropped the capability to edit at the cursor row/col, as this class
  294. // will probably be more concerned with forms. Note that we call EDSTR
  295. // (Which calls ED) to do some of our dirty work for us.)
  296.  
  297. // Please note that the mask will be stored in the returned string,
  298. // so if you give the computer a mask of "  /  /  " and the user types
  299. // 032691 the returned string will be "03/26/91".
  300.  
  301. EDFANCY :: EDFANCY(int urow,
  302.            int ucol,
  303.            char *umask,
  304.            char *udata,
  305.            int ulen) : EDSTR (urow,
  306.                       ucol,
  307.                       udata,
  308.                       ulen)
  309. {
  310.  ERR = 0;
  311.  mask = new char[strlen(umask)];
  312.  if (!mask)
  313.    {
  314.     ERR = 1;
  315.     return;
  316.    }
  317.  strcpy(mask, umask);
  318. }
  319.  
  320. // ~EDFANCY -- We need a destructor now to delete the memory we allocated
  321. // to store mask.
  322.  
  323. EDFANCY :: ~EDFANCY()
  324. {
  325.  delete mask;
  326. }
  327.  
  328. // onmask returns a 1 if we are on a character we can't type over,
  329. // or a 0 if we can put a char in this space in the array.
  330.  
  331. int EDFANCY :: onmask()
  332. {
  333.  if (ISKNOWN()) return 0;
  334.  return 1;
  335. }
  336.  
  337. // onmask is also overloaded to act as mentioned above for any space
  338. // in the array.
  339.  
  340. int EDFANCY :: onmask(int where)
  341. {
  342.  if (ISKNOWN(where)) return 0;
  343.  return 1;
  344. }
  345.  
  346. // ISKNOWN returns a 1 if the character in the mask at the passed location
  347. // is one that we can type on (In this case, a space or a null) in the
  348. // data field. If it is not, the functions keep the user from typing
  349. // a character in that space. This function is of more use in later classes,
  350. // but is placed here to allow late binding to get and other functions.
  351.  
  352. int EDFANCY :: ISKNOWN(int where)
  353. {
  354.  if (where > strlen(mask)) return 1;
  355.  if (!mask[where]) return 1;
  356.  if (mask[where] == ' ') return 1;
  357.  return 0;
  358. }
  359.  
  360. // ISKNOWN is also overloaded to perform as mentioned above for the
  361. // current location in the data array.
  362.  
  363. int EDFANCY :: ISKNOWN()
  364. {
  365.  if (loc > strlen(mask)) return 1;
  366.  if (!mask[loc]) return 1;
  367.  if (mask[loc] == ' ') return 1;
  368.  return 0;
  369. }
  370.  
  371. // INS behaves more or less as INS in the previous class, but because
  372. // it affects (potentially) every character in the array, and because
  373. // we don't want it blundering over a mask characters, so we have to
  374. // redefine it in this class.
  375.  
  376. int EDFANCY :: INS()
  377. {
  378.  register int cur, prev;
  379.  if (datalen == strlen(data)) return 0;
  380.  if (loc > strlen(data)) return 0;
  381.  cur = strlen(data);
  382.  if (onmask(cur)) cur++;
  383.  if (cur >= datalen - 1) return 0;
  384.  curx = startcol() + cur;
  385.  gotoxy(curx, cury);
  386.  prev = cur;
  387.  do
  388.  {
  389.   prev--;
  390.  } while (onmask(prev));
  391.  while(cur != loc && prev >= loc)
  392.    {
  393.     data[cur] = data[prev];
  394.     putchar(data[cur]);
  395.     do
  396.       {
  397.        cur--;
  398.        curx--;
  399.       } while(onmask(cur));
  400.     do
  401.       {
  402.        prev--;
  403.       } while(onmask(prev));
  404.     gotoxy(curx, cury);
  405.    }
  406.  data[loc] = ' ';
  407.  putchar(data[loc]);
  408.  gotoxy(curx, cury);
  409.  return 1;
  410. }
  411.  
  412. // What we said for INS also goes for DEL.
  413.  
  414. int EDFANCY :: DEL()
  415. {
  416.  register int cur, prev;
  417.  int tmpx = curx;
  418.  if (loc > strlen(data)) return 0;
  419.  cur = loc;
  420.  if (onmask(cur)) return 0;
  421.  prev = cur;
  422.  do
  423.  {
  424.   prev++;
  425.  } while (onmask(prev));
  426.  while (data[cur])
  427.    {
  428.     data[cur] = data[prev];
  429.     putchar(data[prev]);
  430.     do
  431.     {
  432.      cur++;
  433.      curx++;
  434.     } while (onmask(cur));
  435.     do
  436.     {
  437.      prev++;
  438.     } while(onmask(prev));
  439.     gotoxy(curx, cury);
  440.    }
  441.  curx = tmpx;
  442.  gotoxy(curx, cury);
  443.  return 1;
  444. }
  445.  
  446. // NORMAL also behaves slightly differently, so we redefine it. It now
  447. // skips over mask characters, as INS and DEL do.
  448.  
  449. int EDFANCY :: NORMAL()
  450. {
  451.  register int i = strlen(data);
  452.  while (i < loc)
  453.    {
  454.     data[i] = ' ';
  455.     ++i;
  456.    }
  457.  if (onmask()) return 0;
  458.  data[loc] = lastkey;
  459.  putchar(lastkey);
  460.  gotoxy(curx, cury);
  461.  do
  462.  {
  463.   if (!RIGHT()) return 1;
  464.  } while (onmask());
  465.  return 1;
  466. }
  467.  
  468. // DISPLAY displays the mask without the user having to edit it. This
  469. // is good if you want to enter forms or something and don't feel like
  470. // deriving a form class or if you feel like building a data entry
  471. // function for one screen.
  472.  
  473. void EDFANCY :: DISPLAY()
  474. {
  475.  register int i = 0;
  476.  int tmpx = startcol();
  477.  gotoxy(tmpx, startrow());
  478.  printf("%s", data);
  479.  gotoxy(tmpx, startrow());
  480.  while(mask[i])
  481.    {
  482.     if (!ISKNOWN(i))
  483.       {
  484.        gotoxy(tmpx, startrow());
  485.        putchar(mask[i]);
  486.       }
  487.     i++;
  488.     tmpx++;
  489.    }
  490.  gotoxy(startcol(), startrow());
  491. }
  492.  
  493. // get's behavior changes here and there, so we redefine it too.
  494. // Overall it is the same function. Carry on...
  495.  
  496. void * EDFANCY::get()
  497. {
  498.  int retval = 0;
  499.  int i;
  500.  i = 0;
  501.  if (ERR) return NULL;
  502.  curx = startcol();
  503.  cury = startrow();
  504.  loc = 0;
  505.  DISPLAY();
  506.  gotoxy(curx, cury);
  507.  while (onmask()) RIGHT();
  508.  while (!INFINITY)
  509.    {
  510.     GETKEY();
  511.     if (special)
  512.       {
  513.        switch(lastkey)
  514.          {
  515.           case LEFTARROW :
  516.            do
  517.            {
  518.         retval = LEFT();
  519.            } while(onmask() && retval);
  520.            break;
  521.       case RIGHTARROW :
  522.            do
  523.            {
  524.         retval = RIGHT();
  525.            } while(onmask() && retval);
  526.            break;
  527.       case ENDKEY :
  528.            END();
  529.                break;
  530.           case HOMEKEY :
  531.                HOME();
  532.                break;
  533.           case INSERTKEY :
  534.                INS();
  535.                break;
  536.           case DELETEKEY :
  537.                DEL();
  538.                break;
  539.         }
  540.       }
  541.     else
  542.       {
  543.        switch(lastkey)
  544.         {
  545.      case BACKSPACE :
  546.           do
  547.           {
  548.            retval = LEFT();
  549.           } while (onmask() && retval);
  550.           if (retval) DEL();
  551.           break;
  552.      case RETURN :
  553.           i = 0;
  554.           while(mask[i])
  555.            {
  556.                 if(!ISKNOWN(i))
  557.           {
  558.            data[i] = mask[i];
  559.           }
  560.         i++;
  561.            }
  562.           return (void *) data;
  563.      default :
  564.               NORMAL();
  565.               break;
  566.         }
  567.       }
  568.    }
  569. }
  570.  
  571.  
  572. // The constructor EDPIC does ABSOLUTELY NOTHING! It allows EDFANCY
  573. // to do ALL its dirty work for it. Since there is not a lot of difference
  574. // between EDPIC and EDFANCY, we can get away with this, and it saves
  575. // a XXXX of a lot of programming time.
  576.  
  577. EDPIC :: EDPIC(int urow,
  578.                int ucol,
  579.            char *umask,
  580.            char *udata,
  581.            int ulen) : EDFANCY(urow,
  582.                                    ucol,
  583.                                    umask,
  584.                                    udata,
  585.                                    ulen)
  586. {
  587.  // No operations.
  588.  // (Don't want you guys to thing *I* made a mistake :-)
  589. }
  590.  
  591. // ISKNOWN's behavior changes. I have some more values to look out
  592. // for. Apart from that, it's the same function. Also is late bound
  593. // to onmask -- ie onmask is EDFANCY's function, but it is called with
  594. // THIS ISKNOWN for THIS class! Isn't that neat?
  595.  
  596. int EDPIC :: ISKNOWN(int where)
  597. {
  598.  char known[] = {"# Aa+XH"};
  599.  register int i;
  600.  if (where > strlen(mask)) return ' ';
  601.  if (!mask[where]) return ' ';
  602.  for(i=0; i < strlen(known); ++i)
  603.    {
  604.     if (mask[where] == known[i]) return (int) known[i];
  605.    }
  606.  return 0;
  607. }
  608.  
  609. // ISKNOWN (again) is overloaded to work with the current array location,
  610. // too.
  611.  
  612. int EDPIC :: ISKNOWN()
  613. {
  614.  return ISKNOWN(loc);
  615. }
  616.  
  617. // ISGOOD is a new function which verifies that the keystroke can indeed
  618. // go in to the data array. ISGOOD is called by NORMAL. If it isn't good,
  619. // the keystroke does not show up on the screen or in the array. If it
  620. // is, it does.
  621.  
  622. int EDPIC :: ISGOOD(int where)
  623. {
  624.  switch(ISKNOWN(where))
  625.    {
  626.     case 0 :
  627.        return 0;
  628.     case ' ' :
  629.        return 1;
  630.     case '#' :
  631.        if (is_in(lastkey, "0123456789.")) return 1;
  632.        return 0;
  633.     case 'A' :
  634.        if (is_in(lastkey, "ABCDEFGHIJKLMNOPQRSTUVWXYZ")) return 1;
  635.        return 0;
  636.     case 'a' :
  637.        if (is_in(lastkey, "abcdefghijklmnopqrstuvwxyz")) return 1;
  638.        return 0;
  639.     case '+' :
  640.        if (is_in(lastkey, "0123456789+-/*^,")) return 1;
  641.        return 0;
  642.     case 'X' :
  643.        if (lastkey < 32 || lastkey > 126) return 0;
  644.        return 1;
  645.     case 'H' :
  646.        if (is_in(lastkey, "0123456789AaBbCcDdEeFf")) return 1;
  647.        return 0;
  648.    }
  649.  return 0;
  650. }
  651.  
  652. // ISGOOD is overloaded to work at the current array location, too.
  653.  
  654. int EDPIC :: ISGOOD()
  655. {
  656.  return ISGOOD(loc);
  657. }
  658.  
  659. // NORMAL (of course) changes its behavior a bit, so that new behavior
  660. // must be redefined.
  661.  
  662. int EDPIC :: NORMAL()
  663. {
  664.  register int i = strlen(data);
  665.  while (i < loc)
  666.    {
  667.     data[i] = ' ';
  668.     ++i;
  669.    }
  670.  if (onmask()) return 0;
  671.  if (!ISGOOD()) return 0;
  672.  data[loc] = lastkey;
  673.  putchar(lastkey);
  674.  gotoxy(curx, cury);
  675.  do
  676.  {
  677.   if (!RIGHT()) return 1;
  678.  } while (onmask());
  679.  return 1;
  680. }
  681.