GRASS Programmer's Manual  6.5.svn(2014)-r66266
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
form.c
Go to the documentation of this file.
1 #include <stdlib.h>
2 #include <string.h>
3 #include <stdio.h>
4 #include <unistd.h>
5 #include <fcntl.h>
6 #include <sys/time.h>
7 #include <sys/types.h>
8 
9 #include <tcl.h>
10 #include <tk.h>
11 
12 #include <locale.h>
13 #include <grass/gis.h>
14 #include <grass/dbmi.h>
15 #include <grass/form.h>
16 
17 /* Structure to store column names and values */
18 typedef struct
19 {
20  char *name;
21  int ctype;
22  char *value;
23 } COLUMN;
24 
25 static char *Drvname, *Dbname, *Tblname, *Key;
26 
27 static COLUMN *Columns = NULL;
28 static int allocatedRows = 0; /* allocated space */
29 static int nRows = 0;
30 
31 /* Start new sql update */
32 int reset_values(ClientData cdata, Tcl_Interp * interp, int argc,
33  char *argv[])
34 {
35  nRows = 0;
36  Drvname = NULL;
37  Dbname = NULL;
38  Tblname = NULL;
39  Key = NULL;
40 
41  return TCL_OK;
42 }
43 
44 int set_value(ClientData cdata, Tcl_Interp * interp, int argc, char *argv[])
45 {
46  G_debug(2, "set_value(): %s %s", argv[1], argv[2]);
47 
48  if (strcmp(argv[1], F_DRIVER_FNAME) == 0) {
49  Drvname = G_store(argv[2]);
50  }
51  else if (strcmp(argv[1], F_DATABASE_FNAME) == 0) {
52  Dbname = G_store(argv[2]);
53  }
54  else if (strcmp(argv[1], F_TABLE_FNAME) == 0) {
55  Tblname = G_store(argv[2]);
56  }
57  else if (strcmp(argv[1], F_KEY_FNAME) == 0) {
58  Key = G_store(argv[2]);
59  }
60  else {
61  if (nRows == allocatedRows) {
62  allocatedRows += 100;
63  Columns =
64  (COLUMN *) G_realloc(Columns,
65  (allocatedRows) * sizeof(COLUMN));
66  }
67  Columns[nRows].name = G_store(argv[1]);
68  Columns[nRows].value = G_store(argv[2]);
69  nRows++;
70  }
71 
72  return TCL_OK;
73 }
74 
75 /* Update table, use the data previously stored by set_value() */
76 int submit(ClientData cdata, Tcl_Interp * interp, int argc, char *argv[])
77 {
78  int i, first, ncols, found, col, sqltype, keyval = 0, ret;
79  char buf[2001];
80  dbString sql, table_name, strval;
81  dbDriver *driver;
82  dbHandle handle;
83  dbTable *table;
84  dbColumn *column;
85 
86  G_debug(2, "submit()");
87 
88  db_init_string(&sql);
89  db_init_string(&table_name);
90  db_init_string(&strval);
91 
92  /* Check if all internal values are set */
93  if (Drvname == NULL || Dbname == NULL || Tblname == NULL || Key == NULL) {
94  G_warning("db connection was not set by form");
95  sprintf(buf, "set submit_msg \"db connection was not set by form.\"");
96  Tcl_Eval(interp, buf);
97  Tcl_Eval(interp, "set submit_result 0");
98  return TCL_OK;
99  }
100 
101  /* Get column types */
102  G_debug(2, "Open driver");
103  driver = db_start_driver(Drvname);
104  if (driver == NULL) {
105  G_warning("Cannot open driver");
106  sprintf(buf, "set submit_msg \"Cannot open driver '%s'\"", Drvname);
107  Tcl_Eval(interp, buf);
108  Tcl_Eval(interp, "set submit_result 0");
109  return TCL_OK;
110  }
111  G_debug(2, "Driver opened");
112 
113  db_init_handle(&handle);
114  db_set_handle(&handle, Dbname, NULL);
115  G_debug(2, "Open database");
116  if (db_open_database(driver, &handle) != DB_OK) {
117  G_warning("Cannot open database");
118  db_shutdown_driver(driver);
119  sprintf(buf,
120  "set submit_msg \"Cannot open database '%s' by driver '%s'\"",
121  Dbname, Drvname);
122 
123  Tcl_Eval(interp, buf);
124  Tcl_Eval(interp, "set submit_result 0");
125  return TCL_OK;
126  }
127  G_debug(2, "Database opened");
128 
129  db_set_string(&table_name, Tblname);
130  if (db_describe_table(driver, &table_name, &table) != DB_OK) {
131  G_warning("Cannot describe table");
132  db_shutdown_driver(driver);
133  db_close_database(driver);
134  sprintf(buf, "set submit_msg \"Cannot describe table '%s'\"",
135  Tblname);
136  Tcl_Eval(interp, buf);
137  Tcl_Eval(interp, "set submit_result 0");
138  return TCL_OK;
139  }
140  ncols = db_get_table_number_of_columns(table);
141 
142  /* For each column get ctype */
143  for (i = 0; i < nRows; i++) {
144  found = 0;
145  for (col = 0; col < ncols; col++) {
146  /* get keyval */
147  if (G_strcasecmp(Columns[i].name, Key) == 0) {
148  keyval = atoi(Columns[i].value);
149  }
150  column = db_get_table_column(table, col);
151  if (G_strcasecmp(db_get_column_name(column), Columns[i].name) ==
152  0) {
153  sqltype = db_get_column_sqltype(column);
154  Columns[i].ctype = db_sqltype_to_Ctype(sqltype);
155  found = 1;
156  break;
157  }
158  }
159  if (!found && (G_strcasecmp(Columns[i].name, F_ENCODING) != 0)) {
160  G_warning("Cannot find column type");
161  db_close_database(driver);
162  db_shutdown_driver(driver);
163  sprintf(buf, "set submit_msg \"Cannot find column type\"");
164  Tcl_Eval(interp, buf);
165  Tcl_Eval(interp, "set submit_result 0");
166  return TCL_OK;
167  }
168  }
169 
170  /* Construct update statement */
171  sprintf(buf, "update %s set ", Tblname);
172  db_set_string(&sql, buf);
173 
174  first = 1;
175  for (i = 0; i < nRows; i++) {
176  G_debug(3, "Index = %d of %d Name = %s, Key = %s", i, nRows,
177  Columns[i].name, Key);
178  if (G_strcasecmp(Columns[i].name, Key) == 0)
179  continue;
180 
181  if (G_strcasecmp(Columns[i].name, F_ENCODING) == 0) {
182 
183  G_debug(3, "GRASS_DB_ENCODING env-var is '%s', col val is '%s'",
184  G__getenv("GRASS_DB_ENCODING"), Columns[i].value);
185 
186  if ((strlen(Columns[i].value) == 0) ||
187  G_strcasecmp(Columns[i].value,
188  G__getenv("GRASS_DB_ENCODING")) == 0)
189  continue;
190  else {
191  G_setenv("GRASS_DB_ENCODING", Columns[i].value);
192  G_debug(3, "Set env var GRASS_DB_ENCODING to '%s'",
193  Columns[i].value);
194  if (Tcl_SetSystemEncoding(interp, Columns[i].value) ==
195  TCL_ERROR) {
196  G_warning
197  ("Could not set Tcl system encoding to '%s' (%s)",
198  Columns[i].value, Tcl_GetStringResult(interp));
199  }
200  }
201  continue;
202  }
203 
204  if (!first) {
205  db_append_string(&sql, ", ");
206  }
207  if (strlen(Columns[i].value) == 0) {
208  sprintf(buf, "%s = null", Columns[i].name);
209  }
210  else {
211  if (Columns[i].ctype == DB_C_TYPE_INT ||
212  Columns[i].ctype == DB_C_TYPE_DOUBLE) {
213  sprintf(buf, "%s = %s", Columns[i].name, Columns[i].value);
214  }
215  else {
216  memset(buf, '\0', strlen(buf));
217  ret = Tcl_UtfToExternal(interp,
218  Tcl_GetEncoding(interp,
219  G__getenv
220  ("GRASS_DB_ENCODING")),
221  Columns[i].value,
222  strlen(Columns[i].value), 0, NULL,
223  buf, 2000, NULL, NULL, NULL);
224 
225  if (ret != TCL_OK) {
226  G_warning("Could not convert UTF to external.");
227  db_set_string(&strval, Columns[i].value);
228  }
229  else {
230  db_set_string(&strval, buf);
231  }
232 
233  db_double_quote_string(&strval);
234  sprintf(buf, "%s = '%s'", Columns[i].name,
235  db_get_string(&strval));
236  }
237  }
238  db_append_string(&sql, buf);
239  first = 0;
240  }
241 
242  sprintf(buf, " where %s = %d", Key, keyval);
243  db_append_string(&sql, buf);
244 
245  G_debug(2, "SQL: %s", db_get_string(&sql));
246 
247  /* Update table */
248  ret = db_execute_immediate(driver, &sql);
249 
250  db_close_database(driver);
251  db_shutdown_driver(driver);
252 
253  if (ret != DB_OK) {
254  G_warning("Cannot update table");
255  Tcl_VarEval(interp, "set submit_msg \"Cannot update table:\n",
256  db_get_error_msg(), "\"", NULL);
257  Tcl_Eval(interp, "set submit_result 0");
258  }
259  else {
260  Tcl_Eval(interp, "set submit_msg \"Record successfully updated\"");
261  Tcl_Eval(interp, "set submit_result 1");
262  }
263 
264  return TCL_OK;
265 }
266 
267 /*
268  * Form
269  */
270 int Tcl_AppInit(Tcl_Interp * interp)
271 {
272  if (Tcl_Init(interp) == TCL_ERROR)
273  return TCL_ERROR;
274 
275  if (Tk_Init(interp) == TCL_ERROR)
276  return TCL_ERROR;
277 
278  Tcl_StaticPackage(interp, "Tk", Tk_Init, Tk_SafeInit);
279 
280  /*
281  * Call Tcl_CreateCommand for application-specific commands, if
282  * they weren't already created by the init procedures called above.
283  */
284 
285  Tcl_CreateCommand(interp, "submit", (Tcl_CmdProc *) submit,
286  (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
287  Tcl_CreateCommand(interp, "set_value",
288  (Tcl_CmdProc *) set_value,
289  (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
290  Tcl_CreateCommand(interp, "reset_values",
291  (Tcl_CmdProc *) reset_values,
292  (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
293  /*
294  * Specify a user-specific startup file to invoke if the application
295  * is run interactively. Typically the startup file is "~/.apprc"
296  * where "app" is the name of the application. If this line is deleted
297  * then no user-specific startup file will be run under any conditions.
298  */
299 
300  Tcl_SetVar(interp, "tcl_rcFileName", "~/.grassformrc", TCL_GLOBAL_ONLY);
301  return TCL_OK;
302 }
303 
304 int main(int argc, char *argv[])
305 {
306  G_gisinit("form");
307  G_debug(2, "Form: main()");
308 
309  Tk_Main(argc, argv, Tcl_AppInit);
310  return 0;
311 }
const char * db_get_error_msg(void)
dbColumn * db_get_table_column(dbTable *table, int n)
returns column structure for given table and column number
int G_strcasecmp(const char *x, const char *y)
String compare ignoring case (upper or lower)
Definition: strings.c:192
sprintf(buf2,"%s", G3D_CATS_ELEMENT)
struct driver * driver
Definition: driver/init.c:26
char * G__getenv(const char *name)
Get environment variable.
Definition: env.c:312
char * G_store(const char *s)
Copy string to allocated memory.
Definition: store.c:32
const char * db_get_column_name(dbColumn *column)
returns column name for given column
string name
Definition: render.py:1314
int db_describe_table(dbDriver *driver, dbString *name, dbTable **table)
Describe table.
Definition: c_desc_table.c:28
int db_shutdown_driver(dbDriver *driver)
Closedown the driver, and free the driver structure.
Definition: shutdown.c:36
int db_close_database(dbDriver *driver)
Close database connection.
Definition: c_closedb.c:26
int submit(ClientData cdata, Tcl_Interp *interp, int argc, char *argv[])
Definition: form.c:76
int db_execute_immediate(dbDriver *driver, dbString *SQLstatement)
Execute SQL statements.
Definition: c_execute.c:27
Definition: form.c:18
char * name
Definition: form.c:20
int db_append_string(dbString *x, const char *s)
Definition: string.c:193
int db_sqltype_to_Ctype(int sqltype)
Definition: sqlCtype.c:9
char * value
Definition: form.c:22
int db_get_column_sqltype(dbColumn *column)
returns column sqltype for column (the function db_sqltype_name() returns sqltype description) ...
int db_get_table_number_of_columns(dbTable *table)
int main(int argc, char *argv[])
Definition: gem/main.c:302
int Tcl_AppInit(Tcl_Interp *interp)
Definition: form.c:270
void db_double_quote_string(dbString *src)
Definition: string.c:223
char * value
Definition: env.c:30
int ctype
Definition: form.c:21
#define COLUMN
Definition: y.tab.c:158
int db_set_handle(dbHandle *handle, const char *dbName, const char *dbSchema)
Definition: handle.c:22
int first
Definition: form/open.c:25
int G_setenv(const char *name, const char *value)
Set environment variable.
Definition: env.c:352
char buf[GNAME_MAX+sizeof(G3D_DIRECTORY)+2]
Definition: g3drange.c:62
int set_value(ClientData cdata, Tcl_Interp *interp, int argc, char *argv[])
Definition: form.c:44
return NULL
Definition: dbfopen.c:1394
G_warning("category support for [%s] in mapset [%s] %s", name, mapset, type)
char * db_get_string(dbString *x)
Definition: string.c:131
int G_debug(int level, const char *msg,...)
Print debugging message.
Definition: gis/debug.c:51
int reset_values(ClientData cdata, Tcl_Interp *interp, int argc, char *argv[])
Definition: form.c:32
void db_init_handle(dbHandle *handle)
Definition: handle.c:10
int db_set_string(dbString *x, const char *s)
Definition: string.c:33
int db_open_database(dbDriver *driver, dbHandle *handle)
Open database connection.
Definition: c_opendb.c:27
dbDriver * db_start_driver(const char *name)
Initialize a new dbDriver for db transaction.
Definition: start.c:43
void db_init_string(dbString *x)
Definition: string.c:11