Example #1
0
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;
}
Example #2
0
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 */
}