GRASS Programmer's Manual  6.4.2(2012)
form.c
Go to the documentation of this file.
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 }
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines