! Database Manager sub-module ! ! ! ! EXTERNAL ROUTINES/PREDICATES FOR THE DATABASE MANAGEMENT ! ! FOR APMTEL By Andie Ness 2/3/88 ! ! ! 9/ 5/88 Added database name parameter. AN ! 9/ 5/88 Added timestamp information. AN ! %begin %include "CONSTS.INC" %include "INC:UTIL.IMP" %include "FILES.INC" %externalroutinespec access file(%string(255)f,%integer m,%integername ref,size) %externalroutinespec deaccess file(%integer ref) %externalroutinespec read region(%integer ref,byte,bytes,%bytename buffer) %externalroutinespec write region(%integer ref,byte,bytes,%bytename buffer) %externalstring(255) %fnspec extract comments(%integer n, %integername i) %constinteger true=1,false=0 ! ! open: attempt to open one of the database files ! success = 1, failure = -1 ! ! needed as there are no low-level file locking routines ! available on the APMs ! %integerfn open ( %string(255) cache file, %integername file handle, file size, %integer mode) %on %event 0,1,2,3,4,5,6,7,8,9 %start %if event_event = 3 %and event_sub = 3 %start print string("GROK - Error occured - ".snl) print string("Event number = "); write(event_event,0); newline print string("Event sub = "); write(event_sub,0); newline print string("Line number = "); write(event_line,0); newline print string("Extra info = ".event_message.snl) print string("Cannot find database file !!!!") newline print string("APMTEL must have been disabled!!!".snl) print string("Stopping .... Byee".snl) %stop %finish %return -1 %finish accessfile(cache file ,mode, file handle,file size) %return 1 %end %externalroutine show comments %integer ch, number, i,j, temp newline print string(" 0...".extract comments(0,number).snl); newline i=0 %cycle i=i+1 ch=test symbol write(i,3); print string("...".extract comments(i,number).snl) %if (i//10)*10 = i %start print string("".snl); %cycle ch = test symbol %repeatuntil ch#-1 %finish %repeatuntil number<=1 %or ch=32 %end ! open cache: routine to repeat a re-open of the database file ! until it succeeds ! %routine open cache( %string(255) cache file, %integername filehandle, filesize, %integer mode) %cycle; %repeatuntil open(cache file,file handle, file size, mode) #-1 %end ! ! close cache: routine to close the database file for use by other users ! %routine close cache(%integer file handle) deaccessfile(file handle) %end ! ! free slot: function that returns the record number of any free slots ! in the database. If none, -1 ! %integerfn free slot(%integer file handle, file size) %integer i %integer max records %bytearray buffer(0:record size) max records = file size // record size i=0 %cycle read region(file handle,i*record size,1,buffer(0)) i = i + 1 %repeatuntil buffer(0)=0 %or i = max records %if buffer(usage offset)=free %start %return i-1 %finish %return -1; ! No free slots %end ! CONVERT TO INTERNAL ! This function takes a pointer to a byte array (actually its a date string ! returned from the system function 'DATETIME') and converts the pointed-at ! array into an easily compared form - ie an integer. I would have prefered ! to have made it a long integer but unfortunately, this compiler doesn't ! support %longintegerfn's ! %integerfn convert to internal(%bytearrayname b) %integer temp,i temp = b(7)-'0' temp = temp * 10 + b(3)-'0' temp = temp * 10 + b(4)-'0' temp = temp * 10 + b(0)-'0' temp = temp * 10 + b(1)-'0' %for i = 9,1,14 %cycle temp = temp * 10 + b(i)-'0' %unless b(i)='.' %or b(i) = ' ' %repeat %return temp %end %integerfn extract stamp(%bytearrayname b) %integer i %bytearray t(0:15) %for i=date stamp offset,1,date stamp offset+15 %cycle t(i-date stamp offset) = b(i) %repeat %return(convert to internal(t)) %end %integerfn current datestamp %string(255) t %bytearray t1(0:15) %integer i t = datetime %for i=1,1,15 %cycle t1(i-1) = charno(t,i) %repeat %return(convert to internal(t1)) %end ! oldest record : function to return the record number of the oldest ! record in the database file. Used when 'free slot' ! fails. %integerfn oldest record(%integer fref, fsize) %integer record no,oldest record, oldest date, temp date %bytearray b(0:14) oldest record= 2 { Dummy value oldest date= 999999999 { Dummy value %for record no =0,1,fsize//record size-1 %cycle read region(fref, record no * record size+ datestamp offset,15,b(0)) temp date = convert to internal(b) %if temp date < oldest date %start oldest date = temp date oldest record = record no %finish %repeat %return oldest record %end ! match: function that returns the record number of a record that ! has the same page number and channel as the passed args. ! Used to replace out of date pages %externalintegerfn match(%integer page,channel, %string(255)cache file,%integer replace) %integer i %bytearray c(0:record size) %integer max records %integer file ref, file size, byte pos %integer page no %integer finished open cache(cache file, file ref, file size, 0) channel = channel - '0' finished = false max records = file size // record size i=0 %cycle read region(file ref,record size * i,64,c(0)) page no = c (page no hi offset) * 256 + c(page no lo offset) %if page no = page %and channel= c(channel offset) %start %if replace = 1 %start %if current datestamp-extract stamp(c)< 100 %then %c finished = true %else finished = true %finish %finish i=i+1 %repeatuntil finished=true %or i = max records close cache(file ref) %if finished=false %then %return -1 %else %return i-1 %end ! insert page: place the supplied page in the database file along ! with page number, channel information and comments %externalroutine insert page(%bytearray page(0:24,0:39),%integer page no, %byte channel, %string(255) file, comments) %integer record no %integer file ref, file size, byte pos,i,j %bytearray this entry(0:1023); %string(15) time stamp this entry (usage offset) = used this entry (channel offset) = channel - '0' this entry (page no lo offset) = page no & 16_FF this entry (page no hi offset) = (page no >> 8) & 16_ff time stamp = datetime %for i=1,1,length(time stamp) %cycle this entry (date stamp offset+i-1)= charno(time stamp,i) %repeat %if length(comments) < 32 %start %for i=length(comments),1,32 %cycle comments = comments." " %repeat %finish %for i=1,1,32 %cycle this entry (comments offset + i -1) = charno(comments,i) %repeat %for i=0,1,23 %cycle %for j= 0,1,39 %cycle this entry (page offset + i*40 + j) = page(i,j) %repeat %repeat %if channel # '5' %then record no = match(page no, channel,file,0) %elsec record no = -1 open cache(file, file ref, file size, 1) record no = free slot(file ref, file size) %unless record no # -1 %if record no = -1 %then record no = oldest record(file ref,file size) byte pos = record no * record size write region(file ref, byte pos, record size, this entry(0)) close cache(file ref) %end %integerfn extract page no (%bytearray packet(0:24,0:39)) %integer i,j %integer actual actual = 0 %for i=0,1,2 %cycle actual = 10*actual + packet(0,i)-'0' %repeat %for i=0,1,23 %cycle %for j=0,1,39 %cycle print symbol(packet(i,j)) %repeat newline %repeat %return actual %end ! extract page: retrieve a page from the database file ! true on success, false on failure %externalpredicate extract page( %integer record no, %bytearrayname page(0:24,0:39), %string (255) filename) %integer byte pos %integer file ref, file size %integer i,j %bytearray entry(0:record size) byte pos = record no * record size open cache(filename, file ref,file size, 0) %if byte pos > file size - record size %then %false read region(file ref, byte pos, record size, entry(0)) close cache(file ref) %for i=0,1,23 %cycle %for j=0,1,39 %cycle page(i,j) = entry(page offset + i*40 + j) %repeat %repeat %true %end %externalstring(255) %fn extract comments(%integer record no,%integername left) %integer fsize, fref,i %string(255) temp %bytearray buffer(0:record size) temp = "" open cache(EUCHANNEL5FILE,fref,fsize,0) %if record no * recordsize > fsize - record size %start left = -1 %return "INVALID RECORD NUMBER" %else read region(fref, record no * record size + comments offset,32,buffer(0)) close cache(fref) temp = temp . tostring(buffer(i)) %for i = 0,1,32 left = fsize // record size - record no -1 %return temp %finish %end %endofprogram