sites.c

Go to the documentation of this file.
00001 /*-
00002  * These functions and definitions support the site format for 5.0
00003  * (format proposed by Dave Gerdes):
00004  *
00005  * easting|northing|[z|[d4|]...][#category_int] [ [@attr_text OR %flt] ... ]
00006  *
00007  * to allow multidimensions (everything preceding the last '|') and any
00008  * number of text or numeric attribute fields.
00009  *
00010  * Author: James Darrell McCauley <mccauley@ecn.purdue.edu>
00011  * 31 Jan 1994
00012  */
00013 
00014 #include <ctype.h>
00015 #include <string.h>
00016 #include <stdio.h>
00017 #include <stdlib.h>
00018 #include <errno.h>
00019 #include "gis.h"
00020 #include "site.h"
00021 
00022 #define DQUOTE '"'
00023 #define SPACE ' '
00024 #define BSLASH 92
00025 #define PIPE '|'
00026 
00027 #define ispipe(c) (c==PIPE)
00028 #define isnull(c) (c==(char)NULL)
00029 #define isquote(c) (c==DQUOTE)
00030 #define isbslash(c) (c==BSLASH)
00031 
00032 static int format_double ( double , char *);
00033 char *next_att (char *);
00034 
00035 void G_site_free_struct (Site *s)
00036 /* Free memory for a Site struct */
00037 {
00038   if(s->dim_alloc)
00039       G_free(s->dim);
00040   if(s->str_alloc)
00041       G_free(s->str_att);
00042   if(s->dbl_alloc)
00043       G_free(s->dbl_att);
00044   G_free(s);
00045 
00046   return;
00047 }
00048 
00049 Site *G_site_new_struct (RASTER_MAP_TYPE cattype,
00050   int n_dim,int n_s_att,int n_d_att)
00051 /* Allocate memory for a Site struct. Returns a properly allocated
00052    site struct or NULL on error. 
00053    cattype= -1 (no cat), CELL_TYPE, FCELL_TYPE, or DCELL_TYPE 
00054 */
00055 {  
00056   int i;
00057   Site *s;
00058 
00059   if (n_dim < 2 || n_s_att < 0 || n_d_att < 0)
00060     G_fatal_error ("G_oldsite_new_struct: invalid # dims or fields\n");
00061 
00062   if ((s = (Site *) G_malloc (sizeof (Site))) == NULL)
00063     return (Site *) NULL;
00064 
00065   s->cattype=cattype;
00066   s->ccat=s->fcat=s->dcat=0;
00067 
00068   if (n_dim > 2)
00069   {
00070     if ((s->dim =
00071          (double *) G_malloc ((n_dim - 2) * sizeof (double))) == NULL) {
00072       G_free(s);
00073       return (Site *) NULL;
00074     }
00075   }
00076   s->dim_alloc = n_dim - 2;
00077 
00078   if (n_d_att > 0)
00079   {
00080     if ((s->dbl_att =
00081          (double *) G_malloc (n_d_att * sizeof (double))) == NULL) {
00082       if (n_dim > 2) G_free(s->dim);
00083       G_free(s);
00084       return (Site *) NULL;
00085     }
00086   }
00087   s->dbl_alloc = n_d_att;
00088 
00089   if (n_s_att > 0)
00090   {
00091     if ((s->str_att =
00092          (char **) G_malloc (n_s_att * sizeof (char *))) == NULL) {
00093       if (n_d_att > 0) G_free(s->dbl_att);
00094       if (n_dim > 2) G_free(s->dim);
00095       G_free(s);
00096       return (Site *) NULL;
00097     }
00098     else
00099       for (i = 0; i < n_s_att; ++i)
00100         if ((s->str_att[i] =
00101           (char *) G_malloc (MAX_SITE_STRING * sizeof (char))) == NULL) {
00102           while (--i) G_free(s->str_att[i]);
00103           G_free(s->str_att);
00104           if (n_d_att > 0) G_free(s->dbl_att);
00105           if (n_dim > 2) G_free(s->dim);
00106           G_free(s);
00107           return (Site *) NULL;
00108         }
00109   }
00110   s->str_alloc = n_s_att;
00111 
00112   return s;
00113 }
00114 
00115 #define FOUND_ALL(s,n,dim,c,d) (((s->cattype != -1 && !n) || \
00116                                  (dim < s->dim_alloc) || \
00117                                  (c < s->str_alloc) || \
00118                                  (d < s->dbl_alloc))?0:1)
00119 
00120 int G_oldsite_get ( FILE *fptr, Site *s)
00121 /* Writes a site to file open on fptr. */
00122 {
00123     return G__oldsite_get (fptr, s, G_projection() );
00124 }
00125 
00126 
00127 int G__oldsite_get ( FILE *ptr, Site *s, int fmt)
00128 /*-
00129  * Reads ptr and returns 0 on success,
00130  *                      -1 on EOF,
00131  *                      -2 on other fatal error or insufficient data,
00132  *                       1 on format mismatch (extra data)
00133  */
00134 {
00135   char sbuf[MAX_SITE_LEN], *buf, *last, *p1, *p2;
00136   char ebuf[128], nbuf[128];
00137   int n = 0, d = 0, c = 0, dim = 0, err = 0, tmp;
00138 
00139   buf = sbuf;
00140 
00141   if ((buf = fgets (sbuf, 1024, ptr)) == (char *) NULL)
00142     return EOF;
00143 
00144   while ((*buf == '#' || !isdigit(*buf)) && *buf != '-' && *buf != '+')
00145     if ((buf = fgets (sbuf, 1024, ptr)) == (char *) NULL)
00146       return EOF;
00147 
00148   if (buf[strlen (buf) - 1] == '\n')
00149     buf[strlen (buf) - 1] = (char) NULL;
00150 
00151   if (sscanf (buf, "%[^|]|%[^|]|%*[^\n]", ebuf, nbuf) < 2)
00152   {
00153     fprintf (stderr, "ERROR: ebuf %s nbuf %s\n", ebuf, nbuf);
00154     return -2;
00155   }
00156 
00157   if (!G_scan_northing (nbuf, &(s->north), fmt) ||
00158       !G_scan_easting (ebuf, &(s->east), fmt))
00159   {
00160     fprintf (stderr, "ERROR: ebuf %s nbuf %s\n", ebuf, nbuf);
00161     return -2;
00162   }
00163 
00164   /* move pointer past easting and northing fields */
00165   if (NULL == (buf = G_index(buf, PIPE)))
00166     return -2;
00167   if (NULL == (buf = G_index(buf+1, PIPE)))
00168     return -2;
00169 
00170   /* check for remaining dimensional fields */
00171   do {
00172     buf++;
00173     if (isnull(*buf)) return (FOUND_ALL(s,n,dim,c,d)? 0: -2);
00174     last = buf;
00175     if (dim < s->dim_alloc)  /* should be more dims to read */
00176     {
00177       if (sscanf (buf, "%lf|", &(s->dim[dim++])) < 1)
00178         return -2;   /* no more dims, though expected */ 
00179     }
00180     else if (NULL != (p1 = G_index(buf, PIPE))) 
00181     {
00182         if (NULL == (p2 = G_index(buf, DQUOTE)))
00183             err = 1;  /* more dims, though none expected */
00184         else if (strlen(p1) > strlen(p2))
00185             err = 1;  /* more dims, though none expected */
00186     }
00187   } while ((buf = G_index (buf, PIPE)) != NULL);
00188   buf = last;
00189 
00190   /* no more dimensions-now we parse attribute fields */
00191   while (!isnull(*buf))
00192   {
00193     switch (*buf)
00194     {
00195     case '#':                   /* category field */
00196       if (n == 0)
00197       {
00198         switch(s->cattype)
00199         {
00200           case CELL_TYPE:
00201           if(sscanf (buf, "#%d", &s->ccat)==1)
00202             n++;
00203           break;
00204           case FCELL_TYPE:
00205           if(sscanf (buf, "#%f", &s->fcat)==1)
00206             n++;
00207           break;
00208           case DCELL_TYPE:
00209           if(sscanf (buf, "#%lf", &s->dcat)==1)
00210             n++;
00211           break;
00212           default:
00213           err = 1; /* has cat, none expected */
00214           break;
00215         }
00216       }
00217       else{
00218         err = 1;  /* extra cat */
00219       }
00220 
00221       /* move to beginning of next attribute */
00222       if ((buf = next_att (buf)) == (char *) NULL)
00223         return (FOUND_ALL(s,n,dim,c,d)? err: -2);
00224       break;
00225 
00226     case '%':                   /* decimal attribute */
00227       if (d < s->dbl_alloc) {
00228         p1 = ++buf;
00229         errno = 0;
00230         s->dbl_att[d++] = strtod(buf, &p1);
00231         if (p1 == buf || errno == ERANGE) {
00232                 /* replace with:
00233                  * s->dbl_att[d - 1] = NAN
00234                  * when we add NULL attribute support
00235                  */
00236                 return -2;
00237         }
00238         /* err = 0; Make sure this is zeroed */
00239       } else {
00240          err = 1;  /* extra decimal */
00241       }
00242 
00243       if ((buf = next_att (buf)) == (char *) NULL) {
00244         return (FOUND_ALL(s,n,dim,c,d)) ? err : -2;
00245       }
00246       break;
00247     case '@':                   /* string attribute */
00248       if (isnull(*buf) || isnull(*(buf + 1)))
00249         return (FOUND_ALL(s,n,dim,c,d)? err: -2);
00250       else
00251         buf++;
00252     default:                    /* defaults to string attribute */
00253       /* allow both prefixed and unprefixed strings */
00254       if (c < s->str_alloc)
00255       {
00256         if ((tmp = cleanse_string (buf)) > 0)
00257         {
00258           G_strncpy (s->str_att[c++], buf, tmp);
00259           buf += tmp;
00260         }
00261         else
00262           return (FOUND_ALL(s,n,dim,c,d)? err: -2);
00263       }
00264       if ((buf = next_att (buf)) == (char *) NULL) {
00265         return (FOUND_ALL(s,n,dim,c,d)? err: -2);
00266       }
00267       break;
00268     }
00269   }
00270 
00271   return (FOUND_ALL(s,n,dim,c,d)? err: -2);
00272 }
00273 
00274 int G_oldsite_describe ( FILE *ptr,
00275   int *dims,int *cat,int *strs,int *dbls)
00276 /*-
00277  * Tries to guess the format of a sites list (the dimensionality,
00278  * the presence/type of a category, and the number of string and decimal
00279  * attributes) by reading the first record in the file.
00280  * Reads ptr and returns 0 on success,
00281  *                      -1 on EOF,
00282  *                      -2 for other error.
00283  */
00284 {
00285   char sbuf[MAX_SITE_LEN], *buf;
00286   char ebuf[128], nbuf[128];
00287   int err;
00288   int itmp;
00289   float ftmp;
00290 
00291   if (ftell (ptr) != 0L)
00292   {
00293     fprintf (stderr, "\nPROGRAMMER ERROR: G_oldsite_describe() must be called\n");
00294     fprintf (stderr, "        immediately after G_fopen_sites_old()\n");
00295     return -2;
00296   }
00297 
00298   *dims = *strs = *dbls = 0;
00299   *cat = -1;
00300   buf = sbuf;
00301 
00302   if ((buf = fgets (sbuf, 1024, ptr)) == (char *) NULL)
00303   {
00304     rewind (ptr);
00305     return EOF;
00306   }
00307   /* skip over comment & header lines */        
00308   while ((*buf == '#' || !isdigit(*buf)) && *buf != '-' && *buf != '+')
00309     if ((buf = fgets (sbuf, 1024, ptr)) == (char *) NULL)
00310     {
00311       rewind (ptr);
00312       return EOF;
00313     }
00314 
00315   if (buf[strlen (buf) - 1] == '\n')
00316     buf[strlen (buf) - 1] = '\0' ;
00317 
00318   if ((err = sscanf (buf, "%[^|]|%[^|]|%*[^\n]", ebuf, nbuf)) < 2)
00319   {
00320     fprintf (stderr, "ERROR: ebuf %s nbuf %s\n", ebuf, nbuf);
00321     rewind (ptr);
00322     return -2;
00323   }
00324   *dims = 2;
00325 
00326   /* move pointer past easting and northing fields */
00327   while (!ispipe(*buf) && !isnull(*buf))
00328     buf++;
00329   if (!isnull(*buf) && !isnull(*(buf + 1)))
00330     buf++;
00331   else
00332   {
00333     rewind (ptr);
00334     return -2;
00335   }
00336   while (!ispipe(*buf) && !isnull(*buf))
00337     buf++;
00338   if (!isnull(*buf) && !isnull(*(buf + 1)))
00339     buf++;
00340   else
00341   {
00342     rewind (ptr);
00343     return 0;
00344   }
00345 
00346   /* check for remaining dimensional fields */
00347   while (G_index (buf, PIPE) != (char *) NULL)
00348   {
00349     (*dims)++;
00350     while (!ispipe(*buf) && !isnull(*buf))
00351       buf++;
00352     if (isnull(*buf) || isnull(*(buf+1)))
00353     {
00354       rewind (ptr);
00355       return 0;
00356     }
00357     if (!isnull(*(buf + 1)))
00358       buf++;
00359     else
00360     {
00361       rewind (ptr);
00362       return -2;
00363     }
00364   }
00365 
00366   /* no more dimensions-now we parse attribute fields */
00367   while (!isnull(*buf))
00368   {
00369     switch (*buf)
00370     {
00371     case '#':                   /* category field */
00372       sscanf(buf,"#%s ",ebuf);
00373       if(G_strstr(ebuf,".")==NULL && sscanf(ebuf,"%d", &itmp) ==1)
00374         *cat=CELL_TYPE;
00375       else if(G_strstr(ebuf,".")!=NULL && sscanf(ebuf,"%f", &ftmp) ==1)
00376         *cat=FCELL_TYPE;
00377       else 
00378         *cat=-1;
00379 
00380       /* move to beginning of next attribute */
00381       while (!isspace (*buf) && !isnull(*buf))
00382         buf++;
00383       if (isnull(*buf) || isnull(*(buf + 1)))
00384       {
00385         rewind (ptr);
00386         return 0;
00387       }
00388       else
00389         buf++;
00390       break;
00391     case '%':                   /* decimal attribute */
00392       (*dbls)++;
00393       /* move to beginning of next attribute */
00394       while (!isspace (*buf) && !isnull(*buf))
00395         buf++;
00396       if (isnull(*buf) || isnull(*(buf + 1)))
00397       {
00398         rewind (ptr);
00399         return 0;
00400       }
00401       else
00402         buf++;
00403       break;
00404     case '@':                   /* string attribute */
00405       if (isnull(*buf) || isnull(*(buf + 1)))
00406       {
00407         rewind (ptr);
00408         return 0;
00409       }
00410       else
00411         buf++;
00412     default:                    /* defaults to string attribute */
00413       /* allow both prefixed and unprefixed strings */
00414       if ((err = cleanse_string (buf)) > 0)
00415       {
00416         (*strs)++;
00417         buf += err;
00418       }
00419 
00420       /* move to beginning of next attribute */
00421       while (!isspace (*buf) && !isnull(*buf))
00422         buf++;
00423       if (isnull(*buf) || isnull(*(buf + 1)))
00424       {
00425         rewind (ptr);
00426         return 0;
00427       }
00428       else
00429         buf++;
00430       break;
00431     }
00432   }
00433 
00434   rewind (ptr);
00435   return 0;
00436 }
00437 
00438 int G_site_in_region ( Site *site, struct Cell_head *region)
00439 /* returns 1 if site is contained within region, 0 otherwise */
00440 {
00441 /* northwest corner is in region, southeast corner is not. */
00442 double e_ing;
00443 double G_adjust_easting();
00444 
00445   e_ing = G_adjust_easting (site->east, region);
00446   if (e_ing >= region->west &&
00447       e_ing < region->east &&
00448       site->north <= region->north &&
00449       site->north > region->south)
00450     return 1;
00451 
00452   return 0;
00453 }
00454 
00455 static int format_double ( double value, char *buf)
00456 {
00457   sprintf (buf, "%.8f", value);
00458   G_trim_decimal (buf);
00459   return 0;
00460 }
00461 
00462 int cleanse_string (char *buf)
00463 {
00464   char *stop, *p, *p2;
00465 
00466   p = buf;
00467 
00468   /*
00469    * get rid of any SPACEs at beginning while ( !isspace(*buf) && *buf !=
00470    * (char) NULL) buf++; if (*buf == (char) NULL) return -1;
00471    */
00472 
00473   /* find where this string terminates */
00474   if ( *buf != DQUOTE)  /* if no DQUOTEs, */
00475   {
00476     stop = G_index (buf, SPACE);/* then SPACE separates */
00477     if (stop == (char *) NULL)
00478       return strlen (buf);
00479     else
00480       return (int) (stop - buf);
00481   }
00482   else                          /* otherwise string is in DQUOTEs */
00483   {                             /* but we must skip over escaped */
00484     /* (BSLASHed) DQUOTEs */
00485     if (*p == DQUOTE)
00486     {
00487       while (*p != (char) NULL) /* get rid of first DQUOTE */
00488       {
00489         *p = *(p + 1);
00490         p++;
00491       }
00492       p = buf;
00493       stop = G_index (p + 1, DQUOTE);
00494       while (*(stop - 1) == BSLASH)
00495         stop = G_index (++stop, DQUOTE);
00496     }
00497   }
00498   /* remove backslashes between buf and stop */
00499   p = buf;
00500   while ((p = G_index (p, BSLASH)) != (char *) NULL && p <= stop)
00501   {
00502     p2 = p + 1;
00503     if (*p2 != (char) NULL && (*p2 == DQUOTE || *p2 == BSLASH))
00504     {
00505       while (*p != (char) NULL)
00506       {
00507         *p = *(p + 1);
00508         p++;
00509       }
00510       stop--;
00511     }
00512     p = p2;
00513   }
00514   return (int) (stop - buf);
00515 }
00516 
00517 char *next_att (char *buf)
00518 {
00519   while (!isspace (*buf) && !isnull(*buf))
00520     buf++;
00521   if (isnull(*buf) || isnull(*(buf + 1)))
00522     return NULL;
00523   else
00524     while (isspace (*(buf + 1)) && !isnull(*(buf + 1)))
00525       buf++;
00526   buf++;
00527   return buf;
00528 }
00529 
00530 int G_site_c_cmp (const void *a, const void *b)
00531 /* qsort() comparison function for sorting an array of
00532    site structures by category. */
00533 {
00534   int result = 0;               /* integer to be returned */
00535   double diff;
00536  
00537   switch((*(Site **)a)->cattype)
00538   {
00539     case CELL_TYPE:
00540       diff = (double) (*(Site **) a)->ccat - (*(Site **) b)->ccat;
00541       break;
00542     case FCELL_TYPE:
00543       diff = (double) (*(Site **) a)->fcat - (*(Site **) b)->fcat;
00544       break;
00545     case DCELL_TYPE:
00546       diff = (double) (*(Site **) a)->dcat - (*(Site **) b)->dcat;
00547       break;
00548   }
00549   if (diff < 0.0 )
00550     result = -1;
00551   else if (diff > 0.0)
00552     result = 1;
00553   return result;
00554 }
00555 
00556 int G_site_d_cmp (const void *a, const void *b)
00557 /* qsort() comparison function for sorting an array of
00558    site structures by first decimal attribute. */
00559 {
00560   int result = 0;               /* integer to be returned */
00561   double diff;
00562  
00563   diff = (*(Site **) a)->dbl_att[0] - (*(Site **) b)->dbl_att[0];
00564   if (diff < 0.0 )
00565     result = -1;
00566   else if (diff > 0.0)
00567     result = 1;
00568   return result;
00569 }
00570 
00571 int G_oldsite_s_cmp (const void *a, const void *b)
00572 /* qsort() comparison function for sorting an array of
00573    site structures by first decimal attribute. */
00574 {
00575   return strcmp((*(char **)((*(Site **) a)->str_att)), 
00576                 (*(char **)((*(Site **) b)->str_att)));
00577 }
00578 
00579 /*-************************************************************************
00580  *
00581  *  FILE *
00582  *  G_oldsites_open_old (name, mapset)
00583  *      opens the existing site list file 'name' in the 'mapset'
00584  *
00585  *  parms
00586  *      char *name            map file name
00587  *      char *mapset          mapset containing map "name"
00588  *
00589  **********************************************************************/
00590 
00591 FILE * G_oldsites_open_old (char *name,char *mapset)
00592 {
00593   return G_fopen_old ("site_lists", name, mapset);
00594 }
00595 
00596 FILE * G_oldsites_open_new (char *name)
00597 {
00598   return G_fopen_new ("site_lists", name);
00599 }
00600 
00601 /*********************************************/
00602 /* The following functions are obsolete.     */
00603 /* They are retained here only for backwards */
00604 /* compatability while porting applications  */
00605 /*********************************************/
00606 
00607 char *G_site_format (Site *s, char *fs, int id)
00608 /* sprintf analog to G_site_put with the addition of a field seperator fs 
00609    and option of printing site attribute identifiers
00610  */
00611 {
00612   char ebuf[MAX_SITE_STRING], nbuf[MAX_SITE_STRING];
00613   char xbuf[MAX_SITE_STRING];
00614   char *nfs, *buf;
00615   int fmt, i, j, k;
00616 
00617   buf=(char *)G_malloc(MAX_SITE_LEN*sizeof(char));
00618 
00619   fmt = G_projection ();
00620 
00621   G_format_northing (s->north, nbuf, fmt);
00622   G_format_easting (s->east, ebuf, fmt);
00623 
00624   nfs = (char *) ((fs == (char *) NULL) ? "|" : fs);
00625 
00626   sprintf (buf, "%s%s%s", ebuf, nfs, nbuf);
00627 
00628   for (i = 0; i < s->dim_alloc; ++i)
00629   {
00630     format_double (s->dim[i], nbuf);
00631     sprintf (xbuf, "%s%s", nfs, nbuf);
00632     G_strcat (buf, xbuf);
00633   }
00634 
00635   nfs= (fs == NULL) ? " " : fs;
00636 
00637   switch(s->cattype)
00638   {
00639     case CELL_TYPE:
00640     sprintf (xbuf, "%s%s%d ", nfs, ((id==0) ? "" : "#"), (int)s->ccat);
00641     G_strcat (buf, xbuf);
00642     break;
00643     case FCELL_TYPE:
00644     case DCELL_TYPE:
00645     sprintf (xbuf, "%s%s%g ", nfs, ((id==0) ? "" : "#"), (float)s->fcat);
00646     G_strcat (buf, xbuf);
00647     break;
00648   }
00649 
00650   for (i = 0; i < s->dbl_alloc; ++i)
00651   {
00652     format_double (s->dbl_att[i], nbuf);
00653     sprintf (xbuf, "%s%s%s", nfs, ((id==0) ? "" : "%"), nbuf);
00654     G_strcat (buf, xbuf);
00655   }
00656 
00657   for (i = 0; i < s->str_alloc; ++i)
00658   {
00659     if (strlen (s->str_att[i]) != 0)
00660     {
00661       /* escape double quotes */
00662       j = k = 0;
00663 
00664       /* do not uncomment this code because sites file was created
00665        * as we want. So it's enough to print them out as it is.
00666        *
00667       if (G_index (s->str_att[i], DQUOTE) != (char *) NULL)
00668       {
00669         while (!isnull(s->str_att[i][j]))
00670         {
00671           if (isquote(s->str_att[i][j]))
00672           {
00673             xbuf[k++] = BSLASH;
00674             xbuf[k++] = DQUOTE;
00675           }
00676           else
00677             xbuf[k++] = s->str_att[i][j];
00678           j++;
00679         }
00680         xbuf[k] = (char) NULL;
00681       }
00682       else
00683       */
00684 
00685         G_strcpy (xbuf, s->str_att[i]);
00686 
00687       G_strcpy (s->str_att[i], xbuf);
00688 
00689       if (G_index (s->str_att[i], SPACE) != (char *) NULL)
00690         sprintf (xbuf, "%s%s\"%s\"", nfs, ((id==0) ? "" : "@"), s->str_att[i]);
00691       else
00692         sprintf (xbuf, "%s%s%s", nfs, ((id==0) ? "" : "@"), s->str_att[i]);
00693       G_strcat (buf, xbuf);
00694     }
00695   }
00696   return buf;
00697 }
00698 

Generated on Sat Jul 22 22:06:15 2006 for GRASS by  doxygen 1.4.7