# This file contain all the routines necessary to create/add/edit/update # Dbase III compatible database files #----------------------------------------------------------------------- #- DBASE.AWK #- Copyright 1995, David W. Miller #- This file contain all the routines necessary to create/add/edit/update #- Dbase III compatible database files #----------------------------------------------------------------------- #- DBT files are NOT currently supported, but provisions have been made #- for a later version to handle these files. #----------------------------------------------------------------------- #- DBF support is provided by the following functions: #- open_dbf #- create_dbf #- close_dbf(area) #- bld_dbf_hdr #- read_dbf_hdr #- read_dbf_flds #- bld_dbf_fld_str #- add_field_dbf #- update_dbf_record #- read_dbf_record #- add_dbf_record #- date_conv #- share_install #----------------------------------------------------------------------- #- DBF support is maintained through the following array structure: #- array["file"] Database file handle #- array["file_name"] Filename of DBF file #- array["shared"] Database sharing enabled #- array["hdr"] DBF Header Array #- array["fld_str"] String used to PACK data #- array["data"] Array of DATA storage #- array["hdr_len"] Header Record Length #- array["fld_len"] Field Definition Length #----------------------------------------------------------------------- #- if specified, mode is the file mode to be shared values are as follows: #- ALL, READ (DENY WRITES), WRITE (DENY READS), NONE (DENY ALL) function open_dbf(area, file, share_mode) { local rval = 0, open_str = "r+b" if(argcount() > 2) { if (mode ~ /ALL/) open_str = open_str "dn" else if(mode ~ /READ/) open_str = open_str "dw" else if(mode ~ /WRITE/) open_str = open_str "dr" else if(mode ~ /NONE/) open_str = open_str "d+" } area["shared"] = (length(open_str) > 3) ? share_install() : 0 if((area["file"] = fopen(file, open_str)) != 0) { area["shared"] = share_install() area["file_name"] = file read_dbf_hdr(area) read_dbf_flds(area) area["fld_str"] = bld_dbffld_str(area["flds"]) #- This is where the planned memo support will be implemented #- if(area["hdr"]["memo"] == 0x84) { #- # Make filename extension ".dbt" #- # And see if we can open it. #- #- area["dbt_name"] = file #- sub(/\..?.?.?/,".dbt",area["dbt_name"]) #- area["dbt_file"] = fopen(area["dbt_name"],open_str) #- } if(area["hdr"]["rec_cnt"] > 0) { area["data"] = read_dbf_record(area, 1) area["rec_num"] = 1 } rval = 1 } return rval; } #----------------------------------------------------------------------- #- Be very careful using this function, it does not currently check #- to see if the database already exists. #- Beware this function will KILL an existing DBF file #----------------------------------------------------------------------- function create_dbf(area, file, mode) { local hdr_str = "memo@b up_yr@b up_mo@b up_day@b rec_cnt@L " \ "first_rec@S rec_size@S unused@20a" local fld_str = "name@11a type@c addr@L length@b dec@b unused@14a" local str, rval = 1, x, locked, open_str = "w+b" if(argcount() > 2) { if (mode ~ /ALL/) open_str = open_str "dn" else if(mode ~ /READ/) open_str = open_str "dw" else if(mode ~ /WRITE/) open_str = open_str "dr" else if(mode ~ /NONE/) open_str = open_str "d+" } #- The following code checks to see if shared is installed #- and will implement record locking based on it return value area["shared"] = (length(open_str) > 3) ? share_install() : 0 if((area["file"] = fopen(file,open_str)) != 0) { area["hdr_len"] = 32 area["fld_len"] = 32 area["hdr"] = bld_dbf_hdr(area["flds"]) area["fld_str"] = bld_dbffld_str(area["flds"]) str = pack(hdr_str,area["hdr"]) if ( length(str) != area["hdr_len"] ) { printf("Invalid header structure.\n") printf("Unable to write header.\n") } else { #- DWM 03-25-95 02:45pm I need to check and see if the header is locked locked = (area["shared"]) ? flock(area["file"],0,area["hdr_len"]) : 1 if(locked) { fwrite(str, area["file"]) if(area["shared"]) funlock(area["file"],0,area["hdr_len"]) } for(x in area["flds"]) { str = pack(fld_str,area["flds"][x]) if(length(str) != area["fld_len"]) { printf("Invalid field structure.\n") printf("Database is now corrupted.\n") } else fwrite(str,area["file"]) } fwrite(0x0D,area["file"]) #- Write 0x0D to end fields } } else { printf("Unable to Create Database.\n") printf("Unable to open file: %s", file) rval = 0 } return rval; } #----------------------------------------------------------------------- #- This function closes and destroys a dbf database file. #----------------------------------------------------------------------- function close_dbf(area) { close(area["file"]) #- memo support #- if(area["hdr"]["memo"] == 0x83) close(area["dbt_file"]) delete area } #----------------------------------------------------------------------- #- This function requires you to pass the field definition values and will #- return an array for an empty header #----------------------------------------------------------------------- function bld_dbf_hdr(fld_def) { local tarr, x, dtstr, t_len #- first rec must follow the 0x0D tarr["first_rec"] = (length(fld_def) * 32) + 33 tarr["memo"] = 0x03 tarr["unused"] = "" timetab(dtstr) tarr["up_yr"] = (dtstr["YEAR"] % 100) tarr["up_mo"] = dtstr["MONTH"] tarr["up_day"] = dtstr["DAY"] tarr["rec_size"] = 1 #- All records have the extra byte isdel #- The following adds up the bytes necessary for 1 record #- Providing field checking as necessary for the header for ( x in fld_def ) { if(fld_def[x]["type"] == "M") { t_len = 10 fld_def[x]["length"] = t_len if(tarr["memo"] != 0x83) tarr["memo"] = 0x83 #- Database with memo fields } else if(fld_def[x]["type"] == "D") { t_len = 8 fld_def[x]["length"] = t_len } else if(fld_def[x]["type"] == "L") { t_len = 1 fld_def[x]["length"] = t_len } else t_len = fld_def[x]["length"] tarr["rec_size"] += t_len } return tarr; } #----------------------------------------------------------------------- #- This function reads the database header in for the appropriate database #- files. #----------------------------------------------------------------------- function read_dbf_hdr(area) { local hdr = "memo@b up_yr@b up_mo@b up_day@b rec_cnt@L " \ "first_rec@S rec_size@S unused@20a" local str, locked area["hdr_len"] = 32 fseek(area["file"],0) #- Seek the beginning of file locked = (area["shared"]) ? flock(area["file"],0,area["hdr_len"]) : 1 if(locked) { str = fread(area["hdr_len"],area["file"]) unpack(hdr,str,area["hdr"]) if(area["shared"]) funlock(area["file"],0,area["hdr_len"]) } } #----------------------------------------------------------------------- function read_dbf_flds(area) { local fld = "name@11a type@c addr@L length@b dec@b unused@14a" local rec_str, i area["fld_len"] = 32 area["num_flds"] = (area["hdr"]["first_rec"] - area["hdr_len"]) / area["fld_len"] for(i=1;i<=area["num_flds"];i++) { rec_str = fread(area["fld_len"], area["file"]) unpack(fld, rec_str, area["flds"][i]) } } #----------------------------------------------------------------------- function bld_dbffld_str(fldarr) { local rec_str, x, i, typ rec_str = "ISDEL@1A " x = length(fldarr) for(i=1;i<=x;i++) { if(fldarr[i]["type"] == "C") typ = "A" else if(fldarr[i]["type"] == "D") typ = "A" else if(fldarr[i]["type"] == "L") typ = "c" else if(fldarr[i]["type"] == "M") typ = "l" else if(fldarr[i]["type"] == "N") typ = "A" rec_str = rec_str fldarr[i]["name"] "@" fldarr[i]["length"] typ if(i < x) rec_str = rec_str " " } return rec_str } #----------------------------------------------------------------------- #- This function is to be used when creating databases only #- Do not use this function on an existing database #----------------------------------------------------------------------- function add_field_dbf(fld_arr, name, type, t_len, t_dec) { local x x = (length(fld_arr)+1) fld_arr[x]["name"] = name fld_arr[x]["type"] = type fld_arr[x]["length"] = t_len fld_arr[x]["dec"] = t_dec fld_arr[x]["unused"] = " " fld_arr[x]["addr"] = " " } #----------------------------------------------------------------------- function update_dbf_record(area, recno) { local str, start, locked, rval = 0 start = area["hdr"]["first_rec"]+(area["hdr"]["rec_size"]*(recno - 1)) locked = (area["shared"]) ? flock(area["file"],start,area["hdr"]["rec_size"]) : 1 if(locked) { fseek(area["file"], start) str = pack(area["fld_str"],area["data"]) bytes = length(str) if(bytes != area["hdr"]["rec_size"]) { printf("Error: Updating Record. Unable to update.\n") printf("Record Size: %d\n",area["hdr"]["rec_size"]) printf("Bytes To Be Written: %d\n", bytes) printf("FLDREC Length: %d\n", length(fld_rec)) } else fwrite(str,area["file"]) if(area["shared"]) funlock(area["file"],start,area["hdr"]["rec_size"]) rval = 1 } return rval } #----------------------------------------------------------------------- function read_dbf_record(area, recno) { local str, tarr #- In a true multi-user enviroment, the number of records could change #- prior to this being read, therefore the record number could be valid #- and the only way to tell is to read the header record. if((recno >= 0) && (recno <= area["hdr"]["rec_cnt"])) { fseek(area["file"],(area["hdr"]["first_rec"]+(area["hdr"]["rec_size"]*(recno - 1)))) str = fread(area["hdr"]["rec_size"], area["file"]) unpack(area["fld_str"],str,tarr) area["rec_num"] = recno } else { printf("Error: Reading Record. Invalid record number.\n") printf("Record Number : %d\n",recno) printf("Number of records: %d\n",area["hdr"]["rec_cnt"]) } return tarr } #----------------------------------------------------------------------- #- This function packs the data element of area into fld_str structure #- for writing to disk. #----------------------------------------------------------------------- function add_dbf_record(area) { local hdr_str = "memo@b up_yr@b up_mo@b up_day@b rec_cnt@L first_rec@S rec_size@S unused@20a" local dtstr, fld_rec, hdr_rec, bytes, x, locked #- I need to pack the data here in the order that they appear in the #- fields argument #- Seek the end of file where the record will be appended if(area["hdr"]["rec_cnt"] == 0) fseek(area["file"],area["hdr"]["first_rec"],0) else fseek(area["file"],0,2) fld_rec = pack(area["fld_str"], area["data"]) bytes = length(fld_rec) if(bytes == area["hdr"]["rec_size"]) { fwrite(fld_rec, area["file"]) #- The following routines update the header #- I seek and read the record, so that my information #- is correct when trying to update the information #- this is done mainly for shared database support in the future. read_dbf_hdr(area) fseek(area["file"],0) locked = (area["shared"]) ? flock(area["file"],0,area["hdr_len"]) : 1 if(locked) { area["hdr"]["rec_cnt"]++ timetab(dtstr) area["hdr"]["up_yr"] = (dtstr["YEAR"] % 100) area["hdr"]["up_mo"] = dtstr["MONTH"] area["hdr"]["up_day"] = dtstr["DAY"] hdr_rec = pack(hdr_str, area["hdr"]) fseek(area["file"],0,0) fwrite(hdr_rec, area["file"]) if(area["shared"]) funlock(area["file"],0,area["hdr_len"]) } area["rec_num"] = area["hdr"]["rec_cnt"] } else { printf("Error: Adding Record. Unable to add.\n") printf("Record Size: %d\n",area["hdr"]["rec_size"]) printf("Bytes Written: %d\n", bytes) printf("FLDREC Length: %d\n", length(fld_rec)) } } #----------------------------------------------------------------------- #- format must be a character str as such "yymmdd" "mmddccyy" "ddmmyy" #- DBF Date fields must be in ccyymmdd format #----------------------------------------------------------------------- function date_conv(str, format) { local nmo, nda, ncc, nyr, dtstr, tstr if ( format == "ccyymmdd" ) dtstr = str else { timetab(tstr) ncc = index(format, "cc") if ((ncc = index(format, "cc")) != 0) dtstr = substr(str,ncc,2) else dtstr = int(tstr["YEAR"] / 100) if((nyr = index(format, "yy")) != 0 ) dtstr = dtstr substr(str,nyr,2) else dtstr = dtstr int(tstr["YEAR"] % 100) if ((nmo = index(format, "mm")) != 0) dtstr = dtstr substr(str,nmo,2) else dtstr = dtstr tstr["MONTH"] nda = index(format, "dd") if((nda = index(format, "dd")) != 0) dtstr = dtstr substr(str,nda,2) else dtstr = dtstr tstr["DAY"] } return dtstr; } #----------------------------------------------------------------------- function share_install() { local tAx tAx = 0x1000 interrupt(0x2F, tAx) return (and(tAx,0xFF) == 0xFF) } #----------------------------------------------------------------------- #- EOF #- DBASE.AWK #-----------------------------------------------------------------------