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