home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Interactive Guide / c-cplusplus-interactive-guide.iso / c_ref / csource1 / chint / useful10.hnt < prev    next >
Text File  |  1993-09-29  |  10KB  |  305 lines

  1. /****************************************************************************
  2.   This useful hint shows how to modify the standard, (single user), DBC.SKL
  3.   so that a whole branch of records of a database can be copied as a block.
  4.  
  5.   IE. Copy a record, and all it's children, and it's childrens children, etc.
  6.  
  7.   To aid in writing the procedure to accomplish this functionallity it is
  8.   first necessary to re-organise the skeleton so that certain functions and
  9.   routines can be made available to outside functions.
  10.  
  11. *****************************************************************************/
  12.  
  13. 1) Copy the Standard skeleton DBC.SKL to COPYBRAN.SKL.  Now make the
  14.    following modifications to COPYBRAN.SKL...
  15.  
  16. ----------------------------------------------------------------------------
  17.  
  18. 2) Certain procedures that we are going to write will need to have some
  19.    lines conditionally compiled depending on whether the database definition
  20.    uses "Memo" fields and/or make use of the automatic "Adjust" function.
  21.  
  22.    At the top of the skeleton add the following :--
  23.  
  24.         ⁿIFDEF MEMOSⁿ
  25.         #define _USESMEMOS_
  26.         ⁿENDDEFⁿ
  27.  
  28.         ⁿIFDEF ADJUSTⁿ
  29.         #define _USESADJUST_
  30.         ⁿENDDEFⁿ
  31.  
  32. ----------------------------------------------------------------------------
  33.  
  34. 3) The function "found()" and the function "getarec()" both use the same
  35.    imbedded DataBoss Macro, "getrec".  This Macro should be re-coded as a
  36.    procedure in its own right, called "getSingleRec()", and both "getarec()"
  37.    and "found()" should now call "getSingleRec()" :--
  38.  
  39.    /* Place this just before the code for the "found" function */
  40.         void getSingleRec(int fno)
  41.         {
  42.           switch (fno) {
  43.             ⁿgetrecⁿ
  44.           }
  45.         }
  46.  
  47.    /* So found() Changes To ... */
  48.         bool found(int fno, int kno, keystr chkkey)
  49.         ...
  50.         ...
  51.           ok = (bool)(ok && (strsearch(aKey, chkkey) == aKey));
  52.           if (ok) getSingleRec(fno);
  53.           tfound = ok;
  54.         ...
  55.         ...
  56.         }
  57.  
  58.    /* And getarec() changes to ... */
  59.        void getarec(int fno)
  60.        ...
  61.        ...
  62.          recavail[fno] = ok;
  63.          if (ok) getSingleRec(fno);
  64.        ⁿIFDEF LINKEDⁿ
  65.        ...
  66.        ...
  67.  
  68. ----------------------------------------------------------------------------
  69.  
  70. 4) The "add_record()" function has two imbedded DataBoss macros that we need
  71.    access to. "clearmemo" and "setfield" both need to be moved into
  72.    procedures of their own.
  73.  
  74.    Create a new function "clearMomoFields()" and add this function directly
  75.    after the "clearmemo" function, and INSIDE the "IFDEF MEMOS" DataBoss
  76.    conditional generation macro, :--
  77.  
  78.         ⁿIFDEF MEMOSⁿ
  79.         void clearmemo(ptr fb)
  80.         ...
  81.         ...
  82.         }
  83.  
  84.         void clearMemoFields(int fno)              /* <-- New */
  85.         {                                          /* <-- New */
  86.           switch (fno) {                           /* <-- New */
  87.             ⁿCLEARMEMOⁿ                            /* <-- New */
  88.           }                                        /* <-- New */
  89.         }                                          /* <-- New */
  90.         ⁿENDDEFⁿ
  91.  
  92.    Also create a new function, called "recDefaultValues()", that is based
  93.    upon the ⁿsetfieldⁿ macro.  The code for this procedure will need to go
  94.    just before "add_record()", and as it may need to call the "autoinc()"
  95.    function this will also need to be moved above both the "add_record()" and
  96.    the "recDefaultValues()" functions.
  97.  
  98.    The current "addarec()" function will also need to be modified so that
  99.    it can be passed a file number to indicate which record to add, (at the
  100.    moment it add a record based on the global "filno" variable).
  101.  
  102.         strptr autoinc(keystr sout, int kno)
  103.         {
  104.         ...
  105.         ...
  106.         }
  107.  
  108.         void recDefaultValues(int filno)      /* New */
  109.         {                                     /* New */
  110.           string tts;                         /* New */
  111.                                               /* New */
  112.           ⁿSETFIELDⁿ                          /* New */
  113.         }                                     /* New */
  114.  
  115.         void addarec(int filno)               /* <-- Modified */
  116.         {
  117.         ...
  118.         ...
  119.         }
  120.  
  121.    /* "Add_Record" can now call "ClearMemoFields" and "RecDefaultValues" */
  122.         void add_record(char func)
  123.         {
  124.         ...
  125.         ...
  126.           cleartop = (bool)(func == 'A');
  127.           clear_rec(filno);
  128.           scrn_active = True;
  129.         ⁿIFDEF MEMOSⁿ
  130.           if (!cleartop) clearMemoFields(filno);      /* <-- New */
  131.         ⁿENDDEFⁿ
  132.           cleartop = True;
  133.           recDefaultValues(filno);                    /* <-- New */
  134.         ⁿIFDEF TABLESⁿ
  135.         ...
  136.         ...
  137.           if (exitcode != QitKey) {
  138.         ⁿIFDEF MUSERⁿ
  139.           must_secure_rec(filno,0L,2);
  140.           addarec(filno);      /* <-- Modified */
  141.           tv = lock_datf(datf[filno],recno[filno],Lock);
  142.           tv = lock_datf(datf[filno],0L,UnLock);
  143.         ⁿELSEDEFⁿ
  144.           addarec(filno);      /* <-- Modified */
  145.         ⁿENDDEFⁿ
  146.           for (keyno = 1; keyno <= maxkeyno; keyno++) savkey[keyno][0] = '\0';
  147.         ...
  148.         ...
  149.         }
  150.  
  151. ----------------------------------------------------------------------------
  152.  
  153. 5) Now that these changes are in place we can write the functions that
  154.    actually copy a block of records.  You could add extra code directly
  155.    to the modified skeleton, however I would suggest you put it in a
  156.    function file, (call it COPYBRAN.FUN).
  157.  
  158. /* The contents of COPYBRAN.FUN */
  159. uchar msg_NeedHoldingFile[] = "Cannot open temporary holding file.  Copy aborted!";
  160.  
  161. typedef struct {
  162.   int fileNumber;
  163.   long recordRef;
  164. } fileAndRecRef;
  165.  
  166. FILE *hFile;
  167.  
  168. void duplicateBranch(int fno)
  169. {
  170.   fileAndRecRef addThisRec;
  171.   bool savOK, tb;
  172.   int i;
  173.   keystr tkey, tkey2;
  174.  
  175.   if (fno != filno) {
  176.     getSingleRec(fno);
  177. #ifdef _USESMEMOS_
  178.     clearMemoFields(fno);
  179. #endif
  180.     addarec(fno);
  181.     addThisRec.fileNumber = fno;
  182.     addThisRec.recordRef = recno[fno];
  183.     fwrite(&addThisRec,sizeof(fileAndRecRef),1,hFile);
  184.   }
  185.   for (i = 1; i <= maxfilno; i++) {
  186.     if ((linkback[i].t == _Unique) &&
  187.        (linkback[i].f == fno) && filinuse[i]) {
  188.       getlink(tkey,i);  strcpy(tkey2,tkey);
  189.       searchkey(idxkey[i][1],&recno[i],tkey2);
  190.       savOK = ok && (strsearch(tkey2,tkey) == tkey2);
  191.       while (savOK) {
  192.         duplicateBranch(i);
  193.         nextkey(idxkey[i][1],&recno[i],tkey2);
  194.         savOK = ok &&(strsearch(tkey2,tkey) == tkey2);
  195.       }
  196.       ok = True;  /* Restore OK to True */
  197.     }
  198.   }
  199. }
  200.  
  201. void setLinksAndAddKeys(void)
  202. {
  203.   int i, j, fno;
  204.   keystr tkey;
  205.   fileAndRecRef changeThisRec;
  206.  
  207.   fseek(hFile,0L,SEEK_SET);
  208.   while (!(feof(hFile))) {
  209.     if (fread(&changeThisRec,sizeof(fileAndRecRef),1,hFile) == 1) {
  210.       fno = changeThisRec.fileNumber;
  211.       recno[fno] = changeThisRec.recordRef;
  212.       getSingleRec(fno);  recavail[fno] = True;
  213.       recDefaultValues(fno);          /* Calls SetLinkage to set link fields */
  214.       putarec(fno);
  215. #ifdef _USESADJUST_
  216.       adjust(fno,'A');
  217. #endif
  218.       for (i=1;i<=maxkeyno; i++) {
  219.         if (keylen[fno][i] > 0) {
  220.           getakey(tkey,fno,i);
  221.           addkey(idxkey[fno][i],&recno[fno],tkey);
  222.         }
  223.       }
  224.     }
  225.   }
  226. }
  227.  
  228. void copyBranch(int fno, long copyRec)
  229. {
  230.   long i;
  231.   long parentRec;
  232.  
  233.   hFile = fopen("~COPYREC.HLD","rb");
  234.   if (hFile != NULL) {
  235.  
  236.     parentRec = recno[fno];
  237.     recno[fno] = copyRec;
  238.     getSingleRec(fno);
  239.     duplicateBranch(fno);
  240.  
  241.     recno[fno] = parentRec;
  242.     getSingleRec(fno);
  243.     setLinksAndAddKeys();
  244.  
  245.     fclose(hFile);
  246.     unlink("~COPYREC.HLD");
  247.  
  248.     scrn_active = False;
  249.     for (i=1; i<=maxfilno; i++) clear_rec(i);
  250.     scrn_active = True;
  251.     align_rec(recno[fno]);
  252.  
  253.   }
  254.   else
  255.     dberrm(msg_NeedHoldingFile);
  256. }
  257.  
  258. ----------------------------------------------------------------------------
  259.  
  260. 6)  Finally we need to add a little more code to the skeleton so that we can
  261.