Problem with sites.c in fp_sites_datetime-3.tar

brown at gis.uiuc.edu brown at gis.uiuc.edu
Mon Jun 16 11:57:20 EDT 1997


Hi Justin,

Yes, that was me.  I guess the last update from CERL didn't 
include the G_TimeStamp routines.

The latest version of the datetime lib is:
ftp://129.229.103.1/pub/grass/outgoing/datetime.tar.Z.newer
which also doesn't include the G_TimeStamp routines or the
sites library routines.  I don't know why the G_TimeStamp
stuff doesn't seem to be there.  With CERL no longer supporting
GRASS, it seems like the last update got a little off-cycle.

below is my latest src/include/gis.h and a file src/libes/gis/timestamp.c
(just add timestamp.o to the Gmakefile in src/libes/gis and recompile there).
I'll also include my latest src/libes/gis/sites.c, but you might want
to save a copy of your old one, as this one has not been well tested
for backward compatibility.

you might want to diff your gis.h with this one to make sure there
aren't changes besides adding the struct TimeStamp.  

It looks like CERL needs to clean up the last updates - there's
still some old ones under outgoing/Sites, too.   Maybe LAS plans
to eventually do this, I don't know.  The TimeStamp routines should
have been in there, as they were done long ago.

let me know if you need more...

- Bill

////////////////////// cut here gis.h //////////////////////

#ifndef __GRASS_GIS_LIB__
#define __GRASS_GIS_LIB__
static char *GRASS_copyright = "GRASS (TM) Public Domain Software" ;
#define MAXEDLINES  50
#define RECORD_LEN  80
#define NEWLINE     '\n'
#define RECLASS_TABLE 1
#define RECLASS_RULES 2
#define RECLASS_SCALE 3

#define METERS    1
#define FEET      2
#define DEGREES   3

typedef int CELL;
typedef double DCELL;
typedef float FCELL;
extern CELL CELL_NODATA;

/*
enum RASTER_MAP_TYPE{ CELL_TYPE = 0,
                FCELL_TYPE = 1,
                DCELL_TYPE = 2
              };
doesn't compile on sun :( ? */

typedef int RASTER_MAP_TYPE;
#define CELL_TYPE 0
#define FCELL_TYPE 1
#define DCELL_TYPE 2

#define PROJECTION_XY  0
#define PROJECTION_UTM 1
#define PROJECTION_SP  2
#define PROJECTION_LL  3
#define PROJECTION_OTHER  99

#define PROJECTION_FILE "PROJ_INFO"
#define UNIT_FILE "PROJ_UNITS"

struct Cell_head
{
    int format       ;  /* max numer of bytes per cell minus 1          */
    int compressed   ;  /* 0 = uncompressed, 1 = compressed, -1 pre 3.0 */
    int rows, cols   ;  /* number of rows and columns in the data       */
    int proj         ;  /* Projection (see #defines above)              */
    int zone         ;  /* Projection zone                              */
    double ew_res    ;  /* East to West cell size                       */
    double ns_res    ;  /* North to South cell size                     */
    double north     ;  /* coordinates of layer                         */
    double south     ;
    double east      ;
    double west      ;
} ;

struct _Color_Rule_
{
    struct
    {
	DCELL value;
	unsigned char red,grn,blu;
    } low, high;
    struct _Color_Rule_ *next;
    struct _Color_Rule_ *prev;
};

struct _Color_Info_
{
    struct _Color_Rule_ *rules;
    int n_rules;
    struct
    {
	unsigned char *red;
	unsigned char *grn;
	unsigned char *blu;
	unsigned char *set;
	int nalloc;
	int active;
    } lookup;
    struct
    {
        DCELL *vals;
	/* pointers to color rules corresponding to the intervals btwn vals */
	struct _Color_Rule_ **rules;
	int nalloc;
	int active;
    } fp_lookup;
    DCELL min, max;
};

struct Colors
{
    int version;	/* set by read_colors: -1=old,1=new */
    DCELL shift;
    int invert;
    int is_float;             /* defined on floating point raster data? */
    int null_set; /* the colors for null are set? */
    unsigned char null_red, null_grn, null_blu;
    int undef_set; /* the colors for cells not in range are set? */
    unsigned char undef_red, undef_grn, undef_blu;
    struct _Color_Info_ fixed, modular;
    DCELL cmin, cmax;
};

struct Reclass
{
    char name[50]           ; /* name of cell file being reclassed    */
    char mapset[50]         ; /* mapset in which "name" is found      */
    int type                ; /* type of reclass                      */
    int num                 ; /* size of reclass table                */
    CELL min,max            ; /* table range                          */
    CELL *table             ; /* reclass table                        */
} ;

struct FPReclass_table
{
  DCELL dLow, dHigh;  /* domain */
  DCELL rLow, rHigh;  /* range */

};

/* reclass structure from double to double 
   used by r.recode to reclass between types:
   int to double, float to int,... 
*/

struct FPReclass {

  int defaultDRuleSet; /* 1 if default domain rule set */
  int defaultRRuleSet; /* 1 if default range rule set */
  int infiniteLeftSet; /* 1 if negative infinite interval rule exists */
  int infiniteRightSet; /* 1 if positive infinite interval rule exists */
  int rRangeSet; /* 1 if range range (i.e. interval) is set */
  int maxNofRules; 
  int nofRules;
  DCELL defaultDMin, defaultDMax; /*default domain minimum and maximum value */
  DCELL defaultRMin, defaultRMax; /* default range minimum and maximum value */
  DCELL infiniteDLeft, infiniteDRight; /* neg infinite rule */
  DCELL infiniteRLeft, infiniteRRight; /* pos infinite rule */
  DCELL dMin, dMax; /* minimum and maximum domain values in rules */
  DCELL rMin, rMax; /* minimum and maximum range values in rules */
  struct FPReclass_table *table;

};

struct Quant_table
{
  DCELL dLow, dHigh;
  CELL cLow, cHigh;
};

struct Quant
{

  int truncate_only;
  int round_only;
  int defaultDRuleSet;
  int defaultCRuleSet;
  int infiniteLeftSet;
  int infiniteRightSet;
  int cRangeSet;
  int maxNofRules;
  int nofRules;
  DCELL defaultDMin, defaultDMax;
  CELL defaultCMin, defaultCMax;
  DCELL infiniteDLeft, infiniteDRight;
  CELL infiniteCLeft, infiniteCRight;
  DCELL dMin, dMax;
  CELL cMin, cMax;
  struct Quant_table *table;
  struct
  {
     DCELL *vals;
     /* pointers to quant rules corresponding to the intervals btwn vals */
     struct Quant_table **rules;
     int nalloc;
     int active;
     DCELL inf_dmin, inf_dmax; 
     CELL inf_min, inf_max; 
     /* all values smaller than inf_dmin become inf_min */
     /* all values larger than inf_dmax become inf_max */
     /* inf_min and/or inf_max can be NULL if there are no inf rules */
  } fp_lookup;

};

