#include #include #include #include #include #include #include #include #include "local_proto.h" #define A_DIR "dig_ascii" int main (int argc, char *argv[]) { FILE *ascii; struct GModule *module; struct Option *old, *new, *delim_opt, *columns_opt, *xcol_opt, *ycol_opt, *zcol_opt, *catcol_opt, *format_opt, *skip_opt; int xcol, ycol, zcol, catcol, format, skip_lines; struct Flag *zcoorf, *t_flag, *e_flag, *noheader_flag, *notopol_flag; char *table; char *fs; int zcoor=WITHOUT_Z, make_table; struct Map_info Map; G_gisinit(argv[0]); module = G_define_module(); module->keywords = _("vector"); module->description = _("Convert GRASS ascii file or points file to binary vector."); /************************** Command Parser ************************************/ old = G_define_option(); old->key = "input"; old->type = TYPE_STRING; old->required = NO; old->multiple = NO; old->gisprompt = "old_file,file,input"; old->description = _("ASCII file to be converted to binary vector file, if not given reads from standard input"); new = G_define_standard_option(G_OPT_V_OUTPUT); format_opt = G_define_option(); format_opt->key = "format"; format_opt->type = TYPE_STRING; format_opt->required = NO; format_opt->multiple = NO; format_opt->options = "point,standard"; format_opt->answer = "point"; format_opt->description = _("Input file format"); delim_opt = G_define_option(); delim_opt->key = "fs"; delim_opt->type = TYPE_STRING; delim_opt->required = NO; delim_opt->description = _("Field separator"); delim_opt->answer = "|"; skip_opt = G_define_option(); skip_opt->key = "skip"; skip_opt->type = TYPE_INTEGER; skip_opt->required = NO; skip_opt->multiple = NO; skip_opt->answer = "0"; skip_opt->description = _("Number of header lines to skip at top of input file (written to map history)"); columns_opt = G_define_option(); columns_opt->key = "columns"; columns_opt->type = TYPE_STRING; columns_opt->required = NO; columns_opt->multiple = NO; columns_opt->description = _("Columns definition for points mode in SQL style, for example:\n" "'x double precision, y double precision, cat int, name varchar(10)'"); xcol_opt = G_define_option(); xcol_opt->key = "x"; xcol_opt->type = TYPE_INTEGER; xcol_opt->required = NO; xcol_opt->multiple = NO; xcol_opt->answer = "1"; xcol_opt->description = _("Number of column used as x coordinate (first column is 1) for points mode"); ycol_opt = G_define_option(); ycol_opt->key = "y"; ycol_opt->type = TYPE_INTEGER; ycol_opt->required = NO; ycol_opt->multiple = NO; ycol_opt->answer = "2"; ycol_opt->description = _("Number of column used as y coordinate (first column is 1) for points mode"); zcol_opt = G_define_option(); zcol_opt->key = "z"; zcol_opt->type = TYPE_INTEGER; zcol_opt->required = NO; zcol_opt->multiple = NO; zcol_opt->answer = "0"; zcol_opt->description = _("Number of column used as z coordinate (first column is 1) for points mode. " "If 0, z coordinate is not used."); catcol_opt = G_define_option(); catcol_opt->key = "cat"; catcol_opt->type = TYPE_INTEGER; catcol_opt->required = NO; catcol_opt->multiple = NO; catcol_opt->answer = "0"; catcol_opt->description = _("Number of column used as category (first column is 1) for points mode. " "If 0, unique category is assigned to each row and written to new column 'cat'."); zcoorf = G_define_flag (); zcoorf->key = 'z'; zcoorf->description = _("Create 3D file"); t_flag = G_define_flag(); t_flag->key = 't'; t_flag->description = _("Do not create table in points mode"); e_flag = G_define_flag(); e_flag->key = 'e'; e_flag->description = _("Create a new empty map and exit. Nothing is read from input."); noheader_flag = G_define_flag(); noheader_flag->key = 'n'; noheader_flag->description = _("Don't expect a header when reading in standard format"); notopol_flag = G_define_flag(); notopol_flag->key = 'b'; notopol_flag->description = _("Do not build topology in points mode"); if (G_parser (argc, argv)) exit(EXIT_FAILURE); if ( format_opt->answer[0] == 'p' ) format = FORMAT_POINT; else format = FORMAT_ALL; skip_lines = atoi(skip_opt->answer); if(skip_lines < 0) G_fatal_error(_("Please specify reasonable number of lines to skip.")); if (zcoorf->answer && format == FORMAT_POINT && zcol_opt->answer == "0") G_fatal_error(_("Please specify z column.")); xcol = atoi(xcol_opt->answer) - 1; ycol = atoi(ycol_opt->answer) - 1; zcol = atoi(zcol_opt->answer) - 1; if (zcoorf->answer && format == FORMAT_POINT && zcol < 0) G_fatal_error(_("Please specify reasonable z column.")); catcol = atoi(catcol_opt->answer) - 1; if ( old->answer != NULL ) { if ( (ascii = fopen ( old->answer, "r" ) ) == NULL ) { G_fatal_error(_("Could not open ascii file [%s]"), old->answer); } } else { ascii = stdin; } fs = delim_opt->answer; if ( strcmp(fs,"\\t") == 0 ) fs = "\t"; if ( strcmp(fs,"tab") == 0 ) fs = "\t"; if ( strcmp(fs,"space") == 0 ) fs = " "; /* check dimension */ if (zcoorf->answer) { zcoor = 1; } Vect_open_new (&Map, new->answer, zcoor); Vect_hist_command ( &Map ); if ( e_flag->answer ) { Vect_build ( &Map, stdout ); Vect_close ( &Map ); exit(EXIT_SUCCESS) ; } if ( format == FORMAT_POINT ) { int i, rowlen, ncols, minncols, *coltype, *coltype2, *collen; int n_int = 0, n_double = 0, n_string = 0; char buf[1000]; struct field_info *Fi; char *tmp, *key; dbDriver *driver; dbString sql; FILE *tmpascii; /* Open temporary file */ tmp = G_tempfile(); if (NULL == (tmpascii = fopen(tmp, "w+"))) { G_fatal_error(_("Can't open temp file %s"), tmp); } unlink(tmp); points_analyse ( ascii, tmpascii, fs, &rowlen, &ncols, &minncols, &coltype, &collen, skip_lines, xcol, ycol ); fprintf ( stderr, "Maximum input row length: %d\n", rowlen); fprintf ( stderr, "Maximum number of columns: %d\n", ncols); fprintf ( stderr, "Minimum number of columns: %d\n", minncols); /* check column numbers */ if ( xcol >= minncols ) { Vect_delete(new->answer); G_fatal_error(_("x column number > minimum last column number\n(incorrect field separator?)")); } if ( ycol >= minncols ) { Vect_delete(new->answer); G_fatal_error(_("y column number > minimum last column number\n(incorrect field separator?)")); } if ( zcol >= minncols ) { Vect_delete(new->answer); G_fatal_error(_("z column number > minimum last column number\n(incorrect field separator?)")); } if ( catcol >= minncols ) { Vect_delete(new->answer); G_fatal_error(_("cat column number > minimum last column number\n(incorrect field separator?)")); } if ( coltype[xcol] == DB_C_TYPE_STRING ) { Vect_delete(new->answer); G_fatal_error(_("x column is not of number type")); } if ( coltype[ycol] == DB_C_TYPE_STRING ) { Vect_delete(new->answer); G_fatal_error(_("y column is not of number type")); } if ( zcol >= 0 && coltype[zcol] == DB_C_TYPE_STRING ) { Vect_delete(new->answer); G_fatal_error(_("z column is not of number type")); } if ( catcol >= 0 && coltype[catcol] == DB_C_TYPE_STRING ) { Vect_delete(new->answer); G_fatal_error(_("cat column is not of number type")); } /* Create table */ make_table = 0; for ( i = 0 ; i < ncols; i++ ) { if ( xcol != i && ycol != i && zcol != i && catcol != i ) { make_table = 1; break; } } if ( t_flag->answer ) { make_table = 0; } if ( make_table ) { Fi = Vect_default_field_info ( &Map, 1, NULL, GV_1TABLE ); driver = db_start_driver_open_database ( Fi->driver, Vect_subst_var(Fi->database,&Map) ); if ( driver == NULL ) { Vect_delete(new->answer); G_fatal_error(_("Cannot open database %s by driver %s"), Vect_subst_var(Fi->database,&Map), Fi->driver ); } db_begin_transaction ( driver ); db_init_string (&sql); sprintf ( buf, "create table %s ( ", Fi->table ); db_append_string ( &sql, buf ); if ( catcol < 0 ) { db_append_string ( &sql, "cat integer, " ); } for ( i = 0 ; i < ncols; i++ ) { fprintf ( stderr, "column: %d type: ", i+1); if ( i > 0 && !columns_opt->answer ) { db_append_string ( &sql, ", " ); } if ( catcol == i && coltype[i] != DB_C_TYPE_INT ) { Vect_delete(new->answer); G_fatal_error(_("Category column is not of integer type")); } switch ( coltype[i] ) { case DB_C_TYPE_INT: fprintf ( stderr, "integer\n"); if ( !columns_opt->answer ) { sprintf ( buf, "int_%d integer", n_int+1); db_append_string ( &sql, buf); if ( catcol == i ) { sprintf ( buf, "int_%d", n_int+1); key = G_store( buf ); } } n_int++; break; case DB_C_TYPE_DOUBLE: fprintf ( stderr, "double\n"); if ( !columns_opt->answer ) { sprintf ( buf, "dbl_%d double precision", n_double+1); db_append_string ( &sql, buf); } n_double++; break; case DB_C_TYPE_STRING: fprintf ( stderr, "string length: %d\n", collen[i]); if ( !columns_opt->answer ) { sprintf ( buf, "str_%d varchar(%d)", n_string+1, collen[i]); db_append_string ( &sql, buf); } n_string++; break; } } if ( columns_opt->answer ) { db_append_string ( &sql, columns_opt->answer ); } db_append_string ( &sql, " )" ); /* this link is added with default 'cat' key, later deleted and replaced by true key name, * otherwise if module crashes when the table exists but link is not written it makes troubles */ Vect_map_add_dblink ( &Map, 1, NULL, Fi->table, "cat", Fi->database, Fi->driver); /* Create table */ G_debug ( 3, db_get_string ( &sql ) ); if (db_execute_immediate (driver, &sql) != DB_OK ) { Vect_delete(new->answer); G_fatal_error(_("Cannot create table: %s"), db_get_string ( &sql ) ); } /* Grant */ if (db_grant_on_table (driver, Fi->table, DB_PRIV_SELECT, DB_GROUP|DB_PUBLIC ) != DB_OK ) { Vect_delete(new->answer); G_fatal_error(_("Cannot grant privileges on table %s"), Fi->table ); } /* Check column types */ if ( columns_opt->answer ) { int nc; dbTable *table; dbColumn *column; db_set_string ( &sql, Fi->table ); if(db_describe_table (driver, &sql, &table) != DB_OK) { Vect_delete(new->answer); G_fatal_error(_("Cannot describe table %s"), Fi->table); } nc = db_get_table_number_of_columns(table); if ( (catcol >= 0 && nc != ncols) || (catcol < 0 && (nc-1) != ncols) ) { Vect_delete(new->answer); G_fatal_error(_("Number of columns defined (%d) does not match number " "of columns (%d) in input."), catcol < 0 ? nc-1 : nc, ncols); } coltype2 = (int *) G_malloc ( ncols * sizeof(int) ); for ( i = 0; i < ncols; i++ ) { int dbcol, ctype, length; if ( catcol < 0 ) dbcol = i+1; /* first is category */ else dbcol = i; column = db_get_table_column ( table, dbcol ); ctype = db_sqltype_to_Ctype ( db_get_column_sqltype(column) ); length = db_get_column_length ( column ); coltype2[i] = ctype; if ( catcol == i ) { /* if catcol == -1 it cannot be tru */ key = G_store(db_get_column_name(column)); } switch ( coltype[i] ) { case DB_C_TYPE_INT: if ( ctype == DB_C_TYPE_DOUBLE ) { G_warning(_("Column %d defined as double has only integer values"), i+1); } else if ( ctype == DB_C_TYPE_STRING ) { G_warning(_("Column %d defined as string has only integer values"), i+1); } break; case DB_C_TYPE_DOUBLE: if ( ctype == DB_C_TYPE_INT ) { Vect_delete(new->answer); G_fatal_error(_("Column %d defined as integer has double values"), i+1); } else if ( ctype == DB_C_TYPE_STRING ) { G_warning(_("Column %d defined as string has double values"), i+1); } break; case DB_C_TYPE_STRING: if ( ctype == DB_C_TYPE_INT ) { Vect_delete(new->answer); G_fatal_error(_("Column %d defined as integer has string values"), i+1); } else if ( ctype == DB_C_TYPE_DOUBLE ) { Vect_delete(new->answer); G_fatal_error(_("Column %d defined as double has string values"), i+1); } if ( length < collen[i] ) { Vect_delete(new->answer); G_fatal_error(_("Length of column %d (%d) is less than maximum value " "length (%d)"), i+1, length, collen[i]); } break; } } } else { coltype2 = coltype; } if ( catcol < 0 ) { key = "cat"; } else if ( !columns_opt->answer ) { } if ( db_create_index2(driver, Fi->table, key ) != DB_OK ) G_warning(_("Cannot create index")); Vect_map_del_dblink ( &Map, 1 ); Vect_map_add_dblink ( &Map, 1, NULL, Fi->table, key, Fi->database, Fi->driver); table = Fi->table; } else { driver = NULL; table = NULL; } points_to_bin ( tmpascii, rowlen, &Map, driver, table, fs, ncols, coltype2, xcol, ycol, zcol, catcol, skip_lines ); if ( driver ) { db_commit_transaction ( driver ); db_close_database_shutdown_driver ( driver ); } fclose (tmpascii); } else { /* FORMAT_ALL = standard mode */ if ( ! noheader_flag->answer ) read_head(ascii, &Map); asc_to_bin(ascii, &Map) ; } if ( old->answer != NULL ) { fclose(ascii) ; } if ( notopol_flag->answer ) { Vect_close ( &Map ); } else { Vect_build ( &Map, stdout ); Vect_close ( &Map ); } exit(EXIT_SUCCESS) ; }