/* ldcodas.c: general CODAS database loader. 2005/03/25 EF Added support for non-native source bin files. This should be modified in a general cleanup of CODAS, eliminating the *_COMPATIBLE_HOST in favor of *ENDIAN or something like that. 2005/11/03 EF Added verbose option. 2007/01/05 EF Added cmd_file_list option. */ #include #include #include #include #include #include #include /* may be temporary; needed now for access to db */ #include extern NAME_LIST_ENTRY_TYPE VALUE_CODE[]; #define BIG 2 #define LITTLE 0 /* for message logging: */ static char msg[256]; static FILE *fp_log; /* load options and variables (could be put in struct) */ static FILE_NAME_TYPE dbname = "", prdname = "", logname = "ldcodas.log"; static int YearBase = -1; static int SourceMachine = HOST_ENVIRONMENT; static int verbose = 0; static int cmd_file_list = 0; static FILE_NAME_TYPE path_buf; static OPTION_TYPE load_options[] = { {"END" , 0 , NULL , (char *) NULL}, {"DATABASE_NAME:" , TYPE_STRING, op_get_param, dbname}, {"DEFINITION_FILE:" , TYPE_STRING, op_get_param, prdname}, {"LOG_FILE:" , TYPE_STRING, op_get_param, logname}, {"YEAR_BASE:" , TYPE_INT , op_get_param, (char *) &YearBase}, {"verbose" , 1 , set_code, (char *) &verbose}, {"cmd_file_list" , 1 , set_code, (char *) &cmd_file_list}, {NULL , 0 , NULL , (char *) NULL} }; /* loading commands and variables */ static FILE *fp_bin; static struct { int db_is_open, block_is_open, profile_is_open; } dbstatus; /* This parallels internal db structures; one could access them instead. In fact, it is not clear to me why the basic calls such as DBNEWBLK do not automatically call DBENDBLK when a block is open, instead of raising an error. Rather than redesign all that, we will just build a higher level here, and maintain the separation between low level calls that access the db structure, and user-level calls that don't. */ static int bin_file(FILE *fp, char *arg, int code) { FILE_NAME_TYPE fname; FILE_NAME_TYPE fname_buf; fscanf(fp, PATH_FMT, fname); printf("Reading %s\n", fname); if (fp_bin) fclose(fp_bin); if (cmd_file_list) { strcpy(fname_buf, path_buf); strncat(fname_buf, fname, strlen(fname)+1); } else { strcpy(fname_buf, fname); } fp_bin = check_fopen(fname_buf, "rb"); if (fp_bin == NULL) { report_msg(fname_buf); report_msg("Error opening binary file"); return 1; } return(0); } static int new_block(FILE *fp, char *arg, int code) { int error; /* TODO: add actual error handling */ if (dbstatus.profile_is_open) { DBENDPRF(&error); DBERROR(&error, "in new_block"); dbstatus.profile_is_open = 0; } if (dbstatus.block_is_open) { DBENDBLK(&error); DBERROR(&error, "in new_block"); dbstatus.block_is_open = 0; } DBNEWBLK(&error); DBERROR(&error, "in new_block"); dbstatus.block_is_open = 1; return(error); } static int new_profile(FILE *fp, char *arg, int code) { int error; YMDHMS_TIME_TYPE prftime; get_time(fp, &prftime); if (dbstatus.profile_is_open) { DBENDPRF(&error); DBERROR(&error, "in new_profile"); dbstatus.profile_is_open = 0; } DBNEWPRF(&prftime, &error); DBERROR(&error, "in new_profile"); dbstatus.profile_is_open = 1; if (verbose) {write_ymdhms_time(stdout, &prftime); puts("");} return(error); } /* The following is very inefficient, because the same info is extracted from the db at each call instead of once at the beginning. But it is easier to code this way, so it will do for now. */ static int binary_data(FILE *fp, char *arg, int code) { char data_name_buf[40], value_type_buf[40]; long offset; int data_id, bin_value_type, db_value_type; int bin_value_size, n; unsigned int nbad, nv, nb; int ierr; static char buf[10000], buf2[10000]; n = fscanf(fp, "%39s %39s %d %ld", data_name_buf, value_type_buf, &nv, &offset); if (verbose) {fputs("loading ", stdout); puts(data_name_buf);} if (n != 4) return(1); /* minimal error check */ data_id = get_data_list_index(data_name_buf); if (data_id == -1) return(1); bin_value_type = get_code(VALUE_CODE, value_type_buf); bin_value_size = VALUE_SIZE[bin_value_type]; /* Q&D method, violates intended separation between low-level and user-level, but let's try it first. */ db_value_type = db_ptr->data_list[data_id].value_type; fseek(fp_bin, offset, SEEK_SET); /* add error check */ fread(buf, 1, nv * bin_value_size, fp_bin); if (SourceMachine != HOST_ENVIRONMENT) { /* printf("Converting, %d, %d\n", SourceMachine, HOST_ENVIRONMENT); */ convert_select(buf, buf, SourceMachine, HOST_ENVIRONMENT, nv, bin_value_type, NULL, NULL); } if (bin_value_type == FLOAT_VALUE_CODE) { DBADD_F(&data_id, (FLOAT *) buf, &nv, &nbad, &ierr); DBERROR(&ierr, "in binary_data"); } else if (bin_value_type < FLOAT_VALUE_CODE) { if (bin_value_size != VALUE_SIZE[db_value_type]) { report_msg("integer size mismatch"); return(1); } nb = nv * bin_value_size; DBADD(&data_id, buf, &nb, &ierr); /* or use dbadd_cnf? */ DBERROR(&ierr, "in binary_data"); } else if (bin_value_type == DOUBLE_VALUE_CODE && db_value_type == STRUCT_VALUE_CODE) { nb = dbl_struc((double *)buf, buf2, data_name_buf, db_ptr->block_strdef); DBADD(&data_id, buf2, &nb, &ierr); DBERROR(&ierr, "in binary_data"); } else { sprintf(msg, "%s %s %d %ld------value type mismatch\n", data_name_buf, value_type_buf, nv, offset); report_msg(msg); return(1); } return ierr; } static int dp_mask(FILE *fp, char *arg, int code) { long dpm; LONG dpm_L; int n, error = 0; n = fscanf(fp, "%ld", &dpm); dpm_L = dpm; if (error_found((n != 1), "scanning dp_mask")) return (1); error = dbadd_cnf(DATA_PROC_MASK, (char *) &dpm_L, sizeof(LONG), "adding dp_mask"); return(error); } static int depth_range(FILE *fp, char *arg, int code) { DEPTH_RANGE_TYPE drt; int dr[2]; int n, error = 0; n = fscanf(fp, "%d %d", dr, dr+1); if (error_found((n != 2), "scanning depth_range")) return (1); drt.min_depth = dr[0]; drt.max_depth = dr[1]; error = dbadd_cnf(DEPTH_RANGE, (char *) &drt, sizeof(DEPTH_RANGE_TYPE), "adding depth_range"); return(error); } /* The following is a slight modification of the version in ioserv/misc.c. A leading underscore prevents name conflict. */ #define isname(c) ((c != '/') && (c != '\\')) static void _split_path(char *all, char *path) /* , char *fname) */ { int i; for (i=strlen(all)-1; i>0 && isname(all[i]); i--) ; /* i is 0 or index of last path character */ if (i>0) i++; /* first character that is part of name; number of path characters */ strncpy(path, all, i); path[i] = '\0'; /* strcpy(name, all+i); */ } #undef isname static OPTION_TYPE load_commands[] = { {"end" , 0 , NULL , (char *) NULL}, {"binary_file:" , 0 , bin_file , (char *) NULL}, {"new_block" , 0 , new_block , (char *) NULL}, {"new_profile:" , 0 , new_profile , (char *) NULL}, {"binary_data:" , 0 , binary_data , (char *) NULL}, {"dp_mask:" , 0 , dp_mask , (char *) NULL}, {"depth_range:" , 0 , depth_range , (char *) NULL}, {"big_endian" , BIG , set_code , (char *) &SourceMachine}, {"little_endian" , LITTLE , set_code , (char *) &SourceMachine}, {NULL , 0 , NULL , (char *) NULL} }; int main(int argc, char *argv[]) { int ierr, db_id = 1, memmode = DIR_IN_MEMORY; int ret = 0; int result; FILE *fpcnt, *fpcmd; int fake_argc = 2; char *fake_argv[2]; char fname_buf[256]; fpcnt = get_fpcnt(argc, argv); if (execute_options(fpcnt, load_options, ECHO) <= 0) { fprintf(stderr, "\n ERROR: executing load_options.\n"); return 1; } fp_log = check_fopen(logname, "w"); set_msg_file(fp_log); if (!strcmp(dbname, "") || !strcmp(prdname, "") || YearBase < 0) { report_msg( "\n ERROR: DATABASE_NAME:, DEFINITION_FILE:, and YEAR_BASE:\n\ must be specified in the control file\n\n"); return 1; } DBCREATE(&db_id, dbname, prdname, &memmode, &ierr); DBERROR(&ierr, "DBCREATE in main"); if (ierr) return 1; dbstatus.block_is_open = 0; dbstatus.profile_is_open = 0; if (cmd_file_list) { fake_argv[1] = fname_buf; while (!feof(fpcnt)) { if (fscanf(fpcnt, "%255s", fname_buf) != 1) break; /* grab and save the directory */ _split_path(fname_buf, path_buf); fpcmd = get_fpcnt(fake_argc, fake_argv); result = execute_options(fpcmd, load_commands, NOECHO); fclose(fpcmd); if (result == 0) { report_msg("\n ERROR: executing load_commands.\n"); ret++; } } } else { if (execute_options(fpcnt, load_commands, NOECHO) <= 0) { report_msg("\n ERROR: executing load_commands.\n"); ret++; } } if (dbstatus.profile_is_open) { DBENDPRF(&ierr); if (ierr) { DBERROR(&ierr, "in main"); ret++; } } if (dbstatus.block_is_open) { DBENDBLK(&ierr); if (ierr) { DBERROR(&ierr, "in main"); ret++; } } DBCLOSE(&ierr); if (ierr) {DBERROR(&ierr, "in main"); ret++;} printf("\nDatabase closed\n"); return ret; }