record format profile f(string (11) key, integer version, offset, length) record format ssprofile f(integer end, start, size, filetype, checksum, datetime, format, sp0, marker, max profiles, no profiles, sp1, record (profile f)array c profile(1:500)); ! 500 will never be approached. ! Structure of profile file: It starts with the format of ssprofile f ! above. The first 8 words are standard Subsystem header. Thereafter: ! marker: to check against overwriting or other corruption. ! max profiles: the maximum number of profiles which this file can currently hold. ! no profiles: the actual number of profiles held. ! profile: a record array (1:max profiles), each element containing the ! following: ! key: the keyword (the only access to profile data) ! version: the version number of the profile format. ! offset: the offset of the start of the profile data. ! length: the length of the profile data, as seen by the ! user. The profile scheme adds a marker word ! and rounds up to word align the data. ! All the above is treated as file header, and the second word of the header ! is set accordingly. The 'data' part of the file is thus the profile data, ! pointed at from the profile array (described above). The format of the ! profile data is determined by the using program. The scheme merely adds ! a marker word to check against corruption. constant integer marker = x'84848484' constant integer no = 0, yes = 1 constant integer read and write = 3, read shared = 9 constant integer data file = 4, unstructured = 3 recordformat rf(integer conad, filetype, data start, data end) externalintegerfnspec exist(string (31) file) externalroutinespec cherish(string (31) file) externalroutinespec ddelay(integer seconds) externalintegerfnspec uinfi(integer entry) systemroutinespec outfile(string (31) file, integer length, maxbytes, protection, integername conad, flag) systemroutinespec connect(string (31) file, integer access, maxbytes, protection, record (rf)name r, integername flag) systemroutinespec disconnect(string (31) file, integername flag) systemroutinespec move(integer length, from, to) systemroutinespec newgen(string (31) updated file, original file, integername flag) !------------------------------------------ externalroutine read profile(string (11) key, integer dr0, address, integername version, uflag) ! (dr0, address) is the descriptor of the %name-type variable passed. integer conad, flag, profad, i, length, ulength, maxtries, secs record (ssprofile f)name ssprofile record (rf) r record (profile f)name p if dr0&x'02000000'#0 start ; ! unscaled - record or string. ulength = dr0&x'00FFFFFF'; ! size of record or string passed. finishelsestart i = dr0>>27&7 - 3; i = 0 if i<0; ! size code ulength = 2¬¬i*(dr0&x'00FFFFFF'); ! size in bytes finish ! Now ulength gives the length of the variable passed. version = 0; length = 0; uflag = 0 uflag = 7 and ->copy if key="" uflag = 3 and ->copy if exist("SS#PROFILE")=no ! Now set up no of tries at connection, and delay time. if uinfi(2) = 2 start ; ! Background. maxtries = 5; secs = 20 finishelsestart ; ! Foreground. maxtries = 3; secs = 1 finish for i = 1,1,maxtries cycle connect("SS#PROFILE", read shared, 0, 0, r, flag) exit if flag=0; ! Success ddelay(secs) repeat uflag = 5 and ->copy unless flag=0; ! Failed to connect. ! Now try to find key. conad = r_conad ssprofile == record(conad) uflag = 6 and ->copy unless ssprofile_marker=marker; ! File corrupt. i = 0 i = i+1 until i>ssprofile_noprofiles or key=ssprofile_profile(i)_key uflag = 4 and -> copy if i>ssprofile_no profiles or c ssprofile_profile(i)_version<0; ! Not found p == ssprofile_profile(i) uflag = 6 and ->copy if integer(conad+p_offset)#marker; ! File corrupt. version = p_version length = p_length profad = conad+p_offset+4; ! 4 to step over marker word. copy: uflag = 1 and length = ulength if length>ulength; ! File data > info parameter. move(length,profad,address) if length>0 byteinteger(i) = 0 for i=address+length,1,address+ulength-1 ! Zero rest of user's variable, if necessary. uflag = 2 if 0<length<ulength; ! Info parameter > file data. disconnect("SS#PROFILE", flag) end ; ! of %external %routine read profile. !------------------------------------------ externalroutine write profile(string (11) key, integer dr0, address, integername version, uflag) ! (dr0, address) is the descriptor of the %name-type variable passed. integer conad, flag, tconad, i, j, k, l, length, mode record (rf) r record (ssprofile f)name ssprofile, tprofile record (profile f)name p routine create profile file(string (31) file, integer size, max profiles, integername flag) integer conad record (ssprofile f)name ssprofile outfile(file, size, 0, 0, conad, flag) return if flag#0; ! Failure. cherish(file) ssprofile == record(conad); ! ssprofile mapped onto file. ssprofile_filetype = data file ssprofile_format = unstructured ssprofile_marker = marker ssprofile_max profiles = max profiles ssprofile_no profiles = 0 ssprofile_start = addr(ssprofile_profile(maxprofiles+1))-conad ssprofile_end = ssprofile_start ! Thus the whole of record ssprofile is taken as the file header, and ! _start and _end refer to the profile data only. end ; ! of %routine create profile file. routine move profile(record (profile f)arrayname profile1, profile2, integer index1, index2, conad1, conad2) ! This routine moves profile1(index1) to profile2(index2). ! conad1 and conad2 give connect addresses, and also "end of data" word. ! The routine does not update the "no profiles" word in the profile2 file. integer l l = (profile1(index1)_length+3)&x'FFFFFFFC' + 4 ! Word aligned, 4 bytes for initial marker. profile2(index2) = profile1(index1) profile2(index2)_offset = integer(conad2) integer(conad2) = integer(conad2) + l; ! Update end of data pointer. move(l, conad1+profile1(index1)_offset, conad2+profile2(index2)_offset) ! Move profile data. end ; ! of %routine move profile. ! Start of write profile code proper. if version<0 start ; ! Means keyword is to be deleted. length = 0 finish else if dr0&x'02000000'#0 start ; ! unscaled - record or string. length = dr0&x'00FFFFFF'; ! size of record or string passed. finishelsestart i = dr0>>27&7 - 3; i = 0 if i<0; ! size code length = 2¬¬i*(dr0&x'00FFFFFF'); ! size in bytes finish ! Now length gives the length of the variable passed. uflag = 0 uflag = 7 and return if key="" uflag = 6 and return if length>4060 if exist("SS#PROFILE")=no start uflag = 1 return if version<0 create profile file("SS#PROFILE", 4096, 16, flag) ! File of 1 epage structured for 16 profile entries. uflag = 2 and return if flag#0 finish cycle ! Try to connect file in read-and-write mode. mode = read and write for i=1,1,2 cycle connect("SS#PROFILE", mode, 0, 0, r, flag) exit if flag=0 ddelay(1); ! 1 second delay, once. repeat if flag#0 start mode = read shared connect("SS#PROFILE", mode, 0, 0, r, flag) uflag = 3 and return if flag#0 finish conad = r_conad ssprofile == record(conad); ! record ssprofile mapped onto file SS#PROFILE. exit unless mode=read shared or ssprofile_no profiles = c ssprofile_max profiles or ssprofile_size<ssprofile_end+length+8 ! SS#PROFILE full or connected in read shared. Create a temporary file then NEWGEN later. uflag = 5 and return if ssprofile_max profiles+16>500; ! Most unlikely. for j = 0,1,1 cycle ! Compaction when j=0. ! Expansion when j=1. create profile file("T#NPROFILE", ssprofile_size+4096*j, ssprofile_max profiles+16*j, flag) ! 1 more epage, 16 more profile entries when j=1. uflag = 4 and return if flag#0 connect("T#NPROFILE", read and write, 0, 0, r, flag) uflag = 4 and return if flag#0 ! Now copy contents of SS#PROFILE into T#NPROFILE. tconad = r_conad tprofile == record(tconad); ! tprofile mapped onto T#NPROFILE. k = 0 for i=1,1,ssprofile_no profiles cycle continue if ssprofile_profile(i)_version<0; ! This entry has been deleted. k = k+1 move profile(ssprofile_profile, tprofile_profile, i, k, conad, tconad) repeat tprofile_no profiles = k exit if tprofile_no profiles<tprofile_max profiles and c tprofile_size>tprofile_end+length+8 repeat newgen("T#NPROFILE", "SS#PROFILE", flag) uflag = 4 and return if flag#0 repeat ! We now know that SS#PROFILE is big enough, and connected in write mode. ! See if given key is in file. i = 0 i = i+1 until i>ssprofile_no profiles or ssprofile_profile(i)_key=key p == ssprofile_profile(i) p_key = key p_version = version p_offset = integer(conad) p_length = length integer(conad+integer(conad)) = marker move(length, address, conad+integer(conad)+4) if length>0 l = (length+3)&x'FFFFFFFC'+4 integer(conad) = integer(conad)+l; ! Update end pointer. ssprofile_no profiles = i if i>ssprofile_no profiles ! Note: we do not attempt to recover old data space. It will be retrieved ! when (if) the whole file gets copied. disconnect("SS#PROFILE", flag) end ; ! of %external %routine write profile. endoffile