GRASS Programmer's Manual
6.4.2(2012)
|
00001 00002 /*- 00003 * These functions and definitions support the site format for 5.0 00004 * (format proposed by Dave Gerdes): 00005 * 00006 * easting|northing|[z|[d4|]...][#category_int] [ [@attr_text OR %flt] ... ] 00007 * 00008 * to allow multidimensions (everything preceding the last '|') and any 00009 * number of text or numeric attribute fields. 00010 * 00011 * Author: James Darrell McCauley <mccauley@ecn.purdue.edu> 00012 * 31 Jan 1994 00013 */ 00014 00015 #include <ctype.h> 00016 #include <string.h> 00017 #include <stdio.h> 00018 #include <stdlib.h> 00019 #include <errno.h> 00020 #include <grass/gis.h> 00021 #include <grass/site.h> 00022 #include <grass/dbmi.h> 00023 #include <grass/Vect.h> 00024 #include <grass/glocale.h> 00025 00026 00027 #define DQUOTE '"' 00028 #define SPACE ' ' 00029 #define BSLASH 92 00030 #define PIPE '|' 00031 00032 #define ispipe(c) (c==PIPE) 00033 #define isnull(c) (c=='\0') 00034 #define isquote(c) (c==DQUOTE) 00035 #define isbslash(c) (c==BSLASH) 00036 00037 static int format_double(double, char *); 00038 static char *next_att(const char *); 00039 static int cleanse_string(char *); 00040 00041 static int site_att_cmp(const void *pa, const void *pb) 00042 { 00043 const SITE_ATT *a = pa, *b = pb; 00044 00045 return a->cat - b->cat; 00046 } 00047 00048 00049 /*- 00050 * Reads ptr and returns 0 on success, 00051 * -1 on EOF, 00052 * -2 on other fatal error or insufficient data, 00053 * 1 on format mismatch (extra data) 00054 */ 00055 int G_site_get(struct Map_info *Map, Site * s) 00056 { 00057 int i, type, cat; 00058 static struct line_pnts *Points = NULL; 00059 static struct line_cats *Cats = NULL; 00060 SITE_ATT *sa; 00061 00062 if (Points == NULL) 00063 Points = Vect_new_line_struct(); 00064 if (Cats == NULL) 00065 Cats = Vect_new_cats_struct(); 00066 00067 while (1) { 00068 type = Vect_read_next_line(Map, Points, Cats); 00069 00070 if (type == -1) 00071 return -2; /* Error */ 00072 if (type == -2) 00073 return -1; /* EOF */ 00074 if (type != GV_POINT) 00075 continue; /* Is not point */ 00076 00077 Vect_cat_get(Cats, 1, &cat); 00078 00079 G_debug(4, "Site: %f|%f|%f|#%d", Points->x[0], Points->y[0], 00080 Points->z[0], cat); 00081 00082 s->east = Points->x[0]; 00083 s->north = Points->y[0]; 00084 if (Vect_is_3d(Map)) 00085 s->dim[0] = Points->z[0]; 00086 00087 s->ccat = cat; 00088 00089 /* find att */ 00090 00091 if (Map->n_site_att > 0) { 00092 sa = (SITE_ATT *) bsearch((void *)&cat, (void *)Map->site_att, 00093 Map->n_site_att, sizeof(SITE_ATT), 00094 site_att_cmp); 00095 00096 if (sa == NULL) { 00097 G_warning(_("Attributes for category %d not found"), cat); 00098 for (i = 0; i < Map->n_site_dbl; i++) 00099 s->dbl_att[i] = 0; 00100 for (i = 0; i < Map->n_site_str; i++) 00101 G_strncpy(s->str_att[i], "", MAX_SITE_STRING); 00102 } 00103 else { 00104 for (i = 0; i < Map->n_site_dbl; i++) 00105 s->dbl_att[i] = sa->dbl[i]; 00106 for (i = 0; i < Map->n_site_str; i++) 00107 G_strncpy(s->str_att[i], sa->str[i], MAX_SITE_STRING); 00108 } 00109 } 00110 00111 return 0; 00112 } 00113 } 00114 00115 00116 /* Writes a site to file open on fptr. */ 00117 int G_site_put(struct Map_info *Map, const Site * s) 00118 { 00119 static struct line_pnts *Points = NULL; 00120 static struct line_cats *Cats = NULL; 00121 00122 if (Points == NULL) 00123 Points = Vect_new_line_struct(); 00124 if (Cats == NULL) 00125 Cats = Vect_new_cats_struct(); 00126 00127 Vect_reset_line(Points); 00128 Vect_reset_cats(Cats); 00129 00130 /* no 3D support so far: s->dim[0] */ 00131 Vect_append_point(Points, s->east, s->north, 0.0); 00132 00133 G_debug(4, "cattype = %d", s->cattype); 00134 00135 if (s->cattype == FCELL_TYPE || s->cattype == DCELL_TYPE) 00136 G_fatal_error(_("Category must be integer")); 00137 00138 if (s->cattype == CELL_TYPE) 00139 Vect_cat_set(Cats, 1, s->ccat); 00140 00141 Vect_write_line(Map, GV_POINT, Points, Cats); 00142 00143 return 0; 00144 } 00145 00146 00147 /*- 00148 * Tries to guess the format of a sites list (the dimensionality, 00149 * the presence/type of a category, and the number of string and decimal 00150 * attributes) by reading the first record in the file. 00151 * Reads ptr and returns 0 on success, 00152 * -1 on EOF, 00153 * -2 for other error. 00154 */ 00155 int G_site_describe(struct Map_info *Map, int *dims, int *cat, int *strs, 00156 int *dbls) 00157 { 00158 if (Vect_is_3d(Map)) { 00159 G_debug(1, "Vector is 3D -> number of site dimensions is 3"); 00160 *dims = 3; 00161 } 00162 else { 00163 G_debug(1, "Vector is 2D -> number of site dimensions is 2"); 00164 *dims = 2; 00165 } 00166 00167 *cat = CELL_TYPE; 00168 00169 /* attributes ignored for now, later read from DB */ 00170 *dbls = Map->n_site_dbl; 00171 *strs = Map->n_site_str; 00172 00173 return 0; 00174 } 00175 00176 00177 /*- 00178 * Writes site_head struct. 00179 */ 00180 int G_site_put_head(struct Map_info *Map, Site_head * head) 00181 { 00182 static char buf[128]; 00183 00184 if (head->name != NULL) 00185 Vect_set_map_name(Map, head->name); 00186 00187 /* crashes: 00188 if (head->desc!=NULL) 00189 Vect_set_comment (Map, head->desc); 00190 */ 00191 00192 /* 00193 if (head->form!=NULL) 00194 fprintf(ptr,"form|%s\n",head->form); 00195 if (head->labels!=NULL) 00196 fprintf(ptr,"labels|%s\n",head->labels); 00197 */ 00198 /* time could be in (char *) stime, (struct TimeStamp *) time, 00199 both, or neither */ 00200 if (head->stime != NULL || head->time != NULL) { 00201 if (head->time != NULL) { /* TimeStamp struct has precendence */ 00202 G_format_timestamp(head->time, buf); 00203 Vect_set_date(Map, buf); 00204 } 00205 else if (head->stime != NULL) { /* next check string */ 00206 if (head->time == NULL) { 00207 if ((head->time = 00208 (struct TimeStamp *)G_malloc(sizeof(struct TimeStamp))) 00209 == NULL) 00210 G_fatal_error(_("Memory error in writing timestamp")); 00211 else if (G_scan_timestamp(head->time, head->stime) < 0) { 00212 G_warning(_("Illegal TimeStamp string")); 00213 return -1; /* added to prevent crash 5/2000 MN */ 00214 } 00215 } 00216 G_format_timestamp(head->time, buf); 00217 head->stime = G_store(buf); 00218 Vect_set_date(Map, head->stime); 00219 } 00220 } 00221 return 0; 00222 } 00223 00224 00225 /*- 00226 * Fills in site_head struct. 00227 */ 00228 int G_site_get_head(struct Map_info *Map, Site_head * head) 00229 { 00230 head->name = Vect_get_name(Map); 00231 head->desc = Vect_get_comment(Map); 00232 head->form = NULL; 00233 head->labels = NULL; 00234 /* head->stime = Vect_get_date(Map); *//* crashes, G_scan_timestamp() needed? */ 00235 head->stime = NULL; 00236 head->time = NULL; 00237 00238 if (head->stime && strlen(head->stime) > 0) { 00239 if ((head->time = 00240 (struct TimeStamp *)G_malloc(sizeof(struct TimeStamp))) == NULL) 00241 G_fatal_error(_("Memory error in allocating timestamp")); 00242 if (G_scan_timestamp(head->time, head->stime) < 0) { 00243 G_warning(datetime_error_msg()); 00244 00245 head->time = NULL; 00246 head->stime = NULL; 00247 } 00248 } 00249 00250 return 0; 00251 } 00252 00253 /*-************************************************************************ 00254 * char * 00255 * G_ask_sites_new(prompt, name)) 00256 * asks user to input name of a new site list file 00257 * 00258 * char * 00259 * G_ask_sites_old(prompt, name) 00260 * asks user to input name of an existing site list file 00261 * 00262 * char * 00263 * G_ask_sites_any(prompt, name) 00264 * asks user to input any site list name 00265 * 00266 * char * 00267 * G_ask_sites_in_mapset(prompt, name) 00268 * asks user to input name of an existing site list file in 00269 * current mapset 00270 * 00271 * parms: 00272 * char *prompt optional prompt for user 00273 * char *name buffer to hold name of map found 00274 * 00275 * returns: 00276 * char *pointer to a string with name of mapset 00277 * where file was found, or NULL if not found 00278 * 00279 * note: 00280 * rejects all names that begin with . 00281 ********************************************************************** 00282 * 00283 * struct Map_info * 00284 * G_sites_open_old (name, mapset) 00285 * opens the existing site list file 'name' in the 'mapset' 00286 * 00287 * struct Map_info * 00288 * G_sites_open_new (name) 00289 * opens a new site list file 'name' in the current mapset 00290 * 00291 * parms 00292 * char *name map file name 00293 * char *mapset mapset containing map "name" 00294 * 00295 **********************************************************************/ 00296 00297 char *G_find_sites(char *name, const char *mapset) 00298 { 00299 return G_find_vector(name, mapset); 00300 } 00301 00302 00303 char *G_find_sites2(const char *name, const char *mapset) 00304 { 00305 return G_find_vector2(name, mapset); 00306 } 00307 00308 00309 char *G_ask_sites_new(const char *prompt, char *name) 00310 { 00311 return G_ask_new(prompt, name, "vector", "vector"); 00312 } 00313 00314 00315 char *G_ask_sites_old(const char *prompt, char *name) 00316 { 00317 return G_ask_old(prompt, name, "vector", "vector"); 00318 } 00319 00320 00321 char *G_ask_sites_any(const char *prompt, char *name) 00322 { 00323 return G_ask_any(prompt, name, "vector", "vector", 1); 00324 } 00325 00326 00327 char *G_ask_sites_in_mapset(const char *prompt, char *name) 00328 { 00329 return G_ask_in_mapset(prompt, name, "vector", "vector"); 00330 } 00331 00332 00333 struct Map_info *G_sites_open_old(const char *name, const char *mapset) 00334 { 00335 struct Map_info *Map; 00336 struct field_info *fi; 00337 int more, nrows, row, ncols, col, ndbl, nstr, adbl, astr, ctype; 00338 SITE_ATT *sa; 00339 00340 dbDriver *driver; 00341 dbString stmt; 00342 dbCursor cursor; 00343 dbTable *table; 00344 dbColumn *column; 00345 dbValue *value; 00346 00347 G_message( 00348 _("Dev note: Adapted sites library used for vector points. " 00349 "(module should be updated to GRASS 6 vector library)")); 00350 00351 Map = (struct Map_info *)G_malloc(sizeof(struct Map_info)); 00352 00353 Vect_set_open_level(1); 00354 Vect_open_old(Map, name, mapset); 00355 00356 G_debug(1, "Vector map opened"); 00357 00358 /* Load attributes */ 00359 Map->site_att = NULL; 00360 Map->n_site_att = 0; 00361 Map->n_site_dbl = 0; 00362 Map->n_site_str = 0; 00363 00364 fi = Vect_get_field(Map, 1); 00365 if (fi == NULL) { /* not attribute table */ 00366 G_debug(1, "No attribute table"); 00367 return Map; 00368 } 00369 00370 driver = db_start_driver_open_database(fi->driver, fi->database); 00371 if (driver == NULL) 00372 G_fatal_error(_("Unable to open database <%s> by driver <%s>"), 00373 fi->database, 00374 fi->driver); 00375 00376 db_init_string(&stmt); 00377 db_set_string(&stmt, "select * from "); 00378 db_append_string(&stmt, fi->table); 00379 00380 if (db_open_select_cursor(driver, &stmt, &cursor, DB_SEQUENTIAL) != DB_OK) 00381 G_fatal_error(_("Unable to open select cursor: '%s'"), 00382 db_get_string(&stmt)); 00383 00384 nrows = db_get_num_rows(&cursor); 00385 G_debug(1, "%d rows selected from vector attribute table", nrows); 00386 00387 Map->site_att = (SITE_ATT *) malloc(nrows * sizeof(SITE_ATT)); 00388 Map->n_site_att = nrows; 00389 00390 table = db_get_cursor_table(&cursor); 00391 ncols = db_get_table_number_of_columns(table); 00392 00393 row = 0; 00394 adbl = astr = 0; 00395 while (1) { 00396 if (db_fetch(&cursor, DB_NEXT, &more) != DB_OK) 00397 G_fatal_error(_("Cannot fetch row")); 00398 00399 if (!more) 00400 break; 00401 00402 /* Get number of each type */ 00403 if (row == 0) { 00404 for (col = 0; col < ncols; col++) { 00405 column = db_get_table_column(table, col); 00406 ctype = db_sqltype_to_Ctype(db_get_column_sqltype(column)); 00407 00408 if (strcmp(db_get_column_name(column), fi->key) == 0) 00409 continue; 00410 00411 switch (ctype) { 00412 case DB_C_TYPE_INT: 00413 case DB_C_TYPE_DOUBLE: 00414 adbl++; 00415 break; 00416 case DB_C_TYPE_STRING: 00417 case DB_C_TYPE_DATETIME: 00418 astr++; 00419 break; 00420 } 00421 } 00422 Map->n_site_dbl = adbl; 00423 Map->n_site_str = astr; 00424 G_debug(1, "adbl = %d astr = %d", adbl, astr); 00425 } 00426 00427 sa = &(Map->site_att[row]); 00428 sa->dbl = (double *)malloc(adbl * sizeof(double)); 00429 sa->str = (char **)malloc(astr * sizeof(char *)); 00430 00431 ndbl = nstr = 0; 00432 for (col = 0; col < ncols; col++) { 00433 column = db_get_table_column(table, col); 00434 ctype = db_sqltype_to_Ctype(db_get_column_sqltype(column)); 00435 value = db_get_column_value(column); 00436 00437 if (strcmp(db_get_column_name(column), fi->key) == 0) { 00438 sa->cat = db_get_value_int(value); 00439 } 00440 else { 00441 switch (ctype) { 00442 case DB_C_TYPE_INT: 00443 sa->dbl[ndbl] = db_get_value_int(value); 00444 ndbl++; 00445 break; 00446 case DB_C_TYPE_DOUBLE: 00447 sa->dbl[ndbl] = db_get_value_double(value); 00448 ndbl++; 00449 break; 00450 case DB_C_TYPE_STRING: 00451 sa->str[nstr] = G_store(db_get_value_string(value)); 00452 nstr++; 00453 break; 00454 case DB_C_TYPE_DATETIME: 00455 sa->str[nstr] = ""; /* TODO */ 00456 nstr++; 00457 break; 00458 } 00459 } 00460 } 00461 row++; 00462 } 00463 db_close_database_shutdown_driver(driver); 00464 00465 /* sort attributes */ 00466 qsort((void *)Map->site_att, Map->n_site_att, sizeof(SITE_ATT), 00467 site_att_cmp); 00468 00469 return Map; 00470 } 00471 00472 00473 struct Map_info *G_sites_open_new(const char *name) 00474 { 00475 struct Map_info *Map; 00476 00477 G_message( 00478 _("Dev note: Adapted sites library used for vector points. " 00479 "(module should be updated to GRASS 6 vector library)")); 00480 G_warning("Site/vector attributes ignored."); 00481 00482 Map = (struct Map_info *)G_malloc(sizeof(struct Map_info)); 00483 00484 Vect_open_new(Map, name, 0); 00485 00486 G_debug(1, "New vector map opened"); 00487 00488 return Map; 00489 } 00490 00491 00492 void G_sites_close(struct Map_info *Map) 00493 { 00494 int i, j; 00495 00496 if (Map->mode == GV_MODE_WRITE || Map->mode == GV_MODE_RW) 00497 Vect_build(Map); 00498 00499 Vect_close(Map); 00500 00501 for (i = 0; i < Map->n_site_att; i++) { 00502 free(Map->site_att[i].dbl); 00503 00504 for (j = 0; j < Map->n_site_str; j++) 00505 free(Map->site_att[i].str[j]); 00506 00507 free(Map->site_att[i].str); 00508 } 00509 free(Map->site_att); 00510 00511 G_free(Map); 00512 } 00513 00514 00515 /*********************************************/ 00516 /* The following functions are obsolete. */ 00517 /* They are retained here only for backwards */ 00518 /* compatability while porting applications */ 00519 00520 /*********************************************/ 00521 struct Map_info *G_fopen_sites_old(const char *name, const char *mapset) 00522 { 00523 return G_sites_open_old(name, mapset); 00524 } 00525 00526 00527 struct Map_info *G_fopen_sites_new(const char *name) 00528 { 00529 return G_sites_open_new(name); 00530 } 00531 00532 00533 int G_get_site(struct Map_info *fd, double *east, double *north, char **desc) 00534 { 00535 /* TODO ? */ 00536 G_fatal_error("G_get_site() not yet updated."); 00537 00538 return -1; 00539 } 00540 00541 00542 int G_put_site(struct Map_info *fd, double east, double north, 00543 const char *desc) 00544 { 00545 /* TODO ? */ 00546 G_fatal_error("G_put_site() not yet updated."); 00547 00548 return 0; 00549 } 00550 00551 00552 /* Functions moved here from lib/gis/sites.c */ 00553 00554 void G_site_free_struct(Site * s) 00555 /* Free memory for a Site struct */ 00556 { 00557 if (s->dim_alloc) 00558 G_free(s->dim); 00559 if (s->str_alloc) 00560 G_free(s->str_att); 00561 if (s->dbl_alloc) 00562 G_free(s->dbl_att); 00563 G_free(s); 00564 00565 return; 00566 } 00567 00568 Site *G_site_new_struct(RASTER_MAP_TYPE cattype, 00569 int n_dim, int n_s_att, int n_d_att) 00570 /* Allocate memory for a Site struct. Returns a properly allocated 00571 site struct or NULL on error. 00572 cattype= -1 (no cat), CELL_TYPE, FCELL_TYPE, or DCELL_TYPE 00573 */ 00574 { 00575 int i; 00576 Site *s; 00577 00578 if (n_dim < 2 || n_s_att < 0 || n_d_att < 0) 00579 G_fatal_error(_("G_oldsite_new_struct: invalid # dims or fields")); 00580 00581 if ((s = (Site *) G_malloc(sizeof(Site))) == NULL) 00582 return (Site *) NULL; 00583 00584 s->cattype = cattype; 00585 s->ccat = s->fcat = s->dcat = 0; 00586 00587 if (n_dim > 2) { 00588 if ((s->dim = 00589 (double *)G_malloc((n_dim - 2) * sizeof(double))) == NULL) { 00590 G_free(s); 00591 return (Site *) NULL; 00592 } 00593 } 00594 s->dim_alloc = n_dim - 2; 00595 00596 if (n_d_att > 0) { 00597 if ((s->dbl_att = 00598 (double *)G_malloc(n_d_att * sizeof(double))) == NULL) { 00599 if (n_dim > 2) 00600 G_free(s->dim); 00601 G_free(s); 00602 return (Site *) NULL; 00603 } 00604 } 00605 s->dbl_alloc = n_d_att; 00606 00607 if (n_s_att > 0) { 00608 if ((s->str_att = 00609 (char **)G_malloc(n_s_att * sizeof(char *))) == NULL) { 00610 if (n_d_att > 0) 00611 G_free(s->dbl_att); 00612 if (n_dim > 2) 00613 G_free(s->dim); 00614 G_free(s); 00615 return (Site *) NULL; 00616 } 00617 else 00618 for (i = 0; i < n_s_att; ++i) 00619 if ((s->str_att[i] = 00620 (char *)G_malloc(MAX_SITE_STRING * sizeof(char))) == 00621 NULL) { 00622 while (--i) 00623 G_free(s->str_att[i]); 00624 G_free(s->str_att); 00625 if (n_d_att > 0) 00626 G_free(s->dbl_att); 00627 if (n_dim > 2) 00628 G_free(s->dim); 00629 G_free(s); 00630 return (Site *) NULL; 00631 } 00632 } 00633 s->str_alloc = n_s_att; 00634 00635 return s; 00636 } 00637 00638 #define FOUND_ALL(s,n,dim,c,d) (((s->cattype != -1 && !n) || \ 00639 (dim < s->dim_alloc) || \ 00640 (c < s->str_alloc) || \ 00641 (d < s->dbl_alloc))?0:1) 00642 00643 int G_oldsite_get(FILE * fptr, Site * s) 00644 /* Writes a site to file open on fptr. */ 00645 { 00646 return G__oldsite_get(fptr, s, G_projection()); 00647 } 00648 00649 00650 int G__oldsite_get(FILE * ptr, Site * s, int fmt) 00651 00652 /*- 00653 * Reads ptr and returns 0 on success, 00654 * -1 on EOF, 00655 * -2 on other fatal error or insufficient data, 00656 * 1 on format mismatch (extra data) 00657 */ 00658 { 00659 char sbuf[MAX_SITE_LEN], *buf, *last, *p1, *p2; 00660 char ebuf[128], nbuf[128]; 00661 int n = 0, d = 0, c = 0, dim = 0, err = 0, tmp; 00662 00663 buf = sbuf; 00664 00665 if ((buf = fgets(sbuf, 1024, ptr)) == (char *)NULL) 00666 return EOF; 00667 00668 while ((*buf == '#' || !isdigit(*buf)) && *buf != '-' && *buf != '+') 00669 if ((buf = fgets(sbuf, 1024, ptr)) == (char *)NULL) 00670 return EOF; 00671 00672 if (buf[strlen(buf) - 1] == '\n') 00673 buf[strlen(buf) - 1] = '\0'; 00674 00675 if (sscanf(buf, "%[^|]|%[^|]|%*[^\n]", ebuf, nbuf) < 2) { 00676 fprintf(stderr, "ERROR: ebuf %s nbuf %s\n", ebuf, nbuf); 00677 return -2; 00678 } 00679 00680 if (!G_scan_northing(nbuf, &(s->north), fmt) || 00681 !G_scan_easting(ebuf, &(s->east), fmt)) { 00682 fprintf(stderr, "ERROR: ebuf %s nbuf %s\n", ebuf, nbuf); 00683 return -2; 00684 } 00685 00686 /* move pointer past easting and northing fields */ 00687 if (NULL == (buf = G_index(buf, PIPE))) 00688 return -2; 00689 if (NULL == (buf = G_index(buf + 1, PIPE))) 00690 return -2; 00691 00692 /* check for remaining dimensional fields */ 00693 do { 00694 buf++; 00695 if (isnull(*buf)) 00696 return (FOUND_ALL(s, n, dim, c, d) ? 0 : -2); 00697 last = buf; 00698 if (dim < s->dim_alloc) { /* should be more dims to read */ 00699 if (sscanf(buf, "%lf|", &(s->dim[dim++])) < 1) 00700 return -2; /* no more dims, though expected */ 00701 } 00702 else if (NULL != (p1 = G_index(buf, PIPE))) { 00703 if (NULL == (p2 = G_index(buf, DQUOTE))) 00704 err = 1; /* more dims, though none expected */ 00705 else if (strlen(p1) > strlen(p2)) 00706 err = 1; /* more dims, though none expected */ 00707 } 00708 } while ((buf = G_index(buf, PIPE)) != NULL); 00709 buf = last; 00710 00711 /* no more dimensions-now we parse attribute fields */ 00712 while (!isnull(*buf)) { 00713 switch (*buf) { 00714 case '#': /* category field */ 00715 if (n == 0) { 00716 switch (s->cattype) { 00717 case CELL_TYPE: 00718 if (sscanf(buf, "#%d", &s->ccat) == 1) 00719 n++; 00720 break; 00721 case FCELL_TYPE: 00722 if (sscanf(buf, "#%f", &s->fcat) == 1) 00723 n++; 00724 break; 00725 case DCELL_TYPE: 00726 if (sscanf(buf, "#%lf", &s->dcat) == 1) 00727 n++; 00728 break; 00729 default: 00730 err = 1; /* has cat, none expected */ 00731 break; 00732 } 00733 } 00734 else { 00735 err = 1; /* extra cat */ 00736 } 00737 00738 /* move to beginning of next attribute */ 00739 if ((buf = next_att(buf)) == (char *)NULL) 00740 return (FOUND_ALL(s, n, dim, c, d) ? err : -2); 00741 break; 00742 00743 case '%': /* decimal attribute */ 00744 if (d < s->dbl_alloc) { 00745 p1 = ++buf; 00746 errno = 0; 00747 s->dbl_att[d++] = strtod(buf, &p1); 00748 if (p1 == buf || errno == ERANGE) { 00749 /* replace with: 00750 * s->dbl_att[d - 1] = NAN 00751 * when we add NULL attribute support 00752 */ 00753 return -2; 00754 } 00755 /* err = 0; Make sure this is zeroed */ 00756 } 00757 else { 00758 err = 1; /* extra decimal */ 00759 } 00760 00761 if ((buf = next_att(buf)) == (char *)NULL) { 00762 return (FOUND_ALL(s, n, dim, c, d)) ? err : -2; 00763 } 00764 break; 00765 case '@': /* string attribute */ 00766 if (isnull(*buf) || isnull(*(buf + 1))) 00767 return (FOUND_ALL(s, n, dim, c, d) ? err : -2); 00768 else 00769 buf++; 00770 default: /* defaults to string attribute */ 00771 /* allow both prefixed and unprefixed strings */ 00772 if (c < s->str_alloc) { 00773 if ((tmp = cleanse_string(buf)) > 0) { 00774 G_strncpy(s->str_att[c++], buf, tmp); 00775 buf += tmp; 00776 } 00777 else 00778 return (FOUND_ALL(s, n, dim, c, d) ? err : -2); 00779 } 00780 if ((buf = next_att(buf)) == (char *)NULL) { 00781 return (FOUND_ALL(s, n, dim, c, d) ? err : -2); 00782 } 00783 break; 00784 } 00785 } 00786 00787 return (FOUND_ALL(s, n, dim, c, d) ? err : -2); 00788 } 00789 00790 int G_oldsite_describe(FILE * ptr, int *dims, int *cat, int *strs, int *dbls) 00791 00792 /*- 00793 * Tries to guess the format of a sites list (the dimensionality, 00794 * the presence/type of a category, and the number of string and decimal 00795 * attributes) by reading the first record in the file. 00796 * Reads ptr and returns 0 on success, 00797 * -1 on EOF, 00798 * -2 for other error. 00799 */ 00800 { 00801 char sbuf[MAX_SITE_LEN], *buf; 00802 char ebuf[128], nbuf[128]; 00803 int err; 00804 int itmp; 00805 float ftmp; 00806 00807 if (ftell(ptr) != 0L) { 00808 fprintf(stderr, 00809 "\nPROGRAMMER ERROR: G_oldsite_describe() must be called\n"); 00810 fprintf(stderr, " immediately after G_fopen_sites_old()\n"); 00811 return -2; 00812 } 00813 00814 *dims = *strs = *dbls = 0; 00815 *cat = -1; 00816 buf = sbuf; 00817 00818 if ((buf = fgets(sbuf, 1024, ptr)) == (char *)NULL) { 00819 rewind(ptr); 00820 return EOF; 00821 } 00822 /* skip over comment & header lines */ 00823 while ((*buf == '#' || !isdigit(*buf)) && *buf != '-' && *buf != '+') 00824 if ((buf = fgets(sbuf, 1024, ptr)) == (char *)NULL) { 00825 rewind(ptr); 00826 return EOF; 00827 } 00828 00829 if (buf[strlen(buf) - 1] == '\n') 00830 buf[strlen(buf) - 1] = '\0'; 00831 00832 if ((err = sscanf(buf, "%[^|]|%[^|]|%*[^\n]", ebuf, nbuf)) < 2) { 00833 fprintf(stderr, "ERROR: ebuf %s nbuf %s\n", ebuf, nbuf); 00834 rewind(ptr); 00835 return -2; 00836 } 00837 *dims = 2; 00838 00839 /* move pointer past easting and northing fields */ 00840 while (!ispipe(*buf) && !isnull(*buf)) 00841 buf++; 00842 if (!isnull(*buf) && !isnull(*(buf + 1))) 00843 buf++; 00844 else { 00845 rewind(ptr); 00846 return -2; 00847 } 00848 while (!ispipe(*buf) && !isnull(*buf)) 00849 buf++; 00850 if (!isnull(*buf) && !isnull(*(buf + 1))) 00851 buf++; 00852 else { 00853 rewind(ptr); 00854 return 0; 00855 } 00856 00857 /* check for remaining dimensional fields */ 00858 while (G_index(buf, PIPE) != (char *)NULL) { 00859 (*dims)++; 00860 while (!ispipe(*buf) && !isnull(*buf)) 00861 buf++; 00862 if (isnull(*buf) || isnull(*(buf + 1))) { 00863 rewind(ptr); 00864 return 0; 00865 } 00866 if (!isnull(*(buf + 1))) 00867 buf++; 00868 else { 00869 rewind(ptr); 00870 return -2; 00871 } 00872 } 00873 00874 /* no more dimensions-now we parse attribute fields */ 00875 while (!isnull(*buf)) { 00876 switch (*buf) { 00877 case '#': /* category field */ 00878 sscanf(buf, "#%s ", ebuf); 00879 if (G_strstr(ebuf, ".") == NULL && sscanf(ebuf, "%d", &itmp) == 1) 00880 *cat = CELL_TYPE; 00881 else if (G_strstr(ebuf, ".") != NULL && 00882 sscanf(ebuf, "%f", &ftmp) == 1) 00883 *cat = FCELL_TYPE; 00884 else 00885 *cat = -1; 00886 00887 /* move to beginning of next attribute */ 00888 while (!isspace(*buf) && !isnull(*buf)) 00889 buf++; 00890 if (isnull(*buf) || isnull(*(buf + 1))) { 00891 rewind(ptr); 00892 return 0; 00893 } 00894 else 00895 buf++; 00896 break; 00897 case '%': /* decimal attribute */ 00898 (*dbls)++; 00899 /* move to beginning of next attribute */ 00900 while (!isspace(*buf) && !isnull(*buf)) 00901 buf++; 00902 if (isnull(*buf) || isnull(*(buf + 1))) { 00903 rewind(ptr); 00904 return 0; 00905 } 00906 else 00907 buf++; 00908 break; 00909 case '@': /* string attribute */ 00910 if (isnull(*buf) || isnull(*(buf + 1))) { 00911 rewind(ptr); 00912 return 0; 00913 } 00914 else 00915 buf++; 00916 default: /* defaults to string attribute */ 00917 /* allow both prefixed and unprefixed strings */ 00918 if ((err = cleanse_string(buf)) > 0) { 00919 (*strs)++; 00920 buf += err; 00921 } 00922 00923 /* move to beginning of next attribute */ 00924 while (!isspace(*buf) && !isnull(*buf)) 00925 buf++; 00926 if (isnull(*buf) || isnull(*(buf + 1))) { 00927 rewind(ptr); 00928 return 0; 00929 } 00930 else 00931 buf++; 00932 break; 00933 } 00934 } 00935 00936 rewind(ptr); 00937 return 0; 00938 } 00939 00940 int G_site_in_region(const Site * site, const struct Cell_head *region) 00941 /* returns 1 if site is contained within region, 0 otherwise */ 00942 { 00943 /* northwest corner is in region, southeast corner is not. */ 00944 double e_ing; 00945 00946 e_ing = G_adjust_easting(site->east, region); 00947 if (e_ing >= region->west && 00948 e_ing < region->east && 00949 site->north <= region->north && site->north > region->south) 00950 return 1; 00951 00952 return 0; 00953 } 00954 00955 static int format_double(double value, char *buf) 00956 { 00957 sprintf(buf, "%.8f", value); 00958 G_trim_decimal(buf); 00959 return 0; 00960 } 00961 00962 int cleanse_string(char *buf) 00963 { 00964 char *stop, *p, *p2; 00965 00966 p = buf; 00967 00968 /* 00969 * get rid of any SPACEs at beginning while ( !isspace(*buf) && *buf != 00970 * (char) NULL) buf++; if (*buf == (char) NULL) return -1; 00971 */ 00972 00973 /* find where this string terminates */ 00974 if (*buf != DQUOTE) { /* if no DQUOTEs, */ 00975 stop = G_index(buf, SPACE); /* then SPACE separates */ 00976 if (stop == (char *)NULL) 00977 return strlen(buf); 00978 else 00979 return (int)(stop - buf); 00980 } 00981 else { /* otherwise string is in DQUOTEs */ 00982 /* but we must skip over escaped */ 00983 /* (BSLASHed) DQUOTEs */ 00984 if (*p == DQUOTE) { 00985 while (*p != (char)NULL) { /* get rid of first DQUOTE */ 00986 *p = *(p + 1); 00987 p++; 00988 } 00989 p = buf; 00990 stop = G_index(p + 1, DQUOTE); 00991 while (*(stop - 1) == BSLASH) 00992 stop = G_index(++stop, DQUOTE); 00993 } 00994 } 00995 /* remove backslashes between buf and stop */ 00996 p = buf; 00997 while ((p = G_index(p, BSLASH)) != (char *)NULL && p <= stop) { 00998 p2 = p + 1; 00999 if (*p2 != (char)NULL && (*p2 == DQUOTE || *p2 == BSLASH)) { 01000 while (*p != (char)NULL) { 01001 *p = *(p + 1); 01002 p++; 01003 } 01004 stop--; 01005 } 01006 p = p2; 01007 } 01008 return (int)(stop - buf); 01009 } 01010 01011 static char *next_att(const char *buf) 01012 { 01013 while (!isspace(*buf) && !isnull(*buf)) 01014 buf++; 01015 if (isnull(*buf) || isnull(*(buf + 1))) 01016 return NULL; 01017 else 01018 while (isspace(*(buf + 1)) && !isnull(*(buf + 1))) 01019 buf++; 01020 buf++; 01021 return (char *)buf; 01022 } 01023 01024 int G_site_c_cmp(const void *a, const void *b) 01025 /* qsort() comparison function for sorting an array of 01026 site structures by category. */ 01027 { 01028 int result = 0; /* integer to be returned */ 01029 double diff = 0; 01030 01031 switch ((*(Site **) a)->cattype) { 01032 case CELL_TYPE: 01033 diff = (double)(*(Site **) a)->ccat - (*(Site **) b)->ccat; 01034 break; 01035 case FCELL_TYPE: 01036 diff = (double)(*(Site **) a)->fcat - (*(Site **) b)->fcat; 01037 break; 01038 case DCELL_TYPE: 01039 diff = (double)(*(Site **) a)->dcat - (*(Site **) b)->dcat; 01040 break; 01041 } 01042 if (diff < 0.0) 01043 result = -1; 01044 else if (diff > 0.0) 01045 result = 1; 01046 return result; 01047 } 01048 01049 int G_site_d_cmp(const void *a, const void *b) 01050 /* qsort() comparison function for sorting an array of 01051 site structures by first decimal attribute. */ 01052 { 01053 int result = 0; /* integer to be returned */ 01054 double diff; 01055 01056 diff = (*(Site **) a)->dbl_att[0] - (*(Site **) b)->dbl_att[0]; 01057 if (diff < 0.0) 01058 result = -1; 01059 else if (diff > 0.0) 01060 result = 1; 01061 return result; 01062 } 01063 01064 int G_oldsite_s_cmp(const void *a, const void *b) 01065 /* qsort() comparison function for sorting an array of 01066 site structures by first decimal attribute. */ 01067 { 01068 return strcmp((*(char **)((*(Site **) a)->str_att)), 01069 (*(char **)((*(Site **) b)->str_att))); 01070 } 01071 01072 /*-************************************************************************ 01073 * 01074 * FILE * 01075 * G_oldsites_open_old (name, mapset) 01076 * opens the existing site list file 'name' in the 'mapset' 01077 * 01078 * parms 01079 * char *name map file name 01080 * char *mapset mapset containing map "name" 01081 * 01082 **********************************************************************/ 01083 01084 FILE *G_oldsites_open_old(const char *name, const char *mapset) 01085 { 01086 return G_fopen_old("site_lists", name, mapset); 01087 } 01088 01089 FILE *G_oldsites_open_new(const char *name) 01090 { 01091 return G_fopen_new("site_lists", name); 01092 } 01093 01094 /*********************************************/ 01095 /* The following functions are obsolete. */ 01096 /* They are retained here only for backwards */ 01097 /* compatability while porting applications */ 01098 01099 /*********************************************/ 01100 01101 char *G_site_format(const Site * s, const char *fs, int id) 01102 /* sprintf analog to G_site_put with the addition of a field separator fs 01103 and option of printing site attribute identifiers 01104 */ 01105 { 01106 char ebuf[MAX_SITE_STRING], nbuf[MAX_SITE_STRING]; 01107 char xbuf[MAX_SITE_STRING]; 01108 const char *nfs; 01109 char *buf; 01110 int fmt, i, j, k; 01111 01112 buf = (char *)G_malloc(MAX_SITE_LEN * sizeof(char)); 01113 01114 fmt = G_projection(); 01115 01116 G_format_northing(s->north, nbuf, fmt); 01117 G_format_easting(s->east, ebuf, fmt); 01118 01119 nfs = (char *)((fs == (char *)NULL) ? "|" : fs); 01120 01121 sprintf(buf, "%s%s%s", ebuf, nfs, nbuf); 01122 01123 for (i = 0; i < s->dim_alloc; ++i) { 01124 format_double(s->dim[i], nbuf); 01125 sprintf(xbuf, "%s%s", nfs, nbuf); 01126 G_strcat(buf, xbuf); 01127 } 01128 01129 nfs = (fs == NULL) ? " " : fs; 01130 01131 switch (s->cattype) { 01132 case CELL_TYPE: 01133 sprintf(xbuf, "%s%s%d ", nfs, ((id == 0) ? "" : "#"), (int)s->ccat); 01134 G_strcat(buf, xbuf); 01135 break; 01136 case FCELL_TYPE: 01137 case DCELL_TYPE: 01138 sprintf(xbuf, "%s%s%g ", nfs, ((id == 0) ? "" : "#"), (float)s->fcat); 01139 G_strcat(buf, xbuf); 01140 break; 01141 } 01142 01143 for (i = 0; i < s->dbl_alloc; ++i) { 01144 format_double(s->dbl_att[i], nbuf); 01145 sprintf(xbuf, "%s%s%s", nfs, ((id == 0) ? "" : "%"), nbuf); 01146 G_strcat(buf, xbuf); 01147 } 01148 01149 for (i = 0; i < s->str_alloc; ++i) { 01150 if (strlen(s->str_att[i]) != 0) { 01151 /* escape double quotes */ 01152 j = k = 0; 01153 01154 /* do not uncomment this code because sites file was created 01155 * as we want. So it's enough to print them out as it is. 01156 * 01157 if (G_index (s->str_att[i], DQUOTE) != (char *) NULL) 01158 { 01159 while (!isnull(s->str_att[i][j])) 01160 { 01161 if (isquote(s->str_att[i][j])) 01162 { 01163 xbuf[k++] = BSLASH; 01164 xbuf[k++] = DQUOTE; 01165 } 01166 else 01167 xbuf[k++] = s->str_att[i][j]; 01168 j++; 01169 } 01170 xbuf[k] = (char) NULL; 01171 } 01172 else 01173 */ 01174 01175 G_strcpy(xbuf, s->str_att[i]); 01176 01177 G_strcpy(s->str_att[i], xbuf); 01178 01179 if (G_index(s->str_att[i], SPACE) != (char *)NULL) 01180 sprintf(xbuf, "%s%s\"%s\"", nfs, ((id == 0) ? "" : "@"), 01181 s->str_att[i]); 01182 else 01183 sprintf(xbuf, "%s%s%s", nfs, ((id == 0) ? "" : "@"), 01184 s->str_att[i]); 01185 G_strcat(buf, xbuf); 01186 } 01187 } 01188 return buf; 01189 } 01190 01191 /*******************************************************************************/ 01192 01193 /*******************************************************************************/ 01194 01195 /*** ACS_MODIFY_BEGIN - sites_attribute management *****************************/ 01196 /* 01197 These functions are used in visualization/nviz/src/site_attr_commands.c 01198 01199 Functions to obtain fields in order to draw sites with each point having a 01200 geometric property depending from database values. 01201 */ 01202 01203 /* 01204 Returns a pointer to the SITE_ATT in Map_info *ptr and with category cat 01205 */ 01206 SITE_ATT *G_sites_get_atts(struct Map_info * Map, int *cat) 01207 { 01208 return (SITE_ATT *) bsearch((void *)cat, (void *)Map->site_att, 01209 Map->n_site_att, sizeof(SITE_ATT), 01210 site_att_cmp); 01211 } 01212 01213 /* 01214 Returns field names, types and indexes in double and string Map_info arrays 01215 01216 WARNING: user is responsible to free allocated memory, directly or calling G_sites_free_fields() 01217 */ 01218 int G_sites_get_fields(struct Map_info *Map, char ***cnames, int **ctypes, 01219 int **ndx) 01220 { 01221 struct field_info *fi; 01222 int nrows, row, ncols, col, ndbl, nstr, ctype; 01223 01224 const char *name; 01225 dbDriver *driver; 01226 dbString stmt; 01227 dbCursor cursor; 01228 dbTable *table; 01229 dbColumn *column; 01230 01231 /*dbValue *value; */ 01232 01233 /* warning: we are using "1" as cat field in Vect_get_field because G_sites_open_old 01234 (in lib/sites/sites.c), that we use here to open sites, does the same and then 01235 queries the db in the same way we do here. 01236 Should it be not true in the future, maybe we'll have to change this by choosing 01237 appropriate fields and multiple categories */ 01238 01239 fi = (struct field_info *)Vect_get_field(Map, 1); 01240 01241 01242 if (fi == NULL) { /* not attribute table */ 01243 G_debug(1, "No attribute table"); 01244 return -1; 01245 } 01246 01247 driver = db_start_driver_open_database(fi->driver, fi->database); 01248 if (driver == NULL) 01249 G_fatal_error(_("Cannot open database %s by driver %s"), fi->database, 01250 fi->driver); 01251 01252 db_init_string(&stmt); 01253 db_set_string(&stmt, "select * from "); 01254 db_append_string(&stmt, fi->table); 01255 01256 if (db_open_select_cursor(driver, &stmt, &cursor, DB_SEQUENTIAL) != DB_OK) 01257 G_fatal_error(_("Cannot select attributes")); 01258 01259 nrows = db_get_num_rows(&cursor); 01260 G_debug(1, "%d rows selected from vector attribute table", nrows); 01261 01262 table = db_get_cursor_table(&cursor); 01263 ncols = db_get_table_number_of_columns(table); 01264 01265 if (ncols <= 0) 01266 return ncols; 01267 01268 row = 0; 01269 01270 /* Get number of each type */ 01271 ndbl = nstr = 0; 01272 01273 *cnames = (char **)malloc(ncols * sizeof(char *)); 01274 *ctypes = (int *)malloc(ncols * sizeof(int)); 01275 *ndx = (int *)malloc(ncols * sizeof(int)); 01276 01277 for (col = 0; col < ncols; col++) { 01278 column = db_get_table_column(table, col); 01279 ctype = db_sqltype_to_Ctype(db_get_column_sqltype(column)); 01280 01281 name = db_get_column_name(column); 01282 01283 *(*cnames + col) = (char *)malloc(strlen(name) + 1); 01284 strcpy(*(*cnames + col), db_get_column_name(column)); 01285 01286 /* ctypes is 'c' for cat, 'd' for double, 's' for string */ 01287 if (strcmp(name, fi->key) == 0) { 01288 *(*ctypes + col) = 'c'; 01289 *(*ndx + col) = -1; 01290 } 01291 else { 01292 switch (ctype) { 01293 case DB_C_TYPE_INT: 01294 case DB_C_TYPE_DOUBLE: 01295 *(*ctypes + col) = 'd'; 01296 *(*ndx + col) = ndbl; 01297 ndbl++; 01298 break; 01299 case DB_C_TYPE_STRING: 01300 case DB_C_TYPE_DATETIME: 01301 *(*ctypes + col) = 's'; 01302 *(*ndx + col) = nstr; 01303 nstr++; 01304 break; 01305 } 01306 } 01307 } 01308 01309 db_close_database_shutdown_driver(driver); 01310 return ncols; 01311 } 01312 01313 01314 /* Frees fields allocated with G_sites_get_fields */ 01315 void G_sites_free_fields(int ncols, char **cnames, int *ctypes, int *ndx) 01316 { 01317 for (; ncols > 0; ncols--) 01318 free(*(cnames + ncols - 1)); 01319 free(cnames); 01320 free(ctypes); 01321 free(ndx); 01322 } 01323 01324 /*** ACS_MODIFY_END - sites_attribute management *******************************/