+/*********************************************************************
+ *
+ * Function : actions_to_radio
+ *
+ * Description : Converts a actionsfile entry into settings for
+ * radio buttons and edit boxes on a HTML form.
+ *
+ * Parameters :
+ * 1 : exports = List of substitutions to add to.
+ * 2 : action = Action to read
+ *
+ * Returns : JB_ERR_OK on success
+ * JB_ERR_MEMORY on out-of-memory
+ *
+ *********************************************************************/
+static jb_err actions_to_radio(struct map * exports,
+ const struct action_spec *action)
+{
+ unsigned mask = action->mask;
+ unsigned add = action->add;
+ int mapped_param;
+ int checked;
+ char current_mode;
+
+ assert(exports);
+ assert(action);
+
+ mask = action->mask;
+ add = action->add;
+
+ /* sanity - prevents "-feature +feature" */
+ mask |= add;
+
+
+#define DEFINE_ACTION_BOOL(name, bit) \
+ if (!(mask & bit)) \
+ { \
+ current_mode = 'n'; \
+ } \
+ else if (add & bit) \
+ { \
+ current_mode = 'y'; \
+ } \
+ else \
+ { \
+ current_mode = 'x'; \
+ } \
+ if (map_radio(exports, name, "ynx", current_mode)) \
+ { \
+ return JB_ERR_MEMORY; \
+ }
+
+#define DEFINE_ACTION_STRING(name, bit, index) \
+ DEFINE_ACTION_BOOL(name, bit); \
+ mapped_param = 0;
+
+#define DEFINE_CGI_PARAM_RADIO(name, bit, index, value, is_default) \
+ if (add & bit) \
+ { \
+ checked = !strcmp(action->string[index], value); \
+ } \
+ else \
+ { \
+ checked = is_default; \
+ } \
+ mapped_param |= checked; \
+ if (map(exports, name "-param-" value, 1, (checked ? "checked" : ""), 1)) \
+ { \
+ return JB_ERR_MEMORY; \
+ }
+
+#define DEFINE_CGI_PARAM_CUSTOM(name, bit, index, default_val) \
+ if (map(exports, name "-param-custom", 1, \
+ ((!mapped_param) ? "checked" : ""), 1)) \
+ { \
+ return JB_ERR_MEMORY; \
+ } \
+ if (map(exports, name "-param", 1, \
+ (((add & bit) && !mapped_param) ? \
+ action->string[index] : default_val), 1)) \
+ { \
+ return JB_ERR_MEMORY; \
+ }
+
+#define DEFINE_CGI_PARAM_NO_RADIO(name, bit, index, default_val) \
+ if (map(exports, name "-param", 1, \
+ ((add & bit) ? action->string[index] : default_val), 1)) \
+ { \
+ return JB_ERR_MEMORY; \
+ }
+
+#define DEFINE_ACTION_MULTI(name, index) \
+ if (action->multi_add[index]->first) \
+ { \
+ current_mode = 'y'; \
+ } \
+ else if (action->multi_remove_all[index]) \
+ { \
+ current_mode = 'n'; \
+ } \
+ else if (action->multi_remove[index]->first) \
+ { \
+ current_mode = 'y'; \
+ } \
+ else \
+ { \
+ current_mode = 'x'; \
+ } \
+ if (map_radio(exports, name, "ynx", current_mode)) \
+ { \
+ return JB_ERR_MEMORY; \
+ }
+
+#define DEFINE_ACTION_ALIAS 0 /* No aliases for output */
+
+#include "actionlist.h"
+
+#undef DEFINE_ACTION_MULTI
+#undef DEFINE_ACTION_STRING
+#undef DEFINE_ACTION_BOOL
+#undef DEFINE_ACTION_ALIAS
+#undef DEFINE_CGI_PARAM_CUSTOM
+#undef DEFINE_CGI_PARAM_RADIO
+#undef DEFINE_CGI_PARAM_NO_RADIO
+
+ return JB_ERR_OK;
+}
+
+
+/*********************************************************************
+ *
+ * Function : javascriptify
+ *
+ * Description : Converts a string into a form JavaScript will like.
+ *
+ * Netscape 4's JavaScript sucks - it doesn't use
+ * "id" parameters, so you have to set the "name"
+ * used to submit a form element to something JavaScript
+ * will like. (Or access the elements by index in an
+ * array. That array contains >60 elements and will
+ * be changed whenever we add a new action to the
+ * editor, so I'm NOT going to use indexes that have
+ * to be figured out by hand.)
+ *
+ * Currently the only thing we have to worry about
+ * is "-" ==> "_" conversion.
+ *
+ * This is a length-preserving operation so it is
+ * carried out in-place, no memory is allocated
+ * or freed.
+ *
+ * Parameters :
+ * 1 : identifier = String to make JavaScript-friendly.
+ *
+ * Returns : N/A
+ *
+ *********************************************************************/
+static void javascriptify(char * identifier)
+{
+ char * p = identifier;
+ while (NULL != (p = strchr(p, '-')))
+ {
+ *p++ = '_';
+ }
+}
+
+
+/*********************************************************************
+ *
+ * Function : actions_from_radio
+ *
+ * Description : Converts a map of parameters passed to a CGI function
+ * into an actionsfile entry.
+ *
+ * Parameters :
+ * 1 : parameters = parameters to the CGI call
+ * 2 : action = Action to change. Must be valid before
+ * the call, actions not specified will be
+ * left unchanged.
+ *
+ * Returns : JB_ERR_OK on success
+ * JB_ERR_MEMORY on out-of-memory
+ *
+ *********************************************************************/
+static jb_err actions_from_radio(const struct map * parameters,
+ struct action_spec *action)
+{
+ static int first_time = 1;
+ const char * param;
+ char * param_dup;
+ char ch;
+ const char * js_name;
+
+ assert(parameters);
+ assert(action);
+
+ /* Statics are generally a potential race condition,
+ * but in this case we're safe and don't need semaphores.
+ * Be careful if you modify this function.
+ * - Jon
+ */
+
+#define JAVASCRIPTIFY(dest_var, string) \
+ { \
+ static char js_name_arr[] = string; \
+ if (first_time) \
+ { \
+ javascriptify(js_name_arr); \
+ } \
+ dest_var = js_name_arr; \
+ } \
+
+#define DEFINE_ACTION_BOOL(name, bit) \
+ JAVASCRIPTIFY(js_name, name); \
+ param = lookup(parameters, js_name); \
+ ch = ijb_toupper(param[0]); \
+ if (ch == 'Y') \
+ { \
+ action->add |= bit; \
+ action->mask |= bit; \
+ } \
+ else if (ch == 'N') \
+ { \
+ action->add &= ~bit; \
+ action->mask &= ~bit; \
+ } \
+ else if (ch == 'X') \
+ { \
+ action->add &= ~bit; \
+ action->mask |= bit; \
+ } \
+
+#define DEFINE_ACTION_STRING(name, bit, index) \
+ JAVASCRIPTIFY(js_name, name); \
+ param = lookup(parameters, js_name); \
+ ch = ijb_toupper(param[0]); \
+ if (ch == 'Y') \
+ { \
+ JAVASCRIPTIFY(js_name, name "-mode"); \
+ param = lookup(parameters, js_name); \
+ if ((*param == '\0') || (0 == strcmp(param, "CUSTOM"))) \
+ { \
+ JAVASCRIPTIFY(js_name, name "-param"); \
+ param = lookup(parameters, js_name); \
+ } \
+ if (*param != '\0') \
+ { \
+ if (NULL == (param_dup = strdup(param))) \
+ { \
+ return JB_ERR_MEMORY; \
+ } \
+ freez(action->string[index]); \
+ action->add |= bit; \
+ action->mask |= bit; \
+ action->string[index] = param_dup; \
+ } \
+ } \
+ else if (ch == 'N') \
+ { \
+ if (action->add & bit) \
+ { \
+ freez(action->string[index]); \
+ } \
+ action->add &= ~bit; \
+ action->mask &= ~bit; \
+ } \
+ else if (ch == 'X') \
+ { \
+ if (action->add & bit) \
+ { \
+ freez(action->string[index]); \
+ } \
+ action->add &= ~bit; \
+ action->mask |= bit; \
+ } \
+
+#define DEFINE_ACTION_MULTI(name, index) \
+ JAVASCRIPTIFY(js_name, name); \
+ param = lookup(parameters, js_name); \
+ ch = ijb_toupper((int)param[0]); \
+ if (ch == 'Y') \
+ { \
+ /* FIXME */ \
+ } \
+ else if (ch == 'N') \
+ { \
+ list_remove_all(action->multi_add[index]); \
+ list_remove_all(action->multi_remove[index]); \
+ action->multi_remove_all[index] = 1; \
+ } \
+ else if (ch == 'X') \
+ { \
+ list_remove_all(action->multi_add[index]); \
+ list_remove_all(action->multi_remove[index]); \
+ action->multi_remove_all[index] = 0; \
+ } \
+
+#define DEFINE_ACTION_ALIAS 0 /* No aliases for URL parsing */
+
+#include "actionlist.h"
+
+#undef DEFINE_ACTION_MULTI
+#undef DEFINE_ACTION_STRING
+#undef DEFINE_ACTION_BOOL
+#undef DEFINE_ACTION_ALIAS
+#undef JAVASCRIPTIFY
+
+ first_time = 0;
+
+ return JB_ERR_OK;
+}
+
+