GRASS Programmer's Manual
6.4.2(2012)
|
00001 #include <stdlib.h> 00002 #include <string.h> 00003 #include <stdio.h> 00004 #include <unistd.h> 00005 #include <fcntl.h> 00006 #include <sys/time.h> 00007 #include <sys/types.h> 00008 00009 /* hack for tcl 8.6 */ 00010 #define USE_INTERP_RESULT 00011 #include <tcl.h> 00012 #include <tk.h> 00013 00014 #include <locale.h> 00015 #include <grass/gis.h> 00016 #include <grass/dbmi.h> 00017 #include <grass/form.h> 00018 00019 /* Structure to store column names and values */ 00020 typedef struct 00021 { 00022 char *name; 00023 int ctype; 00024 char *value; 00025 } COLUMN; 00026 00027 static char *Drvname, *Dbname, *Tblname, *Key; 00028 00029 static COLUMN *Columns = NULL; 00030 static int allocatedRows = 0; /* allocated space */ 00031 static int nRows = 0; 00032 00033 /* Start new sql update */ 00034 int reset_values(ClientData cdata, Tcl_Interp * interp, int argc, 00035 char *argv[]) 00036 { 00037 nRows = 0; 00038 Drvname = NULL; 00039 Dbname = NULL; 00040 Tblname = NULL; 00041 Key = NULL; 00042 00043 return TCL_OK; 00044 } 00045 00046 int set_value(ClientData cdata, Tcl_Interp * interp, int argc, char *argv[]) 00047 { 00048 G_debug(2, "set_value(): %s %s", argv[1], argv[2]); 00049 00050 if (strcmp(argv[1], F_DRIVER_FNAME) == 0) { 00051 Drvname = G_store(argv[2]); 00052 } 00053 else if (strcmp(argv[1], F_DATABASE_FNAME) == 0) { 00054 Dbname = G_store(argv[2]); 00055 } 00056 else if (strcmp(argv[1], F_TABLE_FNAME) == 0) { 00057 Tblname = G_store(argv[2]); 00058 } 00059 else if (strcmp(argv[1], F_KEY_FNAME) == 0) { 00060 Key = G_store(argv[2]); 00061 } 00062 else { 00063 if (nRows == allocatedRows) { 00064 allocatedRows += 100; 00065 Columns = 00066 (COLUMN *) G_realloc(Columns, 00067 (allocatedRows) * sizeof(COLUMN)); 00068 } 00069 Columns[nRows].name = G_store(argv[1]); 00070 Columns[nRows].value = G_store(argv[2]); 00071 nRows++; 00072 } 00073 00074 return TCL_OK; 00075 } 00076 00077 /* Update table, use the data previously stored by set_value() */ 00078 int submit(ClientData cdata, Tcl_Interp * interp, int argc, char *argv[]) 00079 { 00080 int i, first, ncols, found, col, sqltype, keyval = 0, ret; 00081 char buf[2001]; 00082 dbString sql, table_name, strval; 00083 dbDriver *driver; 00084 dbHandle handle; 00085 dbTable *table; 00086 dbColumn *column; 00087 00088 G_debug(2, "submit()"); 00089 00090 db_init_string(&sql); 00091 db_init_string(&table_name); 00092 db_init_string(&strval); 00093 00094 /* Check if all internal values are set */ 00095 if (Drvname == NULL || Dbname == NULL || Tblname == NULL || Key == NULL) { 00096 G_warning("db connection was not set by form"); 00097 sprintf(buf, "set submit_msg \"db connection was not set by form.\""); 00098 Tcl_Eval(interp, buf); 00099 Tcl_Eval(interp, "set submit_result 0"); 00100 return TCL_OK; 00101 } 00102 00103 /* Get column types */ 00104 G_debug(2, "Open driver"); 00105 driver = db_start_driver(Drvname); 00106 if (driver == NULL) { 00107 G_warning("Cannot open driver"); 00108 sprintf(buf, "set submit_msg \"Cannot open driver '%s'\"", Drvname); 00109 Tcl_Eval(interp, buf); 00110 Tcl_Eval(interp, "set submit_result 0"); 00111 return TCL_OK; 00112 } 00113 G_debug(2, "Driver opened"); 00114 00115 db_init_handle(&handle); 00116 db_set_handle(&handle, Dbname, NULL); 00117 G_debug(2, "Open database"); 00118 if (db_open_database(driver, &handle) != DB_OK) { 00119 G_warning("Cannot open database"); 00120 db_shutdown_driver(driver); 00121 sprintf(buf, 00122 "set submit_msg \"Cannot open database '%s' by driver '%s'\"", 00123 Dbname, Drvname); 00124 00125 Tcl_Eval(interp, buf); 00126 Tcl_Eval(interp, "set submit_result 0"); 00127 return TCL_OK; 00128 } 00129 G_debug(2, "Database opened"); 00130 00131 db_set_string(&table_name, Tblname); 00132 if (db_describe_table(driver, &table_name, &table) != DB_OK) { 00133 G_warning("Cannot describe table"); 00134 db_shutdown_driver(driver); 00135 db_close_database(driver); 00136 sprintf(buf, "set submit_msg \"Cannot describe table '%s'\"", 00137 Tblname); 00138 Tcl_Eval(interp, buf); 00139 Tcl_Eval(interp, "set submit_result 0"); 00140 return TCL_OK; 00141 } 00142 ncols = db_get_table_number_of_columns(table); 00143 00144 /* For each column get ctype */ 00145 for (i = 0; i < nRows; i++) { 00146 found = 0; 00147 for (col = 0; col < ncols; col++) { 00148 /* get keyval */ 00149 if (G_strcasecmp(Columns[i].name, Key) == 0) { 00150 keyval = atoi(Columns[i].value); 00151 } 00152 column = db_get_table_column(table, col); 00153 if (G_strcasecmp(db_get_column_name(column), Columns[i].name) == 00154 0) { 00155 sqltype = db_get_column_sqltype(column); 00156 Columns[i].ctype = db_sqltype_to_Ctype(sqltype); 00157 found = 1; 00158 break; 00159 } 00160 } 00161 if (!found && (G_strcasecmp(Columns[i].name, F_ENCODING) != 0)) { 00162 G_warning("Cannot find column type"); 00163 db_close_database(driver); 00164 db_shutdown_driver(driver); 00165 sprintf(buf, "set submit_msg \"Cannot find column type\""); 00166 Tcl_Eval(interp, buf); 00167 Tcl_Eval(interp, "set submit_result 0"); 00168 return TCL_OK; 00169 } 00170 } 00171 00172 /* Construct update statement */ 00173 sprintf(buf, "update %s set ", Tblname); 00174 db_set_string(&sql, buf); 00175 00176 first = 1; 00177 for (i = 0; i < nRows; i++) { 00178 G_debug(3, "Index = %d of %d Name = %s, Key = %s", i, nRows, 00179 Columns[i].name, Key); 00180 if (G_strcasecmp(Columns[i].name, Key) == 0) 00181 continue; 00182 00183 if (G_strcasecmp(Columns[i].name, F_ENCODING) == 0) { 00184 00185 G_debug(3, "GRASS_DB_ENCODING env-var is '%s', col val is '%s'", 00186 G__getenv("GRASS_DB_ENCODING"), Columns[i].value); 00187 00188 if ((strlen(Columns[i].value) == 0) || 00189 G_strcasecmp(Columns[i].value, 00190 G__getenv("GRASS_DB_ENCODING")) == 0) 00191 continue; 00192 else { 00193 G_setenv("GRASS_DB_ENCODING", Columns[i].value); 00194 G_debug(3, "Set env var GRASS_DB_ENCODING to '%s'", 00195 Columns[i].value); 00196 if (Tcl_SetSystemEncoding(interp, Columns[i].value) == 00197 TCL_ERROR) { 00198 G_warning 00199 ("Could not set Tcl system encoding to '%s' (%s)", 00200 Columns[i].value, interp->result); 00201 } 00202 } 00203 continue; 00204 } 00205 00206 if (!first) { 00207 db_append_string(&sql, ", "); 00208 } 00209 if (strlen(Columns[i].value) == 0) { 00210 sprintf(buf, "%s = null", Columns[i].name); 00211 } 00212 else { 00213 if (Columns[i].ctype == DB_C_TYPE_INT || 00214 Columns[i].ctype == DB_C_TYPE_DOUBLE) { 00215 sprintf(buf, "%s = %s", Columns[i].name, Columns[i].value); 00216 } 00217 else { 00218 memset(buf, '\0', strlen(buf)); 00219 ret = Tcl_UtfToExternal(interp, 00220 Tcl_GetEncoding(interp, 00221 G__getenv 00222 ("GRASS_DB_ENCODING")), 00223 Columns[i].value, 00224 strlen(Columns[i].value), 0, NULL, 00225 buf, 2000, NULL, NULL, NULL); 00226 00227 if (ret != TCL_OK) { 00228 G_warning("Could not convert UTF to external."); 00229 db_set_string(&strval, Columns[i].value); 00230 } 00231 else { 00232 db_set_string(&strval, buf); 00233 } 00234 00235 db_double_quote_string(&strval); 00236 sprintf(buf, "%s = '%s'", Columns[i].name, 00237 db_get_string(&strval)); 00238 } 00239 } 00240 db_append_string(&sql, buf); 00241 first = 0; 00242 } 00243 00244 sprintf(buf, " where %s = %d", Key, keyval); 00245 db_append_string(&sql, buf); 00246 00247 G_debug(2, "SQL: %s", db_get_string(&sql)); 00248 00249 /* Update table */ 00250 ret = db_execute_immediate(driver, &sql); 00251 00252 db_close_database(driver); 00253 db_shutdown_driver(driver); 00254 00255 if (ret != DB_OK) { 00256 G_warning("Cannot update table"); 00257 Tcl_VarEval(interp, "set submit_msg \"Cannot update table:\n", 00258 db_get_error_msg(), "\"", NULL); 00259 Tcl_Eval(interp, "set submit_result 0"); 00260 } 00261 else { 00262 Tcl_Eval(interp, "set submit_msg \"Record successfully updated\""); 00263 Tcl_Eval(interp, "set submit_result 1"); 00264 } 00265 00266 return TCL_OK; 00267 } 00268 00269 /* 00270 * Form 00271 */ 00272 int Tcl_AppInit(Tcl_Interp * interp) 00273 { 00274 if (Tcl_Init(interp) == TCL_ERROR) 00275 return TCL_ERROR; 00276 00277 if (Tk_Init(interp) == TCL_ERROR) 00278 return TCL_ERROR; 00279 00280 Tcl_StaticPackage(interp, "Tk", Tk_Init, Tk_SafeInit); 00281 00282 /* 00283 * Call Tcl_CreateCommand for application-specific commands, if 00284 * they weren't already created by the init procedures called above. 00285 */ 00286 00287 Tcl_CreateCommand(interp, "submit", (Tcl_CmdProc *) submit, 00288 (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); 00289 Tcl_CreateCommand(interp, "set_value", 00290 (Tcl_CmdProc *) set_value, 00291 (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); 00292 Tcl_CreateCommand(interp, "reset_values", 00293 (Tcl_CmdProc *) reset_values, 00294 (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); 00295 /* 00296 * Specify a user-specific startup file to invoke if the application 00297 * is run interactively. Typically the startup file is "~/.apprc" 00298 * where "app" is the name of the application. If this line is deleted 00299 * then no user-specific startup file will be run under any conditions. 00300 */ 00301 00302 Tcl_SetVar(interp, "tcl_rcFileName", "~/.grassformrc", TCL_GLOBAL_ONLY); 00303 return TCL_OK; 00304 } 00305 00306 int main(int argc, char *argv[]) 00307 { 00308 G_gisinit("form"); 00309 G_debug(2, "Form: main()"); 00310 00311 Tk_Main(argc, argv, Tcl_AppInit); 00312 return 0; 00313 }