#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 404 * * HONOLULU, HI 96822 * * * * VERSION: 3.00 * * * * DATE: APRIL 1989 * * * *****************************************************************************/ /* FILE: dbput.c FUNCTIONS FOR UPDATING DATA IN AN EXISTING DATABASE */ /*----------------------------------------------------------------------------- FUNCTION: DBPUT It updates data in the database. PARAMETERS: type = pointer to data type data = address of user buffer nb = pointer to no. of bytes in user buffer (should not exceed size of originally reserved space) ierr = pointer to error code RETURNS: VOID */ void DBPUT(int *type, char *data, unsigned int *nb, int *ierr) { if ((*ierr = dbget_flags()) != 0) return; /* ---> PROFILE DATA (types 0 - 99) */ if ((*type >= 0) & (*type < (int)db_ptr->block_hdr.data_list_nentries)) { if (!db_ptr->profile_is_open) {*ierr = NO_PROFILE_IS_OPEN; *nb = 0; return;} if (db_ptr->data_list[*type].access_type == UNUSED) {*ierr = INVALID_TYPE_REQUEST; *nb = 0; return;} if (*nb == 0) {*ierr = INVALID_BUFFER_SIZE; return;} if (put_profile_data(type, data, nb, ierr)) goto error_found; return; } else { switch (*type) { case DATA_PROC_MASK: db_ptr->block_hdr.data_proc_mask = *((ULONG *) data); db_ptr->block_modified = 1; *nb = sizeof(ULONG); break; case POSITION: *ierr = put_position((DMSH_POSITION_TYPE *) data); *nb = 2 * sizeof(DMSH_POSITION_TYPE); break; case DEPTH_RANGE: *ierr = put_depth_range((DEPTH_RANGE_TYPE *) data); *nb = sizeof(DEPTH_RANGE_TYPE); break; case STRUCTURE_DEF: *ierr = put_struct_def((STRUCT_DEF_HDR_TYPE *) data, nb); break; case PRODUCER_ID: strncpy((char *) &(db_ptr->block_hdr.producer_id), data, sizeof(PRODUCER_ID_TYPE)); db_ptr->block_modified = 1; *nb = min_val(sizeof(PRODUCER_ID_TYPE), strlen(data)); break; case DATA_MASK: db_ptr->block_hdr.data_mask = *((ULONG *) data); db_ptr->block_modified = 1; *nb = sizeof(ULONG); break; default: *ierr = INVALID_TYPE_REQUEST; break; } } if (!(*ierr)) return; error_found: report_db_error("DBPUT"); *ierr = db_ptr->error_code * 1000 - db_ptr->error_data; } /*----------------------------------------------------------------------------- FUNCTION: put_profile_data It rewrites user-defined data (types 0 to 99) in current profile. PARAMETERS: type = pointer to data type data = array containing the data to be written to file user_nb = pointer to no. of bytes in user buffer ierr = pointer to error code RETURNS: 0 if okay db_ptr->error_code otherwise */ int put_profile_data(int *type, char *data, unsigned int *user_nb, int *ierr) { unsigned int nb, i, excess_start, excess_end; long ofs; char *copy; int return_value; get_access_param(type, &nb, &ofs); if (*user_nb == nb) return(put_profile_aux(data, nb, ofs)); if (*user_nb > nb) { *ierr = INSUFFICIENT_SPACE; *user_nb = nb; /* update to no. of bytes actually stored */ return(put_profile_aux(data, nb, ofs)); /* store first bytes only */ } /*--- else *user_nb < nb so we must "BAD-out" the excess storage space ---*/ if ((copy = malloc(nb)) == NULL) /* need a bigger buffer */ return(INSUFFICIENT_MEMORY); move_byte(data, copy, *user_nb); /* copy user data to new buffer */ excess_start = *user_nb / VALUE_SIZE[db_ptr->data_list[*type].value_type]; excess_end = nb / VALUE_SIZE[db_ptr->data_list[*type].value_type]; switch (db_ptr->data_list[*type].value_type) { case CHAR_VALUE_CODE : case TEXT_VALUE_CODE : for (i = excess_start; i < excess_end; i++) *(copy + i) = NUL; break; case BYTE_VALUE_CODE : for (i = excess_start; i < excess_end; i++) *(copy + i) = BADBYTE; break; case STRUCT_VALUE_CODE : case UBYTE_VALUE_CODE : for (i = excess_start; i < excess_end; i++) *( ((UBYTE *) copy) + i ) = BADUBYTE; break; case SHORT_VALUE_CODE : for (i = excess_start; i < excess_end; i++) *( ((SHORT *) copy) + i ) = BADSHORT; break; case USHORT_VALUE_CODE : for (i = excess_start; i < excess_end; i++) *( ((USHORT *) copy) + i ) = BADUSHORT; break; case LONG_VALUE_CODE : for (i = excess_start; i < excess_end; i++) *( ((LONG *) copy) + i ) = BADLONG; break; case ULONG_VALUE_CODE : for (i = excess_start; i < excess_end; i++) *( ((ULONG *) copy) + i ) = BADULONG; break; case FLOAT_VALUE_CODE : for (i = excess_start; i < excess_end; i++) *( ((FLOAT *) copy) + i ) = BADFLOAT; break; case DOUBLE_VALUE_CODE: for (i = excess_start; i < excess_end; i++) *( ((DOUBLE *) copy) + i ) = BADDOUBLE; break; case COMPLEX_VALUE_CODE: for (i = excess_start; i < excess_end; i++) { ( ((COMPLEX *) copy) + i )->RE = BADFLOAT; ( ((COMPLEX *) copy) + i )->IM = BADFLOAT; } } return_value = put_profile_aux(copy, nb, ofs); free(copy); *user_nb = nb; /* update to no. of bytes actually stored */ return(return_value); } /*----------------------------------------------------------------------------- FUNCTION: put_profile_aux It performs the actual rewrite of profile data (types 0 to 99). PARAMETERS: data = pointer to where updated data are stored nb = number of bytes to rewrite ofs = offset into file at which to start rewriting RETURNS: 0 if okay SEEK_ERROR or WRITE_ERROR otherwise */ int put_profile_aux(char *data, unsigned int nb, long ofs) { if (nb > 0) { if ((db_ptr->error_code = write_data(db_ptr->fpblkdata, data, ofs, nb)) != 0) { db_ptr->error_data = PROFILE_DATA; goto error_found; } } return(0); error_found: report_db_error("put_profile_aux"); return(db_ptr->error_code); } /*----------------------------------------------------------------------------- FUNCTION: put_position It updates the position parameter in the current profile. PARAMETER: data = array containing the updated longitude and latitude to be written RETURNS: 0 if okay INVALID_POSITION or NO_PROFILE_IS_OPEN otherwise */ int put_position(DMSH_POSITION_TYPE *data) { int profile_key_type; profile_key_type = db_ptr->block_hdr.dir_type % 10; if (invalid_position(&data[0], 0) || invalid_position(&data[1], 1)) return(INVALID_POSITION); if ((profile_key_type == 0) || (profile_key_type == 2)) { db_ptr->block_hdr.lon1 = POSHUN(&data[0]); 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(&data[1]); db_ptr->block_hdr.lat2 = db_ptr->block_hdr.lat1; } else if ((profile_key_type == 1) || (profile_key_type == 3)) { if (!(db_ptr->profile_is_open)) return(NO_PROFILE_IS_OPEN); db_ptr->profile_dir_entry_ptr->lon = POSHUN(&data[0]); 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(&data[1]); write_profile_dir_entry(); } db_ptr->block_modified = 1; return(0); } /*----------------------------------------------------------------------------- FUNCTION: put_depth_range It updates the depth range parameter for the current profile. PARAMETER: data = array containing updated depth range to be written RETURNS: 0 if okay NO_PROFILE_IS_OPEN otherwise */ int put_depth_range(DEPTH_RANGE_TYPE *data) { int profile_key_type; profile_key_type = db_ptr->block_hdr.dir_type % 10; if ((profile_key_type == 0) || (profile_key_type == 1)) { db_ptr->block_hdr.depth1 = data->min_depth; db_ptr->block_hdr.depth2 = data->max_depth; } else if ((profile_key_type == 2) || (profile_key_type == 3)) { if (!(db_ptr->profile_is_open)) return(NO_PROFILE_IS_OPEN); db_ptr->profile_dir_entry_ptr->depth1 = data->min_depth; db_ptr->profile_dir_entry_ptr->depth2 = data->max_depth; write_profile_dir_entry(); } db_ptr->block_modified = 1; return(0); } /*jr++*/ /*----------------------------------------------------------------------------- FUNCTION: put_struct_def It rewrites a block structure definition entry. RETURNS: 0 if okay error code otherwise */ int put_struct_def(STRUCT_DEF_HDR_TYPE *new_sd, unsigned int *nb) { int must_free = 0; STRUCT_DEF_HDR_TYPE *old_sd; if (!db_ptr->block_strdef_loaded) { if ((db_ptr->error_code = load_block_strdef()) != 0) return(db_ptr->error_code); must_free = 1; } if ((old_sd = find_def(new_sd->name, db_ptr->block_strdef)) == NULL) { db_ptr->error_code = STRUCTURE_NOT_PRESENT; goto error_found; } if (new_sd->nelem > old_sd->nelem) { db_ptr->error_code = INSUFFICIENT_SPACE; *nb = 0; /* no bytes stored */ goto error_found; } else { if (new_sd->nelem < old_sd->nelem) /* want to NULL-out the excess */ set_byte((UBYTE *) (old_sd + new_sd->nelem + 1), 0, (old_sd->nelem - new_sd->nelem) * STRUCT_DEF_ENTRY_SIZE); *nb = (old_sd->nelem + 1) * STRUCT_DEF_ENTRY_SIZE; /* no. bytes stored */ move_byte((CHAR *) (new_sd + 1), (CHAR *) (old_sd + 1), new_sd->nelem * STRUCT_DEF_ENTRY_SIZE); /* we want to preserve the old_sd nelem so when we are searching for structure definitions, we don't fall into a hole and mistakenly think we've reached the end of the block structure definitions */ if ((db_ptr->error_code = write_data(db_ptr->fpblkdata, (char *) db_ptr->block_strdef, 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)) != 0) goto error_found; if (must_free) { free(db_ptr->block_strdef); db_ptr->block_strdef_loaded = 0; } return(0); } error_found: if (must_free) { free(db_ptr->block_strdef); db_ptr->block_strdef_loaded = 0; } db_ptr->error_data = STRUCTURE_DEF; return(db_ptr->error_code); } /*----------------------------------------------------------------------------- FUNCTION: write_profile_dir_entry It rewrites the current profile directory entry. RETURNS: 0 if successful db_ptr->error_code otherwise */ int write_profile_dir_entry(void) { unsigned int nb; long ofs; nb = db_ptr->block_hdr.dir_entry_nbytes; ofs = db_ptr->block_hdr.dir_ofs + nb * db_ptr->profile_dir_index; if ((db_ptr->error_code = write_data(db_ptr->fpblkdata, (char *) db_ptr->profile_dir_entry_ptr, ofs, nb)) != 0) { db_ptr->error_data = PROFILE_DIR; goto error_found; } return(0); error_found: report_db_error("write_profile_dir_entry"); return(db_ptr->error_code); }