Array f_getopt(CStrRef options, CVarRef longopts /* = null_variant */) { opt_struct *opts, *orig_opts; int len = parse_opts(options.data(), options.size(), &opts); if (!longopts.isNull()) { Array arropts = longopts.toArray(); int count = arropts.size(); /* the first <len> slots are filled by the one short ops * we now extend our array and jump to the new added structs */ opts = (opt_struct *)realloc(opts, sizeof(opt_struct) * (len + count + 1)); orig_opts = opts; opts += len; memset(opts, 0, count * sizeof(opt_struct)); for (ArrayIter iter(arropts); iter; ++iter) { String entry = iter.second().toString(); opts->need_param = 0; opts->opt_name = strdup(entry.data()); len = strlen(opts->opt_name); if ((len > 0) && (opts->opt_name[len - 1] == ':')) { opts->need_param++; opts->opt_name[len - 1] = '\0'; if ((len > 1) && (opts->opt_name[len - 2] == ':')) { opts->need_param++; opts->opt_name[len - 2] = '\0'; } } opts->opt_char = 0; opts++; } } else { opts = (opt_struct*) realloc(opts, sizeof(opt_struct) * (len + 1)); orig_opts = opts; opts += len; } /* php_getopt want to identify the last param */ opts->opt_char = '-'; opts->need_param = 0; opts->opt_name = NULL; static const StaticString s_argv("argv"); GlobalVariables *g = get_global_variables(); Array vargv = g->get(s_argv).toArray(); int argc = vargv.size(); char **argv = (char **)malloc((argc+1) * sizeof(char*)); vector<String> holders; int index = 0; for (ArrayIter iter(vargv); iter; ++iter) { String arg = iter.second().toString(); holders.push_back(arg); argv[index++] = (char*)arg.data(); } argv[index] = NULL; Array ret = Array::Create(); /* after our pointer arithmetic jump back to the first element */ opts = orig_opts; int o; char *php_optarg = NULL; int php_optind = 1; Variant val; int optchr = 0; int dash = 0; /* have already seen the - */ char opt[2] = { '\0' }; char *optname; int optname_len = 0; int php_optidx; while ((o = php_getopt(argc, argv, opts, &php_optarg, &php_optind, 0, 1, optchr, dash, php_optidx)) != -1) { /* Skip unknown arguments. */ if (o == '?') { continue; } /* Prepare the option character and the argument string. */ if (o == 0) { optname = opts[php_optidx].opt_name; } else { if (o == 1) { o = '-'; } opt[0] = o; optname = opt; } if (php_optarg != NULL) { /* keep the arg as binary, since the encoding is not known */ val = String(php_optarg, CopyString); } else { val = false; } /* Add this option / argument pair to the result hash. */ optname_len = strlen(optname); if (!(optname_len > 1 && optname[0] == '0') && is_numeric_string(optname, optname_len, NULL, NULL, 0) == KindOfInt64) { /* numeric string */ int optname_int = atoi(optname); if (ret.exists(optname_int)) { Variant &e = ret.lvalAt(optname_int); if (!e.isArray()) { ret.set(optname_int, CREATE_VECTOR2(e, val)); } else { e.append(val); } } else { ret.set(optname_int, val); } } else { /* other strings */ String key(optname, strlen(optname), CopyString); if (ret.exists(key)) { Variant &e = ret.lvalAt(key); if (!e.isArray()) { ret.set(key, CREATE_VECTOR2(e, val)); } else { e.append(val); } } else { ret.set(key, val); } } php_optarg = NULL; } free_longopts(orig_opts); free(orig_opts); free(argv); return ret; }
static int lgetopt_long_t(lua_State *l, func_t func) { const char *optstring = NULL; int result = 1; /* assume success */ int argc, ch, idx; char **argv = NULL; int error_func = 0; int numargs = lua_gettop(l); if ((numargs != 2 && numargs != 3 && numargs != 4) || lua_type(l,1) != LUA_TSTRING || lua_type(l,2) != LUA_TTABLE || (numargs >= 3 && (lua_type(l,3) != LUA_TTABLE && lua_type(l,3) != LUA_TNIL))) { ERROR("usage: getopt.long(optionstring, longopts[, resulttable[, errorfunc]])"); } if (numargs == 4 && lua_type(l,4) != LUA_TFUNCTION && lua_type(l,4) != LUA_TNIL) { ERROR("usage: getopt.long(optionstring, longopts[, resulttable[, errorfunc]])"); } if (numargs == 4 && lua_type(l,4) == LUA_TFUNCTION) { // We can't copy the error function - but we can make a // registry pointer. error_func = luaL_ref(l, LUA_REGISTRYINDEX); } optstring = lua_tostring(l, 1); /* Construct fake argc/argv from the magic lua 'arg' table. */ lua_getglobal(l, "arg"); construct_args(l, lua_gettop(l), &argc, &argv); lua_pop(l, 1); /* Construct a longopts struct from the one given. */ char **bound_variable_name = NULL; int *bound_variable_value = NULL; struct option *longopts = build_longopts(l, 2, &bound_variable_name, &bound_variable_value); /* Parse the options and store them in the Lua table. */ idx = -1; /* initialize idx to -1 so we can tell whether or not it's * updated by getopt_long (or whatever func() is) */ while ((ch=func(argc, argv, optstring, longopts, &idx)) > -1) { char buf[2] = { ch, 0 }; if (ch == '?' || ch == ':') { /* This is a special "got a bad option" character. Don't put it * in the table of results; just record that there's a failure. * The getopt call will have emitted an error to stderr. */ if (error_func) { lua_rawgeti(l, LUA_REGISTRYINDEX, error_func); lua_pushstring(l, buf); lua_call(l, 1, 0); // 1 argument, 0 results. Not protecting against errors. } result = 0; break; } if (idx == -1) { /* If idx == -1, then it wasn't updated by the library call; * that happens if it matches a short option. We'll have to dig * through and find it ourself. */ struct option *l = longopts; int i = 0; while (l[i].name) { if (l[i].val != 0 && l[i].val == ch) { idx = i; if (l[i].flag != NULL) { /* Fake the longopt "this is a bound variable thing" even * though it was called with a short variable? :/ */ ch = 0; *l[i].flag = l[i].val; } break; } i++; } } else { /* If we matched a long option with a val set, but the 'ch' is zero, * then we need to dig the character out of the option's "val" field * so we can set the captured value appropriately in the return opts. */ if (longopts[idx].val) { buf[0] = longopts[idx].val; if (longopts[idx].val <= 9) { /* Coerce to a character, rather than an integer */ buf[0] += '0'; } } } /* Call any available callbacks for this element, if we found the * element in the longopts struct list. */ if (idx != -1) { _call_callback(l, 2, &longopts[idx]); } /* Save the values in the user-specified return table. */ if (buf[0] && numargs >= 3 && lua_type(l,3) == LUA_TTABLE) { if (optarg) { lua_pushstring(l, optarg); } else { lua_pushboolean(l, 1); } lua_setfield(l, 3, buf); } if (ch == 0) { /* This is the special "bound a variable" return value. Perform * the bind. */ set_lua_variable(l, bound_variable_name[idx], bound_variable_value[idx]); } idx = -1; } /* Since the default behavior of many (but not all) getopt libraries is to * reorder argv so that non-arguments are all at the end (unless * POSIXLY_CORRECT is set or the options string begins with a '+'), we'll * go do that now. We do it by modifying the existing global table, which * will leave index [-1] in place if it's set (as it sometimes is). */ lua_getglobal(l, "arg"); int i; for (i=0; i<argc; i++) { lua_pushinteger(l, i); lua_pushstring(l, argv[i]); lua_rawset(l, -3); } free_longopts(longopts, bound_variable_name, bound_variable_value); free_args(argc, argv); if (error_func) { luaL_unref(l, LUA_REGISTRYINDEX, error_func); } /* Return 1 item on the stack (boolean) */ lua_pushboolean(l, result); return 1; /* # of arguments returned on stack */ }