struct Categories
{
    CELL ncats            ;   /* total number of categories              */
    CELL num              ;   /* the highest cell values. Only exists    
				 for backwards compatibility = (CELL)
				 max_fp_values in quant rules            */
    char *title           ;   /* name of data layer                      */ 
    char *fmt             ;   /* printf-like format to generate labels   */
    float m1              ;   /* Multiplication coefficient 1            */
    float a1              ;   /* Addition coefficient 1                  */
    float m2              ;   /* Multiplication coefficient 2            */
    float a2              ;   /* Addition coefficient 2                  */
    struct Quant q        ;   /* rules mapping cell values to index in
				 list of labels                          */
    char **labels         ;   /* array of labels of size num             */	
    int * marks           ;   /* was the value with this label was used? */
    int nalloc;
    int last_marked_rule  ;
/* NOTE: to get a rule corresponfing to cats.labels[i], use 
   G_get_ith_c/f/d_raster_cat (pcats, i, val1, val2)
   it calls
   G_quant_get_ith_rule(&cats->q, i, val1, val2, &index, &index); 
   and idex ==i, because rule is added at the same time as a
   label, and quant rules are never reordered. Olga apr,95 */
} ;

struct History
{
    char    mapid[RECORD_LEN];
    char    title[RECORD_LEN];
    char    mapset[RECORD_LEN];
    char    creator[RECORD_LEN];
    char    maptype[RECORD_LEN];
    char    datsrc_1[RECORD_LEN];
    char    datsrc_2[RECORD_LEN];
    char    keywrd[RECORD_LEN];
    int     edlinecnt;
    char    edhist[MAXEDLINES][RECORD_LEN];
} ;

struct Cell_stats
{
    struct Cell_stats_node
    {
	int idx;
	long *count;
	int left;
	int right;
    } *node ;     /* tree of values */
    int tlen ;    /* allocated tree size */
    int N;        /* number of actual nodes in tree */
    int curp;
    long null_data_count;   
    int curoffset;
} ;

struct Histogram
{
    int num;
    struct Histogram_list
    {
	CELL cat;
	long count;
    } *list;
} ;

struct Range
{
    CELL min;		
    CELL max;	
    int first_time;     /* wether or not range was updated */
};

struct FPRange
{
    DCELL min;		
    DCELL max;	
    int first_time;     /* wether or not range was updated */
};


/*
** Structure for I/O of 3dview files  (view.c)
*/
struct G_3dview{
    char pgm_id[40];            /* user-provided identifier */
    float from_to[2][3];        /* eye position & lookat position */
    float fov;                  /* field of view */
    float twist;                /* right_hand rotation about from_to */
    float exag;                 /* terrain elevation exageration */
    int mesh_freq, poly_freq;   /* cells per grid line, cells per polygon */
    int display_type;           /* 1 for mesh, 2 for poly, 3 for both */
    int lightson, dozero, colorgrid, shading, fringe, surfonly, doavg;/*bools*/
    char grid_col[40], bg_col[40], other_col[40]; /* colors */
    float lightpos[4]; /* easting, northing, height, 1.0 for local 0.0 infin */
    float lightcol[3];       /* values between 0.0 to 1.0 for red, grn, blu */
    float ambient, shine;
    struct Cell_head vwin;
};


struct Key_Value
{
    int nitems;
    int nalloc;
    char **key;
    char **value;
};


struct Option                /* Structure that stores option info */
{
    char *key ;                     /* Key word used on command line    */
    int type ;                      /* Option type                      */
    int required ;                  /* REQUIRED or OPTIONAL             */
    int multiple ;                  /* Multiple entries OK              */
    char *options ;                 /* Approved values or range or NULL */
    char *key_desc;                 /* one word describing the key      */
    char *description ;             /* String describing option         */
    char *answer ;                  /* Option answer                    */
    char *def ;                     /* Where original answer gets saved */
    char **answers ;                /* Option answers (for multiple=YES)*/
    struct Option *next_opt ;       /* Pointer to next option struct    */
    char *gisprompt ;               /* Interactive prompt guidance      */
    int (*checker)() ;              /* Routine to check answer or NULL  */
    int count;
} ;

struct Flag                 /* Structure that stores flag info  */
{
    char key ;                      /* Key char used on command line    */
    char answer ;                   /* Stores flag state: 0/1           */
    char *description ;             /* String describing flag meaning   */
    struct Flag *next_flag ;        /* Pointer to next flag struct      */
} ;

/* for G_parser() */
#define TYPE_INTEGER  1
#define TYPE_DOUBLE   2
#define TYPE_STRING   3
#define YES           1
#define NO            0

#ifndef FILE
#include <stdio.h>
#endif

#include "gisdefs.h"

#include "datetime.h"
#include "site.h"

struct TimeStamp {
    DateTime dt[2];   /* two datetimes */
    int count;
};
#endif /*__GRASS_GIS_LIB__*/


////////////////////// cut here timestamp.c //////////////////////

#include "gis.h"

void
G_init_timestamp (ts)
    struct TimeStamp *ts;
{
    ts->count = 0;
}

void
G_set_timestamp (ts, dt)
    struct TimeStamp *ts;
    DateTime *dt;
{
    datetime_copy (&ts->dt[0], dt);
    ts->count = 1;
}

void
G_set_timestamp_range (ts, dt1, dt2)
    struct TimeStamp *ts;
    DateTime *dt1, *dt2;
{
    datetime_copy (&ts->dt[0], dt1);
    datetime_copy (&ts->dt[1], dt2);
    ts->count = 2;
}

int
G__read_timestamp (fd, ts)
    FILE *fd;
    struct TimeStamp *ts;
{
    char buf[1024];
    char comment[2];

    while (fgets(buf, sizeof(buf), fd))
    {
	if (sscanf (buf, "%1s", comment) != 1 || *comment == '#')
	    continue;
	return (G_scan_timestamp (ts, buf) > 0 ? 0 : -1);
    }
    return -2; /* nothing in the file */
}

G__write_timestamp (fd, ts)
    FILE *fd;
    struct TimeStamp *ts;
{
    char buf[1024];

    if (G_format_timestamp (ts, buf) < 0)
	return -1;
    fprintf (fd, "%s\n", buf);
    return 0;
}

G_format_timestamp (ts, buf)
    struct TimeStamp *ts;
    char *buf;
{
    char temp1[128], temp2[128];
    *buf = 0;
    if (ts->count > 0)
    {
	if (datetime_format (&ts->dt[0],temp1) != 0)
	    return -1;
    }
    if (ts->count > 1)
    {
	if (datetime_format (&ts->dt[1],temp2) != 0)
	    return -1;
    }
    if (ts->count == 1)
	strcpy (buf, temp1);
    else if (ts->count == 2)
	sprintf (buf, "%s / %s", temp1, temp2);

    return 1;
}

