home *** CD-ROM | disk | FTP | other *** search
- /****************************************************************************
- This useful hint shows how to modify the standard, (single user), DBC.SKL
- so that a whole branch of records of a database can be copied as a block.
-
- IE. Copy a record, and all it's children, and it's childrens children, etc.
-
- To aid in writing the procedure to accomplish this functionallity it is
- first necessary to re-organise the skeleton so that certain functions and
- routines can be made available to outside functions.
-
- *****************************************************************************/
-
- 1) Copy the Standard skeleton DBC.SKL to COPYBRAN.SKL. Now make the
- following modifications to COPYBRAN.SKL...
-
- ----------------------------------------------------------------------------
-
- 2) Certain procedures that we are going to write will need to have some
- lines conditionally compiled depending on whether the database definition
- uses "Memo" fields and/or make use of the automatic "Adjust" function.
-
- At the top of the skeleton add the following :--
-
- ⁿIFDEF MEMOSⁿ
- #define _USESMEMOS_
- ⁿENDDEFⁿ
-
- ⁿIFDEF ADJUSTⁿ
- #define _USESADJUST_
- ⁿENDDEFⁿ
-
- ----------------------------------------------------------------------------
-
- 3) The function "found()" and the function "getarec()" both use the same
- imbedded DataBoss Macro, "getrec". This Macro should be re-coded as a
- procedure in its own right, called "getSingleRec()", and both "getarec()"
- and "found()" should now call "getSingleRec()" :--
-
- /* Place this just before the code for the "found" function */
- void getSingleRec(int fno)
- {
- switch (fno) {
- ⁿgetrecⁿ
- }
- }
-
- /* So found() Changes To ... */
- bool found(int fno, int kno, keystr chkkey)
- ...
- ...
- ok = (bool)(ok && (strsearch(aKey, chkkey) == aKey));
- if (ok) getSingleRec(fno);
- tfound = ok;
- ...
- ...
- }
-
- /* And getarec() changes to ... */
- void getarec(int fno)
- ...
- ...
- recavail[fno] = ok;
- if (ok) getSingleRec(fno);
- ⁿIFDEF LINKEDⁿ
- ...
- ...
-
- ----------------------------------------------------------------------------
-
- 4) The "add_record()" function has two imbedded DataBoss macros that we need
- access to. "clearmemo" and "setfield" both need to be moved into
- procedures of their own.
-
- Create a new function "clearMomoFields()" and add this function directly
- after the "clearmemo" function, and INSIDE the "IFDEF MEMOS" DataBoss
- conditional generation macro, :--
-
- ⁿIFDEF MEMOSⁿ
- void clearmemo(ptr fb)
- ...
- ...
- }
-
- void clearMemoFields(int fno) /* <-- New */
- { /* <-- New */
- switch (fno) { /* <-- New */
- ⁿCLEARMEMOⁿ /* <-- New */
- } /* <-- New */
- } /* <-- New */
- ⁿENDDEFⁿ
-
- Also create a new function, called "recDefaultValues()", that is based
- upon the ⁿsetfieldⁿ macro. The code for this procedure will need to go
- just before "add_record()", and as it may need to call the "autoinc()"
- function this will also need to be moved above both the "add_record()" and
- the "recDefaultValues()" functions.
-
- The current "addarec()" function will also need to be modified so that
- it can be passed a file number to indicate which record to add, (at the
- moment it add a record based on the global "filno" variable).
-
- strptr autoinc(keystr sout, int kno)
- {
- ...
- ...
- }
-
- void recDefaultValues(int filno) /* New */
- { /* New */
- string tts; /* New */
- /* New */
- ⁿSETFIELDⁿ /* New */
- } /* New */
-
- void addarec(int filno) /* <-- Modified */
- {
- ...
- ...
- }
-
- /* "Add_Record" can now call "ClearMemoFields" and "RecDefaultValues" */
- void add_record(char func)
- {
- ...
- ...
- cleartop = (bool)(func == 'A');
- clear_rec(filno);
- scrn_active = True;
- ⁿIFDEF MEMOSⁿ
- if (!cleartop) clearMemoFields(filno); /* <-- New */
- ⁿENDDEFⁿ
- cleartop = True;
- recDefaultValues(filno); /* <-- New */
- ⁿIFDEF TABLESⁿ
- ...
- ...
- if (exitcode != QitKey) {
- ⁿIFDEF MUSERⁿ
- must_secure_rec(filno,0L,2);
- addarec(filno); /* <-- Modified */
- tv = lock_datf(datf[filno],recno[filno],Lock);
- tv = lock_datf(datf[filno],0L,UnLock);
- ⁿELSEDEFⁿ
- addarec(filno); /* <-- Modified */
- ⁿENDDEFⁿ
- for (keyno = 1; keyno <= maxkeyno; keyno++) savkey[keyno][0] = '\0';
- ...
- ...
- }
-
- ----------------------------------------------------------------------------
-
- 5) Now that these changes are in place we can write the functions that
- actually copy a block of records. You could add extra code directly
- to the modified skeleton, however I would suggest you put it in a
- function file, (call it COPYBRAN.FUN).
-
- /* The contents of COPYBRAN.FUN */
- uchar msg_NeedHoldingFile[] = "Cannot open temporary holding file. Copy aborted!";
-
- typedef struct {
- int fileNumber;
- long recordRef;
- } fileAndRecRef;
-
- FILE *hFile;
-
- void duplicateBranch(int fno)
- {
- fileAndRecRef addThisRec;
- bool savOK, tb;
- int i;
- keystr tkey, tkey2;
-
- if (fno != filno) {
- getSingleRec(fno);
- #ifdef _USESMEMOS_
- clearMemoFields(fno);
- #endif
- addarec(fno);
- addThisRec.fileNumber = fno;
- addThisRec.recordRef = recno[fno];
- fwrite(&addThisRec,sizeof(fileAndRecRef),1,hFile);
- }
- for (i = 1; i <= maxfilno; i++) {
- if ((linkback[i].t == _Unique) &&
- (linkback[i].f == fno) && filinuse[i]) {
- getlink(tkey,i); strcpy(tkey2,tkey);
- searchkey(idxkey[i][1],&recno[i],tkey2);
- savOK = ok && (strsearch(tkey2,tkey) == tkey2);
- while (savOK) {
- duplicateBranch(i);
- nextkey(idxkey[i][1],&recno[i],tkey2);
- savOK = ok &&(strsearch(tkey2,tkey) == tkey2);
- }
- ok = True; /* Restore OK to True */
- }
- }
- }
-
- void setLinksAndAddKeys(void)
- {
- int i, j, fno;
- keystr tkey;
- fileAndRecRef changeThisRec;
-
- fseek(hFile,0L,SEEK_SET);
- while (!(feof(hFile))) {
- if (fread(&changeThisRec,sizeof(fileAndRecRef),1,hFile) == 1) {
- fno = changeThisRec.fileNumber;
- recno[fno] = changeThisRec.recordRef;
- getSingleRec(fno); recavail[fno] = True;
- recDefaultValues(fno); /* Calls SetLinkage to set link fields */
- putarec(fno);
- #ifdef _USESADJUST_
- adjust(fno,'A');
- #endif
- for (i=1;i<=maxkeyno; i++) {
- if (keylen[fno][i] > 0) {
- getakey(tkey,fno,i);
- addkey(idxkey[fno][i],&recno[fno],tkey);
- }
- }
- }
- }
- }
-
- void copyBranch(int fno, long copyRec)
- {
- long i;
- long parentRec;
-
- hFile = fopen("~COPYREC.HLD","rb");
- if (hFile != NULL) {
-
- parentRec = recno[fno];
- recno[fno] = copyRec;
- getSingleRec(fno);
- duplicateBranch(fno);
-
- recno[fno] = parentRec;
- getSingleRec(fno);
- setLinksAndAddKeys();
-
- fclose(hFile);
- unlink("~COPYREC.HLD");
-
- scrn_active = False;
- for (i=1; i<=maxfilno; i++) clear_rec(i);
- scrn_active = True;
- align_rec(recno[fno]);
-
- }
- else
- dberrm(msg_NeedHoldingFile);
- }
-
- ----------------------------------------------------------------------------
-
- 6) Finally we need to add a little more code to the skeleton so that we can
- make a call to this great new function "CopyBranch".
-
- What we will do is activate the function by pressing <Shift>+<F1>. This
- key combination needs to be picked up in the "do_menu()" function. We
- will then pass control to the "do_proc()" function where we will
- implement the function call.
-
- In implementing the function we will first utilise a call to the normal
- "copy" process to copy the record from the current file as we normally
- would. This ensures that any unique linking key will not be violated.
- If the "copy" is successful then "copyBranch()" will be invoked to
- transfer the rest of the branch.
-
- We also need to add an include directive for the function file that you
- have just written, #include "copybran.fun", just before the "do_proc"
- function so that the new functions will be available in the skeleton, :--
-
- #include "copybran.fun" /* <-- New */
-
- void do_proc(int procno, mnufrec *m)
- {
- long copyRecno; /* <-- New */
- ...
- ...
- case 99: if (status_ok(filno)) {
- copyRecno = recno[filno];
- add_record('C');
- if (exitcode == XeptKey) copyBranch(filno,copyRecno);
- } break;
- ...
- ...
- }
-
- void do_menu(void)
- {
- ...
- ...
- case LArr : gorl(&dm,Left); break;
- case RArr : gorl(&dm,Right); break;
- /*New*/ case sF1 : do_proc(99,&dm); break;
- case Enter : if (gvar->sec >= dm.curitm->sec) do_ctl(&dm,dm.curitm); break;
- ...
- ...
- }
-