/* * Copyright (c) 2003-2008, John Wiegley. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * - Neither the name of New Artisans LLC nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "option.h" namespace ledger { namespace { typedef tuple op_bool_tuple; op_bool_tuple find_option(scope_t& scope, const string& name) { char buf[128]; std::strcpy(buf, "opt_"); char * p = &buf[4]; foreach (char ch, name) { if (ch == '-') *p++ = '_'; else *p++ = ch; } *p = '\0'; expr_t::ptr_op_t op = scope.lookup(buf); if (op) return op_bool_tuple(op, false); *p++ = '_'; *p = '\0'; return op_bool_tuple(scope.lookup(buf), true); } op_bool_tuple find_option(scope_t& scope, const char letter) { char buf[10]; std::strcpy(buf, "opt_"); buf[4] = letter; buf[5] = '\0'; expr_t::ptr_op_t op = scope.lookup(buf); if (op) return op_bool_tuple(op, false); buf[5] = '_'; buf[6] = '\0'; return op_bool_tuple(scope.lookup(buf), true); } void process_option(const function_t& opt, scope_t& scope, const char * arg) { try { call_scope_t args(scope); if (arg) args.push_back(string_value(arg)); opt(args); } catch (const std::exception& err) { #if 0 add_error_context("While parsing option '--" << opt->long_opt << "'" << (opt->short_opt != '\0' ? (string(" (-") + opt->short_opt + "):") : ": ")); #endif throw err; } } } void process_option(const string& name, scope_t& scope, const char * arg) { op_bool_tuple opt(find_option(scope, name)); if (opt.get<0>()) process_option(opt.get<0>()->as_function(), scope, arg); } void process_environment(const char ** envp, const string& tag, scope_t& scope) { const char * tag_p = tag.c_str(); unsigned int tag_len = tag.length(); for (const char ** p = envp; *p; p++) if (! tag_p || std::strncmp(*p, tag_p, tag_len) == 0) { char buf[128]; char * r = buf; const char * q; for (q = *p + tag_len; *q && *q != '=' && r - buf < 128; q++) if (*q == '_') *r++ = '-'; else *r++ = std::tolower(*q); *r = '\0'; if (*q == '=') { try { process_option(string(buf), scope, q + 1); } catch (const std::exception& err) { add_error_context("While parsing environment variable option '" << *p << "':"); throw err; } } } } void process_arguments(int, char ** argv, const bool anywhere, scope_t& scope, std::list& args) { for (char ** i = argv; *i; i++) { if ((*i)[0] != '-') { if (anywhere) { args.push_back(*i); continue; } else { for (; *i; i++) args.push_back(*i); break; } } // --long-option or -s if ((*i)[1] == '-') { if ((*i)[2] == '\0') break; char * name = *i + 2; char * value = NULL; if (char * p = std::strchr(name, '=')) { *p++ = '\0'; value = p; } op_bool_tuple opt(find_option(scope, name)); if (! opt.get<0>()) throw_(option_error, "illegal option --" << name); if (opt.get<1>() && value == NULL) { value = *++i; if (value == NULL) throw_(option_error, "missing option argument for --" << name); } process_option(opt.get<0>()->as_function(), scope, value); } else if ((*i)[1] == '\0') { throw_(option_error, "illegal option -"); } else { typedef tuple op_bool_char_tuple; std::list option_queue; int x = 1; for (char c = (*i)[x]; c != '\0'; x++, c = (*i)[x]) { op_bool_tuple opt(find_option(scope, c)); if (! opt.get<0>()) throw_(option_error, "illegal option -" << c); option_queue.push_back (op_bool_char_tuple(opt.get<0>(), opt.get<1>(), c)); } foreach (op_bool_char_tuple& o, option_queue) { char * value = NULL; if (o.get<1>()) { value = *++i; if (value == NULL) throw_(option_error, "missing option argument for -" << o.get<2>()); } process_option(o.get<0>()->as_function(), scope, value); } } } } } // namespace ledger