G_scan_timestamp (ts, buf)
    struct TimeStamp *ts;
    char *buf;
{
    char temp[1024], *t;
    char *slash;
    DateTime dt1, dt2;

    G_init_timestamp(ts);
    for (slash = buf; *slash; slash++)
	if (*slash == '/')
	    break;
    if (*slash)
    {
	t = temp;
	while (buf != slash)
	    *t++ = *buf++;
	*t = 0;
	buf++;
	if (datetime_scan(&dt1,temp) != 0 || datetime_scan(&dt2,buf) != 0)
		return -1;
	G_set_timestamp_range (ts, &dt1, &dt2);
    }
    else
    {
	if(datetime_scan (&dt2, buf) != 0 )
	    return -1;
	G_set_timestamp (ts, &dt2);
    }
    return 1;
}
	
		

G_get_timestamps (ts, dt1, dt2, count)
    struct TimeStamp *ts;
    DateTime *dt1, *dt2;
    int *count;
{
    *count = 0;
    if (ts->count > 0)
    {
	datetime_copy (dt1, &ts->dt[0]);
	*count = 1;
    }
    if (ts->count > 1)
    {
	datetime_copy (dt2, &ts->dt[1]);
	*count = 2;
    }
}

/* write timestamp file
 * 1 ok
 * -1 error - can't create timestamp file
 * -2 error - invalid datetime in ts
 */
static int
write_timestamp (maptype, mapname, element, filename, ts)
    char *maptype, *mapname, *element, *filename;
    struct TimeStamp *ts;
{
    FILE *fd;
    char msg[1024];
    int stat;

    fd = G_fopen_new (element, filename);
    if (fd == NULL)
    {
	sprintf (msg,
		"Can't create timestamp file for %s map %s in mapset %s",
		maptype, mapname, G_mapset());
	G_warning (msg);
	return -1;
    }

    stat = G__write_timestamp (fd, ts);
    fclose (fd);
    if (stat == 0)
	return 1;
    sprintf (msg,
	    "Invalid timestamp specified for %s map %s in mapset %s",
	    maptype, mapname, G_mapset());
    G_warning (msg);
    return -2;
}

/* read timestamp file
 * 0 no timestamp file
 * 1 ok
 * -1 error - can't open timestamp file
 * -2 error - invalid datetime values in timestamp file
 */
static int
read_timestamp (maptype, mapname, mapset, element, filename, ts)
    char *maptype, *mapname, *mapset, *element, *filename;
    struct TimeStamp *ts;
{
    FILE *fd;
    char msg[256];
    int stat;

    if (!G_find_file2 (element, filename, mapset))
	return 0;
    fd = G_fopen_old (element, filename, mapset);
    if (fd == NULL)
    {
	sprintf (msg,
		"Can't open timestamp file for %s map %s in mapset %s",
		maptype, mapname, mapset);
	G_warning (msg);
	return -1;
    }

    stat = G__read_timestamp (fd, ts);
    fclose (fd);
    if (stat == 0)
	return 1;
    sprintf (msg,
	    "Invalid timestamp file for %s map %s in mapset %s",
	    maptype, mapname, mapset);
    G_warning (msg);
    return -2;
}

#define RAST_MISC "cell_misc"
#define VECT_MISC "dig_misc"

G_read_raster_timestamp (name, mapset, ts)
    char *name, *mapset;
    struct TimeStamp *ts;
{
    char element[128];

    sprintf (element, "%s/%s", RAST_MISC, name);
    return read_timestamp ("raster", name, mapset, element, "timestamp", ts);
}

G_remove_raster_timestamp (name)
    char *name;
{
    char element[128];

    sprintf (element, "%s/%s", RAST_MISC, name);
    return G_remove(element, "timestamp");
}

G_read_vector_timestamp (name, mapset, ts)
    char *name, *mapset;
    struct TimeStamp *ts;
{
    char element[128];

    sprintf (element, "%s/%s", VECT_MISC, name);
    return read_timestamp ("vector", name, mapset, element, "timestamp", ts);
}

G_remove_vector_timestamp (name)
    char *name;
{
    char element[128];

    sprintf (element, "%s/%s", VECT_MISC, name);
    return G_remove(element, "timestamp");
}

G_write_raster_timestamp (name, ts)
    char *name;
    struct TimeStamp *ts;
{
    char element[128];

    sprintf (element, "%s/%s", RAST_MISC, name);
    return write_timestamp ("raster", name, element, "timestamp", ts);
}

G_write_vector_timestamp (name, ts)
    char *name;
    struct TimeStamp *ts;
{
    char element[128];

    sprintf (element, "%s/%s", VECT_MISC, name);
    return write_timestamp ("vector", name, element, "timestamp", ts);
}

////////////////////// cut here sites.c //////////////////////

#pragma ident   "$Id: sites.c,v 1.39 1995/08/17 21:03:29 mccauley Exp mccauley $"

/*-
 * These functions and definitions support the site format for 4.2
 * (format proposed by Dave Gerdes):
 *
 * easting|northing|[z|[d4|]...][#category_int] [ [@attr_text OR %flt] ... ]
 *
 * to allow multidimensions (everything preceding the last '|') and any
 * number of text or numeric attribute fields.
 *
 * Author: James Darrell McCauley <mccauley at ecn.purdue.edu>
 * 31 Jan 1994
 */

