#include "dbinc.h" /***************************************************************************** * * * COMMON OCEANOGRAPHIC DATA ACCESS SYSTEM (CODAS) * * * * WRITTEN BY: RAMON CABRERA, ERIC FIRING, and JULIE RANADA * * JOINT INSTITUTE FOR MARINE AND ATMOSPHERIC RESEARCH * * 1000 POPE ROAD MSB 312 * * HONOLULU, HI 96822 * * * * VERSION: 3.10 * * * * DATE: APRIL 1989, AUGUST 1995 * * * *****************************************************************************/ /* FILE: dbcreate.c USER FUNCTIONS FOR CREATING A NEW DATABASE */ /*----------------------------------------------------------------------------- FUNCTION: DBCREATE It opens a new or existing database for appending. PARAMETERS: db_id = pointer to database number db_name = pointer to database name, including path; replaced by name without path. prd_name = pointer to name of producer definition file memory_mode = pointer to memory mode for directories ierr = pointer to error code RETURNS: VOID */ void DBCREATE(int *db_id, char *db_name, char *prd_name, int *memory_mode, int *ierr) { int i, id; FILE_NAME_TYPE path_name, path, db_root; if ((*ierr = alignment_check()) != 0) return; /**jr++**/ if (first_database_call) { for (i = 0; i < MAX_OPEN_DATABASES; i++) database_table[i] = NULL; first_database_call = 0; } id = *db_id - 1; if ((id < 0) || (id >= MAX_OPEN_DATABASES)) { *ierr = INVALID_DATABASE_NUMBER; return; } if (database_table[id]) { db_ptr = database_table[id]; *ierr = DB_ALREADY_OPEN; return; } if ((database_table[id] = (DATABASE_TYPE *) malloc(DATABASE_SIZE)) == NULL) { db_ptr->error_code = INSUFFICIENT_MEMORY; db_ptr->error_data = BLOCK_DIR; goto error_found; } current_database = id; db_ptr = database_table[id]; set_byte((UBYTE *)db_ptr, 0, DATABASE_SIZE); if (*memory_mode) db_ptr->memory_directory = 1; else db_ptr->memory_directory = 0; strtrim(db_ptr->producer_def_file, prd_name, sizeof(FILE_NAME_TYPE)); strtrim(path_name, db_name, sizeof(FILE_NAME_TYPE)); if (strlen(path_name) + 8 > sizeof(FILE_NAME_TYPE)) { /* need 8 char for file number, ext, NUL */ *ierr = PATHNAME_TOO_LONG; return; } split_path(path_name, path, db_root); if ((int)strlen(db_root) > MAX_DBNAME_LENGTH) { *ierr = DBNAME_TOO_LONG; return; } db_ptr->path_nchar = strlen(path); strcpy(db_ptr->block_dir_hdr.block_file_template, db_root); strcat(db_ptr->block_dir_hdr.block_file_template, "%03u.blk"); strcpy(db_ptr->block_file, path); strcpy(db_ptr->block_dir_file, path); strcat(db_ptr->block_dir_file, db_root); strcat(db_ptr->block_dir_file, "dir.blk"); /* ---> ALLOCATE MEMORY FOR PRODUCER DEFINITION */ if ((db_ptr->producer = (PRODUCER_DEFINITION_TYPE *) malloc(sizeof(PRODUCER_DEFINITION_TYPE))) == NULL) { db_ptr->error_code = INSUFFICIENT_MEMORY; db_ptr->error_data = PRODUCER_DEF; goto error_found; } db_ptr->producer_in_memory = 1; set_byte((UBYTE *)db_ptr->producer, '\0', sizeof(PRODUCER_DEFINITION_TYPE)); if (load_producer_definition()) goto error_found; db_ptr->access_mode = READ_WRITE; db_ptr->create_mode = 1; if (!(EXISTS(db_ptr->block_dir_file))) if (create_block_dir()) goto error_found; if (open_block_dir()) goto error_found; if (db_ptr->memory_directory) { if (allocate_memory_for_directories()) goto error_found; if (db_ptr->block_dir_hdr.dir_nentries) if (load_block_dir()) goto error_found; db_ptr->block_dir_loaded = 1; } *ierr = 0; return; error_found: report_db_error("DBCREATE"); *ierr = db_ptr->error_code * 1000 - db_ptr->error_data; release_database(); } /*----------------------------------------------------------------------------- FUNCTION: DBNEWBLK It creates a new block and leaves the database ready for adding data to the block. PARAMETER: ierr = pointer to error code RETURNS: VOID */ void DBNEWBLK(int *ierr) { *ierr = 0; if (!(db_ptr)) { *ierr = DB_IS_NOT_OPEN; return; } if (!(db_ptr->create_mode)) { *ierr = NO_OPEN_FOR_CREATE; return; } if (db_ptr->new_block_is_open) { *ierr = NEW_BLOCK_IS_OPEN; return; } if ((*ierr = create_block_dir_entry())) return; if (create_block()) goto error_found; if (open_block()) goto error_found; if (load_data_list()) goto error_found; /*jr+ -- position block file pointer past structure definitions */ if (fseek(db_ptr->fpblkdata, db_ptr->block_hdr.dir_ofs, 0)) { db_ptr->error_code = SEEK_ERROR; db_ptr->error_data = BLOCK_FILE; goto error_found; } /* ---> OPEN TEMPORARY FILE FOR PROFILE DATA */ db_ptr->fptmpdata = tmpfile(); if (db_ptr->fptmpdata == NULL) { db_ptr->error_code = UNABLE_TO_OPEN; db_ptr->error_data = TEMP_DATA_FILE; goto error_found; } db_ptr->new_block_is_open = 1; if (db_ptr->profile_dir_in_memory) db_ptr->profile_dir_loaded = 1; db_ptr->temp_data_ofs = 0; return; error_found: if (db_ptr->block_is_open) release_block(); report_db_error("DBNEWBLK"); *ierr = db_ptr->error_code * 1000 - db_ptr->error_data; } /*----------------------------------------------------------------------------- FUNCTION: DBNEWPRF It creates a new profile and leaves the database ready for adding data to the profile. PARAMETERS: prf_time = pointer to structure containing profile time ierr = pointer to error code RETURNS: VOID */ void DBNEWPRF(YMDHMS_TIME_TYPE *prf_time, int *ierr) { if (invalid_time(prf_time)) { *ierr = INVALID_TIME; return; } if ((*ierr = dbadd_flags()) != 0) return; if (db_ptr->new_profile_is_open) { *ierr = NEW_PROFILE_IS_OPEN; return; } if (db_ptr->block_hdr.dir_nentries >= MAX_PROFILE_DIR_SIZE) { *ierr = BLOCK_IS_FULL; return; } if (!(db_ptr->block_hdr.dir_nentries)) { db_ptr->block_hdr.time1 = PCKTIM(prf_time); UPCKTIM(&(db_ptr->block_base_time), &(db_ptr->block_hdr.time1)); } create_profile_dir_entry(prf_time); db_ptr->new_profile_is_open = 1; return; } /*----------------------------------------------------------------------------- FUNCTION: DBADD It adds data to a profile or block. PARAMETERS: type = pointer to data type data = address of user buffer nb = pointer to number of bytes ierr = pointer to error code RETURNS: VOID */ void DBADD(int *type, char *data, unsigned int *nb, int *ierr) { if ((*ierr = dbadd_flags()) != 0) return; /* ---> PROFILE DATA (types 0 - 99) */ if ((*type >= 0) & (*type < (int)db_ptr->block_hdr.data_list_nentries)) { if (*nb == 0) { *ierr = INVALID_BUFFER_SIZE; return; } if (add_profile_data(type, data, nb, ierr)) goto error_found; } else switch (*type) { case POSITION: *ierr = set_position((DMSH_POSITION_TYPE *) data); break; case DATA_PROC_MASK: db_ptr->block_hdr.data_proc_mask = *(ULONG *) data; break; case DEPTH_RANGE: *ierr = set_depth_range((DEPTH_RANGE_TYPE *) data); break; default: *ierr = INVALID_TYPE_REQUEST; break; } return; error_found: report_db_error("DBADD"); *ierr = db_ptr->error_code * 1000 - db_ptr->error_data; } /*----------------------------------------------------------------------------- FUNCTION: DBENDPRF It closes a newly created profile. PARAMETER: ierr = pointer to error code RETURNS: VOID */ void DBENDPRF(int *ierr) { unsigned int nb; long ofs; *ierr = 0; if (!(db_ptr)) { *ierr = DB_IS_NOT_OPEN; return; } if (!(db_ptr->create_mode)) { *ierr = NO_OPEN_FOR_CREATE; return; } if (!(db_ptr->new_profile_is_open)) { *ierr = NO_NEW_PROFILE_IS_OPEN; return; } ofs = db_ptr->profile_dir_entry_ptr->ofs; nb = db_ptr->block_hdr.data_dir_nentries * DATA_DIR_ENTRY_SIZE; if ((db_ptr->error_code = write_data(db_ptr->fptmpdata, (char *) db_ptr->data_dir, ofs, nb)) != 0) { db_ptr->error_data = TEMP_DATA_FILE; goto error_found; } if (fseek(db_ptr->fptmpdata, db_ptr->temp_data_ofs, 0)) { db_ptr->error_code = SEEK_ERROR; db_ptr->error_data = TEMP_DATA_FILE; goto error_found; } if (!(db_ptr->profile_dir_loaded)) { nb = db_ptr->block_hdr.dir_entry_nbytes; if (fwrite((char *) db_ptr->profile_dir_entry_ptr, 1, nb, db_ptr->fpblkdata) != nb) { db_ptr->error_code = WRITE_ERROR; db_ptr->error_data = PROFILE_DIR; goto error_found; } db_ptr->block_hdr.block_nbytes += nb; /* jr+ 6/18/90 */ } db_ptr->block_hdr.dir_nentries++; db_ptr->new_profile_is_open = 0; return; error_found: report_db_error("DBENDPRF"); *ierr = db_ptr->error_code * 1000 - db_ptr->error_data; } /*----------------------------------------------------------------------------- FUNCTION: DBENDBLK It closes a newly created block. PARAMETER: ierr = pointer to error code RETURNS: VOID */ void DBENDBLK(int *ierr) { int temp_dir_loaded = 1; unsigned int i, j, nb, m; long ofs1, ofs2; if ((*ierr = dbadd_flags()) != 0) return; if (db_ptr->new_profile_is_open) { *ierr = NEW_PROFILE_IS_OPEN; return; } /* ---> IF PROFILE DIR NOT IN MEMORY LOAD IT */ if (!(db_ptr->profile_dir_loaded)) { nb = db_ptr->block_hdr.dir_nentries * db_ptr->block_hdr.dir_entry_nbytes; if (nb == 0) { db_ptr->error_code = PROFILE_DIR_IS_EMPTY; db_ptr->error_data = PROFILE_DIR; goto error_found; } if ((db_ptr->profile_dir = malloc(nb)) == NULL) { db_ptr->error_code = INSUFFICIENT_MEMORY; db_ptr->error_data = PROFILE_DIR; goto error_found; } db_ptr->profile_dir_in_memory = 1; temp_dir_loaded = 1; if (load_profile_dir()) goto error_found; } /* ---> UPDATE BLOCK HEADER WITH POSITION, TIME, AND DEPTH RANGE OF PROFILES */ update_block(); /* ---> STORE CONSTANT PROFILE DATA */ ofs2 = (db_ptr->block_hdr.dir_ofs) + db_ptr->block_hdr.dir_nentries * db_ptr->block_hdr.dir_entry_nbytes; for (i = 0; i < db_ptr->block_hdr.data_list_nentries; i++) if (db_ptr->data_list[i].access_type == BLOCK_VAR_ACCESS_CODE) { if ((nb = db_ptr->data_list[i].access_1) != 0) { ofs1 = db_ptr->data_list[i].access_0; if ((db_ptr->error_code = copy_data(db_ptr->fptmpdata, db_ptr->fpblkdata, ofs1, ofs2, nb)) != 0) { db_ptr->error_data = PROFILE_DATA; goto error_found; } db_ptr->data_list[i].access_0 = ofs2; ofs2 += nb; db_ptr->block_hdr.block_nbytes += nb; /* jr+ */ } } if (write_data_list()) goto error_found; /* ---> STORE DIR PROFILE DATA */ m = db_ptr->block_hdr.data_dir_nentries * DATA_DIR_ENTRY_SIZE; for (i = 0; i < db_ptr->block_hdr.dir_nentries; i++) { db_ptr->profile_dir_entry_ptr = (PROFILE_DIR_3_ENTRY_TYPE *) (db_ptr->profile_dir + i * db_ptr->block_hdr.dir_entry_nbytes); ofs1 = db_ptr->profile_dir_entry_ptr->ofs; nb = m; if ((db_ptr->error_code = read_data(db_ptr->fptmpdata, (char *) db_ptr->data_dir, ofs1, nb)) != 0) { db_ptr->error_data = DATA_DIR; goto error_found; } for (j = 0; j < db_ptr->block_hdr.data_dir_nentries; j++) nb += db_ptr->data_dir[j].nbytes; if ((db_ptr->error_code = copy_data(db_ptr->fptmpdata, db_ptr->fpblkdata, ofs1, ofs2, nb)) != 0) { db_ptr->error_data = PROFILE_DATA; goto error_found; } db_ptr->profile_dir_entry_ptr->ofs = ofs2; ofs2 += nb; db_ptr->block_hdr.block_nbytes += nb; /* jr+ */ } /* ---> REWRITE BLOCK HDR AND PROFILE DIR */ if (write_block_hdr()) goto error_found; if (write_profile_dir()) goto error_found; /* ---> CLOSE BLOCK */ db_ptr->block_modified = 0; if (close_block()) goto error_found; db_ptr->new_block_is_open = 0; fclose(db_ptr->fptmpdata); db_ptr->fptmpdata = NULL; /* ---> ADD BLOCK DIR ENTRY */ update_block_dir_entry(); if (add_block_dir_entry()) goto error_found; db_ptr->new_block_is_open = 0; db_ptr->block_dir_modified = 1; if (temp_dir_loaded) { free(db_ptr->profile_dir); db_ptr->profile_dir_in_memory = 0; db_ptr->profile_dir_loaded = 0; } return; error_found: report_db_error("DBENDBLK"); if (temp_dir_loaded) { db_ptr->profile_dir_in_memory = 0; free(db_ptr->profile_dir); db_ptr->profile_dir_loaded = 0; } *ierr = db_ptr->error_code * 1000 - db_ptr->error_data; } /*----------------------------------------------------------------------------- FUNCTION: create_block_dir It attempts to create a new block directory file. If successful, it writes the header and an empty directory, and then closes the file. RETURNS: 0 if successful db_ptr->error_code otherwise */ int create_block_dir(void) { int index; /* ---> ATTEMPT TO CREATE A STREAM FILE FOR BLOCK DIRECTORY */ if ((db_ptr->fpblkdir = fopen(db_ptr->block_dir_file, "w+b")) == NULL) { db_ptr->error_code = FILE_PROTECTION_ERROR; db_ptr->error_data = BLOCK_DIR_FILE; goto error_found; } /* ---> INITIALIZE FIELDS FOR AN EMPTY DIRECTORY */ strncpy(db_ptr->block_dir_hdr.db_version, DATABASE_SYSTEM_VERSION, 4); /**jr+**/ strcpy((char *)&(db_ptr->block_dir_hdr.dataset_id), (char *)&(db_ptr->producer->dataset_id)); db_ptr->block_dir_hdr.time1 = MAXULONG; db_ptr->block_dir_hdr.time2 = MINULONG; db_ptr->block_dir_hdr.lat1 = MAXLONG; db_ptr->block_dir_hdr.lon1 = MAXLONG; db_ptr->block_dir_hdr.depth1 = MAXSHORT; db_ptr->block_dir_hdr.lat2 = MINLONG; db_ptr->block_dir_hdr.lon2 = MINLONG; db_ptr->block_dir_hdr.depth2 = MINSHORT; db_ptr->block_dir_hdr.dir_type = db_ptr->producer->block_dir_type; db_ptr->block_dir_hdr.dir_entry_nbytes = BLOCK_DIR_ENTRY_SIZE; db_ptr->block_dir_hdr.dir_nentries = 0; db_ptr->block_dir_hdr.next_seq_number = 1; db_ptr->block_dir_hdr.data_mask = 0; db_ptr->block_dir_hdr.data_proc_mask = 0; db_ptr->block_dir_hdr.unused1 = 0; db_ptr->block_dir_hdr.unused2 = 0; db_ptr->block_dir_hdr.unused3 = 0; db_ptr->block_dir_hdr.unused4 = 0; /* ---> IDENTIFY MACHINE SIGNATURE -- JR 95/07: unused5 is now ms_code */ if ((index = identify_ms((char *) MACHINE_SIGNATURE)) == UNKNOWN_HOST) { db_ptr->error_code = UNKNOWN_HOST_ERROR; db_ptr->error_data = BLOCK_DIR_FILE; goto error_found; } strncpy(db_ptr->block_dir_hdr.ms_code, MS_TABLE[index].ms_code, 4); /* ---> WRITE HEADER */ if (write_block_dir_hdr()) goto error_found; /* ---> CLOSE BLOCK DIR FILE */ if (fclose(db_ptr->fpblkdir)) { db_ptr->error_code = CLOSE_ERROR; db_ptr->error_data = BLOCK_DIR_FILE; goto error_found; } return(0); error_found: report_db_error("create_block_dir"); return(db_ptr->error_code); } /*----------------------------------------------------------------------------- FUNCTION: create_block It attempts to create a new block file. If successful, it writes the header and the data_list, and then closes the file. RETURNS: 0 if successful db_ptr->error_code otherwise */ int create_block(void) { int index; /* ---> SET NAME OF BLOCK FILE */ sprintf( (db_ptr->block_file + db_ptr->path_nchar), db_ptr->block_dir_hdr.block_file_template, db_ptr->block_dir_entry_ptr->file_id); /* ---> IF FILE DOES NOT EXIST, CREATE IT. */ if (!(EXISTS(db_ptr->block_file))) { if ((db_ptr->fpblkdata = fopen(db_ptr->block_file, "w+b")) == NULL) { db_ptr->error_code = FILE_PROTECTION_ERROR; db_ptr->error_data = BLOCK_FILE; goto error_found; } } else if ((db_ptr->fpblkdata = open_binary_file(db_ptr->block_file, db_ptr->access_mode)) == NULL) { db_ptr->error_code = UNABLE_TO_OPEN; db_ptr->error_data = BLOCK_FILE; goto error_found; } db_ptr->block_is_open = 1; /* ---> IDENTIFY MACHINE SIGNATURE Note: 95/08 JR Leave this in place for now (instead of copying from block_dir_hdr.ms_code) in case new blocks are added to an existing database where the block_dir_hdr.ms_code has not been properly initialized (used to be unused5). */ if ((index = identify_ms((char *) MACHINE_SIGNATURE)) == UNKNOWN_HOST) { db_ptr->error_code = UNKNOWN_HOST_ERROR; db_ptr->error_data = BLOCK_FILE; goto error_found; } /* ---> INITIALIZE FIELDS FOR AN EMPTY BLOCK */ strncpy(db_ptr->block_hdr.db_version, DATABASE_SYSTEM_VERSION, 4); strncpy(db_ptr->block_hdr.producer_host, MS_TABLE[index].ms_name, 4); strcpy((char *)&(db_ptr->block_hdr.dataset_id), (char *)&(db_ptr->producer->dataset_id)); strcpy((char *)&(db_ptr->block_hdr.producer_id), (char *)&(db_ptr->producer->producer_id)); db_ptr->block_hdr.time1 = MAXULONG; db_ptr->block_hdr.time2 = MINULONG; db_ptr->block_hdr.lon1 = MAXLONG; db_ptr->block_hdr.lon2 = MINLONG; db_ptr->block_hdr.lat1 = MAXLONG; db_ptr->block_hdr.lat2 = MINLONG; db_ptr->block_hdr.depth1 = MAXSHORT; db_ptr->block_hdr.depth2 = MINSHORT; db_ptr->block_hdr.data_list_ofs = BLOCK_HDR_SIZE; db_ptr->block_hdr.data_list_nentries = db_ptr->producer->data_list_max_nentries; db_ptr->block_hdr.struct_def_nentries = db_ptr->producer->struct_def_max_nentries; db_ptr->block_hdr.dir_ofs = (db_ptr->block_hdr.data_list_ofs) + db_ptr->block_hdr.data_list_nentries * DATA_LIST_ENTRY_SIZE + db_ptr->block_hdr.struct_def_nentries * STRUCT_DEF_ENTRY_SIZE; db_ptr->block_hdr.block_nbytes = db_ptr->block_hdr.dir_ofs; db_ptr->block_hdr.dir_time_flag = db_ptr->producer->dir_time_flag; db_ptr->block_hdr.dir_type = db_ptr->producer->profile_dir_type; switch(db_ptr->block_hdr.dir_type) { case 0: db_ptr->block_hdr.dir_entry_nbytes = PROFILE_DIR_0_ENTRY_SIZE; break; case 1: db_ptr->block_hdr.dir_entry_nbytes = PROFILE_DIR_1_ENTRY_SIZE; break; case 2: db_ptr->block_hdr.dir_entry_nbytes = PROFILE_DIR_2_ENTRY_SIZE; break; case 3: db_ptr->block_hdr.dir_entry_nbytes = PROFILE_DIR_3_ENTRY_SIZE; break; } db_ptr->block_hdr.dir_nentries = 0; db_ptr->block_hdr.data_dir_nentries = db_ptr->producer->profile_var_max_nentries; db_ptr->block_hdr.data_mask = 0; db_ptr->block_hdr.data_proc_mask = 0; strncpy(db_ptr->block_hdr.ms_code, MS_TABLE[index].ms_code, 4); /* ---> WRITE TO DISK */ if (write_block_hdr()) goto error_found; if (write_data_list()) goto error_found; if (write_block_strdef()) goto error_found; /* ---> CLOSE BLOCK FILE */ if (fclose(db_ptr->fpblkdata)) { db_ptr->error_code = CLOSE_ERROR; db_ptr->error_data = BLOCK_FILE; goto error_found; } db_ptr->block_is_open = 0; return(0); error_found: report_db_error("create_block"); return(db_ptr->error_code); } /*----------------------------------------------------------------------------- FUNCTION: create_block_dir_entry It initializes the fields of a block directory entry. RETURNS: int */ int create_block_dir_entry(void) { int nb; int ierr = 0; if (db_ptr->block_dir_hdr.dir_nentries >= db_ptr->block_dir_max_nentries) { ierr = add_memory_for_block_dir(); if (ierr) { ierr = BLOCK_DIR_IS_FULL; /* old error message; not entirely appropriate any more, but should suffice. */ return ierr; } } db_ptr->block_dir_index = db_ptr->block_dir_hdr.dir_nentries; if (db_ptr->block_dir_in_memory) { nb = db_ptr->block_dir_hdr.dir_entry_nbytes; db_ptr->block_dir_entry_ptr = (BLOCK_DIR_ENTRY_TYPE *) (db_ptr->block_dir + nb * db_ptr->block_dir_index); } else db_ptr->block_dir_entry_ptr = &(db_ptr->block_dir_entry); strcpy((char *)&(db_ptr->block_dir_entry_ptr->producer_id), (char *) &(db_ptr->producer->producer_id)); db_ptr->block_dir_entry_ptr->time1 = MAXULONG; db_ptr->block_dir_entry_ptr->time2 = MINULONG; db_ptr->block_dir_entry_ptr->lon1 = MAXLONG; db_ptr->block_dir_entry_ptr->lon2 = MINLONG; db_ptr->block_dir_entry_ptr->lat1 = MAXLONG; db_ptr->block_dir_entry_ptr->lat2 = MINLONG; db_ptr->block_dir_entry_ptr->depth1 = MAXSHORT; db_ptr->block_dir_entry_ptr->depth2 = MINSHORT; db_ptr->block_dir_entry_ptr->block_nbytes = 0; db_ptr->block_dir_entry_ptr->file_id = db_ptr->block_dir_hdr.next_seq_number; db_ptr->block_dir_entry_ptr->data_mask = 0; db_ptr->block_dir_entry_ptr->data_proc_mask = 0; db_ptr->block_dir_entry_ptr->unassigned = 0; /**jr+**/ return 0; } /*----------------------------------------------------------------------------- FUNCTION: create_profile_dir_entry It initializes the fields of a profile directory entry. PARAMETER: prf_time = time stamp for the profile directory entry to be created RETURNS: VOID */ void create_profile_dir_entry(YMDHMS_TIME_TYPE *prf_time) { unsigned int nb; db_ptr->profile_dir_index = db_ptr->block_hdr.dir_nentries; if (db_ptr->profile_dir_in_memory) { nb = db_ptr->block_hdr.dir_entry_nbytes; db_ptr->profile_dir_entry_ptr = (PROFILE_DIR_3_ENTRY_TYPE *) (db_ptr->profile_dir + nb * db_ptr->profile_dir_index); } else db_ptr->profile_dir_entry_ptr = &(db_ptr->profile_dir_entry); db_ptr->profile_dir_entry_ptr->ofs = db_ptr->temp_data_ofs; if (db_ptr->block_hdr.dir_time_flag == DIR_TIME_IN_SECONDS) db_ptr->profile_dir_entry_ptr->time = TIMDIF(&(db_ptr->block_base_time), prf_time); else db_ptr->profile_dir_entry_ptr->time = HTIMDIF(&(db_ptr->block_base_time), prf_time); if ((db_ptr->block_hdr.dir_type == 1) || (db_ptr->block_hdr.dir_type == 3)) { db_ptr->profile_dir_entry_ptr->lon = MAXLONG; db_ptr->profile_dir_entry_ptr->lat = MAXLONG; db_ptr->profile_dir_entry_ptr->spare_key = 0; /**jr+**/ } if ((db_ptr->block_hdr.dir_type == 2) || (db_ptr->block_hdr.dir_type == 3)) { db_ptr->profile_dir_entry_ptr->depth1 = MAXSHORT; db_ptr->profile_dir_entry_ptr->depth2 = MINSHORT; db_ptr->profile_dir_entry_ptr->spare_key = 0; /**jr+**/ } nb = db_ptr->block_hdr.data_dir_nentries * DATA_DIR_ENTRY_SIZE; set_byte((UBYTE *)db_ptr->data_dir, '\0', nb); store_temp_data((char *) db_ptr->data_dir, nb); } /*----------------------------------------------------------------------------- FUNCTION: add_profile_aux It performs the actual writing of additional profile data to the temporary file. PARAMETERS: type = pointer to data type data = array/structure containing the data to be added nb = number of bytes to be written ind = index into data directory RETURNS: 0 if okay db_ptr->error_code otherwise */ int add_profile_aux(int *type, char *data, unsigned int nb, int ind) { static ULONG BIT[] = { BIT0, BIT1, BIT2, BIT3, BIT4, BIT5, BIT6, BIT7, BIT8, BIT9, BIT10, BIT11, BIT12, BIT13, BIT14, BIT15, BIT16, BIT17, BIT18, BIT19, BIT20, BIT21, BIT22, BIT23, BIT24, BIT25, BIT26, BIT27, BIT28, BIT29, BIT30, BIT31 }; if (store_temp_data(data, nb)) goto error_found; if (db_ptr->data_list[*type].access_type == PROFILE_VAR_ACCESS_CODE) db_ptr->data_dir[ind].nbytes = nb; if (*type < 32) db_ptr->block_hdr.data_mask = db_ptr->block_hdr.data_mask | BIT[*type]; return(0); error_found: report_db_error("add_profile_aux"); return(db_ptr->error_code); } /*----------------------------------------------------------------------------- FUNCTION: add_profile_data It adds data to a profile. PARAMETERS: type = pointer to data type to be added data = pointer to start of profile data to be added nb = pointer to number of bytes to be added ierr = pointer to error code RETURNS: 0 if okay or if NO_NEW_PROFILE_IS_OPEN or if INVALID_TYPE_REQUEST db_ptr->error_code otherwise */ int add_profile_data(int *type, char *data, unsigned int *nb, int *ierr) { int ind; set_access_param(type, *nb, &ind, ierr); if (*ierr) return(0); if (add_profile_aux(type, data, *nb, ind)) goto error_found; return(0); error_found: report_db_error("add_profile_data"); return(db_ptr->error_code); } /*----------------------------------------------------------------------------- FUNCTION: dbadd_flags It checks the necessary database status flags prior to adding data to the database using DBADD and DBADD_F. RETURNS: 0 if okay error code otherwise */ int dbadd_flags(void) { if (!(db_ptr)) return(DB_IS_NOT_OPEN); if (!(db_ptr->create_mode)) return(NO_OPEN_FOR_CREATE); if (!(db_ptr->new_block_is_open)) return(NO_NEW_BLOCK_IS_OPEN); return(0); } /*----------------------------------------------------------------------------- FUNCTION: set_position It sets the position parameter in the block/profile directory. PARAMETER: data = array containing latitude and longitude RETURNS: 0 if okay INVALID_POSITION or NO_NEW_PROFILE_IS_OPEN otherwise */ int set_position(DMSH_POSITION_TYPE *data) { DMSH_POSITION_TYPE *lat, *lon; lon = &data[0]; lat = &data[1]; if (invalid_position(lat, 1) || invalid_position(lon, 0)) return(INVALID_POSITION); if ((db_ptr->block_hdr.dir_type == 0) || (db_ptr->block_hdr.dir_type == 2)) { db_ptr->block_hdr.lon1 = POSHUN(lon); if (db_ptr->block_hdr.lon1 < 0) db_ptr->block_hdr.lon1 += 129600000L; db_ptr->block_hdr.lon2 = db_ptr->block_hdr.lon1; db_ptr->block_hdr.lat1 = POSHUN(lat); db_ptr->block_hdr.lat2 = db_ptr->block_hdr.lat1; } else if ((db_ptr->block_hdr.dir_type == 1) || (db_ptr->block_hdr.dir_type == 3)) { if (!(db_ptr->new_profile_is_open)) return(NO_NEW_PROFILE_IS_OPEN); db_ptr->profile_dir_entry_ptr->lon = POSHUN(lon); if (db_ptr->profile_dir_entry_ptr->lon < 0) db_ptr->profile_dir_entry_ptr->lon += 129600000L; db_ptr->profile_dir_entry_ptr->lat = POSHUN(lat); } return(0); } /*----------------------------------------------------------------------------- FUNCTION: set_depth_range It sets the depth range parameter in the block/profile directory. PARAMETER: data = array containing the minimum and maximum depths RETURNS: 0 if okay NO_NEW_PROFILE_IS_OPEN otherwise */ int set_depth_range(DEPTH_RANGE_TYPE *data) { if ((db_ptr->block_hdr.dir_type == 0) || (db_ptr->block_hdr.dir_type == 1)) { db_ptr->block_hdr.depth1 = data->min_depth; db_ptr->block_hdr.depth2 = data->max_depth; } else if ((db_ptr->block_hdr.dir_type == 2) || (db_ptr->block_hdr.dir_type == 3)) { if (!(db_ptr->new_profile_is_open)) return(NO_NEW_PROFILE_IS_OPEN); db_ptr->profile_dir_entry_ptr->depth1 = data->min_depth; db_ptr->profile_dir_entry_ptr->depth2 = data->max_depth; } return(0); } /*----------------------------------------------------------------------------- FUNCTION: set_access_param Given the data type and the number of bytes to be added to a profile, it sets the appropriate access fields in the data directory/data list. PARAMETERS: type = pointer to data type nb = number of bytes to be added ind = pointer to data direectory index ierr = pointer to error code RETURNS: VOID */ void set_access_param(int *type, unsigned int nb, int *ind, int *ierr) { *ierr = 0; if (db_ptr->data_list[*type].access_type == PROFILE_VAR_ACCESS_CODE) { if (db_ptr->new_profile_is_open) { *ind = (int) (db_ptr->data_list[*type].access_0); db_ptr->data_dir[*ind].ofs = (db_ptr->temp_data_ofs) - db_ptr->profile_dir_entry_ptr->ofs; } else *ierr = NO_NEW_PROFILE_IS_OPEN; } else if (db_ptr->data_list[*type].access_type == BLOCK_VAR_ACCESS_CODE) { if (!(db_ptr->new_profile_is_open)) { db_ptr->data_list[*type].access_0 = db_ptr->temp_data_ofs; db_ptr->data_list[*type].access_1 = nb; } else *ierr = NEW_PROFILE_IS_OPEN; } else *ierr = INVALID_TYPE_REQUEST; return; } /*----------------------------------------------------------------------------- FUNCTION: store_temp_data It writes block data in temporary data file. PARAMETERS: data = address of buffer containing data to be written total_nb = number of bytes to be written to temporary file RETURNS: 0 if okay db_ptr->error_code otherwise */ int store_temp_data(char *data, unsigned int total_nb) { unsigned int nb; nb = total_nb; /* ---> WRITE DATA */ while (nb > MAXINT) { if (fwrite(data, 1, MAXINT, db_ptr->fptmpdata) != MAXINT) goto error_found; nb -= MAXINT; } if (fwrite(data, 1, nb, db_ptr->fptmpdata) != nb) { db_ptr->error_code = WRITE_ERROR; db_ptr->error_data = TEMP_DATA_FILE; goto error_found; } db_ptr->temp_data_ofs += total_nb; return(0); error_found: report_db_error("store_temp_data"); return(db_ptr->error_code); } /*----------------------------------------------------------------------------- FUNCTION: flush_block_dir_file It flushes the block directory file buffer by closing the file. It then reopens the file. RETURNS: 0 if successful CLOSE_ERROR or UNABLE_TO_OPEN otherwise */ int flush_block_dir_file(void) { if (fclose(db_ptr->fpblkdir)) { db_ptr->error_code = CLOSE_ERROR; db_ptr->error_data = BLOCK_DIR_FILE; goto error_found; } if ((db_ptr->fpblkdir = open_binary_file(db_ptr->block_dir_file, db_ptr->access_mode)) == NULL) { db_ptr->error_code = UNABLE_TO_OPEN; db_ptr->error_data = BLOCK_DIR_FILE; goto error_found; } return(0); error_found: report_db_error("flush_block_dir_file"); return(db_ptr->error_code); } /*----------------------------------------------------------------------------- FUNCTION: write_data_list It rewrites the block data access list. The block must be open. RETURNS: 0 if successful db_ptr->error_code otherwise */ int write_data_list(void) { unsigned int nb; long ofs; ofs = db_ptr->block_hdr.data_list_ofs; nb = db_ptr->block_hdr.data_list_nentries * DATA_LIST_ENTRY_SIZE; if ((db_ptr->error_code = write_data(db_ptr->fpblkdata, (char *) db_ptr->data_list, ofs, nb)) != 0) { db_ptr->error_data = DATA_LIST; goto error_found; } return(0); error_found: report_db_error("write_data_list"); return(db_ptr->error_code); } /*----------------------------------------------------------------------------- FUNCTION: write_block_strdef It writes an array of STRUCT_DEF_ENTRY_TYPE structures to disk. RETURNS: 0 if successful WRITE_ERROR otherwise */ int write_block_strdef(void) { unsigned int nb, nentries; int i, resize; long ofs; char *src_ptr; STRUCT_DEF_ENTRY_TYPE *sde_ptr; DB_STRUCT_DEF_ENTRY_TYPE *dbsde_ptr; nentries = db_ptr->block_hdr.struct_def_nentries; nb = nentries * DB_STRUCT_DEF_ENTRY_SIZE; ofs = db_ptr->block_hdr.data_list_ofs + db_ptr->block_hdr.data_list_nentries * DATA_LIST_ENTRY_SIZE; if (DB_STRUCT_DEF_ENTRY_SIZE == STRUCT_DEF_ENTRY_SIZE) { resize = 0; src_ptr = (char *) db_ptr->block_strdef; } else { resize = 1; src_ptr = malloc(nentries * DB_STRUCT_DEF_ENTRY_SIZE); if (src_ptr == NULL) { db_ptr->error_code = INSUFFICIENT_MEMORY; db_ptr->error_data = STRUCTURE_DEF; goto error_found; } dbsde_ptr = (DB_STRUCT_DEF_ENTRY_TYPE *) src_ptr; sde_ptr = (STRUCT_DEF_ENTRY_TYPE *) db_ptr->block_strdef; for (i=0; ierror_code = write_data(db_ptr->fpblkdata, (char *) src_ptr, ofs, nb)) != 0) { db_ptr->error_data = STRUCTURE_DEF; goto error_found; } if (resize) { free(src_ptr); } return(0); error_found: report_db_error("write_block_strdef"); return(db_ptr->error_code); } /*----------------------------------------------------------------------------- FUNCTION: add_block_dir_entry It adds the current entry to the block directory. NOTE: - Block directory must already be open. - Header must be in db_ptr->block_dir_hdr. - Entry must be in *db_ptr->block_dir_entry_ptr. - On return, db_ptr->block_dir_index points to the new entry. - Entry is added to the end so the directory must be re-sorted. RETURNS: 0 if okay db_ptr->error_code otherwise */ int add_block_dir_entry(void) { unsigned int nb; long ofs; /* ---> WRITE ENTRY */ nb = db_ptr->block_dir_hdr.dir_entry_nbytes; ofs = BLOCK_DIR_HDR_SIZE + nb * db_ptr->block_dir_hdr.dir_nentries; if ((db_ptr->error_code = write_data(db_ptr->fpblkdir, (char *) db_ptr->block_dir_entry_ptr, ofs, nb)) != 0) { db_ptr->error_data = BLOCK_DIR; goto error_found; } /* ---> REWRITE DIRECTORY HEADER */ db_ptr->block_dir_hdr.dir_nentries++; db_ptr->block_dir_hdr.next_seq_number++; if (write_block_dir_hdr()) goto error_found; if (flush_block_dir_file()) goto error_found; return(0); error_found: report_db_error("add_block_dir_entry"); return(db_ptr->error_code); } /*----------------------------------------------------------------------------- FUNCTION: load_producer_definition It loads the database definition from a given producer definition file. RETURNS: 0 if okay db_ptr->error_code otherwise */ int load_producer_definition(void) { char keyword[80], test[3]; long tmp_long; unsigned long tmp_ulong; /* ---> OPEN PRODUCER DEFINITION FILE */ if ((db_ptr->fpprddef = fopen(db_ptr->producer_def_file, "rb")) == NULL) { db_ptr->error_code = UNABLE_TO_OPEN; db_ptr->error_data = PRODUCER_DEF_FILE; goto error_found; } /* set default directory time unit: */ db_ptr->producer->dir_time_flag = DIR_TIME_IN_SECONDS; /* ---> SCAN PRODUCER DEFINITION FILE FOR REQUIRED DATABASE PARAMETERS */ if (!getword_nc(db_ptr->fpprddef, keyword, 80)) goto read_error; if (strcmp("DATASET_ID", keyword)) goto read_error; get2eol_nc(db_ptr->fpprddef, (char *) &(db_ptr->producer->dataset_id), sizeof(DATASET_ID_TYPE)); if (!getword_nc(db_ptr->fpprddef, keyword, 80)) goto read_error; if (strcmp("PRODUCER_ID", keyword)) goto read_error; get2eol_nc(db_ptr->fpprddef, (char *) &(db_ptr->producer->producer_id), sizeof(PRODUCER_ID_TYPE)); if (getwords_nc(db_ptr->fpprddef, keyword, 80, 2) != 2) goto read_error; if (sscanf(keyword, " BLOCK_DIR_TYPE %lu %2s", &tmp_ulong, test) != 1) goto read_error; db_ptr->producer->block_dir_type = (ULONG) tmp_ulong; if (getwords_nc(db_ptr->fpprddef, keyword, 80, 2) != 2) goto read_error; if (sscanf(keyword, " PROFILE_DIR_TYPE %ld %2s", &tmp_long, test) != 1) goto read_error; db_ptr->producer->profile_dir_type = (LONG) tmp_long; /* ---> ALLOCATE MEMORY FOR STRUCTURE DEFINITION */ if ((db_ptr->block_strdef = (STRUCT_DEF_HDR_TYPE *) calloc(1, STRUCT_DEF_ENTRY_SIZE)) == NULL) { db_ptr->error_code = INSUFFICIENT_MEMORY; goto def_error; } /* ---> SCAN REMAINDER OF PRODUCER DEFINITION FILE FOR OPTIONAL PARAMETERS */ while (getword_nc(db_ptr->fpprddef, keyword, 80)) { if (!strcmp(keyword, "UNUSED")) get2eol_nc(db_ptr->fpprddef, keyword, 79); /* ignore rest-of-line */ else if (!strcmp(keyword, "PROFILE_VAR")) { if ((db_ptr->error_code = define_data(PROFILE_VAR_ACCESS_CODE)) != 0) goto def_error; } else if (!strcmp(keyword, "BLOCK_VAR")) { if ((db_ptr->error_code = define_data(BLOCK_VAR_ACCESS_CODE)) != 0) goto def_error; } else if (!strcmp(keyword, "DEFINE_STRUCT")) { if ((db_ptr->error_code = define_struct(db_ptr->fpprddef, &(db_ptr->block_strdef), &(db_ptr->producer->struct_def_max_nentries))) != 0) goto def_error; } else if (!strcmp(keyword, "DIR_TIME_IN_HUNDREDTHS")) { db_ptr->producer->dir_time_flag = DIR_TIME_IN_HUNDREDTHS; } else if (!strcmp(keyword, "DIR_TIME_IN_SECONDS")) { /* default; do nothing. */ } else { printf("\n ERROR: Unrecognized parameter "); goto read_error; } } fclose(db_ptr->fpprddef); db_ptr->producer->data_list_max_nentries++; /* largest id found + 1 */ if ((db_ptr->block_strdef = (STRUCT_DEF_HDR_TYPE *) realloc((char *) db_ptr->block_strdef, (1 + db_ptr->producer->struct_def_max_nentries) * STRUCT_DEF_ENTRY_SIZE)) == NULL) { db_ptr->error_code = INSUFFICIENT_MEMORY; goto def_error; } set_byte((UBYTE *) (db_ptr->block_strdef + db_ptr->producer->struct_def_max_nentries), 0, STRUCT_DEF_ENTRY_SIZE); db_ptr->producer->struct_def_max_nentries++; /* add entry for NULL terminator */ db_ptr->producer_loaded = 1; return(0); read_error: db_ptr->error_code = READ_ERROR; printf("\n SCANNING: %s \n", keyword); def_error: printf("\n ERROR: In producer definition file"); fclose(db_ptr->fpprddef); if (db_ptr->error_code == INSUFFICIENT_MEMORY) db_ptr->error_data = STRUCTURE_DEF; else db_ptr->error_data = PRODUCER_DEF; error_found: report_db_error("load_producer_definition"); return(db_ptr->error_code); } extern NAME_LIST_ENTRY_TYPE VALUE_CODE[]; /*------------------------------------------------------------------------------ FUNCTION: define_data Processes BLOCK_VAR and PROFILE_VAR statements in the producer definition file by setting the fields of the appropriate data list entry to the values indicated in the producer definition file. PARAMETER: code = BLOCK_VAR_ACCESS_CODE or PROFILE_VAR_ACCESS_CODE RETURNS: 0 if okay READ_ERROR or INVALID_VALUE_TYPE error */ int define_data(int code) { int id, temp; char type[12], buff[80], test[3]; if (!getword_nc(db_ptr->fpprddef, buff, 80)) goto read_error; if (sscanf(buff, " %d %2s", &id, test) != 1) goto read_error; if (getwords_nc(db_ptr->fpprddef, buff, 80, 5) != 5) goto read_error; if (sscanf(buff, " %11s %19s %f %f %11s %2s", type, db_ptr->data_list[id].name, &(db_ptr->data_list[id].offset), &(db_ptr->data_list[id].scale), db_ptr->data_list[id].units, test) != 5) goto read_error; if ((temp = get_code(VALUE_CODE, type)) == BADINT) { printf("\n SCANNING: %s\n", buff); return(INVALID_VALUE_TYPE); } db_ptr->data_list[id].value_type = temp; db_ptr->data_list[id].access_type = code; if (code == PROFILE_VAR_ACCESS_CODE) { db_ptr->data_list[id].access_0 = db_ptr->data_list[id].access_1 = db_ptr->producer->profile_var_max_nentries; (db_ptr->producer->profile_var_max_nentries)++; } db_ptr->data_list[id].index = id; if (id > (int)db_ptr->producer->data_list_max_nentries) db_ptr->producer->data_list_max_nentries = id; return(0); read_error: printf("\n SCANNING: %s \n", buff); return(READ_ERROR); }