/* * POSIX library for Lua 5.1, 5.2 & 5.3. * (c) Gary V. Vaughan , 2013-2015 * (c) Reuben Thomas 2010-2013 * (c) Natanael Copa 2008-2010 * Clean up and bug fixes by Leo Razoumov 2006-10-11 * Luiz Henrique de Figueiredo 07 Apr 2006 23:17:49 * Based on original by Claudio Terra for Lua 3.x. * With contributions by Roberto Ierusalimschy. * With documentation from Steve Donovan 2012 */ /*** Command Line Argument Processing. @module posix.getopt */ #include #include #include "_helpers.c" /* getopt_long */ /* N.B. We don't need the symbolic constants no_argument, required_argument and optional_argument, since their values are defined as 0, 1 and 2 respectively. */ static const char *const arg_types[] = { "none", "required", "optional", NULL }; static int iter_getopt_long(lua_State *L) { int longindex = 0, ret, argc = lua_tointeger(L, lua_upvalueindex(1)); char **argv = (char **)lua_touserdata(L, lua_upvalueindex(3)); struct option *longopts = (struct option *)lua_touserdata(L, lua_upvalueindex(3 + argc + 1)); if (argv == NULL) /* If we have already completed, return now. */ return 0; /* Fetch upvalues to pass to getopt_long. */ ret = getopt_long(argc, argv, lua_tostring(L, lua_upvalueindex(2)), longopts, &longindex); if (ret == -1) return 0; else { char c = ret; lua_pushlstring(L, &c, 1); lua_pushstring(L, optarg); lua_pushinteger(L, optind); lua_pushinteger(L, longindex); return 4; } } /*** Parse command-line options. @function getopt @param arg command line arguments @string shortopts short option specifier @tparam[opt] table longopts long options table @int[opt=0] opterr index of the option with an error @int[opt=1] optind index of the next unprocessed option @return option iterator, returning 4 values @see getopt(3) @see getopt_long(3) @usage local longopts = { {"help", "none", 1}, {"version", "none", 3}, } for r, longindex, err, i in P.getopt (arg, "ho:v", longopts, err, i) do process (arg, err, i) end @see getopt.lua */ static int Pgetopt(lua_State *L) { int argc, i, n = 0; const char *shortopts; char **argv; struct option *longopts; checknargs(L, 5); checktype(L, 1, LUA_TTABLE, "list"); shortopts = luaL_checkstring(L, 2); if (!lua_isnoneornil(L, 3)) checktype(L, 3, LUA_TTABLE, "table or nil"); opterr = optint(L, 4, 0); optind = optint(L, 5, 1); argc = (int)lua_objlen(L, 1) + 1; lua_pushinteger(L, argc); lua_pushstring(L, shortopts); argv = lua_newuserdata(L, (argc + 1) * sizeof(char *)); argv[argc] = NULL; for (i = 0; i < argc; i++) { lua_pushinteger(L, i); lua_gettable(L, 1); argv[i] = (char *)luaL_checkstring(L, -1); } if (lua_type(L, 3) == LUA_TTABLE) { n = (int)lua_objlen(L, 3); } longopts = lua_newuserdata(L, (n + 1) * sizeof(struct option)); longopts[n].name = NULL; longopts[n].has_arg = 0; longopts[n].flag = NULL; longopts[n].val = 0; for (i = 1; i <= n; i++) { const char *name, *val; int has_arg; lua_pushinteger(L, i); lua_gettable(L, 3); luaL_checktype(L, -1, LUA_TTABLE); lua_pushinteger(L, 1); lua_gettable(L, -2); name = luaL_checkstring(L, -1); lua_pushinteger(L, 2); lua_gettable(L, -3); has_arg = luaL_checkoption(L, -1, NULL, arg_types); lua_pop(L, 1); lua_pushinteger(L, 3); lua_gettable(L, -3); val = luaL_checkstring(L, -1); lua_pop(L, 1); longopts[i - 1].name = name; longopts[i - 1].has_arg = has_arg; longopts[i - 1].flag = NULL; longopts[i - 1].val = val[0]; lua_pop(L, 1); } /* Push remaining upvalues, and make and push closure. */ lua_pushcclosure(L, iter_getopt_long, 4 + argc + n); return 1; } static const luaL_Reg posix_getopt_fns[] = { LPOSIX_FUNC( Pgetopt ), {NULL, NULL} }; LUALIB_API int luaopen_posix_getopt(lua_State *L) { luaL_register(L, "posix.getopt", posix_getopt_fns); lua_pushliteral(L, "posix.getopt for " LUA_VERSION " / " PACKAGE_STRING); lua_setfield(L, -2, "version"); return 1; }