GRASS GIS 7 Programmer's Manual  7.9.dev(2021)-e5379bbd7
map.c
Go to the documentation of this file.
1 /*!
2  \file lib/vector/Vlib/map.c
3 
4  \brief Vector library - Manipulate vector map (copy, rename, delete)
5 
6  Higher level functions for reading/writing/manipulating vectors.
7 
8  (C) 2001-2009, 2012 by the GRASS Development Team
9 
10  This program is free software under the GNU General Public License
11  (>=v2). Read the file COPYING that comes with GRASS for details.
12 
13  \author Original author CERL, probably Dave Gerdes or Mike Higgins.
14  \author Update to GRASS 5.7 Radim Blazek and David D. Gray.
15 */
16 
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include <dirent.h>
20 #include <string.h>
21 #include <unistd.h>
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <fcntl.h>
25 #include <errno.h>
26 
27 #include <grass/glocale.h>
28 #include <grass/vector.h>
29 #include <grass/dbmi.h>
30 #include <grass/glocale.h>
31 
32 #include "local_proto.h"
33 
34 /*!
35  \brief Creates and initializes Map_info structure
36 
37  To free allocated memory call Vect_destroy_map_struct().
38 
39  \return pointer to Map_info
40  */
42 {
43  struct Map_info *p;
44 
45  p = (struct Map_info *)malloc(sizeof(struct Map_info));
46 
47  if (NULL == p)
48  G_fatal_error("Vect_new_map_struct(): %s", _("Out of memory"));
49 
50  G_zero(p, sizeof(struct Map_info));
51 
52  return p;
53 }
54 
55 /*!
56  \brief Frees all memory associated with a Map_info structure,
57  including the structure itself
58 
59  \param p pointer to Map_info structure
60  */
62 {
63  /* We should free all allocated member structures, but they may be already
64  freed by other functions (e.g. Vect_close()) without resetting member pointers to zero */
65 
66  G_free((char *)p);
67 }
68 
69 /*!
70  \brief Copy file
71 
72  \param src source file
73  \param[out] dst destination file
74 
75  \return 0 OK
76  \return 1 error
77  */
78 static int copy_file(const char *src, const char *dst)
79 {
80  char buf[4096];
81  int fd, fd2;
82  FILE *f2;
83  int len, len2;
84 
85  if ((fd = open(src, O_RDONLY)) < 0)
86  return 1;
87 
88  /* if((fd2 = open(dst, O_CREAT|O_TRUNC|O_WRONLY)) < 0) { */
89  if ((f2 = fopen(dst, "w")) == NULL) {
90  close(fd);
91  return 1;
92  }
93 
94  fd2 = fileno(f2);
95 
96  len2 = 0;
97  while ((len = read(fd, buf, 4096)) > 0) {
98  while (len && (len2 = write(fd2, buf, len)) >= 0)
99  len -= len2;
100  }
101 
102  close(fd);
103  /* close(fd2); */
104  fclose(f2);
105 
106  if (len == -1 || len2 == -1)
107  return 1;
108 
109  return 0;
110 }
111 
112 /*!
113  \brief Copy vector map including attribute tables
114 
115  Note: Output vector map is overwritten if exists!
116 
117  \param in name if vector map to be copied
118  \param mapset mapset name where the input map is located
119  \param out name for output vector map (new map is created in current mapset)
120 
121  \return -1 error
122  \return 0 success
123  */
124 int Vect_copy(const char *in, const char *mapset, const char *out)
125 {
126  int i, ret;
127  struct Map_info In, Out;
128  char old_path[GPATH_MAX], new_path[GPATH_MAX], buf[GPATH_MAX];
129  const char *files[] = { GV_FRMT_ELEMENT, GV_COOR_ELEMENT,
132  NULL
133  };
134  const char *inmapset;
135  char xname[GNAME_MAX], xmapset[GMAPSET_MAX];
136 
137  G_debug(2, "Copy vector '%s' in '%s' to '%s'", in, mapset, out);
138  /* check for [A-Za-z][A-Za-z0-9_]* in name */
139  if (Vect_legal_filename(out) < 0)
140  G_fatal_error(_("Vector map name is not SQL compliant"));
141 
142  inmapset = G_find_vector2(in, mapset);
143  if (!inmapset) {
144  G_warning(_("Unable to find vector map <%s> in <%s>"), in, mapset);
145  return -1;
146  }
147  mapset = inmapset;
148 
149  /* remove mapset from fully qualified name, confuses G_file_name() */
150  if (G_name_is_fully_qualified(in, xname, xmapset)) {
151  in = xname;
152  }
153 
154  /* Delete old vector if it exists */
155  if (G_find_vector2(out, G_mapset())) {
156  G_warning(_("Vector map <%s> already exists and will be overwritten"),
157  out);
158  ret = Vect_delete(out);
159  if (ret != 0) {
160  G_warning(_("Unable to delete vector map <%s>"), out);
161  return -1;
162  }
163  }
164 
165  /* Copy the directory */
167  sprintf(buf, "%s/%s", GV_DIRECTORY, out);
169 
170  i = 0;
171  while (files[i]) {
172  sprintf(buf, "%s/%s", in, files[i]);
173  G_file_name(old_path, GV_DIRECTORY, buf, mapset);
174  sprintf(buf, "%s/%s", out, files[i]);
175  G_file_name(new_path, GV_DIRECTORY, buf, G_mapset());
176 
177  if (access(old_path, F_OK) == 0) { /* file exists? */
178  G_debug(2, "copy %s to %s", old_path, new_path);
179  if (copy_file(old_path, new_path)) {
180  G_warning(_("Unable to copy vector map <%s> to <%s>"),
181  old_path, new_path);
182  }
183  }
184  i++;
185  }
186 
187  G_file_name(old_path, GV_DIRECTORY, in, mapset);
188  G_file_name(new_path, GV_DIRECTORY, out, G_mapset());
189 
190  /* Open input */
192  if (Vect_open_old_head(&In, in, mapset) < 0)
193  G_fatal_error(_("Unable to open vector map <%s>"), in);
194 
195  if (In.format != GV_FORMAT_NATIVE) { /* Done */
196  Vect_close(&In);
197  return 0;
198  }
199 
200  /* Open output */
202  if (Vect_open_update_head(&Out, out, G_mapset()) < 0)
203  G_fatal_error(_("Unable to open vector map <%s>"), out);
204 
205  /* Copy tables */
206  if (Vect_copy_tables(&In, &Out, 0) != 0) {
207  Vect_close(&In);
208  Vect_close(&Out);
209 
210  return 1;
211  }
212 
213  Vect_close(&In);
214  Vect_close(&Out);
215 
216  return 0;
217 }
218 
219 /*!
220  \brief Rename existing vector map (in the current mapset).
221 
222  Attribute tables are created in the same database where input tables were stored.
223 
224  The origial format (native/OGR) is used.
225 
226  Note: Output vector map is overwritten if exists!
227 
228  \param in name of vector map to be renamed
229  \param out name for output vector map
230 
231  \return -1 error
232  \return 0 success
233  */
234 int Vect_rename(const char *in, const char *out)
235 {
236  int i, n, ret, type;
237  struct Map_info Map;
238  struct field_info *Fin, *Fout;
239  int *fields;
240  dbDriver *driver;
241  char xname[GNAME_MAX], xmapset[GMAPSET_MAX];
242 
243  G_debug(2, "Rename vector '%s' to '%s'", in, out);
244  /* check for [A-Za-z][A-Za-z0-9_]* in name */
245  if (Vect_legal_filename(out) < 0)
246  G_fatal_error(_("Vector map name is not SQL compliant"));
247 
248  /* Delete old vector if it exists */
249  if (G_find_vector2(out, G_mapset())) {
250  G_warning(_("Vector map <%s> already exists and will be overwritten"),
251  out);
252  Vect_delete(out);
253  }
254 
255  /* remove mapset from fully qualified name */
256  if (G_name_is_fully_qualified(in, xname, xmapset)) {
257  in = xname;
258  }
259 
260  /* Move the directory */
261  ret = G_rename(GV_DIRECTORY, in, out);
262 
263  if (ret == 0) {
264  G_warning(_("Vector map <%s> not found"), in);
265  return -1;
266  }
267  else if (ret == -1) {
268  G_warning(_("Unable to copy vector map <%s> to <%s>"), in, out);
269  return -1;
270  }
271 
272  /* Rename all tables if the format is native */
274  if (Vect_open_update_head(&Map, out, G_mapset()) < 0)
275  G_fatal_error(_("Unable to open vector map <%s>"), out);
276 
277  if (Map.format != GV_FORMAT_NATIVE) { /* Done */
278  Vect_close(&Map);
279  return 0;
280  }
281 
282  /* Copy tables */
283  n = Vect_get_num_dblinks(&Map);
284  type = GV_1TABLE;
285  if (n > 1)
286  type = GV_MTABLE;
287 
288  /* Make the list of fields */
289  fields = (int *)G_malloc(n * sizeof(int));
290 
291  for (i = 0; i < n; i++) {
292  Fin = Vect_get_dblink(&Map, i);
293  fields[i] = Fin->number;
294  }
295 
296  for (i = 0; i < n; i++) {
297  G_debug(3, "field[%d] = %d", i, fields[i]);
298 
299  Fin = Vect_get_field(&Map, fields[i]);
300  if (Fin == NULL) {
301  G_warning(_("Database connection not defined for layer %d"),
302  fields[i]);
303  Vect_close(&Map);
304  return -1;
305  }
306 
307  Fout = Vect_default_field_info(&Map, Fin->number, Fin->name, type);
308  G_debug(3, "Copy drv:db:table '%s:%s:%s' to '%s:%s:%s'",
309  Fin->driver, Fin->database, Fin->table, Fout->driver,
310  Fout->database, Fout->table);
311 
312  /* TODO: db_rename_table instead of db_copy_table */
313  ret = db_copy_table(Fin->driver, Fin->database, Fin->table,
314  Fout->driver, Vect_subst_var(Fout->database,
315  &Map), Fout->table);
316 
317  if (ret == DB_FAILED) {
318  G_warning(_("Unable to copy table <%s>"), Fin->table);
319  Vect_close(&Map);
320  return -1;
321  }
322 
323  /* Change the link */
324  Vect_map_del_dblink(&Map, Fin->number);
325 
326  Vect_map_add_dblink(&Map, Fout->number, Fout->name, Fout->table,
327  Fin->key, Fout->database, Fout->driver);
328 
329  /* Delete old table */
330  ret = db_delete_table(Fin->driver, Fin->database, Fin->table);
331  if (ret == DB_FAILED) {
332  G_warning(_("Unable to delete table <%s>"), Fin->table);
333  Vect_close(&Map);
334  return -1;
335  }
336 
337  driver =
339  Vect_subst_var(Fout->database,
340  &Map));
341  if (driver == NULL) {
342  G_warning(_("Unable to open database <%s> by driver <%s>"),
343  Fout->database, Fout->driver);
344  }
345  else {
346  if (db_create_index2(driver, Fout->table, Fin->key) != DB_OK)
347  G_warning(_("Unable to create index for table <%s>, key <%s>"),
348  Fout->table, Fout->key);
349 
351  }
352  }
353 
354  Vect_close(&Map);
355  free(fields);
356 
357  return 0;
358 }
359 
360 /*!
361  \brief Delete vector map including attribute tables
362 
363  Vector map must be located in current mapset.
364 
365  \param map name of vector map to be delete
366 
367  \return -1 error
368  \return 0 success
369  */
370 int Vect_delete(const char *map)
371 {
372  return Vect__delete(map, FALSE);
373 }
374 
375 /*!
376  \brief Delete vector map (internal use only)
377 
378  \param map name of vector map to be delete
379  \param is_tmp TRUE for temporary maps
380 
381  \return -1 error
382  \return 0 success
383 */
384 int Vect__delete(const char *map, int is_tmp)
385 {
386  int ret;
387  char path[GPATH_MAX], path_buf[GPATH_MAX];
388  char xname[GNAME_MAX], xmapset[GMAPSET_MAX];
389  const char *tmp, *mapset, *env;
390 
391  struct Map_info Map;
392 
393  DIR *dir;
394  struct dirent *ent;
395 
396  G_debug(3, "Delete vector '%s' (is_tmp = %d)", map, is_tmp);
397 
398  mapset = G_mapset();
399 
400  /* remove mapset from fully qualified name */
401  if (G_name_is_fully_qualified(map, xname, xmapset)) {
402  if (strcmp(mapset, xmapset) != 0)
403  G_warning(_("Ignoring invalid mapset: %s"), xmapset);
404  map = xname;
405  }
406 
407  if (map == NULL || strlen(map) == 0) {
408  G_warning(_("Invalid vector map name <%s>"), map ? map : "null");
409  return -1;
410  }
411 
412  Vect_set_open_level(1); /* Topo not needed */
413  ret = Vect__open_old(&Map, map, mapset, NULL, FALSE, TRUE, is_tmp);
414  if (ret < 1) {
415  if (is_tmp)
416  return 0; /* temporary vector map doesn't exist */
417  else {
418  G_warning(_("Unable to open header file for vector map <%s>"),
419  map);
420  return -1;
421  }
422  }
423 
425  G_debug(1, "dbln file: %s", path);
426 
427  if (access(path, F_OK) == 0) {
428  int i, n;
429  struct field_info *Fi;
430 
431  /* Delete all tables, NOT external (OGR) */
432  if (Map.format == GV_FORMAT_NATIVE) {
433  n = Vect_get_num_dblinks(&Map);
434  for (i = 0; i < n; i++) {
435  Fi = Vect_get_dblink(&Map, i);
436  if (Fi == NULL) {
437  G_warning(_("Database connection not defined for layer %d"),
438  Map.dblnk->field[i].number);
439  /*
440  Vect_close(&Map);
441  return -1;
442  */
443  continue;
444  }
445  G_debug(3, "Delete drv:db:table '%s:%s:%s'", Fi->driver,
446  Fi->database, Fi->table);
447 
448  ret = db_table_exists(Fi->driver, Fi->database, Fi->table);
449  if (ret == -1) {
450  G_warning(_("Unable to find table <%s> linked to vector map <%s>"),
451  Fi->table, map);
452  /*
453  Vect_close(&Map);
454  return -1;
455  */
456  continue;
457  }
458 
459  if (ret == 1) {
460  ret =
461  db_delete_table(Fi->driver, Fi->database, Fi->table);
462  if (ret == DB_FAILED) {
463  G_warning(_("Unable to delete table <%s>"),
464  Fi->table);
465  /*
466  Vect_close(&Map);
467  return -1;
468  */
469  continue;
470  }
471  }
472  else {
473  G_warning(_("Table <%s> linked to vector map <%s> does not exist"),
474  Fi->table, map);
475  }
476  }
477  }
478  }
479 
480  /* Delete all files from vector/name directory */
481  Vect__get_element_path(path, &Map, NULL);
482  Vect_close(&Map);
483  G_debug(3, "opendir '%s'", path);
484  dir = opendir(path);
485  if (dir == NULL) {
486  G_warning(_("Unable to open directory '%s'"), path);
487  return -1;
488  }
489 
490  while ((ent = readdir(dir))) {
491  G_debug(3, "file = '%s'", ent->d_name);
492  if ((strcmp(ent->d_name, ".") == 0) ||
493  (strcmp(ent->d_name, "..") == 0))
494  continue;
495 
496  sprintf(path_buf, "%s/%s", path, ent->d_name);
497  G_debug(3, "delete file '%s'", path_buf);
498  ret = unlink(path_buf);
499  if (ret == -1) {
500  G_warning(_("Unable to delete file '%s'"), path_buf);
501  closedir(dir);
502  return -1;
503  }
504  }
505  closedir(dir);
506 
507  env = getenv("GRASS_VECTOR_TMPDIR_MAPSET");
508  if (env && strcmp(env, "0") == 0) {
509  tmp = path;
510  }
511  else {
512  /* NFS can create .nfsxxxxxxxx files for those deleted
513  * -> we have to move the directory to ./tmp before it is deleted */
514  tmp = G_tempfile();
515 
516  G_debug(3, "rename '%s' to '%s'", path, tmp);
517 
518  ret = rename(path, tmp);
519  if (ret == -1) {
520  G_warning(_("Unable to rename directory '%s' to '%s'"), path, tmp);
521  return -1;
522  }
523  }
524 
525  G_debug(3, "remove directory '%s'", tmp);
526  /* Warning: remove() fails on Windows */
527  ret = rmdir(tmp);
528  if (ret == -1) {
529  G_warning(_("Unable to remove directory '%s': %s"),
530  tmp, strerror(errno));
531  return -1;
532  }
533 
534  return 0;
535 }
536 
537 /*!
538  \brief Set spatial index to be realease when vector is closed.
539 
540  By default, the memory occupied by spatial index is not released.
541 
542  \param Map vector map
543  */
545 {
546  Map->plus.release_support = TRUE;
547 }
548 
549 /*!
550  \brief Set category index to be updated when vector is changed.
551 
552  By default, category index is not updated if vector is changed,
553  this function sets category index update.
554 
555  WARNING: currently only category for elements is updated not for
556  areas
557 
558  \param Map vector map
559 */
561 {
562  Map->plus.update_cidx = TRUE;
563 }
#define TRUE
Definition: gis.h:59
#define G_malloc(n)
Definition: defs/gis.h:112
int Vect_rename(const char *in, const char *out)
Rename existing vector map (in the current mapset).
Definition: map.c:234
DIR * opendir()
char * G_file_name(char *, const char *, const char *, const char *)
Builds full path names to GIS data files.
Definition: file_name.c:38
void void void void G_fatal_error(const char *,...) __attribute__((format(printf
#define GMAPSET_MAX
Definition: gis.h:168
int open
Open indicator.
Definition: dig_structs.h:1296
char * Vect__get_element_path(char *file_path, const struct Map_info *Map, const char *element)
Get map element full path (internal use only)
#define GV_DIRECTORY
Name of vector directory.
Definition: dig_defines.h:8
#define GV_MTABLE
More tables linked to vector map.
Definition: dig_defines.h:101
int Vect_open_update_head(struct Map_info *, const char *, const char *)
Open header file of existing vector map for updating (mostly for database link updates) ...
#define GV_FRMT_ELEMENT
Format description, data location (OGR)
Definition: dig_defines.h:10
int Vect__open_old(struct Map_info *Map, const char *name, const char *mapset, const char *layer, int update, int head_only, int is_tmp)
Open existing vector map for reading (internal use only)
const char * G_find_vector2(const char *, const char *)
Find a vector map (look but don&#39;t touch)
Definition: find_vect.c:62
#define GV_FORMAT_NATIVE
Geometry data formats supported by lib Don&#39;t change GV_FORMAT_* values, this order is hardcoded in li...
Definition: dig_defines.h:83
#define GV_DBLN_ELEMENT
Native format, link to database.
Definition: dig_defines.h:16
int Vect_map_add_dblink(struct Map_info *, int, const char *, const char *, const char *, const char *, const char *)
Add new db connection to Map_info structure.
Definition: field.c:113
int release_support
Release memory occupied by support structures (topo, spatial, category)
Definition: dig_structs.h:838
char * table
Name of DB table.
Definition: dig_structs.h:155
void Vect_set_category_index_update(struct Map_info *Map)
Set category index to be updated when vector is changed.
Definition: map.c:560
void G_free(void *)
Free allocated memory.
Definition: gis/alloc.c:149
#define GV_TOPO_ELEMENT
Native format, topology file.
Definition: dig_defines.h:20
#define GV_HEAD_ELEMENT
Native format, header information.
Definition: dig_defines.h:14
char * dst
Definition: lz4.h:599
dbDriver * db_start_driver_open_database(const char *, const char *)
Open driver/database connection.
Definition: db.c:28
int db_delete_table(const char *, const char *, const char *)
Delete table.
Definition: delete_tab.c:29
int Vect_close(struct Map_info *)
Close vector map.
void free(void *)
#define NULL
Definition: ccmath.h:32
int Vect__delete(const char *map, int is_tmp)
Delete vector map (internal use only)
Definition: map.c:384
int type
Feature type constraint.
Definition: dig_structs.h:1374
int db_close_database_shutdown_driver(dbDriver *)
Close driver/database connection.
Definition: db.c:62
struct field_info * Vect_get_field(const struct Map_info *, int)
Get information about link to database (by layer number)
Definition: field.c:506
int Vect_get_num_dblinks(const struct Map_info *)
Get number of defined dblinks.
Definition: level_two.c:163
char * database
Definition: dig_structs.h:151
dir_entry * readdir()
void * malloc(YYSIZE_T)
Layer (old: field) information.
Definition: dig_structs.h:134
char * name
Layer name (optional)
Definition: dig_structs.h:143
#define GV_CIDX_ELEMENT
Native format, category index.
Definition: dig_defines.h:24
char * Vect_subst_var(const char *, const struct Map_info *)
Substitute variable in string.
Definition: field.c:1003
#define FALSE
Definition: gis.h:63
char * G_tempfile(void)
Returns a temporary file name.
Definition: tempfile.c:62
struct field_info * Vect_get_dblink(const struct Map_info *, int)
Get information about link to database.
Definition: field.c:466
struct Map_info * Vect_new_map_struct(void)
Creates and initializes Map_info structure.
Definition: map.c:41
#define GV_HIST_ELEMENT
Native format, history file.
Definition: dig_defines.h:18
const struct driver * driver
Definition: driver/init.c:25
struct Plus_head plus
Plus info (topology, version, ...)
Definition: dig_structs.h:1286
int Vect_map_del_dblink(struct Map_info *, int)
Delete db connection from Map_info structure.
Definition: field.c:153
int Vect_delete(const char *map)
Delete vector map including attribute tables.
Definition: map.c:370
#define GPATH_MAX
Definition: gis.h:170
#define GV_1TABLE
One table linked to vector map.
Definition: dig_defines.h:99
int Vect_legal_filename(const char *)
Check if output is legal vector name.
Definition: legal_vname.c:31
int G_rename(const char *, const char *, const char *)
Rename a database file.
Definition: rename.c:70
char * mapset
Mapset name.
Definition: dig_structs.h:1336
int Vect_set_open_level(int)
Predetermine level at which a vector map will be opened for reading.
Vector map info.
Definition: dig_structs.h:1259
int Vect_open_old_head(struct Map_info *, const char *, const char *)
Reads only info about vector map (headers)
int db_create_index2(dbDriver *, const char *, const char *)
Create unique index.
Definition: c_create_idx.c:61
struct dblinks * dblnk
Array of DB links.
Definition: dig_structs.h:1281
char * driver
Name of DB driver (&#39;sqlite&#39;, &#39;dbf&#39;, ...)
Definition: dig_structs.h:147
struct field_info * Vect_default_field_info(struct Map_info *, int, const char *, int)
Get default information about link to database for new dblink.
Definition: field.c:351
int db_copy_table(const char *, const char *, const char *, const char *, const char *, const char *)
Copy a table.
Definition: copy_tab.c:446
#define DB_FAILED
Definition: dbmi.h:72
const char * G_mapset(void)
Get current mapset name.
Definition: gis/mapset.c:33
int Vect_copy(const char *in, const char *mapset, const char *out)
Copy vector map including attribute tables.
Definition: map.c:124
int Vect_copy_tables(const struct Map_info *, struct Map_info *, int)
Copy attribute tables linked to vector map.
void G_zero(void *, int)
Zero out a buffer, buf, of length i.
Definition: gis/zero.c:23
#define GNAME_MAX
Definition: gis.h:167
void G_warning(const char *,...) __attribute__((format(printf
int number
Layer number.
Definition: dig_structs.h:139
Definition: path.h:16
void Vect_destroy_map_struct(struct Map_info *p)
Frees all memory associated with a Map_info structure, including the structure itself.
Definition: map.c:61
#define _(str)
Definition: glocale.h:10
int G_make_mapset_element(const char *)
Create element in the current mapset.
Definition: mapset_msc.c:38
int format
Map format (native, ogr, postgis)
Definition: dig_structs.h:1271
int db_table_exists(const char *, const char *, const char *)
Check if table exists.
#define GV_SIDX_ELEMENT
Native format, spatial index.
Definition: dig_defines.h:22
#define GV_COOR_ELEMENT
Native format, coordinates.
Definition: dig_defines.h:12
int update_cidx
Update category index if vector is modified.
Definition: dig_structs.h:1136
char * getenv()
int G_name_is_fully_qualified(const char *, char *, char *)
Check if map name is fully qualified (map @ mapset)
Definition: nme_in_mps.c:36
void Vect_set_release_support(struct Map_info *Map)
Set spatial index to be realease when vector is closed.
Definition: map.c:544
int G_debug(int, const char *,...) __attribute__((format(printf
#define DB_OK
Definition: dbmi.h:71
char * key
Name of key column (usually &#39;cat&#39;)
Definition: dig_structs.h:159