home *** CD-ROM | disk | FTP | other *** search
/ CP/M / CPM_CDROM.iso / simtel / sigm / vols000 / vol025 / dbunit.3 < prev    next >
Text File  |  1984-04-29  |  22KB  |  687 lines

  1. FUNCTION DBSEEK(*WI:DBWRKINDEX; WHICHITEM:INTEGER):DBERRTYPE*);
  2. (*move pointer to item # itemnum in current level*)
  3. VAR NEWOFFSET,I,LINKV:INTEGER;
  4.   CRACKSW:CRACKSWTYPE;
  5.   RP:RECDESPTR;
  6.  
  7.   PROCEDURE FOLLOWLINKS(NEWOFFSET:PAGEPTR; COUNT:INTEGER);
  8.   VAR I:INTEGER;
  9.   BEGIN
  10.     (*all items assumed to be linked & all lists stopped with nul*)
  11.     WITH WRKTABLE[WI] DO
  12.       WITH WIB^[TOS] DO
  13.         BEGIN
  14.           LINKV:=LINKVALUE(WA,NEWOFFSET);
  15.           (*following should be in external procedure for speed*)
  16.           I:=0;
  17.           WHILE (LINKV > 0 ) AND (I < COUNT) DO
  18.             BEGIN
  19.               NEWOFFSET:=NEWOFFSET+LINKV;
  20.               LINKV:=LINKVALUE(WA,NEWOFFSET);
  21.               I:=I+1;
  22.             END;
  23.           (*end of external proc*)
  24.           IF (LINKV = 0) AND (I < COUNT) THEN
  25.             DBSEEK:=27  (*cannot find requested item*)
  26.           ELSE
  27.             BEGIN
  28.               OFFSET:=NEWOFFSET;
  29.               ITEMNUM:=ITEMNUM+COUNT;
  30.             END;
  31.         END (*WITH WIB*);
  32.   END (*FOLLOWLINKS*);
  33.   
  34. BEGIN (*DBSEEK*)
  35.   DBSEEK:=0;
  36.   TRACEWA(9,WI);
  37.   WITH WRKTABLE[WI] DO
  38.     WITH WIB^[TOS] DO
  39.       BEGIN
  40.         DBSHOWERR('SEEK#1',DBHEAD(WI));
  41.         IF DBTYPECHECK THEN
  42.           BEGIN (*assume that we are at head of this level!*)
  43.             CASE LEVEL OF
  44.               GROUPT,RECORDT:
  45.                 BEGIN  (*all groups and records are linked*)
  46.                   IF WHICHITEM > 0 THEN
  47.                     BEGIN
  48.                       (*item #0 in a record may contain several fixed fields*)
  49.                       FOLLOWLINKS(OFFSET,WHICHITEM); 
  50.                       SETDESCRIPTORNUM(WI);
  51.                     END;
  52.                 END (*GROUPT*);
  53.               FIELDT:
  54.                 BEGIN
  55.                   IF WHICHITEM > 0 THEN
  56.                     BEGIN
  57.                       (*now get offset of field within the record*)
  58.                       RP:=ACTIVERECORDS[WIB^[TOS-1].DESCRIPTORNUM];
  59.                       IF RP = NIL THEN
  60.                         DBSEEK:=32
  61.                       ELSE
  62.                         WITH RP^ DO
  63.                           BEGIN
  64.                             IF WHICHITEM < FIRSTLITEMNUM THEN
  65.                               ITEMNUM:=WHICHITEM
  66.                             ELSE
  67.                               BEGIN (*linked field*)
  68.                                 ITEMNUM:=FIRSTLITEMNUM-1;
  69.                                 FOLLOWLINKS(OFFSET,(WHICHITEM - FIRSTLITEMNUM 
  70.                                                   + ORD(FIRSTLITEMNUM > 0)));
  71.                               END (*linked field*);
  72.                           END (*WITH RP^*);
  73.                         SETDESCRIPTORNUM(WI); 
  74.                     END;
  75.                 END (*FIELDT*)
  76.             END (*CASE*);
  77.           END (*IF DBTYPECHECK*)
  78.         ELSE
  79.           FOLLOWLINKS(OFFSET,WHICHITEM);
  80.       END (*WITH*);
  81.   TRACEWA(10,WI);
  82. END (*DBSEEK*);
  83.  
  84. FUNCTION DBDESCEND(*WI:DBWRKINDEX):DBERRTYPE*);
  85. VAR LINKV:PAGEPTR;
  86.   OLDLVL:DBLEVELTYPE;
  87.   LINKED:BOOLEAN;
  88.   GP:GRPDESPTR;
  89.   RP:RECDESPTR;
  90.   FP:FLDDESPTR;
  91.   CRACKSW:CRACKSWTYPE;
  92.  
  93.   PROCEDURE DOWNLINK;
  94.   (*move down to head of enclosed level*)
  95.   VAR PARENTOFFSET:PAGEPTR;
  96.   BEGIN
  97.     WITH WRKTABLE[WI] DO
  98.       BEGIN
  99.         WITH WIB^[TOS] DO
  100.           BEGIN
  101.             LINKV:=LINKVALUE(WA,OFFSET);
  102.             PARENTOFFSET:=OFFSET;
  103.           END;
  104.         IF LINKV = 0 THEN
  105.           DBDESCEND:=19 (*at end of list, can't descend*)
  106.         ELSE
  107.           BEGIN
  108.             OLDLVL:=WIB^[TOS].LEVEL;
  109.             IF OLDLVL=NONET THEN
  110.               DBDESCEND:=20 (*can't continue from nonet*)
  111.             ELSE
  112.               BEGIN
  113.                 TOS:=TOS+1;
  114.                 WITH WIB^[TOS] DO
  115.                   BEGIN
  116.                     OFFSET:=PARENTOFFSET+LINKSIZE(LINKV);
  117.                     IF OLDLVL = GROUPT THEN
  118.                       (*step over group's tag*)
  119.                       STEPLINK(WI);
  120.                     LEVEL:=NEXTLEVEL(OLDLVL);
  121.                     ITEMNUM:=0;
  122.                   END (*WITH*);
  123.               END (*LEVEL<>NONET*);
  124.           END (*LINKV<>0*);
  125.       END (*WITH WRKTABLE*);
  126.   END (*DOWNLINK*);
  127.   
  128. BEGIN (*DBDESCEND*)
  129.   DBDESCEND:=0;
  130.   TRACEWA(11,WI);
  131.   IF DBTYPECHECK THEN
  132.     WITH WRKTABLE[WI] DO
  133.       BEGIN
  134.         CASE WIB^[TOS].LEVEL OF
  135.           GROUPT:
  136.             BEGIN
  137.               (*point to first record in group*)
  138.               GP:=ACTIVEGROUPS[WIB^[TOS].DESCRIPTORNUM];
  139.               IF GP=NIL THEN
  140.                 DBDESCEND:=33
  141.               ELSE
  142.                 BEGIN
  143.                   DOWNLINK;
  144.                   SETDESCRIPTORNUM(WI);
  145.                 END;
  146.             END (*GROUPT*);
  147.           RECORDT:
  148.             BEGIN (*point to first field in record*)
  149.               RP:=ACTIVERECORDS[WIB^[TOS].DESCRIPTORNUM];
  150.               IF RP=NIL THEN
  151.                 DBDESCEND:=32
  152.               ELSE
  153.                 BEGIN
  154.                   DOWNLINK;
  155.                   SETDESCRIPTORNUM(WI);
  156.                 END (*RP<>NIL*);
  157.             END (*RECORDT*);
  158.           FIELDT:
  159.             BEGIN
  160.               (*if the field is structured, point to the contained group*)
  161.               FP:=ACTIVEFIELDS[WIB^[TOS].DESCRIPTORNUM];
  162.               IF FP=NIL THEN
  163.                 DBDESCEND:=31
  164.               ELSE
  165.                 WITH FP^ DO
  166.                   IF FLDTYPE <> GROUPF THEN
  167.                     DBDESCEND:=34 (*can't descend into a simple field*)
  168.                   ELSE
  169.                     BEGIN
  170.                       DOWNLINK;
  171.                       SETDESCRIPTORNUM(WI);
  172.                     END;
  173.             END (*FIELDT*)
  174.         END (*CASES*);
  175.       END (*WITH WRKTABLE*)
  176.   ELSE
  177.     (*assume that next level, if any, is linked*)
  178.     DOWNLINK;
  179.   TRACEWA(12,WI);
  180. END (*DBDESCEND*);
  181.  
  182. FUNCTION DBASCEND(*WI:DBWRKINDEX):DBERRTYPE*);
  183. (*return to enclosing level*)
  184. BEGIN
  185.   WITH WRKTABLE[WI] DO
  186.     BEGIN
  187.       IF TOS > 0 THEN
  188.         BEGIN
  189.           WITH WIB^[TOS] DO
  190.             BEGIN
  191.               OFFSET:=0;
  192.               LEVEL:=NONET;
  193.               DESCRIPTORNUM:=-1;
  194.               ITEMNUM:=-1;
  195.             END;
  196.           TOS:=TOS-1;
  197.         END (*TOS> 0*);
  198.     END (*WITH WRKTABLE*);
  199.   TRACEWA(31,WI);
  200. END (*DBASCEND*);
  201.  
  202. FUNCTION DBFINDREC(*WI:DBWRKINDEX; RULE:DBFINDRULE; FIELDNUM:INTEGER;
  203.                    KEY:STRING; VAR RECNUM:INTEGER;
  204.                    VAR FOUND:BOOLEAN):DBERRTYPE*);
  205. (*locate a record whose FIELDNUM field matches the KEY according to
  206.   the comparison RULE (ascending,descending, or random equals) *)
  207. (*$G+*)
  208. LABEL 1;
  209. VAR FLINKNUM,FN,RN,RLINKV,FOFFSET,DUMMY:INTEGER;
  210.   RP:RECDESPTR;
  211.   DONE:BOOLEAN;
  212.   S:STRING;
  213. BEGIN
  214.   TRACEWA(27,WI);
  215. (*on entry we should be at RECORDT level, with ITEMNUM=0. First find
  216.   out if field is variable and set FLINKNUM*)
  217.   WITH WRKTABLE[WI] DO
  218.     WITH WIB^[TOS] DO
  219.       BEGIN
  220.         IF LEVEL <> RECORDT THEN
  221.           DBFINDREC:=39 (*must be at record level*)
  222.         ELSE
  223.           BEGIN
  224.             IF ITEMNUM <> 0 THEN
  225.               DUMMY:=DBHEAD(WI);
  226.             RP:=ACTIVERECORDS[DESCRIPTORNUM];
  227.             IF RP = NIL THEN
  228.               DBFINDREC:=32
  229.             ELSE
  230.               WITH RP^ DO
  231.                 BEGIN
  232.                   IF (SWITCHES <> 0) OR (FIELDNUM < FIRSTLITEMNUM) THEN
  233.                     DBFINDREC:=40 (*must be untagged record and
  234.                                     untagged string field*)
  235.                   ELSE
  236.                     BEGIN
  237.                       FLINKNUM:=FIELDNUM - FIRSTLITEMNUM
  238.                                          + ORD(FIRSTLITEMNUM > 0);
  239.                       DONE:=FALSE;
  240.                       FOUND:=FALSE;
  241.                       RN:=0;
  242.                       RLINKV:=LINKVALUE(WA,OFFSET);
  243.                       (*speed-up possibilities: native code; assume all
  244.                         links are single bytes & eliminate proc calls
  245.                         to linksize & linkvalue*)
  246.                       WHILE RLINKV <> 0 DO
  247.                         BEGIN
  248.                           FN:=0;
  249.                           FOFFSET:=OFFSET + LINKSIZE(RLINKV);
  250.                           (*all in-field links assumed 1 byte ! *)
  251.                           (*move to field pointer now*)
  252. (*$R-*)
  253.                           WHILE (FN < FLINKNUM) DO
  254.                             BEGIN
  255.                               FOFFSET:=FOFFSET+WA^[FOFFSET];
  256.                               FN:=FN+1;
  257.                             END;
  258.                           MOVELEFT(WA^[FOFFSET],S,WA^[FOFFSET]);
  259. (*$R+*)
  260.                           DELETE(S,LENGTH(S),1); (*correct link to length*)
  261.                           CASE RULE OF
  262.                             ASCENDING: DONE:= (KEY <= S);
  263.                             DESCENDING:DONE:= (KEY >= S);
  264.                             RANDOM:    DONE:= (KEY =  S)
  265.                           END (*CASES*);
  266.                           IF DONE THEN
  267.                             BEGIN
  268.                               FOUND:= (KEY = S);
  269.                               GOTO 1; (*for efficiency*)
  270.                             END
  271.                           ELSE
  272.                             BEGIN (*jump to next record*)
  273.                               OFFSET:=OFFSET+RLINKV;
  274.                               RLINKV:=LINKVALUE(WA,OFFSET);
  275.                               RN:=RN+1;
  276.                             END (*NOT DONE*);
  277.                         END (*WHILE RLINKV*);
  278. 1:
  279.                       RECNUM:=RN;
  280.                       ITEMNUM:=RN;
  281.                     END (*untagged ok*);
  282.                 END (*WITH RP^*);
  283.           END (*LEVEL = RECORDT*);
  284.       END (*WITH WIB^*);
  285.   TRACEWA(28,WI);
  286. END (*DBFINDREC*);
  287.  
  288.  
  289. (*DATA TRANSFER PRIMITIVES*)
  290. FUNCTION DBCOPY(*SOURCE,DESTINATION:DBWRKINDEX):DBERRTYPE*);
  291. (*zero out the destination workarea. copy source record or group into
  292.   destination. initialize pointers. *)
  293. VAR SLEVEL:DBLEVELTYPE; 
  294.   SINUSE,SDNUM,SOFFSET,SLINKV,STOS:INTEGER;
  295. BEGIN
  296.   TRACEWA(24,SOURCE);
  297.   TRACEWA(25,DESTINATION);
  298.   ZEROWORKAREA(DESTINATION);
  299.   WITH WRKTABLE[SOURCE] DO
  300.     WITH WIB^[TOS] DO
  301.       BEGIN
  302.         SINUSE:=SPACEINUSE;
  303.         SLEVEL:=LEVEL;
  304.         SOFFSET:=OFFSET;
  305.         SLINKV:=LINKVALUE(WA,OFFSET);
  306.         STOS:=TOS;
  307.         SDNUM:=DESCRIPTORNUM;
  308.       END;
  309.   IF (SLEVEL <> GROUPT) OR (STOS <> 0) THEN
  310.     DBCOPY:=12 (*can''t yet handle anything but outer level group*)
  311.   ELSE
  312.     WITH WRKTABLE[DESTINATION] DO
  313.       WITH WIB^[TOS] DO
  314.         IF SLINKV > WSIZE THEN
  315.           DBCOPY:=1 (*insufficient space*)
  316.         ELSE
  317.           BEGIN
  318.             SPACEINUSE:=SINUSE;
  319.             LEVEL:=GROUPT;
  320.             OFFSET:=0;
  321.             DESCRIPTORNUM:=SDNUM;
  322.             ITEMNUM:=0;
  323. (*$R-*)
  324.             MOVELEFT(WRKTABLE[SOURCE].WA^[SOFFSET],
  325.                      WA^[OFFSET], SLINKV);
  326. (*$R+*)
  327.           END;
  328.   TRACEWA(26,DESTINATION);
  329. END (*DBCOPY*);
  330.  
  331. FUNCTION DBEMPTYITEM(*DESTINATION:DBWRKINDEX; LVL:DBLEVELTYPE;
  332.                                               TAG:INTEGER):DBERRTYPE*);
  333. (*creates a new empty item at level LVL and sets its tag if required*)
  334. VAR NEWOFFSET,LINKV:PAGEPTR;
  335.   TAGBYTES,ISTACK:INTEGER;
  336.  
  337.   PROCEDURE NEWLINKITEM(WIDTH:INTEGER; NEWOFFSET:PAGEPTR);
  338.   (*insert an empty linked item WIDTH bytes wide*)
  339.   VAR I:INTEGER;
  340.   BEGIN
  341.     IF TAG >= LINKESCAPE THEN WIDTH:=WIDTH+1;
  342.     WITH WRKTABLE[DESTINATION] DO
  343.       BEGIN
  344.         DBSHOWERR('NEWLINKITEM', MOVETAIL(DESTINATION,WIDTH,NEWOFFSET));
  345. (*$R-*)
  346.         WA^[NEWOFFSET]:=WIDTH;
  347.         IF LVL = GROUPT THEN
  348.           SAVEBIGLINK(DESTINATION,TAG,NEWOFFSET+1);
  349. (*$R+*)
  350.         IF LVL = WIB^[TOS].LEVEL THEN
  351.           BEGIN
  352.             IF TOS > 0 THEN
  353.               FIXLINKS(DESTINATION, (TOS-1), WIDTH);
  354.           END
  355.         ELSE
  356.           FIXLINKS(DESTINATION, TOS, WIDTH);
  357.       END (*WITH*);
  358.   END (*NEWLINKITEM*);
  359.   
  360.   PROCEDURE BLANKRECORD;
  361.   (*lay out empty fields in a blank record*)
  362.   VAR RP:RECDESPTR;
  363.     FP:FLDDESPTR;
  364.     FN,MAXFN,FIXWIDTH,VARWIDTH:INTEGER;
  365.     SW:CRACKSWTYPE;
  366.     FIRSTLINKOFFSET:PAGEPTR;
  367.   BEGIN
  368.     WITH WRKTABLE[DESTINATION] DO
  369.       WITH WIB^[TOS] DO
  370.         BEGIN
  371.           RP:=ACTIVERECORDS[DESCRIPTORNUM];
  372.           WITH RP^ DO
  373.             BEGIN
  374.               FN:=0;
  375.               SW.BL:=SWITCHES;
  376.               FIRSTLINKOFFSET:=OFFSET+1;
  377.               IF SW.A[0] THEN (*tagged*)
  378.                 FIXWIDTH:=1
  379.               ELSE
  380.                 FIXWIDTH:=0;
  381.               MAXFN:=LASTFLDLINK DIV 2 - 1;
  382.               (*fixed fields first*)
  383.               WHILE (FN < FIRSTLITEMNUM) AND (FN < MAXFN) DO
  384.                 BEGIN
  385. (*$R-*)
  386.                   WITH FLDREF[FN] DO
  387. (*$R+*)
  388.                     BEGIN
  389.                       FP:=ACTIVEFIELDS[FDNUM];
  390.                       FIXWIDTH:=FIXWIDTH+FP^.MAXWIDTH;
  391.                     END;
  392.                   FN:=FN+1;
  393.                 END (*WHILE*);
  394.               IF FN > 0 THEN
  395.                 BEGIN
  396.                   (*one link over all fixed fields*)
  397.                   FIXWIDTH:=FIXWIDTH+1;
  398.                   NEWLINKITEM(FIXWIDTH, FIRSTLINKOFFSET);
  399.                 END;
  400.               (*if there are fixed fields, FIXWIDTH now includes the link*)
  401.               NEWOFFSET:=FIRSTLINKOFFSET+FIXWIDTH;
  402.               (*now put links of 1 for each variable size field*)
  403.               VARWIDTH:=MAXFN-FN+1;
  404.               DBEMPTYITEM:=MOVETAIL(DESTINATION, VARWIDTH, NEWOFFSET);
  405.               WHILE FN < MAXFN DO
  406.                 BEGIN
  407. (*$R-*)
  408.                   WA^[NEWOFFSET]:=1;
  409. (*$R+*)
  410.                   NEWOFFSET:=NEWOFFSET+1;
  411.                   FN:=FN+1;
  412.                 END;
  413.             END (*WITH RP^*);
  414.           (*still have to set overlink of record itself*)
  415.           IF (VARWIDTH+FIXWIDTH) >= LINKESCAPE THEN
  416.             BEGIN
  417.               VARWIDTH:=VARWIDTH+1;
  418.               DBEMPTYITEM:=MOVETAIL(DESTINATION,1,OFFSET);
  419.             END;
  420.           SAVEBIGLINK(DESTINATION, 
  421.                 (VARWIDTH+FIXWIDTH+1(*original link assumed small*)), 
  422.                                           OFFSET);
  423.           (* and also the enclosing links*)
  424.           FIXLINKS(DESTINATION, (TOS-1), VARWIDTH);
  425.         END (*WITH WIB^[TOS]*);
  426.   END (*BLANKRECORD*);
  427.   
  428. BEGIN (*DBEMPTYITEM*)
  429.   DBEMPTYITEM:=0;
  430.   WITH WRKTABLE[DESTINATION] DO
  431.     BEGIN
  432.       TRACEWA(0,DESTINATION);
  433.       WITH WIB^[TOS] DO
  434.         IF LVL=LEVEL THEN
  435.           CASE LEVEL OF
  436.             NONET: DBEMPTYITEM:=13; (*undefined level*)
  437.             RECORDT:
  438.               (*insert a single byte link with value of 2, with nul stopper*)
  439.               BEGIN
  440.                 NEWLINKITEM(1,OFFSET);
  441.                 IF DBTYPECHECK THEN
  442.                   BLANKRECORD;
  443.               END;
  444.             GROUPT: 
  445.               BEGIN
  446.                 NEWLINKITEM(3,OFFSET); (*leave byte for required tag*)
  447.                 DESCRIPTORNUM:=TAG;
  448.               END;
  449.             FIELDT:NEWLINKITEM(2,OFFSET)
  450.           END (*CASE LEVEL*)
  451.         ELSE
  452.           BEGIN (*LVL<>LEVEL*)
  453.             IF LVL<>NEXTLEVEL(LEVEL) THEN
  454.               DBEMPTYITEM:=15 (*improper data level*)
  455.             ELSE (*new embedded level, probably have to update earlier link*)
  456.               BEGIN (*create blank linked item, descend to it, make blank
  457.                                 record if needed*)
  458.                 IF LVL = GROUPT THEN
  459.                   TAGBYTES:=2
  460.                 ELSE
  461.                   TAGBYTES:=0;
  462.                 NEWOFFSET:=OFFSET+1+ORD(LINKVALUE(WA,OFFSET) >= LINKESCAPE);
  463.                 IF LEVEL = GROUPT THEN (*step over the tag*)
  464.                   NEWOFFSET:=NEWOFFSET+1
  465.                                +ORD(LINKVALUE(WA,NEWOFFSET) >= LINKESCAPE);
  466.                 NEWLINKITEM(1+TAGBYTES,NEWOFFSET);
  467.                 DBEMPTYITEM:=DBDESCEND(DESTINATION);
  468.                 IF DBTYPECHECK AND (LVL = RECORDT) THEN
  469.                   BLANKRECORD;
  470.               END (*LVL = NEXTLEVEL*);
  471.           END (*LVL<>LEVEL*);
  472.     END (*WITH WRKTABLE*);
  473.   TRACEWA(1,DESTINATION);
  474. END (*DBEMPTYITEM*);
  475.  
  476. FUNCTION DBDELETE(*DESTINATION:DBWRKINDEX):DBERRTYPE*);
  477. (*eliminate the destination item (group or record only) entirely*)
  478. VAR LINKV:INTEGER;
  479. BEGIN
  480.   TRACEWA(17,DESTINATION);
  481.   DBDELETE:=0;
  482.   WITH WRKTABLE[DESTINATION] DO
  483.     WITH WIB^[TOS] DO
  484.       BEGIN
  485.         IF NOT (LEVEL IN [GROUPT,RECORDT]) THEN
  486.           DBDELETE:=41
  487.         ELSE
  488.           BEGIN
  489.             LINKV:=LINKVALUE(WA,OFFSET);
  490.             IF LINKV <> 0 THEN
  491.               DBDELETE:=MOVETAIL(DESTINATION, -LINKV, OFFSET+LINKV);
  492.             IF TOS > 0 THEN
  493.               FIXLINKS(DESTINATION, TOS-1, -LINKV);
  494.           END (*LEVEL OK*);
  495.       END (*WITH WIB^*);
  496.   TRACEWA(18,DESTINATION);
  497. END (*DBDELETE*);
  498.  
  499. FUNCTION DBBLANK(*DESTINATION:DBWRKINDEX):DBERRTYPE*);
  500. (*replace the destination group or record with an empty item*)
  501. VAR RSLT,DELTA:INTEGER;
  502. BEGIN
  503.   TRACEWA(19,DESTINATION);
  504.   RSLT:=DBDELETE(DESTINATION);
  505.   IF RSLT <> 0 THEN
  506.     DBBLANK:=RSLT
  507.   ELSE
  508.     WITH WRKTABLE[DESTINATION] DO
  509.       WITH WIB^[TOS] DO
  510.         BEGIN
  511.           IF LEVEL = GROUPT THEN
  512.             DELTA:=3
  513.           ELSE
  514.             DELTA:=2;
  515.           RSLT:=MOVETAIL(DESTINATION, DELTA, OFFSET);
  516.           IF RSLT <> 0 THEN
  517.             DBBLANK:=RSLT
  518.           ELSE
  519.             BEGIN
  520.               WA^[OFFSET]:=DELTA;
  521.               IF TOS > 0 THEN
  522.                 FIXLINKS(DESTINATION, TOS-1, DELTA);
  523.             END;
  524.           DESCRIPTORNUM:=-1;
  525.         END (*WITH WIB^*);
  526.   TRACEWA(20,DESTINATION);
  527. END (*DBBLANK*);
  528.  
  529. FUNCTION DBREPLACE(*SOURCE,DESTINATION:DBWRKINDEX):DBERRTYPE*);
  530. (*the source item replaces the destination item. must be record or group*)
  531. VAR SLINKV,SOFFSET,STOS,DOFFSET,DTOS,RSLT:INTEGER;
  532.   SLEVEL,DLEVEL:DBLEVELTYPE;
  533. BEGIN
  534.   TRACEWA(21,SOURCE);
  535.   TRACEWA(22,DESTINATION);
  536.   RSLT:=DBDELETE(DESTINATION);
  537.   IF RSLT <> 0 THEN
  538.     DBREPLACE:=RSLT
  539.   ELSE
  540.     BEGIN
  541.       WITH WRKTABLE[SOURCE] DO
  542.         WITH WIB^[TOS] DO
  543.           BEGIN
  544.             SLEVEL:=LEVEL;
  545.             SOFFSET:=OFFSET;
  546.             SLINKV:=LINKVALUE(WA,OFFSET);
  547.             STOS:=TOS;
  548.           END;
  549.       WITH WRKTABLE[DESTINATION] DO
  550.         WITH WIB^[TOS] DO
  551.           BEGIN
  552.             DLEVEL:=LEVEL;
  553.             DOFFSET:=OFFSET;
  554.             DTOS:=TOS;
  555.           END;
  556.       IF DLEVEL <> SLEVEL THEN
  557.         DBREPLACE:=42 (*mismatch*)
  558.       ELSE
  559.         IF NOT (DLEVEL IN [GROUPT,RECORDT]) THEN
  560.           DBREPLACE:=41
  561.         ELSE
  562.           BEGIN
  563.             (*open space up to receive source copy*)
  564.             RSLT:=MOVETAIL(DESTINATION,SLINKV,DOFFSET);
  565.             IF RSLT <> 0 THEN
  566.               DBREPLACE:=RSLT
  567.             ELSE
  568. (*$R-*)
  569.               BEGIN
  570.                 MOVELEFT(WRKTABLE[SOURCE].WA^[SOFFSET],
  571.                        WRKTABLE[DESTINATION].WA^[DOFFSET], SLINKV);
  572. (*$R+*)
  573.                 IF DTOS > 0 THEN
  574.                   FIXLINKS(DESTINATION, DTOS-1, SLINKV);
  575.               END;
  576.             WRKTABLE[DESTINATION].WIB^[DTOS].DESCRIPTORNUM
  577.               := WRKTABLE[SOURCE].WIB^[STOS].DESCRIPTORNUM;
  578.           END (*levels ok*);
  579.     END (*DELETE worked ok*);
  580.   TRACEWA(23,DESTINATION);
  581. END (*DBREPLACE*);
  582.  
  583. FUNCTION DBRESERVE(*DESTINATION:DBWRKINDEX):DBERRTYPE*);
  584. (*reserve empty space at the end of destination group*)
  585. BEGIN
  586.   TRACEWA(32,DESTINATION);
  587.   TRACEWA(33,DESTINATION);
  588. END (*DBRESERVE*);
  589.  
  590. FUNCTION GETFOFFSET(WI:DBWRKINDEX):PAGEPTR;
  591. (*returns the offset (in record) of a fixed width field based on
  592.   its ITEMNUM*)
  593. VAR RP:RECDESPTR;
  594.  DN:INTEGER;
  595. BEGIN
  596.   WITH WRKTABLE[WI] DO
  597.     BEGIN
  598.       DN:=WIB^[TOS-1].DESCRIPTORNUM;
  599.       IF (DN >= 0) AND (DN <= LASTRECDESCRIPTOR) THEN
  600.         BEGIN
  601.           RP:=ACTIVERECORDS[DN];
  602.           IF RP = NIL THEN
  603.             DBSHOWERR('GETOFFSET - Record not active', 100)
  604.           ELSE
  605. (*$R-*)
  606.             GETFOFFSET:=RP^.FLDREF[WIB^[TOS].ITEMNUM].FLDOFFSET;
  607. (*$R+*)
  608.         END
  609.       ELSE
  610.         DBSHOWERR('GETOFFSET - DESCRIPTORNUM not initialized',100);
  611.     END;
  612. END (*GETFOFFSET*);
  613.  
  614. FUNCTION DBGET(*SOURCE:DBWRKINDEX):DBERRTYPE*);
  615. (*extract item value from workarea and place it in DBMAIL for pickup by
  616.   caller*)
  617. CONST FIXEDWIDTH = 1;
  618. VAR LINKV: INTEGER;
  619.   FP:FLDDESPTR;
  620.   RP:RECDESPTR;
  621.   SW:CRACKSWTYPE;
  622.   FOFFSET:INTEGER;
  623.  
  624.   PROCEDURE GETLINKF(FLDTYPE:DBFIELDTYPES);
  625.   BEGIN
  626.     WITH WRKTABLE[SOURCE] DO
  627.       WITH WIB^[TOS] DO
  628.         BEGIN
  629.           LINKV:=LINKVALUE(WA,OFFSET);
  630.           IF LINKV >= LINKESCAPE THEN
  631.             DBGET:=21 (*string too long to assign*)
  632.           ELSE
  633.             BEGIN
  634. (*$R-*)
  635.               MOVELEFT(WA^[OFFSET],DBMAIL.TXT,LINKV);
  636. (*$R+*)
  637.               DBMAIL.TXT[0]:=CHR(LINKV-1);
  638.               DBMAIL.DBMAILTYPE:=FLDTYPE;
  639.             END (*LINKV < LINKESCAPE*);
  640.         END (*WITH WIB*);
  641.   END (*GETLINKF*);
  642.   
  643. BEGIN (*DBGET*)
  644.   DBGET:=0;
  645.   TRACEWA(13,SOURCE);
  646.   IF DBTYPECHECK THEN
  647.     WITH WRKTABLE[SOURCE] DO
  648.       WITH WIB^[TOS] DO
  649.         BEGIN
  650.           IF LEVEL = GROUPT THEN
  651.             GETLINKF(GROUPF)
  652.           ELSE
  653.             IF LEVEL <> FIELDT THEN
  654.               DBGET:=38 (*must be a field*)
  655.             ELSE
  656.           IF (DESCRIPTORNUM >= 0) 
  657.                   AND (DESCRIPTORNUM <= LASTFIELDDESCRIPTOR) THEN
  658.             BEGIN
  659.               FP:=ACTIVEFIELDS[DESCRIPTORNUM];
  660.               IF FP = NIL THEN
  661.                 DBGET:=31 (*no such field exists*)
  662.               ELSE
  663.                 WITH FP^ DO
  664.                   BEGIN
  665.                     SW.BL:=SWITCHES;
  666.                     IF SW.A[FIXEDWIDTH] THEN
  667.                       WITH DBMAIL DO
  668.                         BEGIN
  669. (*$R-*)
  670.                           MOVELEFT(WA^[OFFSET
  671.                                    +GETFOFFSET(SOURCE)], TXT, MAXWIDTH);
  672. (*$R+*)
  673.                           DBMAILTYPE:=FLDTYPE;
  674.                         END
  675.                     ELSE
  676.                       GETLINKF(FLDTYPE);
  677.                   END (*WITH FP^*);
  678.             END (*DESCRIPTORNUM OK*)
  679.           ELSE
  680.             DBGET:=31; (*no such field exists*)
  681.         END (*WITH WIB^[TOS]*)
  682.   ELSE (*no type checking - assume it's linked*)
  683.     GETLINKF(STRINGF);
  684. END (*DBGET*);
  685.  
  686.  
  687.