%% options copyright owner = Dirk Krause copyright year = 2014 license = bsd %% module #include "dk3all.h" #include "dkt.h" #include "dkwt.h" #include "dk3wreg.h" $!trace-include /** @defgroup dkwt_env_cmd_types Commands for dkwt env. */ /**@{*/ /** Set or show variable. */ #define DKWT_ENV_CMD_NORMAL 0 /** Unset variable (remove registry entry). */ #define DKWT_ENV_CMD_UNSET 1 /** Insert directory at start of value if not yet present. */ #define DKWT_ENV_CMD_INSERT 2 /** Append directory at end of value if not yet present. */ #define DKWT_ENV_CMD_APPEND 3 /** Delete directory from value if present. */ #define DKWT_ENV_CMD_DELETE 4 /** Illegal options combination found. */ #define DKWT_ENV_CMD_ERROR 5 /**@}*/ /** Job structure for dkwt env. */ typedef struct { dk3_app_t *app; /**< Application structure. */ dkChar const * const *msg; /**< Localized message texts. */ dkChar const * const *kwnl; /**< Keywords, not localized. */ dkChar const *name; /**< Environment variable name. */ dkChar const *value; /**< Environment variable value. */ dk3_option_set_t *opt; /**< Options set. */ int exv; /**< Exit value. */ int cmd; /**< Command to execute. */ int sys; /**< Flag: Dealing with system variables. */ int exp; /**< Flag: Use REG_EXPAND_SZ for new entry. */ } DKWT_ENV_J; /** Keywords used by the module. */ dkChar const * const dkwt_env_kw[] = { $!string-table macro=dkT # # 0 Space # # # 1 Key name for system environment # SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment # # 2 Key name for user environment # Environment # # 3 Separator # ; $!end }; /** Options allowed for dkwt env. */ static dk3_option_t const dkwt_env_options[] = { { dkT('s'), dkT("system"), 0 }, { dkT('u'), dkT("unset"), 0 }, { dkT('i'), dkT("insert"), 0 }, { dkT('a'), dkT("append"), 0 }, { dkT('d'), dkT("delete"), 0 }, { dkT('e'), dkT("expand"), 0 } }; /** Number of elements in dkwt_env_options array. */ static size_t const dkwt_env_szoptions = sizeof(dkwt_env_options)/sizeof(dk3_option_t); /** Initialize job structure. @param j Job structure to initialize. */ static void dkwt_env_job_init(DKWT_ENV_J *j) { j->app = NULL; j->msg = NULL; j->kwnl = NULL; j->opt = NULL; j->name = NULL; j->value = NULL; j->exv = DKT_RESULT_ERR_UNSPECIFIC; j->cmd = DKWT_ENV_CMD_NORMAL; j->sys = 0; j->exp = 0; } /** Clean up job structure after processing. @param j Job structure to clean up. */ static void dkwt_env_job_cleanup(DKWT_ENV_J *j) { if (j->value) { dk3_delete(j->value); } j->value = NULL; if (j->opt) { dk3opt_close(j->opt); } j->opt = NULL; } /** Process command line arguments. @param j Job structure. @return 1 on success, 0 on error. */ static int dkwt_env_process_args(DKWT_ENV_J *j) { int back = 0; int xargc; dkChar const * const *xargv; xargc = dk3app_get_argc(j->app); xargv = dk3app_get_argv(j->app); if (1 < xargc) { xargv++; xargv++; xargc--; xargc--; j->opt = dk3opt_open_app( dkwt_env_options, dkwt_env_szoptions, dkT('\0'), NULL, xargc, xargv, j->app ); if (j->opt) { if (0 == dk3opt_get_error_code(j->opt)) { back = 1; if (dk3opt_is_set(j->opt, dkT('s'))) { j->sys = 1; } if (dk3opt_is_set(j->opt, dkT('e'))) { j->exp = 1; } if (dk3opt_is_set(j->opt, dkT('u'))) { j->cmd = DKWT_ENV_CMD_UNSET; } if (dk3opt_is_set(j->opt, dkT('i'))) { if (j->cmd) { j->cmd = DKWT_ENV_CMD_ERROR; back = 0; /* ERROR: -u -i -a -d are mutual exclusive */ dk3app_log_1(j->app, DK3_LL_ERROR, j->msg, 142); } else { j->cmd = DKWT_ENV_CMD_INSERT; } } if (dk3opt_is_set(j->opt, dkT('a'))) { if (j->cmd) { j->cmd = DKWT_ENV_CMD_ERROR; back = 0; /* ERROR: Mutual exclusive */ dk3app_log_1(j->app, DK3_LL_ERROR, j->msg, 142); } else { j->cmd = DKWT_ENV_CMD_APPEND; } } if (dk3opt_is_set(j->opt, dkT('d'))) { if (j->cmd) { j->cmd = DKWT_ENV_CMD_ERROR, back = 0; /* ERROR: Mutual exlusive */ dk3app_log_1(j->app, DK3_LL_ERROR, j->msg, 142); } else { j->cmd = DKWT_ENV_CMD_DELETE; } } if (back) { if (0 >= dk3opt_get_num_args(j->opt)) { j->cmd = DKWT_ENV_CMD_ERROR; back = 0; /* ERROR: At least one argument required */ dk3app_log_1(j->app, DK3_LL_ERROR, j->msg, 143); } else { j->name = dk3opt_get_arg(j->opt, 0); if (!(j->name)) { j->cmd = DKWT_ENV_CMD_ERROR; back = 0; $? "! BUG" } } } } } } return back; } /** Check whether an environment variable value contains a directory. @param valptr String to check for a directory name. @param dir Directory name to search for. @return 1 on success (directory found), 0 otherwise. */ static int dkwt_env_value_contains_dir(dkChar *valptr, dkChar const *dir) { dkChar *pc; dkChar *pn; int back = 0; pc = valptr; while ((0 == back) && (pc)) { pn = dk3str_chr(pc, dkT(';')); if (pn) { *(pn++) = dkT('\0'); } if (0 == dk3str_fncmp(pc, dir)) { back = 1; } pc = pn; } return back; } /** Process the request. @param j Job structure containing configuration. */ static void dkwt_env_do_processing(DKWT_ENV_J *j) { dkChar *b1 = NULL; /* Original registry value */ dkChar *b2 = NULL; /* Second buffer */ dkChar *pc; /* Current part */ dkChar *pn; /* Next part */ DWORD dwrv = (DWORD)0UL; /* Return value for message */ DWORD dwtf = REG_SZ; /* Type found */ HKEY hk = (HKEY)0; /* Registry key */ size_t lgt; /* Length */ int fmod = 0; /* Flag: Modification */ int res = 0; /* Registry operation result */ int wre = 0; /* Write expanded */ int hco = 0; /* Flag: Contents in out buf */ switch (j->cmd) { case DKWT_ENV_CMD_NORMAL: case DKWT_ENV_CMD_UNSET: case DKWT_ENV_CMD_INSERT: case DKWT_ENV_CMD_APPEND: case DKWT_ENV_CMD_DELETE: { b1 = dk3_new_app(dkChar, 8192, j->app); if (b1) { if ((DKWT_ENV_CMD_NORMAL == j->cmd) && (!(j->value))) { if (j->sys) { res = dk3wreg_key_open_read( HKEY_LOCAL_MACHINE, dkwt_env_kw[1], &hk, j->app ); } else { res = dk3wreg_key_open_read( HKEY_CURRENT_USER, dkwt_env_kw[2], &hk, j->app ); } } else { if (j->sys) { res = dk3wreg_key_open_modify( HKEY_LOCAL_MACHINE, dkwt_env_kw[1], &hk, j->app ); } else { res = dk3wreg_key_open_modify( HKEY_CURRENT_USER, dkwt_env_kw[2], &hk, j->app ); } } if (res) { switch (j->cmd) { case DKWT_ENV_CMD_NORMAL: { if (j->value) { if (dk3wreg_get_expand_sz(hk, j->name, b1, 8191, &dwtf, NULL)) { if (REG_EXPAND_SZ == dwtf) { wre = 1; } } else { if (j->exp) { wre = 1; } } if (wre) { res = dk3wreg_set_expand_sz(hk, j->name, j->value, j->app); } else { res = dk3wreg_set_sz(hk, j->name, j->value, j->app); } if (res) { fmod = 1; } else { j->exv = DKT_RESULT_ERR_UNSPECIFIC; } } else { if (dk3wreg_get_sz(hk, j->name, b1, 8191, j->app)) { dk3sf_initialize_stdout(); dk3sf_fputs(b1, stdout); dk3sf_fputc(dkT('\n'), stdout); } else { j->exv = DKT_RESULT_ERR_UNSPECIFIC; } } } break; case DKWT_ENV_CMD_UNSET: { if(dk3wreg_entry_delete(hk, j->name, j->app)) { fmod = 1; } else { j->exv = DKT_RESULT_ERR_UNSPECIFIC; } } break; case DKWT_ENV_CMD_INSERT: { if (j->value) { if (dk3wreg_get_expand_sz(hk, j->name, b1, 8191, &dwtf, NULL)) { lgt = dk3str_len(b1) + dk3str_len(j->value) + 2; b2 = dk3_new_app(dkChar, lgt, j->app); if (b2) { dk3str_cpy(b2, b1); if (!(dkwt_env_value_contains_dir(b2, j->value))) { dk3str_cpy(b2, j->value); dk3str_cat(b2, dkwt_env_kw[3]); dk3str_cat(b2, b1); if (REG_EXPAND_SZ == dwtf) { res = dk3wreg_set_expand_sz(hk, j->name, b2, j->app); } else { res = dk3wreg_set_sz(hk, j->name, b2, j->app); } if (res) { fmod = 1; } else { j->exv = DKT_RESULT_ERR_UNSPECIFIC; } } dk3_delete(b2); } else { j->exv = DKT_RESULT_ERR_UNSPECIFIC; } } else { if (j->exp) { res = dk3wreg_set_expand_sz(hk, j->name, j->value, j->app); } else { res = dk3wreg_set_sz(hk, j->name, j->value, j->app); } if (res) { fmod = 1; } else { j->exv = DKT_RESULT_ERR_UNSPECIFIC; } } } else { j->exv = DKT_RESULT_ERR_UNSPECIFIC; /* ERROR: Value required! */ dk3app_log_1(j->app, DK3_LL_ERROR, j->msg, 144); } } break; case DKWT_ENV_CMD_APPEND: { if (j->value) { if (dk3wreg_get_expand_sz(hk, j->name, b1, 8191, &dwtf, NULL)) { lgt = dk3str_len(b1) + dk3str_len(j->value) + 2; b2 = dk3_new_app(dkChar, lgt, j->app); if (b2) { dk3str_cpy(b2, b1); if (!(dkwt_env_value_contains_dir(b2, j->value))) { dk3str_cpy(b2, b1); dk3str_cat(b2, dkwt_env_kw[3]); dk3str_cat(b2, j->value); if (REG_EXPAND_SZ == dwtf) { res = dk3wreg_set_expand_sz(hk, j->name, b2, j->app); } else { res = dk3wreg_set_sz(hk, j->name, b2, j->app); } if (res) { fmod = 1; } else { j->exv = DKT_RESULT_ERR_UNSPECIFIC; } } dk3_delete(b2); } else { j->exv = DKT_RESULT_ERR_UNSPECIFIC; } } else { if (j->exp) { res = dk3wreg_set_expand_sz(hk, j->name, j->value, j->app); } else { res = dk3wreg_set_sz(hk, j->name, j->value, j->app); } if (res) { fmod = 1; } else { j->exv = DKT_RESULT_ERR_UNSPECIFIC; } } } else { j->exv = DKT_RESULT_ERR_UNSPECIFIC; /* ERROR: Value required! */ dk3app_log_1(j->app, DK3_LL_ERROR, j->msg, 144); } } break; case DKWT_ENV_CMD_DELETE: { if (j->value) { if (dk3wreg_get_expand_sz(hk, j->name, b1, 8191, &dwtf, NULL)) { lgt = 1 + dk3str_len(b1); b2 = dk3_new_app(dkChar, lgt, j->app); if (b2) { b2[0] = dkT('\0'); pc = b1; while (pc) { pn = dk3str_chr(pc, dkT(';')); if (pn) { *(pn++) = dkT('\0'); } if (dk3str_fncmp(pc, j->value)) { if (hco) { dk3str_cat(b2, dkwt_env_kw[3]); dk3str_cat(b2, pc); } else { dk3str_cpy(b2, pc); } hco = 1; } pc = pn; } if (hco) { if (REG_EXPAND_SZ == dwtf) { res = dk3wreg_set_expand_sz(hk, j->name, b2, j->app); } else { res = dk3wreg_set_sz(hk, j->name, b2, j->app); } if (res) { fmod = 1; } else { j->exv = DKT_RESULT_ERR_UNSPECIFIC; } } else { if (dk3wreg_entry_delete(hk, j->name, j->app)) { fmod = 1; } else { j->exv = DKT_RESULT_ERR_UNSPECIFIC; } } dk3_delete(b2); } else { j->exv = DKT_RESULT_ERR_UNSPECIFIC; } } } else { j->exv = DKT_RESULT_ERR_UNSPECIFIC; /* ERROR: Value required! */ dk3app_log_1(j->app, DK3_LL_ERROR, j->msg, 144); } } break; } RegCloseKey(hk); } else { j->exv = DKT_RESULT_ERR_UNSPECIFIC; } dk3_delete(b1); if (fmod) { SendMessageTimeout( HWND_BROADCAST, WM_SETTINGCHANGE, 0, (LPARAM)"Environment", SMTO_ABORTIFHUNG, 5000, &dwrv ); } } else { j->exv = DKT_RESULT_ERR_UNSPECIFIC; } } break; default: { j->exv = DKT_RESULT_ERR_UNSPECIFIC; } break; } } /** Do processing. @param j Job structure containing configuration. */ static void dkwt_env_run(DKWT_ENV_J *j) { dkChar const *p1; /* Part of the name */ dkChar *buffer = NULL; /* Buffer to construct value */ size_t vallgt = 0; /* Value length */ int i = 0; /* Traverse options */ j->exv = DKT_RESULT_OK; /* Find value length. */ vallgt = 0; for (i = 1; i < dk3opt_get_num_args(j->opt); i++) { if (1 < i) { vallgt++; } p1 = dk3opt_get_arg(j->opt, i); if (p1) { vallgt += dk3str_len(p1); } else { j->exv = DKT_RESULT_ERR_UNSPECIFIC; } } if (vallgt) { vallgt++; } /* Create value string. */ if (DKT_RESULT_OK == j->exv) { if (0 < vallgt) { buffer = dk3_new_app(dkChar,vallgt,j->app); if (buffer) { j->value = buffer; buffer[0] = dkT('\0'); for (i = 1; i < dk3opt_get_num_args(j->opt); i++) { p1 = dk3opt_get_arg(j->opt, i); if (1 < i) { dk3str_cat(buffer, dkwt_env_kw[0]); dk3str_cat(buffer, p1); } else { dk3str_cpy(buffer, p1); } } } else { j->exv = DKT_RESULT_ERR_UNSPECIFIC; } } } /* Process the request. */ if (DKT_RESULT_OK == j->exv) { dkwt_env_do_processing(j); } } int dkwt_env( dk3_app_t *app, dkChar const * const *msg, dkChar const * const *kwnl ) { DKWT_ENV_J job; int back = DKT_RESULT_ERR_UNSPECIFIC; $? "+ dkwt_env" dkwt_env_job_init(&job); job.app = app; job.msg = msg; job.kwnl = kwnl; if (dkwt_env_process_args(&job)) { dkwt_env_run(&job); } back = job.exv; dkwt_env_job_cleanup(&job); $? "- dkwt_env %d", back return back; }