/*-
 * $Log: sites.c,v $
 * Revision 1.40  1997/05/07  brown
 * changed G_site_get to return 1 on "format mismatch (extra data)" 
 * instead of error
 *
 * $Log: sites.c,v $
 * Revision 1.40  1996/05/23  brown
 * changed DateTime stuff to use TimeStamp instead
 *
 * Revision 1.39  1995/08/17  21:03:29  mccauley
 * fixed bug related to time to stime conversion
 *
 * Revision 1.38  1995/07/25  15:14:45  mccauley
 * fixed error for cat in G_site_describe
 *
 * Revision 1.37  1995/07/17  20:55:48  mccauley
 * change G_strchr to G_strstr
 *
 * Revision 1.36  1995/07/17  11:14:43  mccauley
 * took out has_cat and made part of struct
 * support for floating point categories
 *
 * Revision 1.35  1995/07/14  14:04:14  mccauley
 * renamed G_site_get_fmt to G_site_describe
 *
 * Revision 1.34  1995/07/14  11:39:49  mccauley
 * changed G_site_destroy_struct to G_site_free_struct
 *
 * Revision 1.33  1995/07/13  19:58:28  mccauley
 * added G_site_destroy_struct
 *
 * Revision 1.32  1995/07/05  12:55:40  mccauley
 * added warning flags for old API usage
 *
 * Revision 1.31  1995/07/05  12:25:48  mccauley
 * modified G_site_put to use (Site *) instead of (Site)
 *
 * Revision 1.30  1995/07/05  12:07:17  mccauley
 * removed extra spaces in G_site_puts output
 *
 * Revision 1.29  1995/07/05  12:02:48  mccauley
 * added G_site_puts (analog to sprintf for G_site_put)
 *
 * Revision 1.28  1995/07/05  12:01:20  mccauley
 * fixed bug in G_sites_get_fmt
 *
 * Revision 1.27  1995/06/29  16:27:00  mccauley
 * fixed malloc error in G_site_new_struct.
 *
 * Revision 1.26  1995/06/29  12:08:25  mccauley
 * added G_site_in_region.
 *
 * Revision 1.25  1995/06/20  16:08:24  mccauley
 * first version put in 4.2 release
 *
 * Revision 1.24  1995/05/24  00:36:27  mccauley
 * added old functions for bc while porting
 *
 * Revision 1.23  1995/05/24  00:05:31  mccauley
 * added DateTime stuff
 *
 * Revision 1.22  1995/04/17  22:56:59  mccauley
 * added G_site_put_hdr/G_site_get_hdr. Header records include
 * "name|", "desc|", "labels|", and "time|".
 *
 * Revision 1.21  1995/02/22  03:23:19  mccauley
 * more ctype-like changes.
 *
 * Revision 1.20  1995/02/22  03:14:23  mccauley
 * changed conditionals to use ctype-like defines (e.g., ispipe).
 *
 * Revision 1.19  1995/02/22  02:53:48  mccauley
 * skip over header lines in G_site_get and G_site_get_fmt.
 *
 * Revision 1.18  1995/02/22  02:45:54  mccauley
 * added sites functions from 4.1 that we'll keep.
 *
 * Revision 1.17  1995/02/22  02:25:03  mccauley
 * changed names of functions to G_site_xxx().
 *
 * Revision 1.16  1995/02/21  07:53:48  mccauley
 * changed "static char sites_api_rcsid" to pragma ident.
 * added function declarations for those int functions that
 * should be defined in gis.h. fixed pointer-int comparison
 * in next_att().
 * No warnings (from this code) for "gcc -Wall."
 *
 * Revision 1.15  1995/02/21  07:27:32  mccauley
 * added qsort comparison functions.
 * still need to re-write G_guess_site_fmt to reflect changes in
 * G_new_get_site.
 *
 * Revision 1.14  1995/02/21  07:21:49  mccauley
 * replaced repititive code with next_att()
 * removed erroneous comments. ran indent.
 *
 * Revision 1.13  1995/02/21  02:33:14  mccauley
 * changes to ignore superflous spaces not contained within quotes.
 * changes to use ctyle functions and to do selective reads.
 *
 * Revision 1.12  1995/02/18  22:34:37  mccauley
 * a few changes to read selective fields (according to what
 * was allocated for).
 *
 * Revision 1.11  1995/02/09  02:49:20  mccauley
 * Added check for dim_alloc in G_new_get_site.
 * Removed erroneous check in G_new_put_site.
 * Still have error in selective reads.
 *
 * Revision 1.10  1995/02/09  00:07:03  mccauley
 * Debugged G_guess_site_fmt and ran indent.
 * Still need to rewrite G_guess_site_fmt and G_new_get_site so
 * that we don't have multiple exits points (too many 'return 0's).
 *
 * Revision 1.9  1995/02/08  23:12:20  mccauley
 * Added first version of G_guess_site_fmt (untested).
 *
 * Revision 1.8  1995/02/08  01:26:27  mccauley
 * Changed return vals of G_new_get_site for easier diagnostics.
 * For category and decimal attributes, on possible reason for a
 * non zero return value is the value does not immediately follow
 * the attribute tag (# or %). E.g., "# 2" or "% 23.4" will cause
 * an error. Remember to put this in programmers' docs!
 *
 * Revision 1.7  1995/02/08  00:54:49  mccauley
 * Added a few more checks. Fixed a bug in cleanse_string.
 *
 * Revision 1.6  1995/02/08  00:06:24  mccauley
 * Added a few checks, combined a few, and changed do/while to while after #.
 *
 * Revision 1.5  1995/02/07  23:33:07  mccauley
 * fixed bug with G_new_put_site [.dim_alloc already decremented by 2]
 *
 * Revision 1.4  1995/02/07  23:24:06  mccauley
 * added comments and ran 'indent'
 *
 * Revision 1.3  1995/02/07  23:16:04  mccauley
 * if length of string attribute is zero, it is not printed. if there
 * are no non-zero string attributes, no string attributes are printed.
 *
 * Revision 1.2  1995/02/07  21:15:13  mccauley
 * recompiled with 'gcc -Wall' and got rid of "unused var" warnings.
 * added return values to some functions.
 *
 * Revision 1.1  1995/02/07  21:01:12  mccauley Initial revision
 */

#include "gis.h"
#include <ctype.h>
#include <string.h>

#define DQUOTE '"'
#define SPACE ' '
#define BSLASH 92
#define PIPE '|'

#define ispipe(c) (c==PIPE)
#define isnull(c) (c==(char)NULL)
#define isquote(c) (c==DQUOTE)

void G_site_free_struct (s)
  Site *s;
/* Free memory for a Site struct */
{
  if(s->dim_alloc)
      free(s->dim);
  if(s->str_alloc)
      free(s->str_att);
  if(s->dbl_alloc)
      free(s->dbl_att);
  free(s);
}

Site *G_site_new_struct (cattype, n_dim, n_s_att, n_d_att)
  RASTER_MAP_TYPE cattype; 
  int n_dim, n_s_att, n_d_att;

/* Allocate memory for a Site struct. Returns a properly allocated
   site struct or NULL on error. 
   cattype= -1 (no cat), CELL_TYPE, FCELL_TYPE, or DCELL_TYPE 
*/
{  
  int i;
  Site *s;

  if (n_dim < 2 || n_s_att < 0 || n_d_att < 0)
  {
    fprintf (stderr, "PROGRAMMER ERROR: invalid # dims or fields in %s\n",
	     "G_site_new_struct");
    exit (-1);
  }

  if ((s = (Site *) G_malloc (sizeof (Site))) == NULL)
    return (Site *) NULL;

  s->cattype=cattype;
  s->ccat=s->fcat=s->dcat=0;

  if (n_dim > 2)
  {
    if ((s->dim =
	 (double *) G_malloc ((n_dim - 2) * sizeof (double))) == NULL)
      return (Site *) NULL;
  }
  s->dim_alloc = n_dim - 2;

  if (n_d_att > 0)
  {
    if ((s->dbl_att =
	 (double *) G_malloc (n_d_att * sizeof (double))) == NULL)
      return (Site *) NULL;
  }
  s->dbl_alloc = n_d_att;

  if (n_s_att > 0)
  {
    if ((s->str_att =
	 (char **) G_malloc (n_s_att * sizeof (char *))) == NULL)
      return (Site *) NULL;
    else
      for (i = 0; i < n_s_att; ++i)
	if ((s->str_att[i] =
	  (char *) G_malloc (MAX_SITE_STRING * sizeof (char))) == NULL)
	  return (Site *) NULL;
  }
  s->str_alloc = n_s_att;

  return s;
}

#define FOUND_ALL(s,n,dim,c,d) (((s->cattype != -1 && !n) || \
				 (dim < s->dim_alloc) || \
				 (c < s->str_alloc) || \
				 (d < s->dbl_alloc))?0:1)

int G_site_get (ptr, s)
  FILE *ptr;
  Site *s;

/*-
 * Reads ptr and returns 0 on success,
 *                      -1 on EOF,
 *                      -2 on other fatal error or insufficient data,
 *                       1 on format mismatch (extra data)
 */
{
  int cleanse_string ();
  char sbuf[MAX_SITE_LEN], *buf, *last, *p1, *p2;
  char ebuf[128], nbuf[128];
  char *next_att ();
  int G_projection(), G_scan_northing(), G_scan_easting();
  int n = 0, d = 0, c = 0, dim = 0, err = 0, tmp;

  buf = sbuf;

  if ((buf = fgets (sbuf, 1024, ptr)) == (char *) NULL)
    return EOF;

  while ((*buf == '#' || !isdigit(*buf)) && *buf != '-' && *buf != '+')
    if ((buf = fgets (sbuf, 1024, ptr)) == (char *) NULL)
      return EOF;

  if (buf[strlen (buf) - 1] == '\n')
    buf[strlen (buf) - 1] = (char) NULL;

  if (sscanf (buf, "%[^|]|%[^|]|%*[^\n]", ebuf, nbuf) < 2)
  {
    fprintf (stderr, "ERROR: ebuf %s nbuf %s\n", ebuf, nbuf);
    return -2;
  }

  if (!G_scan_northing (nbuf, &(s->north), G_projection ()) ||
      !G_scan_easting (ebuf, &(s->east), G_projection ()))
  {
    fprintf (stderr, "ERROR: ebuf %s nbuf %s\n", ebuf, nbuf);
    return -2;
  }

  /* move pointer past easting and northing fields */
  if (NULL == (buf = G_index(buf, PIPE)))
    return -2;
  if (NULL == (buf = G_index(buf+1, PIPE)))
    return -2;

  /* check for remaining dimensional fields */
  do {
    buf++;
    if (isnull(*buf)) return (FOUND_ALL(s,n,dim,c,d)? 0: -2);
    last = buf;
    if (dim < s->dim_alloc)  /* should be more dims to read */
    {
      if (sscanf (buf, "%lf|", &(s->dim[dim++])) < 1)
	return -2;   /* no more dims, though expected */ 
    }
    else if (NULL != (p1 = G_index(buf, PIPE))) 
    {
	if (NULL == (p2 = G_index(buf, DQUOTE)))
	    err = 1;  /* more dims, though none expected */
	else if (strlen(p1) > strlen(p2))
	    err = 1;  /* more dims, though none expected */
    }
  } while ((buf = G_index (buf, PIPE)) != NULL);
  buf = last;

  /* no more dimensions-now we parse attribute fields */
  while (!isnull(*buf))
  {
    switch (*buf)
    {
    case '#':			/* category field */
      if (n == 0)
      {
        switch(s->cattype)
        {
          case CELL_TYPE:
          if(sscanf (buf, "#%d", &s->ccat)==1)
	    n++;
          break;
          case FCELL_TYPE:
          if(sscanf (buf, "#%f", &s->fcat)==1)
	    n++;
          break;
          case DCELL_TYPE:
          if(sscanf (buf, "#%lf", &s->dcat)==1)
	    n++;
          break;
	  default:
	  err = 1; /* has cat, none expected */
	  break;
        }
      }
      else{
	err = 1;  /* extra cat */
      }

      /* move to beginning of next attribute */
      if ((buf = next_att (buf)) == (char *) NULL)
	return (FOUND_ALL(s,n,dim,c,d)? err: -2);
      break;
    case '%':			/* decimal attribute */
      if (d < s->dbl_alloc)
	if (sscanf (buf, "%%%lf", &(s->dbl_att[d++])) < 1)
	  return -2;
      else
	err = 1;  /* extra decimal */

      if ((buf = next_att (buf)) == (char *) NULL)
	return (FOUND_ALL(s,n,dim,c,d)? err: -2);
      break;
    case '@':			/* string attribute */
      if (isnull(*buf) || isnull(*(buf + 1)))
	return (FOUND_ALL(s,n,dim,c,d)? err: -2);
      else
	buf++;
    default:			/* defaults to string attribute */
      /* allow both prefixed and unprefixed strings */
      if (c < s->str_alloc)
      {
	if ((tmp = cleanse_string (buf)) > 0)
	{
	  G_strncpy (s->str_att[c++], buf, tmp);
	  buf += tmp;
	}
	else
	  return (FOUND_ALL(s,n,dim,c,d)? err: -2);
      }
      if ((buf = next_att (buf)) == (char *) NULL)
	return (FOUND_ALL(s,n,dim,c,d)? err: -2);
      break;
    }
  }

  return (FOUND_ALL(s,n,dim,c,d)? err: -2);
}


int G_site_put (fptr, s)
  FILE *fptr;
  Site *s;

/* Writes a site to file open on fptr. */
{
  char ebuf[MAX_SITE_STRING], nbuf[MAX_SITE_STRING];
  char xbuf[MAX_SITE_STRING], buf[MAX_SITE_LEN];
  static int format_double ();
  int fmt, i, j, k;
  int G_format_northing(), G_format_easting(), G_projection();

  fmt = G_projection ();

  G_format_northing (s->north, nbuf, fmt);
  G_format_easting (s->east, ebuf, fmt);
  sprintf (buf, "%s|%s|", ebuf, nbuf);
  for (i = 0; i < s->dim_alloc; ++i)
  {
    format_double (s->dim[i], nbuf);
    sprintf (xbuf, "%s|", nbuf);
    G_strcat (buf, xbuf);
  }
  switch(s->cattype)
  {
    case CELL_TYPE:
    sprintf (xbuf, "#%d ", s->ccat);
    G_strcat (buf, xbuf);
    break;
    case FCELL_TYPE:
    sprintf (xbuf, "#%g ", s->fcat);
    G_strcat (buf, xbuf);
    break;
    case DCELL_TYPE:
    sprintf (xbuf, "#%g ", s->dcat);
    G_strcat (buf, xbuf);
    break;
  }

  for (i = 0; i < s->dbl_alloc; ++i)
  {
    format_double (s->dbl_att[i], nbuf);
    sprintf (xbuf, "%%%s ", nbuf);
    G_strcat (buf, xbuf);
  }
  for (i = 0; i < s->str_alloc; ++i)
  {
    if (strlen (s->str_att[i]) != 0)
    {
      /* escape double quotes */
      j = k = 0;
      if (G_index (s->str_att[i], DQUOTE) != (char *) NULL)
      {
	while (!isnull(s->str_att[i][j]))
	{
	  if (isquote(s->str_att[i][j]))
	  {
	    xbuf[k++] = BSLASH;
	    xbuf[k++] = DQUOTE;
	  }
	  else
	    xbuf[k++] = s->str_att[i][j];
	  j++;
	}
	xbuf[k] = (char) NULL;
      }
      else
	G_strcpy (xbuf, s->str_att[i]);

      G_strcpy (s->str_att[i], xbuf);

      if (G_index (s->str_att[i], SPACE) != (char *) NULL)
	sprintf (xbuf, "@\"%s\" ", s->str_att[i]);
      else
	sprintf (xbuf, "@%s ", s->str_att[i]);
      G_strcat (buf, xbuf);
    }
  }
  fprintf (fptr, "%s\n", buf);
  return 0;
}

int G_site_describe (ptr, dims, cat, strs, dbls)
  FILE *ptr;
  int *dims, *cat, *strs, *dbls;

/*-
 * Tries to guess the format of a sites list (the dimensionality,
 * the presence/type of a category, and the number of string and decimal
 * attributes) by reading the first record in the file.
 * Reads ptr and returns 0 on success,
 *                      -1 on EOF,
 *                      -2 for other error.
 */
{
  int cleanse_string ();
  char sbuf[MAX_SITE_LEN], *buf;
  char ebuf[128], nbuf[128];
  int err;
  int itmp;
  float ftmp;

  if (ftell (ptr) != 0L)
  {
    fprintf (stderr, "\nPROGRAMMER ERROR: G_site_describe() must be called\n");
    fprintf (stderr, "        immediately after G_fopen_sites_old()\n");
    return -2;
  }

  *dims = *strs = *dbls = 0;
  *cat = -1;
  buf = sbuf;

  if ((buf = fgets (sbuf, 1024, ptr)) == (char *) NULL)
  {
    rewind (ptr);
    return EOF;
  }
  /* skip over comment & header lines */	
  while ((*buf == '#' || !isdigit(*buf)) && *buf != '-' && *buf != '+')
    if ((buf = fgets (sbuf, 1024, ptr)) == (char *) NULL)
    {
      rewind (ptr);
      return EOF;
    }

  if (buf[strlen (buf) - 1] == '\n')
    buf[strlen (buf) - 1] = (char) NULL;

  if ((err = sscanf (buf, "%[^|]|%[^|]|%*[^\n]", ebuf, nbuf)) < 2)
  {
    fprintf (stderr, "ERROR: ebuf %s nbuf %s\n", ebuf, nbuf);
    rewind (ptr);
    return -2;
  }
  *dims = 2;

  /* move pointer past easting and northing fields */
  while (!ispipe(*buf) && !isnull(*buf))
    buf++;
  if (!isnull(*buf) && !isnull(*(buf + 1)))
    buf++;
  else
  {
    rewind (ptr);
    return -2;
  }
  while (!ispipe(*buf) && !isnull(*buf))
    buf++;
  if (!isnull(*buf) && !isnull(*(buf + 1)))
    buf++;
  else
  {
    rewind (ptr);
    return 0;
  }

  /* check for remaining dimensional fields */
  while (G_index (buf, PIPE) != (char) NULL)
  {
    (*dims)++;
    while (!ispipe(*buf) && !isnull(*buf))
      buf++;
    if (isnull(*buf))
    {
      rewind (ptr);
      return 0;
    }
    if (!isnull(*(buf + 1)))
      buf++;
    else
    {
      rewind (ptr);
      return -2;
    }
  }

  /* no more dimensions-now we parse attribute fields */
  while (!isnull(*buf))
  {
    switch (*buf)
    {
    case '#':			/* category field */
      sscanf(buf,"#%s ",ebuf);
      if(G_strstr(ebuf,".")==NULL && sscanf(ebuf,"%d", &itmp) ==1)
        *cat=CELL_TYPE;
      else if(G_strstr(ebuf,".")!=NULL && sscanf(ebuf,"%f", &ftmp) ==1)
        *cat=FCELL_TYPE;
      else 
        *cat=-1;

      /* move to beginning of next attribute */
      while (!isspace (*buf) && !isnull(*buf))
	buf++;
      if (isnull(*buf) || isnull(*(buf + 1)))
      {
	rewind (ptr);
	return 0;
      }
      else
	buf++;
      break;
    case '%':			/* decimal attribute */
      (*dbls)++;
      /* move to beginning of next attribute */
      while (!isspace (*buf) && !isnull(*buf))
	buf++;
      if (isnull(*buf) || isnull(*(buf + 1)))
      {
	rewind (ptr);
	return 0;
      }
      else
	buf++;
      break;
    case '@':			/* string attribute */
      if (isnull(*buf) || isnull(*(buf + 1)))
      {
	rewind (ptr);
	return 0;
      }
      else
	buf++;
    default:			/* defaults to string attribute */
      /* allow both prefixed and unprefixed strings */
      if ((err = cleanse_string (buf)) > 0)
      {
	(*strs)++;
	buf += err;
      }

      /* move to beginning of next attribute */
      while (!isspace (*buf) && !isnull(*buf))
	buf++;
      if (isnull(*buf) || isnull(*(buf + 1)))
      {
	rewind (ptr);
	return 0;
      }
      else
	buf++;
      break;
    }
  }


  rewind (ptr);
  return 0;
}

int G_site_put_head (ptr, head)
  FILE *ptr;
  Site_head *head;
/*-
 * Writes site_head struct.
 */
{
  static char buf[128];
  static struct TimeStamp ts;

  if (head->name!=NULL)
    fprintf(ptr,"name|%s\n",head->name);
  if (head->desc!=NULL)
    fprintf(ptr,"desc|%s\n",head->desc);
  if (head->form!=NULL)
    fprintf(ptr,"form|%s\n",head->form);
  if (head->labels!=NULL)
    fprintf(ptr,"labels|%s\n",head->labels);
  /* time could be in (char *) stime, (struct TimeStamp *) time, 
     both, or neither */
  if (head->stime!=NULL || head->time !=NULL)
  {
    if (head->time != NULL)   /* TimeStamp struct has precendence */
    {
      G_format_timestamp (head->time, buf);
      fprintf(ptr,"time|%s\n",buf);
    }
    else if (head->stime != NULL)  /* next check string */
    {
      if (head->time==NULL)
         if ((head->time=(struct TimeStamp *) 
                         G_malloc(sizeof(struct TimeStamp)))==NULL)
	     G_fatal_error("Memory error in writing timestamp");
	 else if (G_scan_timestamp (head->time, head->stime) < 0)
	     G_warning("Illegal TimeStamp string");

      G_format_timestamp (head->time, head->stime);
      fprintf(ptr,"time|%s\n",head->stime);
    }
  }
  return 0;
}

int G_site_get_head (ptr, head)
  FILE *ptr;
  Site_head *head;

/*-
 * Fills in site_head struct.
 */
{
  char sbuf[MAX_SITE_LEN], *buf;
  int len;

  if (ftell (ptr) != 0L)
  {
    fprintf (stderr, "\nPROGRAMMER ERROR: G_site_get_head() must be called\n");
    fprintf (stderr, "        immediately after G_fopen_sites_old()\n");
    return -2;
  }

  head->name=NULL;
  head->desc=NULL;
  head->form=NULL;
  head->labels=NULL;
  head->stime=NULL;
  head->time=NULL;

  buf = sbuf;

  if ((buf = fgets (sbuf, 1024, ptr)) == (char *) NULL)
  {
    rewind (ptr);
    return EOF;
  }
  /* assume header lines are always first records. allow for comments */
  while ((*buf == '#' || !isdigit(*buf)) && *buf != '-' && *buf != '+')
  {
    len=strlen(buf);
    if (buf[len-1]=='\n')
         buf[len-1]=NULL;
    if (!strncmp(buf,"name|",5))
    {
       buf+=5;
       head->name=G_strdup(buf);
    }
    else if (!strncmp(buf,"desc|",5))
    {
       buf+=5;
       head->desc=G_strdup(buf);
    }
    else if (!strncmp(buf,"form|",5))
    {
       buf+=5;
       head->form=G_strdup(buf);
    }
    else if (!strncmp(buf,"labels|",7))
    {
       buf+=7;
       head->labels=G_strdup(buf);
    }
    else if (!strncmp(buf,"time|",5))
    {
       buf+=5;
       head->stime=G_strdup(buf);
       if ((head->time=(struct TimeStamp *) 
                       G_malloc(sizeof(struct TimeStamp)))==NULL)
         G_fatal_error("Memory error in allocating timestamp");
       if (G_scan_timestamp (head->time , head->stime)<0)
       {
         G_warning(datetime_error_msg());
         head->time=NULL;
         head->stime=NULL;
       }
    }
    /* else is it a comment or some invalid header (not a decimal digit) */

    if ((buf = fgets (sbuf, 1024, ptr)) == (char *) NULL)
    {
      rewind (ptr);
      return EOF;
    }
  }

  rewind (ptr);
  return 0;
}

int G_site_in_region (site, region)
  Site *site;
  struct Cell_head *region;
/* returns 1 if site is contained within region, 0 otherwise */
{
/* northwest corner is in region, southeast corner is not. */
double e_ing;
double G_adjust_easting();

  e_ing = G_adjust_easting (site->east, region);
  if (e_ing >= region->west &&
      e_ing < region->east &&
      site->north <= region->north &&
      site->north > region->south)
    return 1;
  else
    return 0;
}

static int format_double (value, buf)
  double value;
  char *buf;
{
  int G_trim_decimal ();
  sprintf (buf, "%.8f", value);
  G_trim_decimal (buf);
  return 0;
}


int cleanse_string (buf)
  char *buf;
{
  char *stop, *p;

  p = buf;

  /*
   * get rid of any SPACEs at beginning while ( !isspace(*buf) && *buf !=
   * (char) NULL) buf++; if (*buf == (char) NULL) return -1;
   */

  /* find where this string terminates */
  if (G_index (buf, DQUOTE) == (char) NULL)	/* if no DQUOTEs, */
  {
    stop = G_index (buf, SPACE);/* then SPACE separates */
    if (stop == (char *) NULL)
      return strlen (buf);
    else
      return (int) (stop - buf);
  }
  else				/* otherwise string is in DQUOTEs */
  {				/* but we must skip over escaped */
    /* (BSLASHed) DQUOTEs */
    if (*p == DQUOTE)
    {
      while (*p != (char) NULL)	/* get rid of first DQUOTE */
      {
	*p = *(p + 1);
	p++;
      }
      p = buf;
      stop = G_index (p + 1, DQUOTE);
      while (*(stop - 1) == BSLASH)
	stop = G_index (++stop, DQUOTE);
    }
  }
  /* remove backslashes between buf and stop */
  while ((p = G_index (buf, BSLASH)) != (char *) NULL && p <= stop)
  {
    if (*(p + 1) != (char) NULL && *(p + 1) == DQUOTE)
    {
      while (*p != (char) NULL)
      {
	*p = *(p + 1);
	p++;
      }
      stop--;
    }
  }
  return (int) (stop - buf);
}

char *next_att (buf)
  char *buf;
{
  while (!isspace (*buf) && !isnull(*buf))
    buf++;
  if (isnull(*buf) || isnull(*(buf + 1)))
    return 0;
  else
    while (isspace (*(buf + 1)) && !isnull(*(buf + 1)))
      buf++;
  buf++;
  return buf;
}

int G_site_c_cmp (a, b)
  void *a, *b;
 
/* qsort() comparison function for sorting an array of
   site structures by category. */
{
  int result = 0;               /* integer to be returned */
  double diff;
 
  switch((*(Site **)a)->cattype)
  {
    case CELL_TYPE:
      diff = (double) (*(Site **) a)->ccat - (*(Site **) b)->ccat;
      break;
    case FCELL_TYPE:
      diff = (double) (*(Site **) a)->fcat - (*(Site **) b)->fcat;
      break;
    case DCELL_TYPE:
      diff = (double) (*(Site **) a)->dcat - (*(Site **) b)->dcat;
      break;
  }
  if (diff < 0.0 )
    result = -1;
  else if (diff > 0.0)
    result = 1;
  return result;
}

int G_site_d_cmp (a, b)
  void *a, *b;
 
/* qsort() comparison function for sorting an array of
   site structures by first decimal attribute. */
{
  int result = 0;               /* integer to be returned */
  double diff;
 
  diff = (*(Site **) a)->dbl_att[0] - (*(Site **) b)->dbl_att[0];
  if (diff < 0.0 )
    result = -1;
  else if (diff > 0.0)
    result = 1;
  return result;
}

int G_site_s_cmp (a, b)
  void *a, *b;
 
/* qsort() comparison function for sorting an array of
   site structures by first decimal attribute. */
{
  return strcmp((*(char **)((*(Site **) a)->str_att)), 
                (*(char **)((*(Site **) b)->str_att)));
}

/*-************************************************************************
 *   char *
 *   G_ask_sites_new(prompt, name))
 *       asks user to input name of a new site list file
 *
 *   char *
 *   G_ask_sites_old(prompt, name)
 *       asks user to input name of an existing site list file
 *
 *   char *
 *   G_ask_sites_any(prompt, name)
 *       asks user to input any site list name
 *
 *   char *
 *   G_ask_sites_in_mapset(prompt, name)
 *       asks user to input name of an existing site list file in
 *       current mapset
 *
 *   parms:
 *      char *prompt    optional prompt for user
 *      char *name      buffer to hold name of map found
 *
 *   returns:
 *      char *pointer to a string with name of mapset
 *       where file was found, or NULL if not found
 *
 *   note:
 *      rejects all names that begin with .
 **********************************************************************
 *
 *  FILE *
 *  G_sites_open_old (name, mapset)
 *      opens the existing site list file 'name' in the 'mapset'
 *
 *  FILE *
 *  G_sites_open_new (name)
 *      opens a new site list file 'name' in the current mapset
 *
 *  parms
 *      char *name            map file name
 *      char *mapset          mapset containing map "name"
 *
 **********************************************************************/

char * G_find_sites (name, mapset)
  char *name, *mapset;
{
  return G_find_file ("site_lists", name, mapset);
}

char * G_find_sites2 (name, mapset)
  char *name, *mapset;
{
  return G_find_file2 ("site_lists", name, mapset);
}


char * G_ask_sites_new (prompt, name)
  char *prompt, *name;
{
  char *G_ask_new ();

  return G_ask_new (prompt, name, "site_lists", "site list");
}

char * G_ask_sites_old (prompt, name)
  char *prompt, *name;
{
  char *G_ask_old ();

  return G_ask_old (prompt, name, "site_lists", "site list");
}

char * G_ask_sites_any (prompt, name)
  char *prompt, *name;
{
  char *G_ask_any ();

  return G_ask_any (prompt, name, "site_lists", "site list", 1);
}

char * G_ask_sites_in_mapset (prompt, name)
  char *prompt, *name;
{
  char *G_ask_in_mapset ();

  return G_ask_in_mapset (prompt, name, "site_lists", "site list");
}

FILE * G_sites_open_old (name, mapset)
  char *name, *mapset;
{
  return G_fopen_old ("site_lists", name, mapset);
}

FILE * G_sites_open_new (name)
  char *name;
{
  return G_fopen_new ("site_lists", name);
}

/*********************************************/
/* The following functions are obsolete.     */
/* They are retained here only for backwards */
/* compatability while porting applications  */
/*********************************************/
FILE *
G_fopen_sites_old (name, mapset)
    char *name;
    char *mapset;
{
    return G_fopen_old ("site_lists", name, mapset);
}

FILE *
G_fopen_sites_new (name)
    char *name;
{
    return G_fopen_new ("site_lists", name);
}

G_get_site (fd, east, north, desc)
    FILE *fd;
    double *east, *north;
    char **desc;
{
    char buf[400];
    char temp[400];
    char ebuf[128], nbuf[128];
    static char *desc_ptr = NULL;

    fprintf(stderr,"WARNING: %s needs modified for the new Sites API\n",
            G_program_name() );

    if (desc_ptr != NULL)
    {
	free (desc_ptr);
	desc_ptr = NULL;
    }
    *temp = 0;
    while (fgets (buf, sizeof buf, fd))
    {
	if (sscanf (buf, "point|%[^|]|%[^|]|%[^\n]", ebuf, nbuf, temp) >= 2
	||  sscanf (buf, "%[^|]|%[^|]|%[^\n]", ebuf, nbuf, temp) >= 2)
	{
	    if (G_scan_northing (nbuf, north, G_projection())
	    &&  G_scan_easting (ebuf, east, G_projection()))
	    {
		G_strip (temp);
		*desc = desc_ptr = G_store (temp);
		return 1;
	    }
	}
    }
    return -1;
}

G_put_site (fd, east, north, desc)
    FILE *fd;
    double east, north;
    char *desc;
{
    char ebuf[128], nbuf[128];
    int fmt;
    fprintf(stderr,"WARNING: %s needs modified for the new Sites API\n",
            G_program_name() );

/*  fmt = G_projection(); */ 
    fmt = -1;

    G_format_northing (north, nbuf, fmt);
    G_format_easting  (east,  ebuf, fmt);
    fprintf (fd, "%s|%s|%s\n", ebuf, nbuf, desc?desc:"");
}

char * G_site_format (s, fs, id)
  Site *s;
  char *fs;
  int id;

/* sprintf analog to G_site_put with the addition of a field seperator fs 
   and option of printing site attribute identifiers
 */
{
  char ebuf[MAX_SITE_STRING], nbuf[MAX_SITE_STRING];
  char xbuf[MAX_SITE_STRING];
  char *nfs, *buf;
  static int format_double ();
  int fmt, i, j, k;
  int G_format_northing(), G_format_easting(), G_projection();

  buf=(char *)G_malloc(MAX_SITE_LEN*sizeof(char));

  fmt = G_projection ();

  G_format_northing (s->north, nbuf, fmt);
  G_format_easting (s->east, ebuf, fmt);

  nfs = (char *) ((fs == (char *) NULL) ? "|" : fs);

  sprintf (buf, "%s%s%s", ebuf, nfs, nbuf);

  for (i = 0; i < s->dim_alloc; ++i)
  {
    format_double (s->dim[i], nbuf);
    sprintf (xbuf, "%s%s", nfs, nbuf);
    G_strcat (buf, xbuf);
  }

  nfs= (fs == NULL) ? " " : fs;

  switch(s->cattype)
  {
    case CELL_TYPE:
    sprintf (xbuf, "%s%s%d ", nfs, ((id==0) ? "" : "#"), (int)s->ccat);
    G_strcat (buf, xbuf);
    break;
    case FCELL_TYPE:
    case DCELL_TYPE:
    sprintf (xbuf, "%s%s%g ", nfs, ((id==0) ? "" : "#"), (float)s->fcat);
    G_strcat (buf, xbuf);
    break;
  }

  for (i = 0; i < s->dbl_alloc; ++i)
  {
    format_double (s->dbl_att[i], nbuf);
    sprintf (xbuf, "%s%s%s", nfs, ((id==0) ? "" : "%"), nbuf);
    G_strcat (buf, xbuf);
  }

  for (i = 0; i < s->str_alloc; ++i)
  {
    if (strlen (s->str_att[i]) != 0)
    {
      /* escape double quotes */
      j = k = 0;
      if (G_index (s->str_att[i], DQUOTE) != (char *) NULL)
      {
	while (!isnull(s->str_att[i][j]))
	{
	  if (isquote(s->str_att[i][j]))
	  {
	    xbuf[k++] = BSLASH;
	    xbuf[k++] = DQUOTE;
	  }
	  else
	    xbuf[k++] = s->str_att[i][j];
	  j++;
	}
	xbuf[k] = (char) NULL;
      }
      else
	G_strcpy (xbuf, s->str_att[i]);

      G_strcpy (s->str_att[i], xbuf);

      if (G_index (s->str_att[i], SPACE) != (char *) NULL)
	sprintf (xbuf, "%s%s\"%s\"", nfs, ((id==0) ? "" : "@"), s->str_att[i]);
      else
	sprintf (xbuf, "%s%s%s", nfs, ((id==0) ? "" : "@"), s->str_att[i]);
      G_strcat (buf, xbuf);
    }
  }
  return buf;
}



More information about the grass-user mailing list