sites.c 31 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273
  1. /*-
  2. * These functions and definitions support the site format for 5.0
  3. * (format proposed by Dave Gerdes):
  4. *
  5. * easting|northing|[z|[d4|]...][#category_int] [ [@attr_text OR %flt] ... ]
  6. *
  7. * to allow multidimensions (everything preceding the last '|') and any
  8. * number of text or numeric attribute fields.
  9. *
  10. * Author: James Darrell McCauley <mccauley@ecn.purdue.edu>
  11. * 31 Jan 1994
  12. */
  13. #include <ctype.h>
  14. #include <string.h>
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #include <errno.h>
  18. #include <grass/gis.h>
  19. #include <grass/site.h>
  20. #include <grass/dbmi.h>
  21. #include <grass/vector.h>
  22. #include <grass/glocale.h>
  23. #define DQUOTE '"'
  24. #define SPACE ' '
  25. #define BSLASH 92
  26. #define PIPE '|'
  27. #define ispipe(c) (c==PIPE)
  28. #define isnull(c) (c=='\0')
  29. #define isquote(c) (c==DQUOTE)
  30. #define isbslash(c) (c==BSLASH)
  31. static int format_double(double, char *);
  32. static char *next_att(const char *);
  33. static int cleanse_string(char *);
  34. static int site_att_cmp(const void *pa, const void *pb)
  35. {
  36. const struct site_att *a = pa, *b = pb;
  37. return a->cat - b->cat;
  38. }
  39. /*-
  40. * Reads ptr and returns 0 on success,
  41. * -1 on EOF,
  42. * -2 on other fatal error or insufficient data,
  43. * 1 on format mismatch (extra data)
  44. */
  45. int G_site_get(struct Map_info *Map, Site * s)
  46. {
  47. int i, type, cat;
  48. static struct line_pnts *Points = NULL;
  49. static struct line_cats *Cats = NULL;
  50. struct site_att *sa;
  51. if (Points == NULL)
  52. Points = Vect_new_line_struct();
  53. if (Cats == NULL)
  54. Cats = Vect_new_cats_struct();
  55. while (1) {
  56. type = Vect_read_next_line(Map, Points, Cats);
  57. if (type == -1)
  58. return -2; /* Error */
  59. if (type == -2)
  60. return -1; /* EOF */
  61. if (type != GV_POINT)
  62. continue; /* Is not point */
  63. Vect_cat_get(Cats, 1, &cat);
  64. G_debug(4, "Site: %f|%f|%f|#%d", Points->x[0], Points->y[0],
  65. Points->z[0], cat);
  66. s->east = Points->x[0];
  67. s->north = Points->y[0];
  68. if (Vect_is_3d(Map))
  69. s->dim[0] = Points->z[0];
  70. s->ccat = cat;
  71. /* find att */
  72. if (Map->n_site_att > 0) {
  73. sa = (struct site_att *) bsearch((void *)&cat, (void *)Map->site_att,
  74. Map->n_site_att, sizeof(struct site_att),
  75. site_att_cmp);
  76. if (sa == NULL) {
  77. G_warning(_("Attributes for category %d not found"), cat);
  78. for (i = 0; i < Map->n_site_dbl; i++)
  79. s->dbl_att[i] = 0;
  80. for (i = 0; i < Map->n_site_str; i++)
  81. strncpy(s->str_att[i], "", MAX_SITE_STRING);
  82. }
  83. else {
  84. for (i = 0; i < Map->n_site_dbl; i++)
  85. s->dbl_att[i] = sa->dbl[i];
  86. for (i = 0; i < Map->n_site_str; i++)
  87. strncpy(s->str_att[i], sa->str[i], MAX_SITE_STRING);
  88. }
  89. }
  90. return 0;
  91. }
  92. }
  93. /* Writes a site to file open on fptr. */
  94. int G_site_put(struct Map_info *Map, const Site * s)
  95. {
  96. static struct line_pnts *Points = NULL;
  97. static struct line_cats *Cats = NULL;
  98. if (Points == NULL)
  99. Points = Vect_new_line_struct();
  100. if (Cats == NULL)
  101. Cats = Vect_new_cats_struct();
  102. Vect_reset_line(Points);
  103. Vect_reset_cats(Cats);
  104. /* no 3D support so far: s->dim[0] */
  105. Vect_append_point(Points, s->east, s->north, 0.0);
  106. G_debug(4, "cattype = %d", s->cattype);
  107. if (s->cattype == FCELL_TYPE || s->cattype == DCELL_TYPE)
  108. G_fatal_error(_("Category must be integer"));
  109. if (s->cattype == CELL_TYPE)
  110. Vect_cat_set(Cats, 1, s->ccat);
  111. Vect_write_line(Map, GV_POINT, Points, Cats);
  112. return 0;
  113. }
  114. /*-
  115. * Tries to guess the format of a sites list (the dimensionality,
  116. * the presence/type of a category, and the number of string and decimal
  117. * attributes) by reading the first record in the file.
  118. * Reads ptr and returns 0 on success,
  119. * -1 on EOF,
  120. * -2 for other error.
  121. */
  122. int G_site_describe(struct Map_info *Map, int *dims, int *cat, int *strs,
  123. int *dbls)
  124. {
  125. if (Vect_is_3d(Map)) {
  126. G_debug(1, "Vector is 3D -> number of site dimensions is 3");
  127. *dims = 3;
  128. }
  129. else {
  130. G_debug(1, "Vector is 2D -> number of site dimensions is 2");
  131. *dims = 2;
  132. }
  133. *cat = CELL_TYPE;
  134. /* attributes ignored for now, later read from DB */
  135. *dbls = Map->n_site_dbl;
  136. *strs = Map->n_site_str;
  137. return 0;
  138. }
  139. /*-
  140. * Writes site_head struct.
  141. */
  142. int G_site_put_head(struct Map_info *Map, Site_head * head)
  143. {
  144. static char buf[128];
  145. if (head->name != NULL)
  146. Vect_set_map_name(Map, head->name);
  147. /* crashes:
  148. if (head->desc!=NULL)
  149. Vect_set_comment (Map, head->desc);
  150. */
  151. /*
  152. if (head->form!=NULL)
  153. fprintf(ptr,"form|%s\n",head->form);
  154. if (head->labels!=NULL)
  155. fprintf(ptr,"labels|%s\n",head->labels);
  156. */
  157. /* time could be in (char *) stime, (struct TimeStamp *) time,
  158. both, or neither */
  159. if (head->stime != NULL || head->time != NULL) {
  160. if (head->time != NULL) { /* TimeStamp struct has precendence */
  161. G_format_timestamp(head->time, buf);
  162. Vect_set_date(Map, buf);
  163. }
  164. else if (head->stime != NULL) { /* next check string */
  165. if (head->time == NULL) {
  166. if ((head->time =
  167. (struct TimeStamp *)G_malloc(sizeof(struct TimeStamp)))
  168. == NULL)
  169. G_fatal_error(_("Memory error in writing timestamp"));
  170. else if (G_scan_timestamp(head->time, head->stime) < 0) {
  171. G_warning(_("Illegal TimeStamp string"));
  172. return -1; /* added to prevent crash 5/2000 MN */
  173. }
  174. }
  175. G_format_timestamp(head->time, buf);
  176. head->stime = G_store(buf);
  177. Vect_set_date(Map, head->stime);
  178. }
  179. }
  180. return 0;
  181. }
  182. /*-
  183. * Fills in site_head struct.
  184. */
  185. int G_site_get_head(struct Map_info *Map, Site_head * head)
  186. {
  187. head->name = Vect_get_name(Map);
  188. head->desc = Vect_get_comment(Map);
  189. head->form = NULL;
  190. head->labels = NULL;
  191. /* head->stime = Vect_get_date(Map); *//* crashes, G_scan_timestamp() needed? */
  192. head->stime = NULL;
  193. head->time = NULL;
  194. if (head->stime && strlen(head->stime) > 0) {
  195. if ((head->time =
  196. (struct TimeStamp *)G_malloc(sizeof(struct TimeStamp))) == NULL)
  197. G_fatal_error(_("Memory error in allocating timestamp"));
  198. if (G_scan_timestamp(head->time, head->stime) < 0) {
  199. G_warning(datetime_error_msg());
  200. head->time = NULL;
  201. head->stime = NULL;
  202. }
  203. }
  204. return 0;
  205. }
  206. /*-************************************************************************
  207. *
  208. * struct Map_info *
  209. * G_sites_open_old (name, mapset)
  210. * opens the existing site list file 'name' in the 'mapset'
  211. *
  212. * struct Map_info *
  213. * G_sites_open_new (name)
  214. * opens a new site list file 'name' in the current mapset
  215. *
  216. * parms
  217. * char *name map file name
  218. * char *mapset mapset containing map "name"
  219. *
  220. **********************************************************************/
  221. const char *G_find_sites(char *name, const char *mapset)
  222. {
  223. return G_find_vector(name, mapset);
  224. }
  225. const char *G_find_sites2(const char *name, const char *mapset)
  226. {
  227. return G_find_vector2(name, mapset);
  228. }
  229. struct Map_info *G_sites_open_old(const char *name, const char *mapset)
  230. {
  231. struct Map_info *Map;
  232. struct field_info *fi;
  233. int more, nrows, row, ncols, col, ndbl, nstr, adbl, astr, ctype;
  234. struct site_att *sa;
  235. dbDriver *driver;
  236. dbString stmt;
  237. dbCursor cursor;
  238. dbTable *table;
  239. dbColumn *column;
  240. dbValue *value;
  241. G_message(
  242. _("Dev note: Adapted sites library used for vector points. "
  243. "(module should be updated to GRASS 6 vector library)"));
  244. Map = (struct Map_info *)G_malloc(sizeof(struct Map_info));
  245. Vect_set_open_level(1);
  246. Vect_open_old(Map, name, mapset);
  247. G_debug(1, "Vector map opened");
  248. /* Load attributes */
  249. Map->site_att = NULL;
  250. Map->n_site_att = 0;
  251. Map->n_site_dbl = 0;
  252. Map->n_site_str = 0;
  253. fi = Vect_get_field(Map, 1);
  254. if (fi == NULL) { /* not attribute table */
  255. G_debug(1, "No attribute table");
  256. return Map;
  257. }
  258. driver = db_start_driver_open_database(fi->driver, fi->database);
  259. if (driver == NULL)
  260. G_fatal_error(_("Unable to open database <%s> by driver <%s>"),
  261. fi->database,
  262. fi->driver);
  263. db_init_string(&stmt);
  264. db_set_string(&stmt, "select * from ");
  265. db_append_string(&stmt, fi->table);
  266. if (db_open_select_cursor(driver, &stmt, &cursor, DB_SEQUENTIAL) != DB_OK)
  267. G_fatal_error(_("Unable to open select cursor: '%s'"),
  268. db_get_string(&stmt));
  269. nrows = db_get_num_rows(&cursor);
  270. G_debug(1, "%d rows selected from vector attribute table", nrows);
  271. Map->site_att = (struct site_att *) malloc(nrows * sizeof(struct site_att));
  272. Map->n_site_att = nrows;
  273. table = db_get_cursor_table(&cursor);
  274. ncols = db_get_table_number_of_columns(table);
  275. row = 0;
  276. adbl = astr = 0;
  277. while (1) {
  278. if (db_fetch(&cursor, DB_NEXT, &more) != DB_OK)
  279. G_fatal_error(_("Cannot fetch row"));
  280. if (!more)
  281. break;
  282. /* Get number of each type */
  283. if (row == 0) {
  284. for (col = 0; col < ncols; col++) {
  285. column = db_get_table_column(table, col);
  286. ctype = db_sqltype_to_Ctype(db_get_column_sqltype(column));
  287. if (strcmp(db_get_column_name(column), fi->key) == 0)
  288. continue;
  289. switch (ctype) {
  290. case DB_C_TYPE_INT:
  291. case DB_C_TYPE_DOUBLE:
  292. adbl++;
  293. break;
  294. case DB_C_TYPE_STRING:
  295. case DB_C_TYPE_DATETIME:
  296. astr++;
  297. break;
  298. }
  299. }
  300. Map->n_site_dbl = adbl;
  301. Map->n_site_str = astr;
  302. G_debug(1, "adbl = %d astr = %d", adbl, astr);
  303. }
  304. sa = &(Map->site_att[row]);
  305. sa->dbl = (double *)malloc(adbl * sizeof(double));
  306. sa->str = (char **)malloc(astr * sizeof(char *));
  307. ndbl = nstr = 0;
  308. for (col = 0; col < ncols; col++) {
  309. column = db_get_table_column(table, col);
  310. ctype = db_sqltype_to_Ctype(db_get_column_sqltype(column));
  311. value = db_get_column_value(column);
  312. if (strcmp(db_get_column_name(column), fi->key) == 0) {
  313. sa->cat = db_get_value_int(value);
  314. }
  315. else {
  316. switch (ctype) {
  317. case DB_C_TYPE_INT:
  318. sa->dbl[ndbl] = db_get_value_int(value);
  319. ndbl++;
  320. break;
  321. case DB_C_TYPE_DOUBLE:
  322. sa->dbl[ndbl] = db_get_value_double(value);
  323. ndbl++;
  324. break;
  325. case DB_C_TYPE_STRING:
  326. sa->str[nstr] = G_store(db_get_value_string(value));
  327. nstr++;
  328. break;
  329. case DB_C_TYPE_DATETIME:
  330. sa->str[nstr] = ""; /* TODO */
  331. nstr++;
  332. break;
  333. }
  334. }
  335. }
  336. row++;
  337. }
  338. db_close_database_shutdown_driver(driver);
  339. /* sort attributes */
  340. qsort((void *)Map->site_att, Map->n_site_att, sizeof(struct site_att),
  341. site_att_cmp);
  342. return Map;
  343. }
  344. struct Map_info *G_sites_open_new(const char *name)
  345. {
  346. struct Map_info *Map;
  347. G_message(
  348. _("Dev note: Adapted sites library used for vector points. "
  349. "(module should be updated to GRASS 6 vector library)"));
  350. G_warning("Site/vector attributes ignored.");
  351. Map = (struct Map_info *)G_malloc(sizeof(struct Map_info));
  352. Vect_open_new(Map, name, 0);
  353. G_debug(1, "New vector map opened");
  354. return Map;
  355. }
  356. void G_sites_close(struct Map_info *Map)
  357. {
  358. int i, j;
  359. if (Map->mode == GV_MODE_WRITE || Map->mode == GV_MODE_RW)
  360. Vect_build(Map);
  361. Vect_close(Map);
  362. for (i = 0; i < Map->n_site_att; i++) {
  363. free(Map->site_att[i].dbl);
  364. for (j = 0; j < Map->n_site_str; j++)
  365. free(Map->site_att[i].str[j]);
  366. free(Map->site_att[i].str);
  367. }
  368. free(Map->site_att);
  369. G_free(Map);
  370. }
  371. /*********************************************/
  372. /* The following functions are obsolete. */
  373. /* They are retained here only for backwards */
  374. /* compatability while porting applications */
  375. /*********************************************/
  376. struct Map_info *G_fopen_sites_old(const char *name, const char *mapset)
  377. {
  378. return G_sites_open_old(name, mapset);
  379. }
  380. struct Map_info *G_fopen_sites_new(const char *name)
  381. {
  382. return G_sites_open_new(name);
  383. }
  384. int G_get_site(struct Map_info *fd, double *east, double *north, char **desc)
  385. {
  386. /* TODO ? */
  387. G_fatal_error("G_get_site() not yet updated.");
  388. return -1;
  389. }
  390. int G_put_site(struct Map_info *fd, double east, double north,
  391. const char *desc)
  392. {
  393. /* TODO ? */
  394. G_fatal_error("G_put_site() not yet updated.");
  395. return 0;
  396. }
  397. /* Functions moved here from lib/gis/sites.c */
  398. void G_site_free_struct(Site * s)
  399. /* Free memory for a Site struct */
  400. {
  401. if (s->dim_alloc)
  402. G_free(s->dim);
  403. if (s->str_alloc)
  404. G_free(s->str_att);
  405. if (s->dbl_alloc)
  406. G_free(s->dbl_att);
  407. G_free(s);
  408. return;
  409. }
  410. Site *G_site_new_struct(RASTER_MAP_TYPE cattype,
  411. int n_dim, int n_s_att, int n_d_att)
  412. /* Allocate memory for a Site struct. Returns a properly allocated
  413. site struct or NULL on error.
  414. cattype= -1 (no cat), CELL_TYPE, FCELL_TYPE, or DCELL_TYPE
  415. */
  416. {
  417. int i;
  418. Site *s;
  419. if (n_dim < 2 || n_s_att < 0 || n_d_att < 0)
  420. G_fatal_error(_("G_oldsite_new_struct: invalid # dims or fields"));
  421. if ((s = (Site *) G_malloc(sizeof(Site))) == NULL)
  422. return (Site *) NULL;
  423. s->cattype = cattype;
  424. s->ccat = s->fcat = s->dcat = 0;
  425. if (n_dim > 2) {
  426. if ((s->dim =
  427. (double *)G_malloc((n_dim - 2) * sizeof(double))) == NULL) {
  428. G_free(s);
  429. return (Site *) NULL;
  430. }
  431. }
  432. s->dim_alloc = n_dim - 2;
  433. if (n_d_att > 0) {
  434. if ((s->dbl_att =
  435. (double *)G_malloc(n_d_att * sizeof(double))) == NULL) {
  436. if (n_dim > 2)
  437. G_free(s->dim);
  438. G_free(s);
  439. return (Site *) NULL;
  440. }
  441. }
  442. s->dbl_alloc = n_d_att;
  443. if (n_s_att > 0) {
  444. if ((s->str_att =
  445. (char **)G_malloc(n_s_att * sizeof(char *))) == NULL) {
  446. if (n_d_att > 0)
  447. G_free(s->dbl_att);
  448. if (n_dim > 2)
  449. G_free(s->dim);
  450. G_free(s);
  451. return (Site *) NULL;
  452. }
  453. else
  454. for (i = 0; i < n_s_att; ++i)
  455. if ((s->str_att[i] =
  456. (char *)G_malloc(MAX_SITE_STRING * sizeof(char))) ==
  457. NULL) {
  458. while (--i)
  459. G_free(s->str_att[i]);
  460. G_free(s->str_att);
  461. if (n_d_att > 0)
  462. G_free(s->dbl_att);
  463. if (n_dim > 2)
  464. G_free(s->dim);
  465. G_free(s);
  466. return (Site *) NULL;
  467. }
  468. }
  469. s->str_alloc = n_s_att;
  470. return s;
  471. }
  472. #define FOUND_ALL(s,n,dim,c,d) (((s->cattype != -1 && !n) || \
  473. (dim < s->dim_alloc) || \
  474. (c < s->str_alloc) || \
  475. (d < s->dbl_alloc))?0:1)
  476. int G_oldsite_get(FILE * fptr, Site * s)
  477. /* Writes a site to file open on fptr. */
  478. {
  479. return G__oldsite_get(fptr, s, G_projection());
  480. }
  481. int G__oldsite_get(FILE * ptr, Site * s, int fmt)
  482. /*-
  483. * Reads ptr and returns 0 on success,
  484. * -1 on EOF,
  485. * -2 on other fatal error or insufficient data,
  486. * 1 on format mismatch (extra data)
  487. */
  488. {
  489. char sbuf[MAX_SITE_LEN], *buf, *last, *p1, *p2;
  490. char ebuf[128], nbuf[128];
  491. int n = 0, d = 0, c = 0, dim = 0, err = 0, tmp;
  492. buf = sbuf;
  493. if ((buf = fgets(sbuf, 1024, ptr)) == (char *)NULL)
  494. return EOF;
  495. while ((*buf == '#' || !isdigit(*buf)) && *buf != '-' && *buf != '+')
  496. if ((buf = fgets(sbuf, 1024, ptr)) == (char *)NULL)
  497. return EOF;
  498. if (buf[strlen(buf) - 1] == '\n')
  499. buf[strlen(buf) - 1] = '\0';
  500. if (sscanf(buf, "%[^|]|%[^|]|%*[^\n]", ebuf, nbuf) < 2) {
  501. fprintf(stderr, "ERROR: ebuf %s nbuf %s\n", ebuf, nbuf);
  502. return -2;
  503. }
  504. if (!G_scan_northing(nbuf, &(s->north), fmt) ||
  505. !G_scan_easting(ebuf, &(s->east), fmt)) {
  506. fprintf(stderr, "ERROR: ebuf %s nbuf %s\n", ebuf, nbuf);
  507. return -2;
  508. }
  509. /* move pointer past easting and northing fields */
  510. if (NULL == (buf = strchr(buf, PIPE)))
  511. return -2;
  512. if (NULL == (buf = strchr(buf + 1, PIPE)))
  513. return -2;
  514. /* check for remaining dimensional fields */
  515. do {
  516. buf++;
  517. if (isnull(*buf))
  518. return (FOUND_ALL(s, n, dim, c, d) ? 0 : -2);
  519. last = buf;
  520. if (dim < s->dim_alloc) { /* should be more dims to read */
  521. if (sscanf(buf, "%lf|", &(s->dim[dim++])) < 1)
  522. return -2; /* no more dims, though expected */
  523. }
  524. else if (NULL != (p1 = strchr(buf, PIPE))) {
  525. if (NULL == (p2 = strchr(buf, DQUOTE)))
  526. err = 1; /* more dims, though none expected */
  527. else if (strlen(p1) > strlen(p2))
  528. err = 1; /* more dims, though none expected */
  529. }
  530. } while ((buf = strchr(buf, PIPE)) != NULL);
  531. buf = last;
  532. /* no more dimensions-now we parse attribute fields */
  533. while (!isnull(*buf)) {
  534. switch (*buf) {
  535. case '#': /* category field */
  536. if (n == 0) {
  537. switch (s->cattype) {
  538. case CELL_TYPE:
  539. if (sscanf(buf, "#%d", &s->ccat) == 1)
  540. n++;
  541. break;
  542. case FCELL_TYPE:
  543. if (sscanf(buf, "#%f", &s->fcat) == 1)
  544. n++;
  545. break;
  546. case DCELL_TYPE:
  547. if (sscanf(buf, "#%lf", &s->dcat) == 1)
  548. n++;
  549. break;
  550. default:
  551. err = 1; /* has cat, none expected */
  552. break;
  553. }
  554. }
  555. else {
  556. err = 1; /* extra cat */
  557. }
  558. /* move to beginning of next attribute */
  559. if ((buf = next_att(buf)) == (char *)NULL)
  560. return (FOUND_ALL(s, n, dim, c, d) ? err : -2);
  561. break;
  562. case '%': /* decimal attribute */
  563. if (d < s->dbl_alloc) {
  564. p1 = ++buf;
  565. errno = 0;
  566. s->dbl_att[d++] = strtod(buf, &p1);
  567. if (p1 == buf || errno == ERANGE) {
  568. /* replace with:
  569. * s->dbl_att[d - 1] = NAN
  570. * when we add NULL attribute support
  571. */
  572. return -2;
  573. }
  574. /* err = 0; Make sure this is zeroed */
  575. }
  576. else {
  577. err = 1; /* extra decimal */
  578. }
  579. if ((buf = next_att(buf)) == (char *)NULL) {
  580. return (FOUND_ALL(s, n, dim, c, d)) ? err : -2;
  581. }
  582. break;
  583. case '@': /* string attribute */
  584. if (isnull(*buf) || isnull(*(buf + 1)))
  585. return (FOUND_ALL(s, n, dim, c, d) ? err : -2);
  586. else
  587. buf++;
  588. default: /* defaults to string attribute */
  589. /* allow both prefixed and unprefixed strings */
  590. if (c < s->str_alloc) {
  591. if ((tmp = cleanse_string(buf)) > 0) {
  592. strncpy(s->str_att[c++], buf, tmp);
  593. buf += tmp;
  594. }
  595. else
  596. return (FOUND_ALL(s, n, dim, c, d) ? err : -2);
  597. }
  598. if ((buf = next_att(buf)) == (char *)NULL) {
  599. return (FOUND_ALL(s, n, dim, c, d) ? err : -2);
  600. }
  601. break;
  602. }
  603. }
  604. return (FOUND_ALL(s, n, dim, c, d) ? err : -2);
  605. }
  606. int G_oldsite_describe(FILE * ptr, int *dims, int *cat, int *strs, int *dbls)
  607. /*-
  608. * Tries to guess the format of a sites list (the dimensionality,
  609. * the presence/type of a category, and the number of string and decimal
  610. * attributes) by reading the first record in the file.
  611. * Reads ptr and returns 0 on success,
  612. * -1 on EOF,
  613. * -2 for other error.
  614. */
  615. {
  616. char sbuf[MAX_SITE_LEN], *buf;
  617. char ebuf[128], nbuf[128];
  618. int err;
  619. int itmp;
  620. float ftmp;
  621. if (G_ftell(ptr) != 0L) {
  622. fprintf(stderr,
  623. "\nPROGRAMMER ERROR: G_oldsite_describe() must be called\n");
  624. fprintf(stderr, " immediately after G_fopen_sites_old()\n");
  625. return -2;
  626. }
  627. *dims = *strs = *dbls = 0;
  628. *cat = -1;
  629. buf = sbuf;
  630. if ((buf = fgets(sbuf, 1024, ptr)) == (char *)NULL) {
  631. rewind(ptr);
  632. return EOF;
  633. }
  634. /* skip over comment & header lines */
  635. while ((*buf == '#' || !isdigit(*buf)) && *buf != '-' && *buf != '+')
  636. if ((buf = fgets(sbuf, 1024, ptr)) == (char *)NULL) {
  637. rewind(ptr);
  638. return EOF;
  639. }
  640. if (buf[strlen(buf) - 1] == '\n')
  641. buf[strlen(buf) - 1] = '\0';
  642. if ((err = sscanf(buf, "%[^|]|%[^|]|%*[^\n]", ebuf, nbuf)) < 2) {
  643. fprintf(stderr, "ERROR: ebuf %s nbuf %s\n", ebuf, nbuf);
  644. rewind(ptr);
  645. return -2;
  646. }
  647. *dims = 2;
  648. /* move pointer past easting and northing fields */
  649. while (!ispipe(*buf) && !isnull(*buf))
  650. buf++;
  651. if (!isnull(*buf) && !isnull(*(buf + 1)))
  652. buf++;
  653. else {
  654. rewind(ptr);
  655. return -2;
  656. }
  657. while (!ispipe(*buf) && !isnull(*buf))
  658. buf++;
  659. if (!isnull(*buf) && !isnull(*(buf + 1)))
  660. buf++;
  661. else {
  662. rewind(ptr);
  663. return 0;
  664. }
  665. /* check for remaining dimensional fields */
  666. while (strchr(buf, PIPE) != (char *)NULL) {
  667. (*dims)++;
  668. while (!ispipe(*buf) && !isnull(*buf))
  669. buf++;
  670. if (isnull(*buf) || isnull(*(buf + 1))) {
  671. rewind(ptr);
  672. return 0;
  673. }
  674. if (!isnull(*(buf + 1)))
  675. buf++;
  676. else {
  677. rewind(ptr);
  678. return -2;
  679. }
  680. }
  681. /* no more dimensions-now we parse attribute fields */
  682. while (!isnull(*buf)) {
  683. switch (*buf) {
  684. case '#': /* category field */
  685. sscanf(buf, "#%s ", ebuf);
  686. if (strstr(ebuf, ".") == NULL && sscanf(ebuf, "%d", &itmp) == 1)
  687. *cat = CELL_TYPE;
  688. else if (strstr(ebuf, ".") != NULL &&
  689. sscanf(ebuf, "%f", &ftmp) == 1)
  690. *cat = FCELL_TYPE;
  691. else
  692. *cat = -1;
  693. /* move to beginning of next attribute */
  694. while (!isspace(*buf) && !isnull(*buf))
  695. buf++;
  696. if (isnull(*buf) || isnull(*(buf + 1))) {
  697. rewind(ptr);
  698. return 0;
  699. }
  700. else
  701. buf++;
  702. break;
  703. case '%': /* decimal attribute */
  704. (*dbls)++;
  705. /* move to beginning of next attribute */
  706. while (!isspace(*buf) && !isnull(*buf))
  707. buf++;
  708. if (isnull(*buf) || isnull(*(buf + 1))) {
  709. rewind(ptr);
  710. return 0;
  711. }
  712. else
  713. buf++;
  714. break;
  715. case '@': /* string attribute */
  716. if (isnull(*buf) || isnull(*(buf + 1))) {
  717. rewind(ptr);
  718. return 0;
  719. }
  720. else
  721. buf++;
  722. default: /* defaults to string attribute */
  723. /* allow both prefixed and unprefixed strings */
  724. if ((err = cleanse_string(buf)) > 0) {
  725. (*strs)++;
  726. buf += err;
  727. }
  728. /* move to beginning of next attribute */
  729. while (!isspace(*buf) && !isnull(*buf))
  730. buf++;
  731. if (isnull(*buf) || isnull(*(buf + 1))) {
  732. rewind(ptr);
  733. return 0;
  734. }
  735. else
  736. buf++;
  737. break;
  738. }
  739. }
  740. rewind(ptr);
  741. return 0;
  742. }
  743. int G_site_in_region(const Site * site, const struct Cell_head *region)
  744. /* returns 1 if site is contained within region, 0 otherwise */
  745. {
  746. /* northwest corner is in region, southeast corner is not. */
  747. double e_ing;
  748. e_ing = G_adjust_easting(site->east, region);
  749. if (e_ing >= region->west &&
  750. e_ing < region->east &&
  751. site->north <= region->north && site->north > region->south)
  752. return 1;
  753. return 0;
  754. }
  755. static int format_double(double value, char *buf)
  756. {
  757. sprintf(buf, "%.8f", value);
  758. G_trim_decimal(buf);
  759. return 0;
  760. }
  761. int cleanse_string(char *buf)
  762. {
  763. char *stop, *p, *p2;
  764. p = buf;
  765. /*
  766. * get rid of any SPACEs at beginning while ( !isspace(*buf) && *buf !=
  767. * (char) NULL) buf++; if (*buf == (char) NULL) return -1;
  768. */
  769. /* find where this string terminates */
  770. if (*buf != DQUOTE) { /* if no DQUOTEs, */
  771. stop = strchr(buf, SPACE); /* then SPACE separates */
  772. if (stop == (char *)NULL)
  773. return strlen(buf);
  774. else
  775. return (int)(stop - buf);
  776. }
  777. else { /* otherwise string is in DQUOTEs */
  778. /* but we must skip over escaped */
  779. /* (BSLASHed) DQUOTEs */
  780. if (*p == DQUOTE) {
  781. while (*p != '\0') { /* get rid of first DQUOTE */
  782. *p = *(p + 1);
  783. p++;
  784. }
  785. p = buf;
  786. stop = strchr(p + 1, DQUOTE);
  787. while (*(stop - 1) == BSLASH)
  788. stop = strchr(++stop, DQUOTE);
  789. }
  790. }
  791. /* remove backslashes between buf and stop */
  792. p = buf;
  793. while ((p = strchr(p, BSLASH)) != (char *)NULL && p <= stop) {
  794. p2 = p + 1;
  795. if (*p2 != '\0' && (*p2 == DQUOTE || *p2 == BSLASH)) {
  796. while (*p != '\0') {
  797. *p = *(p + 1);
  798. p++;
  799. }
  800. stop--;
  801. }
  802. p = p2;
  803. }
  804. return (int)(stop - buf);
  805. }
  806. static char *next_att(const char *buf)
  807. {
  808. while (!isspace(*buf) && !isnull(*buf))
  809. buf++;
  810. if (isnull(*buf) || isnull(*(buf + 1)))
  811. return NULL;
  812. else
  813. while (isspace(*(buf + 1)) && !isnull(*(buf + 1)))
  814. buf++;
  815. buf++;
  816. return (char *)buf;
  817. }
  818. int G_site_c_cmp(const void *a, const void *b)
  819. /* qsort() comparison function for sorting an array of
  820. site structures by category. */
  821. {
  822. int result = 0; /* integer to be returned */
  823. double diff = 0;
  824. switch ((*(Site **) a)->cattype) {
  825. case CELL_TYPE:
  826. diff = (double)(*(Site **) a)->ccat - (*(Site **) b)->ccat;
  827. break;
  828. case FCELL_TYPE:
  829. diff = (double)(*(Site **) a)->fcat - (*(Site **) b)->fcat;
  830. break;
  831. case DCELL_TYPE:
  832. diff = (double)(*(Site **) a)->dcat - (*(Site **) b)->dcat;
  833. break;
  834. }
  835. if (diff < 0.0)
  836. result = -1;
  837. else if (diff > 0.0)
  838. result = 1;
  839. return result;
  840. }
  841. int G_site_d_cmp(const void *a, const void *b)
  842. /* qsort() comparison function for sorting an array of
  843. site structures by first decimal attribute. */
  844. {
  845. int result = 0; /* integer to be returned */
  846. double diff;
  847. diff = (*(Site **) a)->dbl_att[0] - (*(Site **) b)->dbl_att[0];
  848. if (diff < 0.0)
  849. result = -1;
  850. else if (diff > 0.0)
  851. result = 1;
  852. return result;
  853. }
  854. int G_oldsite_s_cmp(const void *a, const void *b)
  855. /* qsort() comparison function for sorting an array of
  856. site structures by first decimal attribute. */
  857. {
  858. return strcmp((*(char **)((*(Site **) a)->str_att)),
  859. (*(char **)((*(Site **) b)->str_att)));
  860. }
  861. /*-************************************************************************
  862. *
  863. * FILE *
  864. * G_oldsites_open_old (name, mapset)
  865. * opens the existing site list file 'name' in the 'mapset'
  866. *
  867. * parms
  868. * char *name map file name
  869. * char *mapset mapset containing map "name"
  870. *
  871. **********************************************************************/
  872. FILE *G_oldsites_open_old(const char *name, const char *mapset)
  873. {
  874. return G_fopen_old("site_lists", name, mapset);
  875. }
  876. FILE *G_oldsites_open_new(const char *name)
  877. {
  878. return G_fopen_new("site_lists", name);
  879. }
  880. /*********************************************/
  881. /* The following functions are obsolete. */
  882. /* They are retained here only for backwards */
  883. /* compatability while porting applications */
  884. /*********************************************/
  885. char *G_site_format(const Site * s, const char *fs, int id)
  886. /* sprintf analog to G_site_put with the addition of a field separator fs
  887. and option of printing site attribute identifiers
  888. */
  889. {
  890. char ebuf[MAX_SITE_STRING], nbuf[MAX_SITE_STRING];
  891. char xbuf[MAX_SITE_STRING];
  892. const char *nfs;
  893. char *buf;
  894. int fmt, i, j, k;
  895. buf = (char *)G_malloc(MAX_SITE_LEN * sizeof(char));
  896. fmt = G_projection();
  897. G_format_northing(s->north, nbuf, fmt);
  898. G_format_easting(s->east, ebuf, fmt);
  899. nfs = (char *)((fs == (char *)NULL) ? "|" : fs);
  900. sprintf(buf, "%s%s%s", ebuf, nfs, nbuf);
  901. for (i = 0; i < s->dim_alloc; ++i) {
  902. format_double(s->dim[i], nbuf);
  903. sprintf(xbuf, "%s%s", nfs, nbuf);
  904. strcat(buf, xbuf);
  905. }
  906. nfs = (fs == NULL) ? " " : fs;
  907. switch (s->cattype) {
  908. case CELL_TYPE:
  909. sprintf(xbuf, "%s%s%d ", nfs, ((id == 0) ? "" : "#"), (int)s->ccat);
  910. strcat(buf, xbuf);
  911. break;
  912. case FCELL_TYPE:
  913. case DCELL_TYPE:
  914. sprintf(xbuf, "%s%s%g ", nfs, ((id == 0) ? "" : "#"), (float)s->fcat);
  915. strcat(buf, xbuf);
  916. break;
  917. }
  918. for (i = 0; i < s->dbl_alloc; ++i) {
  919. format_double(s->dbl_att[i], nbuf);
  920. sprintf(xbuf, "%s%s%s", nfs, ((id == 0) ? "" : "%"), nbuf);
  921. strcat(buf, xbuf);
  922. }
  923. for (i = 0; i < s->str_alloc; ++i) {
  924. if (strlen(s->str_att[i]) != 0) {
  925. /* escape double quotes */
  926. j = k = 0;
  927. /* do not uncomment this code because sites file was created
  928. * as we want. So it's enough to print them out as it is.
  929. *
  930. if (strchr (s->str_att[i], DQUOTE) != (char *) NULL)
  931. {
  932. while (!isnull(s->str_att[i][j]))
  933. {
  934. if (isquote(s->str_att[i][j]))
  935. {
  936. xbuf[k++] = BSLASH;
  937. xbuf[k++] = DQUOTE;
  938. }
  939. else
  940. xbuf[k++] = s->str_att[i][j];
  941. j++;
  942. }
  943. xbuf[k] = (char) NULL;
  944. }
  945. else
  946. */
  947. strcpy(xbuf, s->str_att[i]);
  948. strcpy(s->str_att[i], xbuf);
  949. if (strchr(s->str_att[i], SPACE) != (char *)NULL)
  950. sprintf(xbuf, "%s%s\"%s\"", nfs, ((id == 0) ? "" : "@"),
  951. s->str_att[i]);
  952. else
  953. sprintf(xbuf, "%s%s%s", nfs, ((id == 0) ? "" : "@"),
  954. s->str_att[i]);
  955. strcat(buf, xbuf);
  956. }
  957. }
  958. return buf;
  959. }
  960. /*******************************************************************************/
  961. /*******************************************************************************/
  962. /*** ACS_MODIFY_BEGIN - sites_attribute management *****************************/
  963. /*
  964. These functions are used in visualization/nviz/src/site_attr_commands.c
  965. Functions to obtain fields in order to draw sites with each point having a
  966. geometric property depending from database values.
  967. */
  968. /*
  969. Returns a pointer to the struct site_att in Map_info *ptr and with category cat
  970. */
  971. struct site_att *G_sites_get_atts(struct Map_info * Map, int *cat)
  972. {
  973. return (struct site_att *) bsearch((void *)cat, (void *)Map->site_att,
  974. Map->n_site_att, sizeof(struct site_att),
  975. site_att_cmp);
  976. }
  977. /*
  978. Returns field names, types and indexes in double and string Map_info arrays
  979. WARNING: user is responsible to free allocated memory, directly or calling G_sites_free_fields()
  980. */
  981. int G_sites_get_fields(struct Map_info *Map, char ***cnames, int **ctypes,
  982. int **ndx)
  983. {
  984. struct field_info *fi;
  985. int nrows, row, ncols, col, ndbl, nstr, ctype;
  986. const char *name;
  987. dbDriver *driver;
  988. dbString stmt;
  989. dbCursor cursor;
  990. dbTable *table;
  991. dbColumn *column;
  992. /*dbValue *value; */
  993. /* warning: we are using "1" as cat field in Vect_get_field because G_sites_open_old
  994. (in lib/sites/sites.c), that we use here to open sites, does the same and then
  995. queries the db in the same way we do here.
  996. Should it be not true in the future, maybe we'll have to change this by choosing
  997. appropriate fields and multiple categories */
  998. fi = (struct field_info *)Vect_get_field(Map, 1);
  999. if (fi == NULL) { /* not attribute table */
  1000. G_debug(1, "No attribute table");
  1001. return -1;
  1002. }
  1003. driver = db_start_driver_open_database(fi->driver, fi->database);
  1004. if (driver == NULL)
  1005. G_fatal_error(_("Cannot open database %s by driver %s"), fi->database,
  1006. fi->driver);
  1007. db_init_string(&stmt);
  1008. db_set_string(&stmt, "select * from ");
  1009. db_append_string(&stmt, fi->table);
  1010. if (db_open_select_cursor(driver, &stmt, &cursor, DB_SEQUENTIAL) != DB_OK)
  1011. G_fatal_error(_("Cannot select attributes"));
  1012. nrows = db_get_num_rows(&cursor);
  1013. G_debug(1, "%d rows selected from vector attribute table", nrows);
  1014. table = db_get_cursor_table(&cursor);
  1015. ncols = db_get_table_number_of_columns(table);
  1016. if (ncols <= 0)
  1017. return ncols;
  1018. row = 0;
  1019. /* Get number of each type */
  1020. ndbl = nstr = 0;
  1021. *cnames = (char **)malloc(ncols * sizeof(char *));
  1022. *ctypes = (int *)malloc(ncols * sizeof(int));
  1023. *ndx = (int *)malloc(ncols * sizeof(int));
  1024. for (col = 0; col < ncols; col++) {
  1025. column = db_get_table_column(table, col);
  1026. ctype = db_sqltype_to_Ctype(db_get_column_sqltype(column));
  1027. name = db_get_column_name(column);
  1028. *(*cnames + col) = (char *)malloc(strlen(name) + 1);
  1029. strcpy(*(*cnames + col), db_get_column_name(column));
  1030. /* ctypes is 'c' for cat, 'd' for double, 's' for string */
  1031. if (strcmp(name, fi->key) == 0) {
  1032. *(*ctypes + col) = 'c';
  1033. *(*ndx + col) = -1;
  1034. }
  1035. else {
  1036. switch (ctype) {
  1037. case DB_C_TYPE_INT:
  1038. case DB_C_TYPE_DOUBLE:
  1039. *(*ctypes + col) = 'd';
  1040. *(*ndx + col) = ndbl;
  1041. ndbl++;
  1042. break;
  1043. case DB_C_TYPE_STRING:
  1044. case DB_C_TYPE_DATETIME:
  1045. *(*ctypes + col) = 's';
  1046. *(*ndx + col) = nstr;
  1047. nstr++;
  1048. break;
  1049. }
  1050. }
  1051. }
  1052. db_close_database_shutdown_driver(driver);
  1053. return ncols;
  1054. }
  1055. /* Frees fields allocated with G_sites_get_fields */
  1056. void G_sites_free_fields(int ncols, char **cnames, int *ctypes, int *ndx)
  1057. {
  1058. for (; ncols > 0; ncols--)
  1059. free(*(cnames + ncols - 1));
  1060. free(cnames);
  1061. free(ctypes);
  1062. free(ndx);
  1063. }
  1064. /*** ACS_MODIFY_END - sites_attribute management *******************************/