a580e12000-09-27Fredrik Hübinette (Hubbe) #pike __REAL_VERSION__
a20af62000-09-26Fredrik Hübinette (Hubbe) 
883adb2000-12-13Henrik Grubbström (Grubba) //! @[Getopt] is a group of function which can be used to find command //! line options. //! //! Command line options come in two flavors: long and short. The short ones //! consists of a dash followed by a character (@tt{-t@}), the long ones //! consist of two dashes followed by a string of text (@tt{--test@}). //! The short options can also be combined, which means that you can write //! @tt{-tda@} instead of @tt{-t -d -a@}. //! //! Options can also require arguments, in which case they cannot be //! combined. To write an option with an argument you write //! @tt{-t @i{argument@}@} or @tt{-t@i{argument@}@} or //! @tt{--test=@i{argument@}@}.
c2a4061997-02-06Fredrik Hübinette (Hubbe) // startpid = (int)find_arg(argv, "s", ({ "start-script-pid" }), // ({ "ROXEN_START_SCRIPT_PID"})); // configuration_dir = find_arg(argv, "d", ({ "config-dir", // "configurations", // "configuration-directory" }), // ({ "ROXEN_CONFIGDIR", "CONFIGURATIONS" }), // "../configurations");
7f4f862001-05-10Henrik Grubbström (Grubba) //! This is a generic function to parse command line options of the //! type @tt{-f@}, @tt{--foo@} or @tt{--foo=bar@}.
883adb2000-12-13Henrik Grubbström (Grubba) //!
7f4f862001-05-10Henrik Grubbström (Grubba) //! @param argv //! The first argument should be the array of strings that was sent as //! the second argument to your @tt{main()@} function.
883adb2000-12-13Henrik Grubbström (Grubba) //!
7f4f862001-05-10Henrik Grubbström (Grubba) //! @param shortform //! The second is a string with the short form of your option. //! The short form must be only one character long.
883adb2000-12-13Henrik Grubbström (Grubba) //!
7f4f862001-05-10Henrik Grubbström (Grubba) //! @param longform //! This is an alternative and maybe more readable way to //! give the same option. If you give @tt{"foo"@} as @[longform] your program //! will accept @tt{--foo@} as argument.
883adb2000-12-13Henrik Grubbström (Grubba) //!
7f4f862001-05-10Henrik Grubbström (Grubba) //! @param envvars //! This argument specifies the environment variables that can be //! used to specify the same option. This option exists to make it easier //! to customize program usage.
883adb2000-12-13Henrik Grubbström (Grubba) //!
7f4f862001-05-10Henrik Grubbström (Grubba) //! @param def //! This argument has two functions: It specifies if the option takes an //! argument or not, and it informs @[find_option()] what to return if the //! option is not present. If @[def] is given and the option does not have an //! argument @[find_option()] will fail.
883adb2000-12-13Henrik Grubbström (Grubba) //!
7f4f862001-05-10Henrik Grubbström (Grubba) //! @param throw_errors //! If @[throw_errors] has been specified @[find_option] will throw errors //! on failure. If it has been left out, or is @tt{0@} (zero), it will //! instead print an error message and exit the program on failure.
883adb2000-12-13Henrik Grubbström (Grubba) //!
7f4f862001-05-10Henrik Grubbström (Grubba) //! Also, as an extra bonus: @[shortform], @[longform] and @[envvars] can //! all be arrays, in which case any of the options in the array will be //! accepted. //! //! @returns //! Returns the value the option has been set to if any. //! //! If the option is present, but has not been set to anything @tt{1@} //! will be returned. //! //! Otherwise if any of the environment variables specified in @[env] has //! been set, that value will be return. //! //! If all else fails, @[def] will be returned.
883adb2000-12-13Henrik Grubbström (Grubba) //! //! @note
7f4f862001-05-10Henrik Grubbström (Grubba) //! @[find_option()] modifies argv. //! //! This function reads options even if they are written after the first //! non-option on the line.
883adb2000-12-13Henrik Grubbström (Grubba) //!
7f4f862001-05-10Henrik Grubbström (Grubba) //! Index @tt{0@} (zero) of @[argv] is not scanned for options, since it //! is reserved for the program name.
883adb2000-12-13Henrik Grubbström (Grubba) //! //! @seealso
7f4f862001-05-10Henrik Grubbström (Grubba) //! @[Getopt.get_args()]
883adb2000-12-13Henrik Grubbström (Grubba) //!
0662a92000-07-12Henrik Grubbström (Grubba) string|int find_option(array(string) argv, array(string)|string shortform, array(string)|string|void longform, array(string)|string|void envvars, string|int|void def,
1a95de1997-08-31Henrik Grubbström (Grubba)  int|void throw_errors)
c2a4061997-02-06Fredrik Hübinette (Hubbe) {
0662a92000-07-12Henrik Grubbström (Grubba)  string|int value;
c2a4061997-02-06Fredrik Hübinette (Hubbe)  int i,hasarg; hasarg=query_num_arg() > 4;
0662a92000-07-12Henrik Grubbström (Grubba)  if(!arrayp(longform)) longform=({[string]longform}); if(!arrayp(shortform)) shortform=({[string]shortform}); if(!arrayp(envvars)) envvars=({[string]envvars});
c2a4061997-02-06Fredrik Hübinette (Hubbe)  for(i=1; i<sizeof(argv); i++) { if(argv[i] && strlen(argv[i]) > 1) { if(argv[i][0] == '-') { if(argv[i][1] == '-') { string tmp; int nf; if(argv[i]=="--") break; sscanf(tmp=argv[i], "%s=%s", tmp, value); if(search(longform, tmp[2..]) != -1) { argv[i]=0; if(hasarg) { if(!value) { if(i == sizeof(argv)-1) {
1a95de1997-08-31Henrik Grubbström (Grubba)  if (throw_errors) { throw(({ "No argument to option "+tmp+".\n", backtrace() })); } else { werror("No argument to option "+tmp+".\n"); exit(1); }
c2a4061997-02-06Fredrik Hübinette (Hubbe)  } value=argv[i+1]; argv[i+1]=0; } return value; } else { return value || 1; } } } else { int j; for(j=1;j<strlen(argv[i]);j++) { string opt; int pos; if(search(shortform, opt=argv[i][j..j]) != -1) { string arg; arg=argv[i][j+1..]; if(hasarg) { if(arg=="") { if(i == sizeof(argv)-1) {
1a95de1997-08-31Henrik Grubbström (Grubba)  if (throw_errors) { throw(({ "No argument to option -"+argv[i][j..j]+".\n", backtrace() })); } else { werror("No argument to option -"+argv[i][j..j]+".\n"); exit(1); } }
c2a4061997-02-06Fredrik Hübinette (Hubbe)  value=argv[i+1]; argv[i+1] = 0; } else { value=arg; arg=""; } } else { value=1; } argv[i]=argv[i][..j-1]+arg; if(argv[i]=="-") argv[i]=0; return value; } } } } } } if(arrayp(envvars))
0662a92000-07-12Henrik Grubbström (Grubba)  foreach([array(string)]envvars, value) if(value && (value=[string]getenv([string]value)))
c2a4061997-02-06Fredrik Hübinette (Hubbe)  return value; return def; } /* * ({ "name", type, ({aliases}), env_var, default }) */ constant HAS_ARG=1; constant NO_ARG=2; constant MAY_HAVE_ARG=3; #define NAME 0 #define TYPE 1 #define ALIASES 2 #define ENV 3 #define DEF 4
7f4f862001-05-10Henrik Grubbström (Grubba) //! This function does the job of several calls to @[find_option()]. //! The main advantage of this is that it allows it to handle the //! @tt{@b{POSIX_ME_HARDER@}@} environment variable better. When the either //! the argument @[posix_me_harder] or the environment variable //! @tt{@b{POSIX_ME_HARDER@}@} is true, no arguments will be parsed after //! the first non-option on the command line. //! //! @param argv //! The should be the array of strings that was sent as //! the second argument to your @tt{main()@} function. //! //! @param options //! Each element in the array @[options] should be an array on the //! following form: //! @array //! @elem string name //! Name is a tag used to identify the option in the output. //! @elem int type //! Type is one of @[Getopt.HAS_ARG], @[Getopt.NO_ARG] and //! @[Getopt.MAY_HAVE_ARG] and it affects how the error handling //! and parsing works. //! You should use @[HAS_ARG] for options that require a path, a number //! or similar. @[NO_ARG] should be used for options that do not need an //! argument, such as @tt{--version@}. @[MAY_HAVE_ARG] should be used //! for options that may or may not need an argument. //! @elem string|array(string) aliases //! This is a string or an array of string of options that will be //! looked for. Short and long options can be mixed, and short options //! can be combined into one string. Note that you must include the //! dashes so that @[find_all_options()] can distinguish between //! long and short options. Example: @tt{({"-tT","--test"})@} //! This would make @[find_all_options] look for @tt{-t@}, //! @tt{-T@} and @tt{--test@}. //! @elem void|string|array(string) env_var //! This is a string or an array of strings containing names of //! environment variables that can be used instead of the //! command line option. //! @elem void|mixed default //! This is the default value the option will have in the output //! from this function. Options without defaults will be omitted //! from the output if they are not found in argv. //! @endarray //! //! Only the first three elements need to be included. //! //! @param posix_me_harder //! Don't scan for arguments after the first non-option. //! //! @param throw_errors //! If @[throw_errors] has been specified @[find_all_options()] will throw //! errors on failure. If it has been left out, or is @tt{0@} (zero), it will //! instead print an error message and exit the program on failure.
883adb2000-12-13Henrik Grubbström (Grubba) //! //! @returns
7f4f862001-05-10Henrik Grubbström (Grubba) //! The good news is that the output from this function is a lot simpler. //! @[find_all_options()] returns an array where each element is an array on //! this form: //! @array //! @elem string name //! Option identifier name from the input. //! @elem mixed value //! Value given. If no value was specified, and no default has been //! specified, the value will be 1. //! @endarray
883adb2000-12-13Henrik Grubbström (Grubba) //! //! @note
7f4f862001-05-10Henrik Grubbström (Grubba) //! @[find_all_options()] modifies @[argv]. //! //! Index @tt{0@} (zero) of @[argv] is not scanned for options, since it //! is reserved for the program name.
883adb2000-12-13Henrik Grubbström (Grubba) //! //! @seealso
7f4f862001-05-10Henrik Grubbström (Grubba) //! @[Getopt.get_args()], @[Getopt.find_option()]
883adb2000-12-13Henrik Grubbström (Grubba) //!
0662a92000-07-12Henrik Grubbström (Grubba) array find_all_options(array(string) argv, array(array(array(string)|string)) options,
1790d12000-03-30Henrik Grubbström (Grubba)  void|int posix_me_harder, void|int throw_errors)
c2a4061997-02-06Fredrik Hübinette (Hubbe) {
0662a92000-07-12Henrik Grubbström (Grubba)  mapping(string:array(string|array(string))) quick=([]); foreach(options, array(array(string)|string) opt)
c2a4061997-02-06Fredrik Hübinette (Hubbe)  {
0662a92000-07-12Henrik Grubbström (Grubba)  array(string)|string aliases=[array(string)|string]opt[ALIASES]; if(!arrayp(aliases)) aliases=({[string]aliases}); foreach([array(string)]aliases, string optname)
c2a4061997-02-06Fredrik Hübinette (Hubbe)  { if(optname[0..1]=="--") { quick[optname]=opt; }else{ foreach(optname[1..]/"",string optletter) { quick["-"+optletter]=opt; } } } }
1790d12000-03-30Henrik Grubbström (Grubba)  array ret=({});
c2a4061997-02-06Fredrik Hübinette (Hubbe)  for(int e=1;e<sizeof(argv);e++) { if(!argv[e]) continue; if(strlen(argv[e]) && argv[e][0]=='-') { if(strlen(argv[e])>1 && argv[e][1]=='-') { string opt=argv[e]; if(opt=="--") break; string arg; sscanf(opt,"%s=%s",opt, arg);
adfab72000-03-30Henrik Grubbström (Grubba)  if(array option=quick[opt])
c2a4061997-02-06Fredrik Hübinette (Hubbe)  { argv[e]=0; if(!arg && option[TYPE]==HAS_ARG) { if(e==sizeof(argv)-1) {
1a95de1997-08-31Henrik Grubbström (Grubba)  if (throw_errors) { throw(({ "No argument to option "+opt+".\n", backtrace() })); } else { werror("No argument to option "+opt+".\n"); exit(1); }
c2a4061997-02-06Fredrik Hübinette (Hubbe)  } arg=argv[e+1]; argv[e+1]=0; } ret+=({ ({ option[0], arg || 1 }) }); } }else{
1790d12000-03-30Henrik Grubbström (Grubba)  array(string) foo=argv[e]/"";
c2a4061997-02-06Fredrik Hübinette (Hubbe)  for(int j=1;j<strlen(foo);j++) { string opt="-"+foo[j];
1790d12000-03-30Henrik Grubbström (Grubba)  if(array option=quick[opt])
c2a4061997-02-06Fredrik Hübinette (Hubbe)  { foo[j]=0; string arg; if(option[TYPE]!=NO_ARG) { arg=argv[e][j+1..]; if(option[TYPE]==HAS_ARG && arg=="") { if(e==sizeof(argv)-1) {
1a95de1997-08-31Henrik Grubbström (Grubba)  if (throw_errors) { throw(({ "No argument to option "+opt+".\n", backtrace() })); } else { werror("No argument to option "+opt+".\n"); exit(1); }
c2a4061997-02-06Fredrik Hübinette (Hubbe)  } arg=argv[e+1]; argv[e+1]=0; }else{ foo=foo[..j]; } } ret+=({ ({ option[0], arg || 1 }) }); } } argv[e]=foo*""; if(argv[e]=="-") argv[e]=0; } }else{
d554cc2000-07-06Fredrik Hübinette (Hubbe)  if(posix_me_harder != -1) if(posix_me_harder || getenv("POSIX_ME_HARDER")) break;
c2a4061997-02-06Fredrik Hübinette (Hubbe)  } } multiset done=mkmultiset(column(ret, 0));
0662a92000-07-12Henrik Grubbström (Grubba)  foreach(options, array(string|array(string)) option)
c2a4061997-02-06Fredrik Hübinette (Hubbe)  {
0662a92000-07-12Henrik Grubbström (Grubba)  string name=[string]option[NAME];
4943ca1997-04-21Fredrik Hübinette (Hubbe)  if(done[name]) continue;
fd0fdf1997-03-16Fredrik Hübinette (Hubbe)  if(sizeof(option) > ENV)
c2a4061997-02-06Fredrik Hübinette (Hubbe)  {
0662a92000-07-12Henrik Grubbström (Grubba)  array(string)|string foo=option[ENV];
c2a4061997-02-06Fredrik Hübinette (Hubbe)  if(!foo) continue;
0662a92000-07-12Henrik Grubbström (Grubba)  if(stringp(foo)) foo=({[string]foo}); foreach([array(string)]foo, foo)
c2a4061997-02-06Fredrik Hübinette (Hubbe)  {
0662a92000-07-12Henrik Grubbström (Grubba)  if(foo=[string]getenv([string]foo))
c2a4061997-02-06Fredrik Hübinette (Hubbe)  { ret+=({ ({name, foo}) }); done[name]=1; break; } } if(!done && sizeof(option)>3 && option[3]) { ret+=({ ({name, option[3]}) }); done[name]=1; } } } return ret; }
883adb2000-12-13Henrik Grubbström (Grubba) //! This function returns the remaining command line arguments after //! you have run @[find_options()] or @[find_all_options()] to find //! all the options in the argument list. If there are any options //! left not handled by @[find_options()] or @[find_all_options()] //! this function will fail. //! //! If @[throw_errors] has been specified @[get_args()] will throw errors //! on failure. If it has been left out, or is @tt{0@} (zero), it will //! instead print an error message and exit the program on failure. //! //! @returns //! On success a new @[argv] array without the parsed options is //! returned. //! //! @seealso //! @[Getopt.find_option()], @[Getopt.find_all_options()] //!
1790d12000-03-30Henrik Grubbström (Grubba) array(string) get_args(array(string) argv, void|int posix_me_harder, void|int throw_errors)
c2a4061997-02-06Fredrik Hübinette (Hubbe) { int i; for(i=1;i<sizeof(argv);i++) { if(argv[i] && strlen(argv[i])>1 && argv[i][0]=='-') { if(argv[i][1]=='-') { if(argv[i]=="--") { argv[i]=0; break; }else{
1a95de1997-08-31Henrik Grubbström (Grubba)  if (throw_errors) { throw(({ "Unknown option "+argv[i]+".\n", backtrace() })); } else { werror("Unknown option "+argv[i]+".\n"); exit(1); }
c2a4061997-02-06Fredrik Hübinette (Hubbe)  } }else{
1a95de1997-08-31Henrik Grubbström (Grubba)  if(strlen(argv[i]) == 2) { if (throw_errors) { throw(({ "Unknown option "+argv[i]+".\n", backtrace() })); } else { werror("Unknown option "+argv[i]+".\n"); } } else { if (throw_errors) { throw(({ "Unknown options "+argv[i]+".\n", backtrace() })); } else { werror("Unknown options "+argv[i]+".\n"); } }
c2a4061997-02-06Fredrik Hübinette (Hubbe)  exit(1); } }else{
2d7a4f2000-07-05Fredrik Hübinette (Hubbe)  if(posix_me_harder != -1) if(posix_me_harder || getenv("POSIX_ME_HARDER")) break;
c2a4061997-02-06Fredrik Hübinette (Hubbe)  } } argv-=({0,1}); return argv; }