1 // -*- related-file-name: "../include/click/args.hh" -*-
2 /*
3 * args.{cc,hh} -- type-safe argument & configuration string parsing
4 * Eddie Kohler
5 *
6 * Copyright (c) 2011 Regents of the University of California
7 * Copyright (c) 2012-2013 Eddie Kohler
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, subject to the conditions
12 * listed in the Click LICENSE file. These conditions include: you must
13 * preserve this copyright notice, and you cannot mention the copyright
14 * holders in advertising related to the Software without their permission.
15 * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This
16 * notice is a summary of the Click LICENSE file; the license in that file is
17 * legally binding.
18 */
19
20 #include <click/config.h>
21 #include <click/glue.hh>
22 #include <click/args.hh>
23 #include <click/error.hh>
24 #include <click/bigint.hh>
25 #if !CLICK_TOOL
26 # include <click/router.hh>
27 # include <click/nameinfo.hh>
28 # include <click/packet_anno.hh>
29 #endif
30 #if CLICK_USERLEVEL || CLICK_TOOL
31 # include <pwd.h>
32 #endif
33 #include <stdarg.h>
34 CLICK_DECLS
35
36 const ArgContext blank_args;
37
38 inline void
initialize(const Vector<String> * conf)39 Args::initialize(const Vector<String> *conf)
40 {
41 static_assert(has_trivial_copy<int>::value && !has_trivial_copy<String>::value, "has_trivial_copy problems");
42
43 _conf = conf ? new Vector<String>(*conf) : 0;
44 _slots = 0;
45 _simple_slotbuf[0] = 0;
46 _my_conf = !!_conf;
47 #if CLICK_DEBUG_ARGS_USAGE
48 _consumed = false;
49 #endif
50 _status = true;
51 _simple_slotpos = 0;
52 if (_conf)
53 reset();
54 }
55
Args(ErrorHandler * errh)56 Args::Args(ErrorHandler *errh)
57 : ArgContext(errh)
58 {
59 initialize(0);
60 }
61
Args(const Vector<String> & conf,ErrorHandler * errh)62 Args::Args(const Vector<String> &conf, ErrorHandler *errh)
63 : ArgContext(errh)
64 {
65 initialize(&conf);
66 }
67
68 #if !CLICK_TOOL
Args(const Element * context,ErrorHandler * errh)69 Args::Args(const Element *context, ErrorHandler *errh)
70 : ArgContext(context, errh)
71 {
72 initialize(0);
73 }
74
Args(const Vector<String> & conf,const Element * context,ErrorHandler * errh)75 Args::Args(const Vector<String> &conf,
76 const Element *context, ErrorHandler *errh)
77 : ArgContext(context, errh)
78 {
79 initialize(&conf);
80 }
81 #endif
82
Args(const Args & x)83 Args::Args(const Args &x)
84 : ArgContext(x),
85 _my_conf(false), _simple_slotpos(0), _conf(0), _slots(0)
86 {
87 #if CLICK_DEBUG_ARGS_USAGE
88 _consumed = true;
89 #endif
90 _simple_slotbuf[0] = 0;
91 *this = x;
92 }
93
~Args()94 Args::~Args()
95 {
96 #if CLICK_DEBUG_ARGS_USAGE
97 if (_my_conf && _consumed && errh())
98 errh()->warning("Args::consume() did nothing; did you mean Args(this, errh).bind(conf)?");
99 #endif
100 if (_my_conf)
101 delete _conf;
102 while (Slot *s = _slots) {
103 _slots = s->_next;
104 delete s;
105 }
106 }
107
108 Args &
operator =(const Args & x)109 Args::operator=(const Args &x)
110 {
111 if (&x != this) {
112 if ((_slots || _simple_slotbuf[0] || x._slots || x._simple_slotbuf[0])
113 && _errh)
114 _errh->warning("internal warning: ignoring assignment of Args slots");
115
116 if (_my_conf)
117 delete _conf;
118 if (x._my_conf) {
119 _conf = new Vector<String>(*x._conf);
120 _my_conf = true;
121 } else {
122 _conf = x._conf;
123 _my_conf = false;
124 }
125 _kwpos = x._kwpos;
126 #if !CLICK_TOOL
127 _context = x._context;
128 #endif
129 _errh = x._errh;
130
131 _arg_keyword = x._arg_keyword;
132 _read_status = x._read_status;
133 _status = x._status;
134 #if CLICK_DEBUG_ARGS_USAGE
135 _consumed = x._consumed;
136 #endif
137 }
138 return *this;
139 }
140
141 void
reset_from(int i)142 Args::reset_from(int i)
143 {
144 _kwpos.resize(i);
145 if (_conf) {
146 _kwpos.reserve(_conf->size());
147 for (String *it = _conf->begin() + i; it != _conf->end(); ++it) {
148 const char *s = it->begin(), *ends = it->end();
149 if (s != ends && (isalpha((unsigned char) *s) || *s == '_')) {
150 do {
151 ++s;
152 } while (s != ends &&
153 (isalnum((unsigned char) *s) || *s == '_'
154 || *s == ':' || *s == '.' || *s == '?' || *s == '!'));
155 }
156 const char *t = s;
157 while (t != ends && isspace((unsigned char) *t))
158 ++t;
159 if (s == it->begin() || s == t || t == ends)
160 _kwpos.push_back(0);
161 else
162 _kwpos.push_back(s - it->begin());
163 }
164 #if CLICK_DEBUG_ARGS_USAGE
165 _consumed = false;
166 #endif
167 }
168 }
169
170 Args &
bind(Vector<String> & conf)171 Args::bind(Vector<String> &conf)
172 {
173 if (_my_conf)
174 delete _conf;
175 _conf = &conf;
176 _my_conf = false;
177 #if CLICK_DEBUG_ARGS_USAGE
178 _consumed = false;
179 #endif
180 return reset();
181 }
182
183 Args &
push_back(const String & arg)184 Args::push_back(const String &arg)
185 {
186 if (!_conf) {
187 _conf = new Vector<String>();
188 _my_conf = true;
189 }
190 if (_conf) {
191 int old_size = _conf->size();
192 _conf->push_back(arg);
193 reset_from(old_size);
194 }
195 return *this;
196 }
197
198 Args &
push_back_args(const String & str)199 Args::push_back_args(const String &str)
200 {
201 if (!_conf) {
202 _conf = new Vector<String>();
203 _my_conf = true;
204 }
205 if (_conf) {
206 int old_size = _conf->size();
207 cp_argvec(str, *_conf);
208 reset_from(old_size);
209 }
210 return *this;
211 }
212
213 Args &
push_back_words(const String & str)214 Args::push_back_words(const String &str)
215 {
216 if (!_conf) {
217 _conf = new Vector<String>();
218 _my_conf = true;
219 }
220 if (_conf) {
221 int old_size = _conf->size();
222 cp_spacevec(str, *_conf);
223 reset_from(old_size);
224 }
225 return *this;
226 }
227
228 inline int
simple_slot_size(int size)229 Args::simple_slot_size(int size)
230 {
231 #if HAVE_INDIFFERENT_ALIGNMENT
232 return 1 + size + SIZEOF_VOID_P;
233 #else
234 if (size & (size - 1))
235 // not power of 2, assume no alignment
236 size = 1 + size;
237 else
238 size = size + size;
239 if (size & (SIZEOF_VOID_P - 1))
240 size += SIZEOF_VOID_P - (size & (SIZEOF_VOID_P - 1));
241 return size + SIZEOF_VOID_P;
242 #endif
243 }
244
245 inline void
simple_slot_info(int offset,int size,void * & slot,void ** & pointer)246 Args::simple_slot_info(int offset, int size, void *&slot, void **&pointer)
247 {
248 #if HAVE_INDIFFERENT_ALIGNMENT
249 slot = &_simple_slotbuf[offset + 1];
250 pointer = reinterpret_cast<void **>(&_simple_slotbuf[offset + 1 + size]);
251 #else
252 if (size & (size - 1))
253 offset += 1;
254 else
255 offset += size;
256 slot = &_simple_slotbuf[offset];
257 offset += size;
258 if (offset & (SIZEOF_VOID_P - 1))
259 offset += SIZEOF_VOID_P - (offset & (SIZEOF_VOID_P - 1));
260 pointer = reinterpret_cast<void **>(&_simple_slotbuf[offset]);
261 #endif
262 }
263
264 void *
simple_slot(void * ptr,size_t size)265 Args::simple_slot(void *ptr, size_t size)
266 {
267 int offset = _simple_slotpos;
268 while (offset < simple_slotbuf_size && _simple_slotbuf[offset] != 0)
269 offset += simple_slot_size(_simple_slotbuf[offset]);
270
271 if (size < (size_t) simple_slotbuf_size) {
272 int new_offset = offset + simple_slot_size((int) size);
273 if (new_offset <= simple_slotbuf_size) {
274 void *slot, **pointer;
275 simple_slot_info(offset, (int) size, slot, pointer);
276 _simple_slotbuf[offset] = (int) size;
277 *pointer = ptr;
278 if (new_offset < simple_slotbuf_size)
279 _simple_slotbuf[new_offset] = 0;
280 return slot;
281 }
282 }
283
284 BytesSlot *store = new BytesSlot(ptr, size);
285 if (store && store->_slot) {
286 store->_next = _slots;
287 _slots = store;
288 return store->_slot;
289 } else {
290 delete store;
291 error("out of memory");
292 return 0;
293 }
294 }
295
296 String
error_prefix() const297 ArgContext::error_prefix() const
298 {
299 return _arg_keyword ? String(_arg_keyword) + ": " : String();
300 }
301
302 void
error(const char * fmt,...) const303 ArgContext::error(const char *fmt, ...) const
304 {
305 va_list val;
306 va_start(val, fmt);
307 xmessage(ErrorHandler::e_error, fmt, val);
308 va_end(val);
309 }
310
311 void
warning(const char * fmt,...) const312 ArgContext::warning(const char *fmt, ...) const
313 {
314 va_list val;
315 va_start(val, fmt);
316 xmessage(ErrorHandler::e_warning_annotated, fmt, val);
317 va_end(val);
318 }
319
320 void
message(const char * fmt,...) const321 ArgContext::message(const char *fmt, ...) const
322 {
323 va_list val;
324 va_start(val, fmt);
325 xmessage(ErrorHandler::e_info, fmt, val);
326 va_end(val);
327 }
328
329 void
xmessage(const String & anno,const String & str) const330 ArgContext::xmessage(const String &anno, const String &str) const
331 {
332 PrefixErrorHandler perrh(_errh, error_prefix());
333 perrh.xmessage(anno, str);
334 if (perrh.nerrors())
335 _read_status = false;
336 }
337
338 void
xmessage(const String & anno,const char * fmt,va_list val) const339 ArgContext::xmessage(const String &anno, const char *fmt, va_list val) const
340 {
341 PrefixErrorHandler perrh(_errh, error_prefix());
342 perrh.xmessage(anno, fmt, val);
343 if (perrh.nerrors())
344 _read_status = false;
345 }
346
347
348 String
find(const char * keyword,int flags,Slot * & slot_status)349 Args::find(const char *keyword, int flags, Slot *&slot_status)
350 {
351 _arg_keyword = keyword;
352 _read_status = true;
353 #if CLICK_DEBUG_ARGS_USAGE
354 _consumed = false;
355 #endif
356 slot_status = _slots;
357
358 // Check for common errors.
359 // Note that we don't check the whole keyword for validity; there are
360 // sometimes good reasons to pass something like "BADSRC*", which can only
361 // match a positional argument (no keyword will ever match) but still
362 // looks helpful in error messages.
363 if (keyword && isdigit((unsigned char) *keyword))
364 error("keywords must start with a letter or underscore");
365
366 // Find matching keyword -- normally last, sometimes first.
367 int keyword_length = keyword ? strlen(keyword) : 0;
368 int got = -1, got_kwpos = -1, position = -1;
369 for (int i = 0; i < _kwpos.size(); ++i) {
370 if (position == -1 && _kwpos[i] != -1)
371 position = (_kwpos[i] >= 0 ? i : -2);
372 if (_kwpos[i] == keyword_length
373 && memcmp((*_conf)[i].data(), keyword, keyword_length) == 0) {
374 got = i;
375 got_kwpos = _kwpos[i];
376 _kwpos[i] = -2;
377 if (flags & firstmatch)
378 break;
379 }
380 }
381
382 // Check positional arguments.
383 // If the current argument lacks a keyword, assign it to this position.
384 // But if the requested keyword is mandatory but so far lacking, take the
385 // current argument even if it appears to have a keyword.
386 if ((flags & positional) && position >= 0 && _kwpos[position] >= 0
387 && ((got < 0 && (flags & mandatory)) || _kwpos[position] == 0)
388 && (!(flags & firstmatch) || got < 0 || position < got)) {
389 _kwpos[position] = -1;
390 if ((flags & firstmatch) && position < got)
391 _kwpos[got] = keyword_length;
392 if ((flags & firstmatch) || got < position) {
393 got = position;
394 got_kwpos = 0;
395 }
396 }
397
398 if (got < 0) {
399 if (flags & mandatory) {
400 error("required argument missing");
401 _status = false;
402 }
403 _read_status = false;
404 return String();
405 }
406 if (flags & deprecated)
407 warning("argument deprecated");
408
409 if (got_kwpos) {
410 const char *s = (*_conf)[got].begin() + got_kwpos,
411 *ends = (*_conf)[got].end();
412 while (s < ends && isspace((unsigned char) *s))
413 ++s;
414 return (*_conf)[got].substring(s, ends);
415 } else
416 return (*_conf)[got];
417 }
418
419 void
postparse(bool ok,Slot * slot_status)420 Args::postparse(bool ok, Slot *slot_status)
421 {
422 if (!ok && _read_status) {
423 error("parse error");
424 _read_status = false;
425 }
426 _arg_keyword = 0;
427
428 if (ok) {
429 while (_simple_slotpos < simple_slotbuf_size
430 && _simple_slotbuf[_simple_slotpos] != 0)
431 _simple_slotpos +=
432 simple_slot_size(_simple_slotbuf[_simple_slotpos]);
433 } else {
434 _status = false;
435 if (_simple_slotpos < simple_slotbuf_size)
436 _simple_slotbuf[_simple_slotpos] = 0;
437 while (_slots != slot_status) {
438 Slot *slot = _slots;
439 _slots = _slots->_next;
440 delete slot;
441 }
442 }
443 }
444
445 Args &
strip()446 Args::strip()
447 {
448 int delta = 0;
449 for (int i = 0; i < _kwpos.size(); ++i)
450 if (_kwpos[i] < 0)
451 ++delta;
452 else if (delta > 0) {
453 (*_conf)[i - delta] = (*_conf)[i];
454 _kwpos[i - delta] = _kwpos[i];
455 }
456 if (_conf)
457 _conf->resize(_kwpos.size() - delta);
458 _kwpos.resize(_kwpos.size() - delta);
459 return *this;
460 }
461
462 void
check_complete()463 Args::check_complete()
464 {
465 bool too_many_positional = false;
466 for (int i = 0; i < _kwpos.size(); ++i)
467 if (_kwpos[i] == 0) {
468 too_many_positional = true;
469 _status = false;
470 } else if (_kwpos[i] > 0) {
471 if (_errh)
472 _errh->error("%.*s: unknown argument", _kwpos[i], (*_conf)[i].data());
473 _status = false;
474 }
475 if (too_many_positional && _errh)
476 _errh->error("too many arguments");
477 }
478
479 int
execute()480 Args::execute()
481 {
482 if (!_status)
483 return -EINVAL;
484 while (Slot *s = _slots) {
485 _slots = s->_next;
486 s->store();
487 delete s;
488 }
489 for (int offset = 0; offset < _simple_slotpos;
490 offset += simple_slot_size(_simple_slotbuf[offset])) {
491 void *slot, **pointer;
492 simple_slot_info(offset, _simple_slotbuf[offset], slot, pointer);
493 memcpy(*pointer, slot, _simple_slotbuf[offset]);
494 }
495 _simple_slotpos = _simple_slotbuf[0] = 0;
496 return 0;
497 }
498
499 int
consume()500 Args::consume()
501 {
502 strip();
503 #if CLICK_DEBUG_ARGS_USAGE
504 _consumed = true;
505 #endif
506 return execute();
507 }
508
509 int
complete()510 Args::complete()
511 {
512 check_complete();
513 return execute();
514 }
515
516
517 const char *
span(const char * begin,const char * end,bool is_signed,int & b)518 IntArg::span(const char *begin, const char *end, bool is_signed, int &b)
519 {
520 const char *s = begin;
521 if (s != end && ((is_signed && *s == '-') || *s == '+'))
522 ++s;
523
524 if ((b == 0 || b == 16) && s + 2 < end
525 && *s == '0' && (s[1] == 'x' || s[1] == 'X')) {
526 s += 2;
527 b = 16;
528 } else if (b == 0 && s + 2 < end
529 && *s == '0' && (s[1] == 'b' || s[1] == 'B')) {
530 s += 2;
531 b = 2;
532 } else if (b == 0 && s != end && *s == '0')
533 b = 8;
534 else if (b == 0)
535 b = 10;
536
537 int ndigits = (b > 10 ? 10 : b), nletters = (b > 10 ? b - 10 : 0);
538 const char *firstdigit = s, *lastdigit = s - 1;
539 for (; s != end; ++s) {
540 if (*s == '_' && lastdigit == s)
541 /* allow underscores between digits */;
542 else if ((*s >= '0' && *s < '0' + ndigits)
543 || (*s >= 'A' && *s < 'A' + nletters)
544 || (*s >= 'a' && *s < 'a' + nletters))
545 lastdigit = s + 1;
546 else
547 break;
548 }
549
550 if (s != firstdigit)
551 return lastdigit;
552 else if (firstdigit > begin + 1)
553 // Happens in cases like "0x!" or "+0x": parse the initial "0".
554 return firstdigit - 1;
555 else
556 return begin;
557 }
558
559 const char *
parse(const char * begin,const char * end,bool is_signed,int size,limb_type * value,int nlimb)560 IntArg::parse(const char *begin, const char *end, bool is_signed, int size,
561 limb_type *value, int nlimb)
562 {
563 int b = base;
564 const char *xend = span(begin, end, is_signed, b);
565 if (b < 2 || b > 36 || xend == begin) {
566 status = status_inval;
567 return begin;
568 }
569
570 constexpr limb_type threshold = integer_traits<limb_type>::const_max / 36;
571 uint32_t v0 = 0;
572 memset(value, 0, sizeof(limb_type) * nlimb);
573 int nletters = (b > 10 ? b - 10 : 0);
574 status = status_ok;
575 for (const char *s = begin; s != xend; ++s) {
576 int digit;
577 if (*s >= '0' && *s <= '9')
578 digit = *s - '0';
579 else if (*s >= 'A' && *s < 'A' + nletters)
580 digit = *s - 'A' + 10;
581 else if (*s >= 'a' && *s < 'a' + nletters)
582 digit = *s - 'a' + 10;
583 else
584 continue;
585 if (v0 < threshold)
586 value[0] = v0 = v0 * b + digit;
587 else if (Bigint<limb_type>::multiply_half(value, value, nlimb, b, digit))
588 status = status_range;
589 }
590
591 bool negative = is_signed && *begin == '-';
592 int bitsize = size * 8 - is_signed;
593 constexpr int limb_bits = int(sizeof(limb_type)) * 8;
594
595 int bpos = 0;
596 for (limb_type *x = value; x != value + nlimb && status == status_ok;
597 ++x, bpos += limb_bits)
598 if ((bpos >= bitsize && *x != 0)
599 || (bpos < bitsize && bitsize < bpos + limb_bits
600 && *x >= (1U << (bitsize - bpos)) + negative))
601 status = status_range;
602
603 if (status == status_range) {
604 memset(value, negative ? 0 : 255, size);
605 if (is_signed)
606 value[bitsize / limb_bits] ^= 1U << (bitsize & (limb_bits - 1));
607 }
608
609 if (negative) {
610 limb_type *first_zero = value + nlimb;
611 for (limb_type *x = value; x != value + nlimb; ++x)
612 if ((*x = -*x))
613 first_zero = x + 1;
614 for (limb_type *x = first_zero; x != value + nlimb; ++x)
615 --*x;
616 }
617
618 return xend;
619 }
620
621 void
range_error(const ArgContext & args,bool is_signed,click_intmax_t value)622 IntArg::range_error(const ArgContext &args, bool is_signed,
623 click_intmax_t value)
624 {
625 status = status_range;
626 if (is_signed)
627 args.error("out of range, bound %" CLICK_ERRHdMAX, value);
628 else
629 args.error("out of range, bound %" CLICK_ERRHuMAX, click_uintmax_t(value));
630 }
631
632
633 namespace {
634 typedef click_uintmax_t value_type;
635 typedef click_intmax_t signed_value_type;
636
637 const char *
preparse_fraction(const char * begin,const char * end,bool is_signed,int & integer_digits)638 preparse_fraction(const char *begin, const char *end, bool is_signed,
639 int &integer_digits)
640 {
641 const char *s = begin;
642 if (s != end && ((is_signed && *s == '-') || *s == '+'))
643 ++s;
644
645 const char *firstdigit = s, *lastdigit = firstdigit - 1;
646 bool decimalpoint = false;
647 for (; s != end; ++s) {
648 if (*s == '_' && lastdigit == s)
649 /* OK */;
650 else if (*s == '.' && !decimalpoint
651 && (lastdigit == s || firstdigit == s))
652 decimalpoint = true;
653 else if (*s >= '0' && *s <= '9') {
654 if (!decimalpoint)
655 ++integer_digits;
656 lastdigit = s + 1;
657 } else
658 break;
659 }
660
661 // error if no digits at all
662 if (lastdigit == firstdigit - 1)
663 return begin;
664
665 // optional exponent
666 if (s != end && (*s == 'E' || *s == 'e') && s + 1 != end) {
667 const char *echar = s;
668 s += (s[1] == '-' || s[1] == '+' ? 2 : 1);
669 if (s != end && isdigit((unsigned char) *s)) {
670 int exponent = *s - '0';
671 // XXX overflow
672 for (++s; s != end && isdigit((unsigned char) *s); ++s)
673 exponent = 10 * exponent + *s - '0';
674 integer_digits += (echar[1] == '-' ? -exponent : exponent);
675 } else
676 s = echar;
677 }
678
679 return s;
680 }
681
682 const char *
parse_integer_portion(const char * s,const char * end,int integer_digits,value_type & ivalue,int & status)683 parse_integer_portion(const char *s, const char *end, int integer_digits,
684 value_type &ivalue, int &status)
685 {
686 constexpr value_type thresh = integer_traits<value_type>::const_max / 10;
687 constexpr int thresh_digit = integer_traits<value_type>::const_max - thresh * 10;
688 ivalue = 0;
689 while (integer_digits > 0) {
690 int digit;
691 if (s == end || *s == 'E' || *s == 'e')
692 digit = 0;
693 else if (*s >= '0' && *s <= '9') {
694 digit = *s - '0';
695 ++s;
696 } else {
697 ++s;
698 continue;
699 }
700 if (ivalue > thresh || (ivalue == thresh && digit > thresh_digit)) {
701 ivalue = integer_traits<value_type>::const_max;
702 status = NumArg::status_range;
703 } else
704 ivalue = 10 * ivalue + digit;
705 --integer_digits;
706 }
707 return s;
708 }
709
710 const char *
parse_decimal_fraction(const char * begin,const char * end,bool is_signed,int exponent_delta,value_type & ivalue,int fraction_digits,uint32_t & fvalue,int & status)711 parse_decimal_fraction(const char *begin, const char *end,
712 bool is_signed, int exponent_delta,
713 value_type &ivalue,
714 int fraction_digits, uint32_t &fvalue,
715 int &status)
716 {
717 int integer_digits = exponent_delta;
718 end = preparse_fraction(begin, end, is_signed, integer_digits);
719 if (end == begin) {
720 status = NumArg::status_inval;
721 return begin;
722 }
723
724 status = NumArg::status_ok;
725 const char *s = begin;
726
727 ivalue = 0;
728 if (integer_digits > 0) {
729 s = parse_integer_portion(s, end, integer_digits, ivalue, status);
730 integer_digits = 0;
731 }
732
733 fvalue = 0;
734 uint32_t maxfvalue = 1;
735 while (fraction_digits > 0) {
736 int digit;
737 if (integer_digits < 0) {
738 digit = 0;
739 ++integer_digits;
740 } else if (s == end || *s == 'E' || *s == 'e')
741 digit = 0;
742 else if (*s >= '0' && *s <= '9') {
743 digit = *s - '0';
744 ++s;
745 } else {
746 ++s;
747 continue;
748 }
749 fvalue = fvalue * 10 + digit;
750 maxfvalue = maxfvalue * 10;
751 --fraction_digits;
752 }
753 // perhaps round up
754 while (s != end && *s != 'E' && *s != 'e' && (*s < '0' || *s > '9'))
755 ++s;
756 if (s != end && *s >= '5' && *s <= '9' && ++fvalue == maxfvalue) {
757 fvalue = 0;
758 if (++ivalue == 0)
759 status = NumArg::status_range;
760 }
761
762 return end;
763 }
764
765 template<typename V, typename L = uint32_t>
766 struct fraction_accum {
767 enum { nlimb = (sizeof(V) / sizeof(L)) + 1 };
fraction_accum__anoncfbfd9190111::fraction_accum768 fraction_accum()
769 : zero(true) {
770 static_assert(sizeof(V) % sizeof(L) == 0, "V must be a size multiple of L");
771 for (int i = 0; i < nlimb; ++i)
772 limbs[i] = 0;
773 }
add_decimal_digit__anoncfbfd9190111::fraction_accum774 void add_decimal_digit(int d) {
775 if (d || !zero) {
776 zero = false;
777 limbs[nlimb - 1] += d << 1;
778 Bigint<L>::divide(limbs, limbs, nlimb, 10);
779 }
780 }
extract__anoncfbfd9190111::fraction_accum781 bool extract(V &value) {
782 if (zero)
783 value = 0;
784 else {
785 for (L *l = limbs; true; ++l)
786 if (++*l != 0)
787 break;
788 extract_integer(limbs, value);
789 value >>= 1;
790 if (limbs[nlimb - 1] & 1)
791 value |= V(1) << (sizeof(V) * 8 - 1);
792 }
793 return limbs[nlimb - 1] > 1;
794 }
is_zero__anoncfbfd9190111::fraction_accum795 bool is_zero() const {
796 return zero;
797 }
798 L limbs[nlimb];
799 bool zero;
800 };
801
802 #if HAVE_INT64_TYPES
803 template<>
804 struct fraction_accum<uint32_t, uint32_t> {
fraction_accum__anoncfbfd9190111::fraction_accum805 fraction_accum()
806 : accum(0) {
807 }
add_decimal_digit__anoncfbfd9190111::fraction_accum808 void add_decimal_digit(int d) {
809 accum = int_divide(accum + (uint64_t(d) << 33), 10);
810 }
extract__anoncfbfd9190111::fraction_accum811 bool extract(uint32_t &value) {
812 ++accum;
813 value = (accum >> 1);
814 return accum >= (uint64_t(1) << 33);
815 }
is_zero__anoncfbfd9190111::fraction_accum816 bool is_zero() const {
817 return accum == 0;
818 }
819 uint64_t accum;
820 };
821 #endif
822
823 const char *
parse_fraction(const char * begin,const char * end,bool is_signed,int exponent_delta,value_type & ivalue,uint32_t & fvalue,int & status)824 parse_fraction(const char *begin, const char *end,
825 bool is_signed, int exponent_delta,
826 value_type &ivalue, uint32_t &fvalue, int &status)
827 {
828 int integer_digits = exponent_delta;
829 end = preparse_fraction(begin, end, is_signed, integer_digits);
830 if (end == begin) {
831 status = NumArg::status_inval;
832 return begin;
833 }
834
835 status = NumArg::status_ok;
836 const char *s = begin;
837
838 ivalue = 0;
839 if (integer_digits > 0) {
840 s = parse_integer_portion(s, end, integer_digits, ivalue, status);
841 integer_digits = 0;
842 }
843
844 const char *x = s;
845 while (x != end && *x != 'E' && *x != 'e')
846 ++x;
847 fraction_accum<uint32_t> fwork;
848 while (x != s) {
849 --x;
850 if (*x >= '0' && *x <= '9') {
851 fwork.add_decimal_digit(*x - '0');
852 ++integer_digits;
853 }
854 }
855 while (integer_digits <= 0 && !fwork.is_zero()) {
856 fwork.add_decimal_digit(0);
857 ++integer_digits;
858 }
859 if (fwork.extract(fvalue) && ++ivalue == 0)
860 status = NumArg::status_range;
861
862 return end;
863 }
864 }
865
866
867 bool
underparse(const String & str,bool is_signed,uint32_t & result)868 FixedPointArg::underparse(const String &str, bool is_signed, uint32_t &result)
869 {
870 value_type ivalue;
871 uint32_t fvalue;
872 const char *end = parse_fraction(str.begin(), str.end(),
873 is_signed, exponent_delta,
874 ivalue, fvalue, status);
875 if (end != str.end())
876 status = status_inval;
877 if (status && status != status_range)
878 return false;
879
880 if (fraction_bits == 32) {
881 // Separating this case helps avoid undefined behavior like <<32
882 if (ivalue == 0)
883 result = fvalue;
884 else
885 status = status_range;
886 } else {
887 value_type mivalue = ivalue;
888 uint32_t mfvalue = fvalue + (1U << (31 - fraction_bits));
889 if (mfvalue < fvalue)
890 ++mivalue;
891 if (mivalue >= ivalue && mivalue < (1U << (32 - fraction_bits)))
892 result = (uint32_t(mivalue) << fraction_bits)
893 | (mfvalue >> (32 - fraction_bits));
894 else
895 status = status_range;
896 }
897 if (status == status_range)
898 result = 0xFFFFFFFFU;
899 return true;
900 }
901
902 bool
parse(const String & str,uint32_t & result,const ArgContext & args)903 FixedPointArg::parse(const String &str, uint32_t &result, const ArgContext &args)
904 {
905 uint32_t x;
906 if (!underparse(str, false, x))
907 return false;
908 else if (status == status_range) {
909 args.error("out of range, bound %s", cp_unparse_real2(x, fraction_bits).c_str());
910 return false;
911 } else {
912 result = x;
913 return true;
914 }
915 }
916
917 bool
parse_saturating(const String & str,int32_t & result,const ArgContext &)918 FixedPointArg::parse_saturating(const String &str, int32_t &result, const ArgContext &)
919 {
920 uint32_t x;
921 if (!underparse(str, true, x))
922 return false;
923 bool negative = str[0] == '-';
924 if (status == status_ok
925 && x > uint32_t(integer_traits<int32_t>::const_max) + negative) {
926 status = status_range;
927 x = uint32_t(integer_traits<int32_t>::const_max) + negative;
928 }
929 result = negative ? -x : x;
930 return true;
931 }
932
933 bool
parse(const String & str,int32_t & result,const ArgContext & args)934 FixedPointArg::parse(const String &str, int32_t &result, const ArgContext &args)
935 {
936 int32_t x;
937 if (!parse_saturating(str, x, args))
938 return false;
939 else if (status == status_range) {
940 args.error("out of range, bound %s", cp_unparse_real2(int32_t(x), fraction_bits).c_str());
941 return false;
942 } else {
943 result = x;
944 return true;
945 }
946 }
947
948
949 static uint32_t exp10val[] = { 1, 10, 100, 1000, 10000, 100000, 1000000,
950 10000000, 100000000, 1000000000 };
951
952 bool
underparse(const String & str,bool is_signed,uint32_t & result)953 DecimalFixedPointArg::underparse(const String &str, bool is_signed, uint32_t &result)
954 {
955 assert(fraction_digits < int(sizeof(exp10val) / sizeof(exp10val[0])));
956
957 value_type ivalue;
958 uint32_t fvalue;
959 const char *end = parse_decimal_fraction(str.begin(), str.end(),
960 is_signed, exponent_delta,
961 ivalue, fraction_digits, fvalue, status);
962 if (end != str.end())
963 status = status_inval;
964 if (status && status != status_range)
965 return false;
966
967 uint32_t mivalue(ivalue);
968 if (mivalue == ivalue) {
969 uint32_t imul[2];
970 int_multiply(mivalue, exp10val[fraction_digits], imul[0], imul[1]);
971 if (imul[1] == 0 && imul[0] + fvalue >= imul[0])
972 mivalue = imul[0] + fvalue;
973 else
974 status = status_range;
975 } else
976 status = status_range;
977
978 if (status == status_range)
979 mivalue = integer_traits<uint32_t>::const_max;
980 result = mivalue;
981 return true;
982 }
983
984 bool
parse(const String & str,uint32_t & result,const ArgContext & args)985 DecimalFixedPointArg::parse(const String &str, uint32_t &result,
986 const ArgContext &args)
987 {
988 uint32_t x;
989 if (!underparse(str, false, x))
990 return false;
991 else if (status == status_range) {
992 args.error("out of range");
993 return false;
994 } else {
995 result = x;
996 return true;
997 }
998 }
999
1000 bool
parse_saturating(const String & str,int32_t & result,const ArgContext &)1001 DecimalFixedPointArg::parse_saturating(const String &str, int32_t &result,
1002 const ArgContext &)
1003 {
1004 uint32_t x;
1005 if (!underparse(str, true, x))
1006 return false;
1007 bool negative = str[0] == '-';
1008 uint32_t limit(negative ? integer_traits<int32_t>::const_min
1009 : integer_traits<int32_t>::const_max);
1010 if (x > limit) {
1011 status = status_range;
1012 result = limit;
1013 } else
1014 result = x;
1015 return true;
1016 }
1017
1018 bool
parse(const String & str,int32_t & result,const ArgContext & args)1019 DecimalFixedPointArg::parse(const String &str, int32_t &result,
1020 const ArgContext &args)
1021 {
1022 int32_t x;
1023 if (!parse_saturating(str, x, args))
1024 return false;
1025 else if (status == status_range) {
1026 args.error("out of range");
1027 return false;
1028 } else {
1029 result = x;
1030 return true;
1031 }
1032 }
1033
1034 bool
parse_saturating(const String & str,uint32_t & iresult,uint32_t & fresult,const ArgContext &)1035 DecimalFixedPointArg::parse_saturating(const String &str, uint32_t &iresult,
1036 uint32_t &fresult, const ArgContext &)
1037 {
1038 value_type ivalue;
1039 uint32_t fvalue;
1040 const char *end = parse_decimal_fraction(str.begin(), str.end(),
1041 false, exponent_delta,
1042 ivalue, fraction_digits, fvalue, status);
1043 if (end != str.end())
1044 status = status_inval;
1045 if (status && status != status_range)
1046 return false;
1047 if (uint32_t(ivalue) != ivalue)
1048 status = status_range;
1049 if (status == status_range) {
1050 iresult = integer_traits<uint32_t>::const_max;
1051 fresult = exp10val[fraction_digits] - 1;
1052 } else {
1053 iresult = ivalue;
1054 fresult = fvalue;
1055 }
1056 return true;
1057 }
1058
1059 bool
parse(const String & str,uint32_t & iresult,uint32_t & fresult,const ArgContext & args)1060 DecimalFixedPointArg::parse(const String &str, uint32_t &iresult,
1061 uint32_t &fresult, const ArgContext &args)
1062 {
1063 uint32_t ivalue, fvalue;
1064 if (!parse_saturating(str, ivalue, fvalue, args))
1065 return false;
1066 else if (status == status_range) {
1067 args.error("out of range");
1068 return false;
1069 } else {
1070 iresult = ivalue;
1071 fresult = fvalue;
1072 return true;
1073 }
1074 }
1075
1076
1077 #if HAVE_FLOAT_TYPES
1078 bool
parse(const String & str,double & result,const ArgContext & args)1079 DoubleArg::parse(const String &str, double &result, const ArgContext &args)
1080 {
1081 if (str.length() == 0 || isspace((unsigned char) str[0])) {
1082 format_error:
1083 // check for space because strtod() accepts leading whitespace
1084 status = status_inval;
1085 return false;
1086 }
1087
1088 errno = 0;
1089 char *endptr;
1090 double value = strtod(str.c_str(), &endptr);
1091 if (endptr != str.end()) // bad format; garbage after number
1092 goto format_error;
1093
1094 if (errno == ERANGE) {
1095 status = status_range;
1096 const char *fmt;
1097 if (value == 0)
1098 fmt = "underflow, rounded to %g";
1099 else
1100 fmt = "out of range, bound %g";
1101 args.error(fmt, value);
1102 return false;
1103 }
1104
1105 status = status_ok;
1106 result = value;
1107 return true;
1108 }
1109 #endif
1110
1111
1112 bool
parse(const String & str,bool & result,const ArgContext &)1113 BoolArg::parse(const String &str, bool &result, const ArgContext &)
1114 {
1115 const char *s = str.data();
1116 int len = str.length();
1117
1118 if (len == 1 && (s[0] == '0' || s[0] == 'n' || s[0] == 'f'))
1119 result = false;
1120 else if (len == 1 && (s[0] == '1' || s[0] == 'y' || s[0] == 't'))
1121 result = true;
1122 else if (len == 5 && memcmp(s, "false", 5) == 0)
1123 result = false;
1124 else if (len == 4 && memcmp(s, "true", 4) == 0)
1125 result = true;
1126 else if (len == 2 && memcmp(s, "no", 2) == 0)
1127 result = false;
1128 else if (len == 3 && memcmp(s, "yes", 3) == 0)
1129 result = true;
1130 else
1131 return false;
1132
1133 return true;
1134 }
1135
1136
1137 void
check_units()1138 UnitArg::check_units()
1139 {
1140 const unsigned char *u = units_;
1141 Vector<String> suffixes;
1142 while (*u) {
1143 assert(*u >= 1 && *u <= 7 && *u != 4);
1144 const unsigned char *next = u + 2 + (*u & 3);
1145 assert(*next);
1146 const unsigned char *post = next + 1;
1147 while (*post > 7)
1148 ++post;
1149 String suffix(next, post);
1150 for (String *it = suffixes.begin(); it != suffixes.end(); ++it)
1151 assert(suffix.length() < it->length()
1152 || it->substring(-suffix.length()) != suffix);
1153 suffixes.push_back(suffix);
1154 u = post;
1155 }
1156 }
1157
1158 const char *
parse(const char * begin,const char * end,int & power,int & factor) const1159 UnitArg::parse(const char *begin, const char *end, int &power, int &factor) const
1160 {
1161 const unsigned char *units = units_;
1162
1163 while (*units) {
1164 const unsigned char *ubegin = units + 2 + (*units & 3);
1165 const unsigned char *uend = ubegin + 1;
1166 while (*uend > 7)
1167 ++uend;
1168
1169 if (uend - ubegin <= end - begin
1170 && memcmp(ubegin, end - (uend - ubegin), uend - ubegin) == 0) {
1171 factor = units[2];
1172 if ((*units & 3) >= 2)
1173 factor = 256 * factor + units[3];
1174 if ((*units & 3) >= 3)
1175 factor = 256 * factor + units[4];
1176
1177 power = units[1];
1178 if (*units >= 4)
1179 power = -power;
1180
1181 end = end - (uend - ubegin);
1182 if (prefix_chars_ && end > begin)
1183 for (const unsigned char *prefix_chars = prefix_chars_;
1184 *prefix_chars; prefix_chars += 2)
1185 if ((char) *prefix_chars == end[-1]) {
1186 power += prefix_chars[1] - 64;
1187 --end;
1188 break;
1189 }
1190
1191 while (end > begin && isspace((unsigned char) end[-1]))
1192 --end;
1193 return end;
1194 }
1195
1196 units = uend;
1197 }
1198
1199 power = 0;
1200 factor = 1;
1201 return end;
1202 }
1203
1204
1205 static const char byte_bandwidth_units[] = "\
1206 \5\3\175baud\
1207 \5\3\175bps\
1208 \5\3\175b/s\
1209 \1\0\1Bps\
1210 \1\0\1B/s\
1211 ";
1212 static const char byte_bandwidth_prefixes[] = "\
1213 k\103K\103M\106G\111";
1214
1215 static uint32_t
multiply_factor(uint32_t ix,uint32_t fx,uint32_t factor,int & status)1216 multiply_factor(uint32_t ix, uint32_t fx, uint32_t factor, int &status)
1217 {
1218 if (factor == 1) {
1219 if (int32_t(fx) < 0 && ++ix == 0)
1220 status = NumArg::status_range;
1221 return ix;
1222 } else {
1223 uint32_t flow, ftoint, ilow, ihigh;
1224 int_multiply(fx, factor, flow, ftoint);
1225 if (int32_t(flow) < 0)
1226 ++ftoint;
1227 int_multiply(ix, factor, ilow, ihigh);
1228 if (ihigh != 0 || ilow + ftoint < ftoint)
1229 status = NumArg::status_range;
1230 return ilow + ftoint;
1231 }
1232 }
1233
1234 bool
parse(const String & str,uint32_t & result,const ArgContext & args)1235 BandwidthArg::parse(const String &str, uint32_t &result, const ArgContext &args)
1236 {
1237 int power, factor;
1238 const char *unit_end = UnitArg(byte_bandwidth_units, byte_bandwidth_prefixes).parse(str.begin(), str.end(), power, factor);
1239
1240 value_type ix;
1241 uint32_t fx;
1242 const char *xend = parse_fraction(str.begin(), unit_end,
1243 false, power, ix, fx, status);
1244 if (status == status_inval || xend != unit_end) {
1245 status = status_inval;
1246 return false;
1247 }
1248 if (uint32_t(ix) != ix)
1249 status = status_range;
1250 ix = multiply_factor(ix, fx, factor, status);
1251 if (status == status_range) {
1252 args.error("out of range");
1253 result = 0xFFFFFFFFU;
1254 return false;
1255 } else {
1256 if (unit_end == str.end() && ix)
1257 status = status_unitless;
1258 result = ix;
1259 return true;
1260 }
1261 }
1262
1263 String
unparse(uint32_t x)1264 BandwidthArg::unparse(uint32_t x)
1265 {
1266 if (x >= 0x20000000U)
1267 return cp_unparse_real10(x, 6) + "MBps";
1268 else if (x >= 125000000)
1269 return cp_unparse_real10(x * 8, 9) + "Gbps";
1270 else if (x >= 125000)
1271 return cp_unparse_real10(x * 8, 6) + "Mbps";
1272 else
1273 return cp_unparse_real10(x * 8, 3) + "kbps";
1274 }
1275
1276
1277 static const char seconds_units[] = "\
1278 \1\0\1s\
1279 \1\0\1sec\
1280 \1\1\6m\
1281 \1\1\6min\
1282 \1\2\044h\
1283 \1\2\044hr\
1284 \2\2\003\140d\
1285 \2\2\003\140day";
1286 static const char seconds_prefixes[] = "m\075u\072n\067";
1287
1288 bool
parse_saturating(const String & str,uint32_t & result,const ArgContext &)1289 SecondsArg::parse_saturating(const String &str, uint32_t &result, const ArgContext &)
1290 {
1291 int power, factor;
1292 const char *unit_end = UnitArg(seconds_units, seconds_prefixes).parse(str.begin(), str.end(), power, factor);
1293
1294 value_type ix;
1295 uint32_t fx;
1296 const char *xend = parse_fraction(str.begin(), unit_end,
1297 false, power + fraction_digits, ix, fx, status);
1298 if (status == status_inval || xend != unit_end) {
1299 status = status_inval;
1300 return false;
1301 }
1302 if (uint32_t(ix) != ix)
1303 status = status_range;
1304 ix = multiply_factor(ix, fx, factor, status);
1305 if (status == status_range)
1306 ix = integer_traits<uint32_t>::const_max;
1307 result = ix;
1308 return true;
1309 }
1310
1311 bool
parse(const String & str,uint32_t & result,const ArgContext & args)1312 SecondsArg::parse(const String &str, uint32_t &result, const ArgContext &args)
1313 {
1314 uint32_t x;
1315 if (!parse_saturating(str, x, args))
1316 return false;
1317 else if (status == status_range) {
1318 args.error("out of range");
1319 return false;
1320 } else {
1321 result = x;
1322 return true;
1323 }
1324 }
1325
1326 #if HAVE_FLOAT_TYPES
1327 bool
parse(const String & str,double & result,const ArgContext &)1328 SecondsArg::parse(const String &str, double &result, const ArgContext &)
1329 {
1330 int power, factor;
1331 const char *unit_end = UnitArg(seconds_units, seconds_prefixes).parse(str.begin(), str.end(), power, factor);
1332 if (!DoubleArg().parse(str.substring(str.begin(), unit_end), result))
1333 return false;
1334 if (factor != 1)
1335 result *= factor;
1336 power += fraction_digits;
1337 if (power != 0)
1338 result *= pow(10, power);
1339 return true;
1340 }
1341 #endif
1342
1343
1344 #if CLICK_USERLEVEL || CLICK_TOOL
1345 bool
parse(const String & str,String & result,const ArgContext &)1346 FilenameArg::parse(const String &str, String &result, const ArgContext &)
1347 {
1348 String fn;
1349 if (!cp_string(str, &fn) || !fn)
1350 return false;
1351
1352 // expand home directory substitutions
1353 if (fn[0] == '~') {
1354 if (fn.length() == 1 || fn[1] == '/') {
1355 const char *home = getenv("HOME");
1356 if (home)
1357 fn = String(home) + fn.substring(1);
1358 } else {
1359 int off = 1;
1360 while (off < fn.length() && fn[off] != '/')
1361 off++;
1362 String username = fn.substring(1, off - 1);
1363 struct passwd *pwd = getpwnam(username.c_str());
1364 if (pwd && pwd->pw_dir)
1365 fn = String(pwd->pw_dir) + fn.substring(off);
1366 }
1367 }
1368
1369 // replace double slashes with single slashes
1370 int len = fn.length();
1371 for (int i = 0; i < len - 1; i++)
1372 if (fn[i] == '/' && fn[i+1] == '/') {
1373 fn = fn.substring(0, i) + fn.substring(i + 1);
1374 i--;
1375 len--;
1376 }
1377
1378 // return
1379 result = fn;
1380 return true;
1381 }
1382 #endif
1383
1384
1385 #if !CLICK_TOOL
1386 bool
parse(const String & str,int & result,const ArgContext & args)1387 AnnoArg::parse(const String &str, int &result, const ArgContext &args)
1388 {
1389 int32_t annoval;
1390 if (!NameInfo::query_int(NameInfo::T_ANNOTATION, args.context(),
1391 str, &annoval))
1392 return false;
1393 if (size > 0) {
1394 if (ANNOTATIONINFO_SIZE(annoval) && ANNOTATIONINFO_SIZE(annoval) != size)
1395 return false;
1396 # if !HAVE_INDIFFERENT_ALIGNMENT
1397 if ((size == 2 || size == 4 || size == 8)
1398 && (ANNOTATIONINFO_OFFSET(annoval) % size) != 0)
1399 return false;
1400 # endif
1401 if (ANNOTATIONINFO_OFFSET(annoval) + size > Packet::anno_size)
1402 return false;
1403 annoval = ANNOTATIONINFO_OFFSET(annoval);
1404 } else if (ANNOTATIONINFO_OFFSET(annoval) >= Packet::anno_size)
1405 return false;
1406 result = annoval;
1407 return true;
1408 }
1409
1410 bool
parse(const String & str,Element * & result,const ArgContext & args)1411 ElementArg::parse(const String &str, Element *&result, const ArgContext &args)
1412 {
1413 const Element *context = args.context();
1414 assert(context);
1415
1416 result = context->router()->find(str, context);
1417 if (!result)
1418 args.error("does not name an element");
1419 return result;
1420 }
1421
1422 bool
parse(const String & str,Element * & result,const ArgContext & args)1423 ElementCastArg::parse(const String &str, Element *&result, const ArgContext &args)
1424 {
1425 if (ElementArg::parse(str, result, args)
1426 && !(result = reinterpret_cast<Element *>(result->cast(type))))
1427 args.error("element type mismatch, expected %s", type);
1428 return result;
1429 }
1430 #endif
1431
1432 CLICK_ENDDECLS
1433