+ if (*s == '\'')
+ goto squote;
+ do {
+ const char *p = strchrnul(s, '\'');
+ /* print 'xxxx', possibly just '' */
+ printf("'%.*s'", (int)(p - s), s);
+ if (*p == '\0')
+ break;
+ s = p;
+ squote:
+ /* s points to '; print "'''...'''" */
+ putchar('"');
+ do putchar('\''); while (*++s == '\'');
+ putchar('"');
+ } while (*s);
+}
+
+#if !ENABLE_HUSH_LOCAL
+#define helper_export_local(argv, exp, lvl) \
+ helper_export_local(argv, exp)
+#endif
+static void helper_export_local(char **argv, int exp, int lvl)
+{
+ do {
+ char *name = *argv;
+
+ /* So far we do not check that name is valid (TODO?) */
+
+ if (strchr(name, '=') == NULL) {
+ struct variable *var;
+
+ var = get_local_var(name);
+ if (exp == -1) { /* unexporting? */
+ /* export -n NAME (without =VALUE) */
+ if (var) {
+ var->flg_export = 0;
+ debug_printf_env("%s: unsetenv '%s'\n", __func__, name);
+ unsetenv(name);
+ } /* else: export -n NOT_EXISTING_VAR: no-op */
+ continue;
+ }
+ if (exp == 1) { /* exporting? */
+ /* export NAME (without =VALUE) */
+ if (var) {
+ var->flg_export = 1;
+ debug_printf_env("%s: putenv '%s'\n", __func__, var->varstr);
+ putenv(var->varstr);
+ continue;
+ }
+ }
+ /* Exporting non-existing variable.
+ * bash does not put it in environment,
+ * but remembers that it is exported,
+ * and does put it in env when it is set later.
+ * We just set it to "" and export. */
+ /* Or, it's "local NAME" (without =VALUE).
+ * bash sets the value to "". */
+ name = xasprintf("%s=", name);
+ } else {
+ /* (Un)exporting/making local NAME=VALUE */
+ name = xstrdup(name);
+ }
+ set_local_var(name, /*exp:*/ exp, /*lvl:*/ lvl, /*ro:*/ 0);
+ } while (*++argv);
+}
+
+static int FAST_FUNC builtin_export(char **argv)
+{
+ unsigned opt_unexport;
+
+#if ENABLE_HUSH_EXPORT_N
+ /* "!": do not abort on errors */
+ opt_unexport = getopt32(argv, "!n");
+ if (opt_unexport == (uint32_t)-1)
+ return EXIT_FAILURE;
+ argv += optind;
+#else
+ opt_unexport = 0;
+ argv++;
+#endif
+
+ if (argv[0] == NULL) {