GRASS Programmer's Manual  6.4.2(2012)
sites.c
Go to the documentation of this file.
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 *******************************/
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines