sites.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903
  1. /*!
  2. \brief Old sites library
  3. These functions and definitions support the site format for 5.0
  4. (format proposed by Dave Gerdes):
  5. \verbatim
  6. easting|northing|[z|[d4|]...][#category_int] [ [@attr_text OR %flt] ... ]
  7. \endverbatim
  8. to allow multidimensions (everything preceding the last '|') and any
  9. number of text or numeric attribute fields.
  10. \author James Darrell McCauley <mccauley@ecn.purdue.edu> (31 Jan 1994)
  11. */
  12. #include <ctype.h>
  13. #include <string.h>
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <errno.h>
  17. #include <grass/gis.h>
  18. #include <grass/site.h>
  19. #include <grass/dbmi.h>
  20. #include <grass/vector.h>
  21. #include <grass/glocale.h>
  22. #define DQUOTE '"'
  23. #define SPACE ' '
  24. #define BSLASH 92
  25. #define PIPE '|'
  26. #define ispipe(c) (c==PIPE)
  27. #define isnull(c) (c=='\0')
  28. #define FOUND_ALL(s,n,dim,c,d) (((s->cattype != -1 && !n) || \
  29. (dim < s->dim_alloc) || \
  30. (c < s->str_alloc) || \
  31. (d < s->dbl_alloc))?0:1)
  32. static char *next_att(const char *);
  33. static int cleanse_string(char *);
  34. static int G__oldsite_get(FILE *, Site *, int);
  35. static int site_att_cmp(const void *pa, const void *pb)
  36. {
  37. const struct site_att *a = pa, *b = pb;
  38. return a->cat - b->cat;
  39. }
  40. /*!
  41. \brief Get site
  42. \param Map
  43. \param s
  44. \return 0 on success
  45. \return -1 on EOF
  46. \return -2 on other fatal error or insufficient data,
  47. \return 1 on format mismatch (extra data)
  48. */
  49. int G_site_get(struct Map_info *Map, Site * s)
  50. {
  51. int i, type, cat;
  52. static struct line_pnts *Points = NULL;
  53. static struct line_cats *Cats = NULL;
  54. struct site_att *sa;
  55. if (Points == NULL)
  56. Points = Vect_new_line_struct();
  57. if (Cats == NULL)
  58. Cats = Vect_new_cats_struct();
  59. while (1) {
  60. type = Vect_read_next_line(Map, Points, Cats);
  61. if (type == -1)
  62. return -2; /* Error */
  63. if (type == -2)
  64. return -1; /* EOF */
  65. if (type != GV_POINT)
  66. continue; /* Is not point */
  67. Vect_cat_get(Cats, 1, &cat);
  68. G_debug(4, "Site: %f|%f|%f|#%d", Points->x[0], Points->y[0],
  69. Points->z[0], cat);
  70. s->east = Points->x[0];
  71. s->north = Points->y[0];
  72. if (Vect_is_3d(Map))
  73. s->dim[0] = Points->z[0];
  74. s->ccat = cat;
  75. /* find att */
  76. if (Map->n_site_att > 0) {
  77. sa = (struct site_att *) bsearch((void *)&cat, (void *)Map->site_att,
  78. Map->n_site_att, sizeof(struct site_att),
  79. site_att_cmp);
  80. if (sa == NULL) {
  81. G_warning(_("Attributes for category %d not found"), cat);
  82. for (i = 0; i < Map->n_site_dbl; i++)
  83. s->dbl_att[i] = 0;
  84. for (i = 0; i < Map->n_site_str; i++)
  85. strncpy(s->str_att[i], "", MAX_SITE_STRING);
  86. }
  87. else {
  88. for (i = 0; i < Map->n_site_dbl; i++)
  89. s->dbl_att[i] = sa->dbl[i];
  90. for (i = 0; i < Map->n_site_str; i++)
  91. strncpy(s->str_att[i], sa->str[i], MAX_SITE_STRING);
  92. }
  93. }
  94. return 0;
  95. }
  96. }
  97. /*!
  98. \brief Writes a site to file open on fptr
  99. \param Map
  100. \param s
  101. \return
  102. */
  103. int G_site_put(struct Map_info *Map, const Site * s)
  104. {
  105. static struct line_pnts *Points = NULL;
  106. static struct line_cats *Cats = NULL;
  107. if (Points == NULL)
  108. Points = Vect_new_line_struct();
  109. if (Cats == NULL)
  110. Cats = Vect_new_cats_struct();
  111. Vect_reset_line(Points);
  112. Vect_reset_cats(Cats);
  113. /* no 3D support so far: s->dim[0] */
  114. Vect_append_point(Points, s->east, s->north, 0.0);
  115. G_debug(4, "cattype = %d", s->cattype);
  116. if (s->cattype == FCELL_TYPE || s->cattype == DCELL_TYPE)
  117. G_fatal_error(_("Category must be integer"));
  118. if (s->cattype == CELL_TYPE)
  119. Vect_cat_set(Cats, 1, s->ccat);
  120. Vect_write_line(Map, GV_POINT, Points, Cats);
  121. return 0;
  122. }
  123. /*!
  124. \brief Tries to guess the format of a sites list
  125. The dimensionality, the presence/type of a category, and the number
  126. of string and decimal attributes) by reading the first record in
  127. the file.
  128. \return 0 on success
  129. \return -1 on EOF
  130. \return -2 for other error
  131. */
  132. int G_site_describe(struct Map_info *Map, int *dims, int *cat, int *strs,
  133. int *dbls)
  134. {
  135. if (Vect_is_3d(Map)) {
  136. G_debug(1, "Vector is 3D -> number of site dimensions is 3");
  137. *dims = 3;
  138. }
  139. else {
  140. G_debug(1, "Vector is 2D -> number of site dimensions is 2");
  141. *dims = 2;
  142. }
  143. *cat = CELL_TYPE;
  144. /* attributes ignored for now, later read from DB */
  145. *dbls = Map->n_site_dbl;
  146. *strs = Map->n_site_str;
  147. return 0;
  148. }
  149. /*!
  150. \brief Writes site_head struct
  151. */
  152. int G_site_put_head(struct Map_info *Map, Site_head * head)
  153. {
  154. static char buf[128];
  155. if (head->name != NULL)
  156. Vect_set_map_name(Map, head->name);
  157. /* crashes:
  158. if (head->desc!=NULL)
  159. Vect_set_comment (Map, head->desc);
  160. */
  161. /*
  162. if (head->form!=NULL)
  163. fprintf(ptr,"form|%s\n",head->form);
  164. if (head->labels!=NULL)
  165. fprintf(ptr,"labels|%s\n",head->labels);
  166. */
  167. /* time could be in (char *) stime, (struct TimeStamp *) time,
  168. both, or neither */
  169. if (head->stime != NULL || head->time != NULL) {
  170. if (head->time != NULL) { /* TimeStamp struct has precendence */
  171. G_format_timestamp(head->time, buf);
  172. Vect_set_date(Map, buf);
  173. }
  174. else if (head->stime != NULL) { /* next check string */
  175. if (head->time == NULL) {
  176. if ((head->time =
  177. (struct TimeStamp *)G_malloc(sizeof(struct TimeStamp)))
  178. == NULL)
  179. G_fatal_error(_("Memory error in writing timestamp"));
  180. else if (G_scan_timestamp(head->time, head->stime) < 0) {
  181. G_warning(_("Illegal TimeStamp string"));
  182. return -1; /* added to prevent crash 5/2000 MN */
  183. }
  184. }
  185. G_format_timestamp(head->time, buf);
  186. head->stime = G_store(buf);
  187. Vect_set_date(Map, head->stime);
  188. }
  189. }
  190. return 0;
  191. }
  192. struct Map_info *G_sites_open_old(const char *name, const char *mapset)
  193. {
  194. struct Map_info *Map;
  195. struct field_info *fi;
  196. int more, nrows, row, ncols, col, ndbl, nstr, adbl, astr, ctype;
  197. struct site_att *sa;
  198. dbDriver *driver;
  199. dbString stmt;
  200. dbCursor cursor;
  201. dbTable *table;
  202. dbColumn *column;
  203. dbValue *value;
  204. G_message(
  205. _("Dev note: Adapted sites library used for vector points. "
  206. "(module should be updated to GRASS 6 vector library)"));
  207. Map = (struct Map_info *)G_malloc(sizeof(struct Map_info));
  208. Vect_set_open_level(1);
  209. Vect_open_old(Map, name, mapset);
  210. G_debug(1, "Vector map opened");
  211. /* Load attributes */
  212. Map->site_att = NULL;
  213. Map->n_site_att = 0;
  214. Map->n_site_dbl = 0;
  215. Map->n_site_str = 0;
  216. fi = Vect_get_field(Map, 1);
  217. if (fi == NULL) { /* not attribute table */
  218. G_debug(1, "No attribute table");
  219. return Map;
  220. }
  221. driver = db_start_driver_open_database(fi->driver, fi->database);
  222. if (driver == NULL)
  223. G_fatal_error(_("Unable to open database <%s> by driver <%s>"),
  224. fi->database,
  225. fi->driver);
  226. db_init_string(&stmt);
  227. db_set_string(&stmt, "select * from ");
  228. db_append_string(&stmt, fi->table);
  229. if (db_open_select_cursor(driver, &stmt, &cursor, DB_SEQUENTIAL) != DB_OK)
  230. G_fatal_error(_("Unable to open select cursor: '%s'"),
  231. db_get_string(&stmt));
  232. nrows = db_get_num_rows(&cursor);
  233. G_debug(1, "%d rows selected from vector attribute table", nrows);
  234. Map->site_att = (struct site_att *) malloc(nrows * sizeof(struct site_att));
  235. Map->n_site_att = nrows;
  236. table = db_get_cursor_table(&cursor);
  237. ncols = db_get_table_number_of_columns(table);
  238. row = 0;
  239. adbl = astr = 0;
  240. while (1) {
  241. if (db_fetch(&cursor, DB_NEXT, &more) != DB_OK)
  242. G_fatal_error(_("Cannot fetch row"));
  243. if (!more)
  244. break;
  245. /* Get number of each type */
  246. if (row == 0) {
  247. for (col = 0; col < ncols; col++) {
  248. column = db_get_table_column(table, col);
  249. ctype = db_sqltype_to_Ctype(db_get_column_sqltype(column));
  250. if (strcmp(db_get_column_name(column), fi->key) == 0)
  251. continue;
  252. switch (ctype) {
  253. case DB_C_TYPE_INT:
  254. case DB_C_TYPE_DOUBLE:
  255. adbl++;
  256. break;
  257. case DB_C_TYPE_STRING:
  258. case DB_C_TYPE_DATETIME:
  259. astr++;
  260. break;
  261. }
  262. }
  263. Map->n_site_dbl = adbl;
  264. Map->n_site_str = astr;
  265. G_debug(1, "adbl = %d astr = %d", adbl, astr);
  266. }
  267. sa = &(Map->site_att[row]);
  268. sa->dbl = (double *)malloc(adbl * sizeof(double));
  269. sa->str = (char **)malloc(astr * sizeof(char *));
  270. ndbl = nstr = 0;
  271. for (col = 0; col < ncols; col++) {
  272. column = db_get_table_column(table, col);
  273. ctype = db_sqltype_to_Ctype(db_get_column_sqltype(column));
  274. value = db_get_column_value(column);
  275. if (strcmp(db_get_column_name(column), fi->key) == 0) {
  276. sa->cat = db_get_value_int(value);
  277. }
  278. else {
  279. switch (ctype) {
  280. case DB_C_TYPE_INT:
  281. sa->dbl[ndbl] = db_get_value_int(value);
  282. ndbl++;
  283. break;
  284. case DB_C_TYPE_DOUBLE:
  285. sa->dbl[ndbl] = db_get_value_double(value);
  286. ndbl++;
  287. break;
  288. case DB_C_TYPE_STRING:
  289. sa->str[nstr] = G_store(db_get_value_string(value));
  290. nstr++;
  291. break;
  292. case DB_C_TYPE_DATETIME:
  293. sa->str[nstr] = ""; /* TODO */
  294. nstr++;
  295. break;
  296. }
  297. }
  298. }
  299. row++;
  300. }
  301. db_close_database_shutdown_driver(driver);
  302. /* sort attributes */
  303. qsort((void *)Map->site_att, Map->n_site_att, sizeof(struct site_att),
  304. site_att_cmp);
  305. return Map;
  306. }
  307. struct Map_info *G_sites_open_new(const char *name)
  308. {
  309. struct Map_info *Map;
  310. G_message(
  311. _("Dev note: Adapted sites library used for vector points. "
  312. "(module should be updated to GRASS 6 vector library)"));
  313. G_warning("Site/vector attributes ignored.");
  314. Map = (struct Map_info *)G_malloc(sizeof(struct Map_info));
  315. Vect_open_new(Map, name, 0);
  316. G_debug(1, "New vector map opened");
  317. return Map;
  318. }
  319. struct Map_info *G_fopen_sites_old(const char *name, const char *mapset)
  320. {
  321. return G_sites_open_old(name, mapset);
  322. }
  323. struct Map_info *G_fopen_sites_new(const char *name)
  324. {
  325. return G_sites_open_new(name);
  326. }
  327. /*!
  328. \brief Free memory for a Site struct
  329. \param s
  330. */
  331. void G_site_free_struct(Site * s)
  332. {
  333. if (s->dim_alloc)
  334. G_free(s->dim);
  335. if (s->str_alloc)
  336. G_free(s->str_att);
  337. if (s->dbl_alloc)
  338. G_free(s->dbl_att);
  339. G_free(s);
  340. return;
  341. }
  342. /*!
  343. \brief Allocate memory for a Site struct.
  344. cattype= -1 (no cat), CELL_TYPE, FCELL_TYPE, or DCELL_TYPE
  345. \return properly allocated site struct or NULL on error.
  346. */
  347. Site *G_site_new_struct(RASTER_MAP_TYPE cattype,
  348. int n_dim, int n_s_att, int n_d_att)
  349. {
  350. int i;
  351. Site *s;
  352. if (n_dim < 2 || n_s_att < 0 || n_d_att < 0)
  353. G_fatal_error(_("G_oldsite_new_struct: invalid # dims or fields"));
  354. if ((s = (Site *) G_malloc(sizeof(Site))) == NULL)
  355. return (Site *) NULL;
  356. s->cattype = cattype;
  357. s->ccat = s->fcat = s->dcat = 0;
  358. if (n_dim > 2) {
  359. if ((s->dim =
  360. (double *)G_malloc((n_dim - 2) * sizeof(double))) == NULL) {
  361. G_free(s);
  362. return (Site *) NULL;
  363. }
  364. }
  365. s->dim_alloc = n_dim - 2;
  366. if (n_d_att > 0) {
  367. if ((s->dbl_att =
  368. (double *)G_malloc(n_d_att * sizeof(double))) == NULL) {
  369. if (n_dim > 2)
  370. G_free(s->dim);
  371. G_free(s);
  372. return (Site *) NULL;
  373. }
  374. }
  375. s->dbl_alloc = n_d_att;
  376. if (n_s_att > 0) {
  377. if ((s->str_att =
  378. (char **)G_malloc(n_s_att * sizeof(char *))) == NULL) {
  379. if (n_d_att > 0)
  380. G_free(s->dbl_att);
  381. if (n_dim > 2)
  382. G_free(s->dim);
  383. G_free(s);
  384. return (Site *) NULL;
  385. }
  386. else
  387. for (i = 0; i < n_s_att; ++i)
  388. if ((s->str_att[i] =
  389. (char *)G_malloc(MAX_SITE_STRING * sizeof(char))) ==
  390. NULL) {
  391. while (--i)
  392. G_free(s->str_att[i]);
  393. G_free(s->str_att);
  394. if (n_d_att > 0)
  395. G_free(s->dbl_att);
  396. if (n_dim > 2)
  397. G_free(s->dim);
  398. G_free(s);
  399. return (Site *) NULL;
  400. }
  401. }
  402. s->str_alloc = n_s_att;
  403. return s;
  404. }
  405. /*!
  406. \brief Writes a site to file open on fptr
  407. */
  408. int G_oldsite_get(FILE * fptr, Site * s)
  409. {
  410. return G__oldsite_get(fptr, s, G_projection());
  411. }
  412. /*!
  413. \brief Get site (old version)
  414. \return 0 on success,
  415. \return -1 on EOF,
  416. \return -2 on other fatal error or insufficient data,
  417. \return 1 on format mismatch (extra data)
  418. */
  419. int G__oldsite_get(FILE * ptr, Site * s, int fmt)
  420. {
  421. char sbuf[MAX_SITE_LEN], *buf, *last, *p1, *p2;
  422. char ebuf[128], nbuf[128];
  423. int n = 0, d = 0, c = 0, dim = 0, err = 0, tmp;
  424. buf = sbuf;
  425. if ((buf = fgets(sbuf, 1024, ptr)) == (char *)NULL)
  426. return EOF;
  427. while ((*buf == '#' || !isdigit(*buf)) && *buf != '-' && *buf != '+')
  428. if ((buf = fgets(sbuf, 1024, ptr)) == (char *)NULL)
  429. return EOF;
  430. if (buf[strlen(buf) - 1] == '\n')
  431. buf[strlen(buf) - 1] = '\0';
  432. if (sscanf(buf, "%[^|]|%[^|]|%*[^\n]", ebuf, nbuf) < 2) {
  433. fprintf(stderr, "ERROR: ebuf %s nbuf %s\n", ebuf, nbuf);
  434. return -2;
  435. }
  436. if (!G_scan_northing(nbuf, &(s->north), fmt) ||
  437. !G_scan_easting(ebuf, &(s->east), fmt)) {
  438. fprintf(stderr, "ERROR: ebuf %s nbuf %s\n", ebuf, nbuf);
  439. return -2;
  440. }
  441. /* move pointer past easting and northing fields */
  442. if (NULL == (buf = strchr(buf, PIPE)))
  443. return -2;
  444. if (NULL == (buf = strchr(buf + 1, PIPE)))
  445. return -2;
  446. /* check for remaining dimensional fields */
  447. do {
  448. buf++;
  449. if (isnull(*buf))
  450. return (FOUND_ALL(s, n, dim, c, d) ? 0 : -2);
  451. last = buf;
  452. if (dim < s->dim_alloc) { /* should be more dims to read */
  453. if (sscanf(buf, "%lf|", &(s->dim[dim++])) < 1)
  454. return -2; /* no more dims, though expected */
  455. }
  456. else if (NULL != (p1 = strchr(buf, PIPE))) {
  457. if (NULL == (p2 = strchr(buf, DQUOTE)))
  458. err = 1; /* more dims, though none expected */
  459. else if (strlen(p1) > strlen(p2))
  460. err = 1; /* more dims, though none expected */
  461. }
  462. } while ((buf = strchr(buf, PIPE)) != NULL);
  463. buf = last;
  464. /* no more dimensions-now we parse attribute fields */
  465. while (!isnull(*buf)) {
  466. switch (*buf) {
  467. case '#': /* category field */
  468. if (n == 0) {
  469. switch (s->cattype) {
  470. case CELL_TYPE:
  471. if (sscanf(buf, "#%d", &s->ccat) == 1)
  472. n++;
  473. break;
  474. case FCELL_TYPE:
  475. if (sscanf(buf, "#%f", &s->fcat) == 1)
  476. n++;
  477. break;
  478. case DCELL_TYPE:
  479. if (sscanf(buf, "#%lf", &s->dcat) == 1)
  480. n++;
  481. break;
  482. default:
  483. err = 1; /* has cat, none expected */
  484. break;
  485. }
  486. }
  487. else {
  488. err = 1; /* extra cat */
  489. }
  490. /* move to beginning of next attribute */
  491. if ((buf = next_att(buf)) == (char *)NULL)
  492. return (FOUND_ALL(s, n, dim, c, d) ? err : -2);
  493. break;
  494. case '%': /* decimal attribute */
  495. if (d < s->dbl_alloc) {
  496. p1 = ++buf;
  497. errno = 0;
  498. s->dbl_att[d++] = strtod(buf, &p1);
  499. if (p1 == buf || errno == ERANGE) {
  500. /* replace with:
  501. * s->dbl_att[d - 1] = NAN
  502. * when we add NULL attribute support
  503. */
  504. return -2;
  505. }
  506. /* err = 0; Make sure this is zeroed */
  507. }
  508. else {
  509. err = 1; /* extra decimal */
  510. }
  511. if ((buf = next_att(buf)) == (char *)NULL) {
  512. return (FOUND_ALL(s, n, dim, c, d)) ? err : -2;
  513. }
  514. break;
  515. case '@': /* string attribute */
  516. if (isnull(*buf) || isnull(*(buf + 1)))
  517. return (FOUND_ALL(s, n, dim, c, d) ? err : -2);
  518. else
  519. buf++;
  520. default: /* defaults to string attribute */
  521. /* allow both prefixed and unprefixed strings */
  522. if (c < s->str_alloc) {
  523. if ((tmp = cleanse_string(buf)) > 0) {
  524. strncpy(s->str_att[c++], buf, tmp);
  525. buf += tmp;
  526. }
  527. else
  528. return (FOUND_ALL(s, n, dim, c, d) ? err : -2);
  529. }
  530. if ((buf = next_att(buf)) == (char *)NULL) {
  531. return (FOUND_ALL(s, n, dim, c, d) ? err : -2);
  532. }
  533. break;
  534. }
  535. }
  536. return (FOUND_ALL(s, n, dim, c, d) ? err : -2);
  537. }
  538. /*!
  539. \brief Tries to guess the format of a sites list (old version)
  540. The dimensionality, the presence/type of a category, and the number
  541. of string and decimal attributes) by reading the first record in the
  542. file.
  543. \return 0 on success,
  544. \return -1 on EOF,
  545. \return -2 for other error
  546. */
  547. int G_oldsite_describe(FILE * ptr, int *dims, int *cat, int *strs, int *dbls)
  548. {
  549. char sbuf[MAX_SITE_LEN], *buf;
  550. char ebuf[128], nbuf[128];
  551. int err;
  552. int itmp;
  553. float ftmp;
  554. if (G_ftell(ptr) != 0L) {
  555. G_warning(_("G_oldsite_describe() must be called "
  556. "immediately after G_fopen_sites_old()."));
  557. return -2;
  558. }
  559. *dims = *strs = *dbls = 0;
  560. *cat = -1;
  561. buf = sbuf;
  562. if ((buf = fgets(sbuf, 1024, ptr)) == (char *)NULL) {
  563. rewind(ptr);
  564. return EOF;
  565. }
  566. /* skip over comment & header lines */
  567. while ((*buf == '#' || !isdigit(*buf)) && *buf != '-' && *buf != '+')
  568. if ((buf = fgets(sbuf, 1024, ptr)) == (char *)NULL) {
  569. rewind(ptr);
  570. return EOF;
  571. }
  572. if (buf[strlen(buf) - 1] == '\n')
  573. buf[strlen(buf) - 1] = '\0';
  574. if ((err = sscanf(buf, "%[^|]|%[^|]|%*[^\n]", ebuf, nbuf)) < 2) {
  575. G_debug(1, "ebuf %s nbuf %s", ebuf, nbuf);
  576. rewind(ptr);
  577. return -2;
  578. }
  579. *dims = 2;
  580. /* move pointer past easting and northing fields */
  581. while (!ispipe(*buf) && !isnull(*buf))
  582. buf++;
  583. if (!isnull(*buf) && !isnull(*(buf + 1)))
  584. buf++;
  585. else {
  586. rewind(ptr);
  587. return -2;
  588. }
  589. while (!ispipe(*buf) && !isnull(*buf))
  590. buf++;
  591. if (!isnull(*buf) && !isnull(*(buf + 1)))
  592. buf++;
  593. else {
  594. rewind(ptr);
  595. return 0;
  596. }
  597. /* check for remaining dimensional fields */
  598. while (strchr(buf, PIPE) != (char *)NULL) {
  599. (*dims)++;
  600. while (!ispipe(*buf) && !isnull(*buf))
  601. buf++;
  602. if (isnull(*buf) || isnull(*(buf + 1))) {
  603. rewind(ptr);
  604. return 0;
  605. }
  606. if (!isnull(*(buf + 1)))
  607. buf++;
  608. else {
  609. rewind(ptr);
  610. return -2;
  611. }
  612. }
  613. /* no more dimensions-now we parse attribute fields */
  614. while (!isnull(*buf)) {
  615. switch (*buf) {
  616. case '#': /* category field */
  617. sscanf(buf, "#%s ", ebuf);
  618. if (strstr(ebuf, ".") == NULL && sscanf(ebuf, "%d", &itmp) == 1)
  619. *cat = CELL_TYPE;
  620. else if (strstr(ebuf, ".") != NULL &&
  621. sscanf(ebuf, "%f", &ftmp) == 1)
  622. *cat = FCELL_TYPE;
  623. else
  624. *cat = -1;
  625. /* move to beginning of next attribute */
  626. while (!isspace(*buf) && !isnull(*buf))
  627. buf++;
  628. if (isnull(*buf) || isnull(*(buf + 1))) {
  629. rewind(ptr);
  630. return 0;
  631. }
  632. else
  633. buf++;
  634. break;
  635. case '%': /* decimal attribute */
  636. (*dbls)++;
  637. /* move to beginning of next attribute */
  638. while (!isspace(*buf) && !isnull(*buf))
  639. buf++;
  640. if (isnull(*buf) || isnull(*(buf + 1))) {
  641. rewind(ptr);
  642. return 0;
  643. }
  644. else
  645. buf++;
  646. break;
  647. case '@': /* string attribute */
  648. if (isnull(*buf) || isnull(*(buf + 1))) {
  649. rewind(ptr);
  650. return 0;
  651. }
  652. else
  653. buf++;
  654. default: /* defaults to string attribute */
  655. /* allow both prefixed and unprefixed strings */
  656. if ((err = cleanse_string(buf)) > 0) {
  657. (*strs)++;
  658. buf += err;
  659. }
  660. /* move to beginning of next attribute */
  661. while (!isspace(*buf) && !isnull(*buf))
  662. buf++;
  663. if (isnull(*buf) || isnull(*(buf + 1))) {
  664. rewind(ptr);
  665. return 0;
  666. }
  667. else
  668. buf++;
  669. break;
  670. }
  671. }
  672. rewind(ptr);
  673. return 0;
  674. }
  675. /*!
  676. \brief Test if site is in region
  677. \return 1 if site is contained within region
  678. \return 0 otherwise
  679. */
  680. int G_site_in_region(const Site * site, const struct Cell_head *region)
  681. {
  682. /* northwest corner is in region, southeast corner is not. */
  683. double e_ing;
  684. e_ing = G_adjust_easting(site->east, region);
  685. if (e_ing >= region->west &&
  686. e_ing < region->east &&
  687. site->north <= region->north && site->north > region->south)
  688. return 1;
  689. return 0;
  690. }
  691. int cleanse_string(char *buf)
  692. {
  693. char *stop, *p, *p2;
  694. p = buf;
  695. /*
  696. * get rid of any SPACEs at beginning while ( !isspace(*buf) && *buf !=
  697. * (char) NULL) buf++; if (*buf == (char) NULL) return -1;
  698. */
  699. /* find where this string terminates */
  700. if (*buf != DQUOTE) { /* if no DQUOTEs, */
  701. stop = strchr(buf, SPACE); /* then SPACE separates */
  702. if (stop == (char *)NULL)
  703. return strlen(buf);
  704. else
  705. return (int)(stop - buf);
  706. }
  707. else { /* otherwise string is in DQUOTEs */
  708. /* but we must skip over escaped */
  709. /* (BSLASHed) DQUOTEs */
  710. if (*p == DQUOTE) {
  711. while (*p != '\0') { /* get rid of first DQUOTE */
  712. *p = *(p + 1);
  713. p++;
  714. }
  715. p = buf;
  716. stop = strchr(p + 1, DQUOTE);
  717. while (*(stop - 1) == BSLASH)
  718. stop = strchr(++stop, DQUOTE);
  719. }
  720. }
  721. /* remove backslashes between buf and stop */
  722. p = buf;
  723. while ((p = strchr(p, BSLASH)) != (char *)NULL && p <= stop) {
  724. p2 = p + 1;
  725. if (*p2 != '\0' && (*p2 == DQUOTE || *p2 == BSLASH)) {
  726. while (*p != '\0') {
  727. *p = *(p + 1);
  728. p++;
  729. }
  730. stop--;
  731. }
  732. p = p2;
  733. }
  734. return (int)(stop - buf);
  735. }
  736. char *next_att(const char *buf)
  737. {
  738. while (!isspace(*buf) && !isnull(*buf))
  739. buf++;
  740. if (isnull(*buf) || isnull(*(buf + 1)))
  741. return NULL;
  742. else
  743. while (isspace(*(buf + 1)) && !isnull(*(buf + 1)))
  744. buf++;
  745. buf++;
  746. return (char *)buf;
  747. }
  748. int G_oldsite_s_cmp(const void *a, const void *b)
  749. /* qsort() comparison function for sorting an array of
  750. site structures by first decimal attribute. */
  751. {
  752. return strcmp((*(char **)((*(Site **) a)->str_att)),
  753. (*(char **)((*(Site **) b)->str_att)));
  754. }
  755. /*!
  756. \brief Open site list (old version)
  757. Opens the existing site list file 'name' in the 'mapset'.
  758. \param name
  759. \param mapset mapset (empty for search path)
  760. \return pointer to FILE
  761. */
  762. FILE *G_oldsites_open_old(const char *name, const char *mapset)
  763. {
  764. return G_fopen_old("site_lists", name, mapset);
  765. }