FS2_Open
Open source remastering of the Freespace 2 engine
consoleparse.cpp
Go to the documentation of this file.
1 // Command-line parsing functions for z64555's debug console, created for the FreeSpace Source Code project
3 //
4 // Portions of this source code are based on works by Volition, Inc. circa 1999. You may not sell or otherwise
5 // commercially exploit the source or things you created based on the source.
6 //
7 // This file contains documentation on locally referenced functions. For documentation on globally referenced
8 // functions, see consoleparse.h
10 
12 // @todo Make a fast version of the parse_long, parse_ulong, etc. That just checks the first 1-3 characters. The fast version will be used in retail builds while the slow/safe version will be in debug's
13 // @todo Maybe make parser functions case-insensitive
15 
17 #include "parse/parselo.h"
18 
19 #include <algorithm>
20 #include <cmath>
21 #include <cstdarg>
22 #include <cstring>
23 #include <limits.h>
24 
25 
26 // ========================= LOCALS =========================
28 char *Cp = NULL;
29 
30 enum state_int {
31  si_start = 0,
32  si_end = 1,
40 };
41 
43  sf_start = 0,
44  sf_end = 1,
53 };
54 
55 bool ch_is_sign(char ch);
56 bool ch_is_numeral(char ch);
57 bool ch_is_decimal(char ch);
58 bool ch_is_binary(char ch);
59 bool ch_is_octal(char ch);
60 bool ch_is_hex(char ch);
61 
62 bool ch_is_prefix(char ch);
63 bool ch_is_binary_prefix(char ch);
64 bool ch_is_octal_prefix(char ch);
65 bool ch_is_hex_prefix(char ch);
66 bool ch_is_exp_prefix(char ch);
67 
74 void dc_get_token(SCP_string &out_str);
75 
82 void dc_get_token_no_advance(SCP_string &out_str);
83 
95 double dc_parse_double(const char *ch, dc_token type);
96 
112 long dc_parse_long(const char *ch, dc_token type);
113 
127 ulong dc_parse_ulong(const char *ch, dc_token type);
128 
129 // State processes for dc_parse_double
130 state_float dc_parse_double_sign(const char* &ch_ptr, SCP_string &buffer_str);
131 state_float dc_parse_double_whole(const char* &ch_ptr, SCP_string &buffer_str);
132 state_float dc_parse_double_decimal(const char* &ch_ptr, SCP_string &buffer_str);
133 state_float dc_parse_double_fraction(const char* &ch_ptr, SCP_string &buffer_str);
134 state_float dc_parse_double_expprefix(const char* &ch_ptr, SCP_string &buffer_str);
135 state_float dc_parse_double_expsign(const char* &ch_ptr, SCP_string &buffer_str);
136 state_float dc_parse_double_exponent(const char* &ch_ptr, SCP_string &buffer_str);
137 
138 // State processes for dc_parse_long and dc_parse_ulong.
139 state_int dc_parse_long_prefix(const char* &ch_ptr, SCP_string &buffer_str, int &base);
140 state_int dc_parse_long_sign(const char* &ch_ptr, SCP_string &buffer_str);
141 state_int dc_parse_long_numeral(const char* &ch_ptr, SCP_string &buffer_str);
142 state_int dc_parse_long_numeral_bin(const char* &ch_ptr, SCP_string &buffer_str);
143 state_int dc_parse_long_numeral_hex(const char* &ch_ptr, SCP_string &buffer_str);
144 state_int dc_parse_long_numeral_octal(const char* &ch_ptr, SCP_string &buffer_str);
145 
146 
147 // ============================== IMPLEMENTATIONS =============================
148 inline
149 bool ch_is_sign(char ch)
150 {
151  return ((ch == '-') || (ch == '+'));
152 }
153 
154 inline
155 bool ch_is_numeral(char ch)
156 {
157  return ((ch >= '0') && (ch <= '9'));
158 }
159 
160 inline
161 bool ch_is_decimal(char ch)
162 {
163  return (ch == '.');
164 }
165 
166 inline
167 bool ch_is_binary(char ch)
168 {
169  return ((ch == '0') || (ch == '1'));
170 }
171 
172 inline
173 bool ch_is_octal(char ch)
174 {
175  return ((ch >= '0') && (ch <= '7'));
176 }
177 
178 inline
179 bool ch_is_hex(char ch)
180 {
181  return (((ch >= '0') && (ch <= '9')) || ((ch >= 'a') && (ch <= 'f')) || ((ch >= 'A') && (ch <= 'F')));
182 };
183 
184 inline
185 bool ch_is_prefix(char ch)
186 {
187  return (ch == '0');
188 }
189 
190 inline
191 bool ch_is_binary_prefix(char ch)
192 {
193  return ((ch == 'b') || (ch == 'B'));
194 }
195 
196 inline
197 bool ch_is_octal_prefix(char ch)
198 {
199  return ((ch == 'o') || (ch == 'O'));
200 }
201 
202 inline
203 bool ch_is_hex_prefix(char ch)
204 {
205  return ((ch == 'x') || (ch == 'X'));
206 }
207 
208 inline
209 bool ch_is_exp_prefix(char ch)
210 {
211  return ((ch == 'e') || (ch == 'E'));
212 }
213 
214 void dc_get_token(SCP_string &out_str) {
215  size_t count = 0;
216  char *c_ptr;
217 
218  Assert(Cp);
219 
221 
222  out_str = "";
223  // Bail if we're at the terminator
224  if (*Cp == '\0') {
225  return;
226  }
227 
228  // Scan the string, stopping at grayspace, null terminator, or before we go over MAX_TOKEN_LENGTH
229  c_ptr = Cp;
230  while (!is_gray_space(*c_ptr) && (*c_ptr != '\0') && (count < MAX_TOKEN_LENGTH)) {
231  count++;
232  c_ptr++;
233  }
234 
235  // Copy string into out_str
236  out_str.assign(Cp, count);
237 
238  // Advance the parser pointer past what we copied
239  Cp = c_ptr;
240 }
241 
243  size_t count = 0;
244  char *c_ptr;
245 
246  Assert(Cp);
247 
249 
250  out_str = "";
251  // Bail if we're at the terminator
252  if (*Cp == '\0') {
253  return;
254  }
255 
256  // Scan the string, stopping at grayspace, null terminator, or before we go over MAX_TOKEN_LENGTH
257  c_ptr = Cp;
258  while (!is_gray_space(*c_ptr) && (*c_ptr != '\0') && (count < MAX_TOKEN_LENGTH)) {
259  count++;
260  c_ptr++;
261  }
262 
263  // Copy string into out_str
264  out_str.assign(Cp, count);
265 }
266 
268  while (is_white_space(*Cp) && (*Cp != '\0')) {
269  Cp++;
270  }
271 }
272 
274  while (is_gray_space(*Cp) && (*Cp != '\0')) {
275  Cp++;
276  }
277 }
278 
280 {
282 
283  if (*Cp != '\0') {
284  dc_stuff_float(f);
285  return true;
286 
287  } else {
288  *f = 0;
289  return false;
290  }
291 }
292 
294 {
296 
297  if (*Cp != '\0') {
298  dc_stuff_int(i);
299  return true;
300  } else {
301  *i = 0;
302  return false;
303  }
304 }
305 
307 {
309 
310  if (*Cp != '\0') {
311  dc_stuff_uint(i);
312  return true;
313  } else {
314  *i = 0;
315  return false;
316  }
317 }
318 
320 {
322 
323  if (*Cp != '\0') {
324  dc_stuff_ubyte(i);
325  return true;
326  } else {
327  *i = 0;
328  return false;
329  }
330 }
331 
333 {
335 
336  if (*Cp != '\0') {
337  dc_stuff_boolean(b);
338  return true;
339  } else {
340  *b = false;
341  return false;
342  }
343 }
344 
346 {
348 
349  if (*Cp != '\0') {
350  dc_stuff_boolean(i);
351  return true;
352  } else {
353  *i = 0;
354  return false;
355  }
356 }
357 
358 bool dc_maybe_stuff_string(char *out_str, size_t maxlen)
359 {
360  size_t count = 0;
361  char *c_ptr = Cp;
362 
363  Assert(Cp);
364  Assert(out_str);
365 
366  // Advance past grayspace, stopping at null terminator
367  while (is_gray_space(*c_ptr) && (*c_ptr != '\0')) {
368  c_ptr++;
369  }
370 
371  // Bail if we're at the terminator
372  if (*c_ptr == '\0') {
373  return false;
374  }
375 
376  // Scan the string, stopping at null terminator, or before we overflow
377  while ((*c_ptr != '\0') && (count < maxlen)) {
378  count++;
379  c_ptr++;
380  }
381 
382  // Bail if overflow
383  if (count == maxlen) {
384  throw errParse("", DCT_STRING);
385  }
386 
387  // Copy string into out_str
388  strncpy(out_str, Cp, count);
389 
390  // Advance the parser pointer past what we copied
391  Cp = c_ptr;
392 
393  return true;
394 }
395 
397 {
398  size_t count = 0;
399  char *c_ptr = Cp;
400 
401  Assert(Cp);
402 
403  // Advance past grayspace, stopping at null terminator
404  while (is_gray_space(*c_ptr) && (*c_ptr != '\0')) {
405  c_ptr++;
406  }
407 
408  // Bail if we're at the terminator
409  if (*c_ptr == '\0') {
410  return false;
411  }
412 
413  // Scan the string, stopping at null terminator, or before we overflow
414  while ((*c_ptr != '\0') && (count < out_str.max_size())) {
415  count++;
416  c_ptr++;
417  }
418 
419  // Bail if overflow
420  if (count == out_str.max_size()) {
421  return false;
422  }
423 
424  // Copy string into out_str
425  out_str.assign(Cp, count);
426 
427  // Advance the parser pointer past what we copied
428  Cp = c_ptr;
429 
430  return true;
431 }
432 
433 bool dc_maybe_stuff_string_white(char *str, size_t len)
434 {
436 
437  if (*Cp != '\0') {
438  dc_stuff_string_white(str, len);
439  return true;
440  } else {
441  *str = '\0';
442  return false;
443  }
444 }
445 
447 {
449 
450  if (*Cp != '\0') {
452  return true;
453  } else {
454  str = "";
455  return false;
456  }
457 }
458 
459 void dc_required_string(char *pstr)
460 {
461  char *str_found = NULL;
462 
464 
465  if (strncmp(pstr, Cp, strlen(pstr)) == 0) {
466  str_found = pstr;
467  }
468 
469  if (str_found != NULL) {
470  // Found a required string
471  if (Dc_debug_on) {
472  dc_printf("<debug> Found required string [%s]\n", str_found);
473  }
474 
475  Cp += strlen(str_found);
476  } else {
477  // Didn't find a required string.
478  SCP_string token;
480  throw errParseString(token.c_str(), pstr);
481  }
482 }
483 
484 int dc_required_string_either(char *str1, char *str2)
485 {
486  char *str_found = NULL;
487  int i = -1;
488 
490 
491  if (strncmp(str1, Cp, strlen(str1)) == 0) {
492  str_found = str1;
493  i = 0;
494  } else if (strncmp(str2, Cp, strlen(str2)) == 0) {
495  str_found = str2;
496  i = 1;
497  }
498 
499  if (i > -1) {
500  // Found a required string
501  if (Dc_debug_on) {
502  dc_printf("<debug> Found required string [%s]\n", str_found);
503  }
504 
505  Cp += strlen(str_found);
506  } else {
507  // Didn't find a required string.
508  SCP_string token;
510  throw errParseString(token.c_str(), str1, str2);
511  }
512 
513  return i;
514 }
515 
517 {
518  va_list vl;
520  const char *str_found = NULL;
521  uint i;
522 
524 
525  // Populate the vector.
526  va_start(vl, n);
527  for (i = 0; i < n; ++i) {
528  strings.push_back(va_arg(vl, char *));
529  }
530  va_end(vl);
531 
532  // Search for the required string. If found, i = index of the string passed
533  for (i = 0; i < n; ++i) {
534  if (strcmp(Cp, strings[i].c_str()) == 0)
535  {
536  str_found = strings[i].c_str();
537  break;
538  }
539  }
540 
541  if (str_found != NULL) {
542  // Found a required string
543  if (Dc_debug_on) {
544  dc_printf("<debug> Found required string [%s}\n", str_found);
545  }
546 
547  Cp += strlen(str_found);
548  } else {
549  // Didn't find a required string.
550  SCP_string token;
552  throw errParseString(token.c_str(), strings);
553  }
554 
555  return i;
556 }
557 
558 bool dc_optional_string(const char *pstr)
559 {
561 
562  if (strncmp(pstr, Cp, strlen(pstr)) != 0) {
563  return false;
564  } // Else, optional string was found
565 
566  if (Dc_debug_on) {
567  dc_printf("<debug> Found optional string [%s]\n", pstr);
568  }
569 
570  Cp += strlen(pstr);
571  return true;
572 }
573 
574 bool dc_optional_string_either(const char *str1, const char *str2)
575 {
576  const char *str_found = NULL;
577 
579 
580  if (strncmp(str1, Cp, strlen(str1)) == 0) {
581  str_found = str1;
582  } else if (strncmp(str2, Cp, strlen(str2)) == 0) {
583  str_found = str2;
584  } else {
585  return false;
586  }
587 
588  if (Dc_debug_on) {
589  dc_printf("<debug> Found optional string [%s]\n",str_found);
590  }
591 
592  Cp += strlen(str_found);
593  return true;;
594 }
595 
597 {
598  strcpy_s(Command_string, str.c_str());
599  Cp = Command_string;
600 }
601 
602 double dc_parse_double(const char *ch, dc_token type) {
603  const char *ch_ptr = ch;
604  char *end_ptr;
605  double ret;
606  state_float state = sf_start;
607  SCP_string buffer_str;
608 
609  while ((*ch_ptr != '\0') && is_white_space(*ch_ptr)) {
610  ch_ptr++;
611  }
612 
613  if (*ch_ptr == '\0') {
614  if (Dc_debug_on) {
615  dc_printf("<debug> [parse_double] no argument found\n");
616  }
617  throw errParse("", type);
618  }
619 
620  do {
621  switch (state) {
622  case sf_start:
623  if (ch_is_sign(*ch_ptr)) {
624  state = sf_sign;
625  if (*ch_ptr == '-') {
626  buffer_str.push_back(*ch_ptr);
627  } // Else, sign is positive, and isn't needed on the buffer
628  ch_ptr++;
629 
630  } else if (ch_is_numeral(*ch_ptr)) {
631  state = sf_whole;
632  buffer_str.push_back(*ch_ptr);
633  ch_ptr++;
634 
635  } else if (ch_is_decimal(*ch_ptr)) {
636  state = sf_decimal;
637  buffer_str.push_back(*ch_ptr);
638  ch_ptr++;
639 
640  } else {
641  if (Dc_debug_on) {
642  dc_printf("<debug> [parse_double] Invalid character '%c' found in sf_start\n", *ch_ptr);
643  }
644  state = sf_invalid;
645 
646  }
647  break;
648  case sf_end:
649  if (buffer_str == "") {
650  state = sf_invalid;
651  } // Else, we can convert the token.
652  // Do nothing, and allow the while loop exit condition to trigger
653  break;
654  case sf_sign:
655  state = dc_parse_double_sign(ch_ptr, buffer_str);
656  break;
657 
658  case sf_whole:
659  state = dc_parse_double_whole(ch_ptr, buffer_str);
660  break;
661 
662  case sf_decimal:
663  state = dc_parse_double_decimal(ch_ptr, buffer_str);
664  break;
665 
666  case sf_fraction:
667  state = dc_parse_double_fraction(ch_ptr, buffer_str);
668  break;
669 
670  case sf_expprefix:
671  state = dc_parse_double_expprefix(ch_ptr, buffer_str);
672  break;
673 
674  case sf_expsign:
675  state = dc_parse_double_expsign(ch_ptr, buffer_str);
676  break;
677 
678  case sf_exponent:
679  state = dc_parse_double_exponent(ch_ptr, buffer_str);
680  break;
681 
682  case sf_invalid:
683  default:
684  throw errParse(ch, type);
685  }
686  } while (state != sf_end);
687 
688  ret = strtod(buffer_str.c_str(), &end_ptr);
689 
690  return ret;
691 }
692 
693 state_float dc_parse_double_sign(const char* &ch_ptr, SCP_string &buffer_str)
694 {
695  state_float state = sf_invalid;
696 
697  if (ch_is_numeral(*ch_ptr)) {
698  state = sf_whole;
699  buffer_str.push_back(*ch_ptr);
700  ch_ptr++;
701 
702  } else if (ch_is_decimal(*ch_ptr)) {
703  state = sf_decimal;
704  buffer_str.push_back(*ch_ptr);
705  ch_ptr++;
706 
707  } else {
708  state = sf_invalid;
709  if (Dc_debug_on) {
710  dc_printf("<debug> [parse_double] Invalid character '%c' found in sf_sign\n", *ch_ptr);
711  }
712  }
713 
714  return state;
715 }
716 
717 state_float dc_parse_double_whole(const char* &ch_ptr, SCP_string &buffer_str)
718 {
719  state_float state = sf_invalid;
720 
721  if (ch_is_numeral(*ch_ptr)) {
722  state = sf_whole;
723  buffer_str.push_back(*ch_ptr);
724  ch_ptr++;
725 
726  } else if (ch_is_decimal(*ch_ptr)) {
727  state = sf_decimal;
728  buffer_str.push_back(*ch_ptr);
729  ch_ptr++;
730 
731  } else if (ch_is_exp_prefix(*ch_ptr)) {
732  state = sf_expprefix;
733  buffer_str.push_back(*ch_ptr);
734  ch_ptr++;
735 
736  } else if ((*ch_ptr == '\0') || is_white_space(*ch_ptr)) {
737  state = sf_end;
738 
739  } else {
740  state = sf_invalid;
741  if (Dc_debug_on) {
742  dc_printf("<debug> [parse_double] Invalid character '%c' found in sf_whole\n", *ch_ptr);
743  }
744  }
745 
746  return state;
747 }
748 
749 state_float dc_parse_double_decimal(const char* &ch_ptr, SCP_string &buffer_str)
750 {
751  state_float state = sf_invalid;
752 
753  if (ch_is_numeral(*ch_ptr)) {
754  state = sf_fraction;
755  buffer_str.push_back(*ch_ptr);
756  ch_ptr++;
757 
758  } else if (ch_is_exp_prefix(*ch_ptr)) {
759  state = sf_expprefix;
760  buffer_str.push_back(*ch_ptr);
761  ch_ptr++;
762 
763  } else if ((*ch_ptr == '\0') || is_white_space(*ch_ptr)) {
764  state = sf_end;
765 
766  } else {
767  state = sf_invalid;
768  if (Dc_debug_on) {
769  dc_printf("<debug> [parse_double] Invalid character '%c' found in sf_decimal\n", *ch_ptr);
770  }
771  }
772 
773  return state;
774 }
775 
776 state_float dc_parse_double_fraction(const char* &ch_ptr, SCP_string &buffer_str)
777 {
778  state_float state = sf_invalid;
779 
780  if (ch_is_numeral(*ch_ptr)) {
781  state = sf_fraction;
782  buffer_str.push_back(*ch_ptr);
783  ch_ptr++;
784 
785  } else if (ch_is_exp_prefix(*ch_ptr)) {
786  state = sf_expprefix;
787  buffer_str.push_back(*ch_ptr);
788  ch_ptr++;
789 
790  } else if ((*ch_ptr == '\0') || is_white_space(*ch_ptr)) {
791  state = sf_end;
792 
793  } else {
794  state = sf_invalid;
795  if (Dc_debug_on) {
796  dc_printf("<debug> [parse_double] Invalid character '%c' found in sf_faction\n", *ch_ptr);
797  }
798  }
799 
800  return state;
801 }
802 
803 state_float dc_parse_double_expprefix(const char* &ch_ptr, SCP_string &buffer_str)
804 {
805  state_float state = sf_invalid;
806 
807  if (ch_is_sign(*ch_ptr)) {
808  state = sf_expsign;
809  buffer_str.push_back(*ch_ptr);
810  ch_ptr++;
811 
812  } else if (ch_is_numeral(*ch_ptr)) {
813  state = sf_exponent;
814  buffer_str.push_back(*ch_ptr);
815  ch_ptr++;
816 
817  } else {
818  state = sf_invalid;
819  if (Dc_debug_on) {
820  dc_printf("<debug> [parse_double] Invalid character '%c' found in sf_expprefix\n", *ch_ptr);
821  }
822  }
823 
824  return state;
825 }
826 
827 state_float dc_parse_double_expsign(const char* &ch_ptr, SCP_string &buffer_str)
828 {
829  state_float state = sf_invalid;
830 
831  if (ch_is_numeral(*ch_ptr)) {
832  state = sf_exponent;
833  buffer_str.push_back(*ch_ptr);
834  ch_ptr++;
835 
836  } else {
837  state = sf_invalid;
838  if (Dc_debug_on) {
839  dc_printf("<debug> [parse_double] Invalid character '%c' found in sf_expsign\n", *ch_ptr);
840  }
841  }
842 
843  return state;
844 }
845 
846 state_float dc_parse_double_exponent(const char* &ch_ptr, SCP_string &buffer_str)
847 {
848  state_float state = sf_invalid;
849 
850  if (ch_is_numeral(*ch_ptr)) {
851  state = sf_exponent;
852  buffer_str.push_back(*ch_ptr);
853  ch_ptr++;
854 
855  } else if ((*ch_ptr == '\0') || is_white_space(*ch_ptr)) {
856  state = sf_end;
857 
858  } else {
859  state = sf_invalid;
860  if (Dc_debug_on) {
861  dc_printf("<debug> [parse_double] Invalid character '%c' found in sf_exponent\n", *ch_ptr);
862  }
863  }
864 
865  return state;
866 }
867 
868 long dc_parse_long(const char *ch, dc_token type) {
869  const char *ch_ptr = ch;
870  char *end_ptr = NULL;
871  int base = 10;
872  long ret;
873  state_int state = si_start;
874  SCP_string buffer_str;
875 
876  while ((*ch_ptr != '\0') && is_white_space(*ch_ptr)) {
877  ch_ptr++;
878  }
879 
880  if (*ch_ptr == '\0') {
881  if (Dc_debug_on) {
882  dc_printf("<debug> [parse_long] no argument found\n");
883  }
884  throw errParse("", type);
885  }
886 
887  do {
888  switch (state) {
889  case si_start:
890  if (ch_is_sign(*ch_ptr)) {
891  state = si_sign;
892  if (*ch_ptr == '-') {
893  buffer_str.push_back(*ch_ptr);
894  } // Else, it's positive. Positive sign isn't needed for conversion
895  ch_ptr++;
896 
897  } else if (ch_is_prefix(*ch_ptr)) {
898  // prefixes must be checked before numeral, because they all start with a numeral zero
899  state = si_prefix;
900  ch_ptr++;
901 
902  } else if (ch_is_numeral(*ch_ptr)) {
903  state = si_numeral;
904  buffer_str.push_back(*ch_ptr);
905  ch_ptr++;
906 
907  } else {
908  if (Dc_debug_on) {
909  dc_printf("<debug> [parse_long] Invalid character '%c' found in si_start\n", *ch_ptr);
910  }
911  state = si_invalid;
912 
913  }
914  break;
915  case si_end:
916  if (buffer_str == "") {
917  state = si_invalid;
918  } // Else, we can convert the token.
919  // Do nothing, and allow the while loop exit condition to trigger
920  break;
921 
922  case si_sign:
923  state = dc_parse_long_sign(ch_ptr, buffer_str);
924  break;
925 
926  case si_prefix:
927  state = dc_parse_long_prefix(ch_ptr, buffer_str, base);
928  break;
929 
930  case si_numeral_bin:
931  state = dc_parse_long_numeral_bin(ch_ptr, buffer_str);
932  break;
933 
934  case si_numeral_octal:
935  state = dc_parse_long_numeral_octal(ch_ptr, buffer_str);
936  break;
937 
938  case si_numeral_hex:
939  state = dc_parse_long_numeral_hex(ch_ptr, buffer_str);
940  break;
941 
942  case si_numeral:
943  state = dc_parse_long_numeral(ch_ptr, buffer_str);
944  break;
945 
946  case si_invalid:
947  default:
948  throw errParse(ch, type);
949  break;
950  }
951  } while (state != si_end);
952 
953  ret = strtol(buffer_str.c_str(), &end_ptr, base);
954 
955  // This last check can be omitted once I can verify the operation of strtol in this sense
956  if (*end_ptr != '\0') {
957  dc_printf("Error: Could not convert all of the buffer '%s'.\n", buffer_str.c_str());
958  if (Dc_debug_on) {
959  dc_printf("<debug> Buffer value: %s\n", buffer_str.c_str());
960  dc_printf("<debug> Return value: %i", ret);
961  }
962  throw errParse(ch, type);
963  }
964 
965  return ret;
966 }
967 
968 ulong dc_parse_ulong(const char *ch, dc_token type) {
969  const char *ch_ptr = ch;
970  char *end_ptr;
971  int base = 10;
972  ulong ret;
973  state_int state = si_start;
974  SCP_string buffer_str;
975 
976  while ((*ch_ptr != '\0') && is_white_space(*ch_ptr)) {
977  ch_ptr++;
978  }
979 
980  if (*ch_ptr == '\0') {
981  if (Dc_debug_on) {
982  dc_printf("<debug> [parse_long] no argument found\n");
983  }
984  throw errParse("", type);
985  }
986 
987  do {
988  switch (state) {
989  case si_start:
990  if (ch_is_prefix(*ch_ptr)) {
991  // prefixes must be checked before numeral, because they all start with a numeral zero
992  state = si_prefix;
993  ch_ptr++;
994 
995  } else if (ch_is_numeral(*ch_ptr)) {
996  state = si_numeral;
997  buffer_str.push_back(*ch_ptr);
998  ch_ptr++;
999 
1000  } else {
1001  if (Dc_debug_on) {
1002  dc_printf("<debug> [parse_long] Invalid character '%c' found in si_start\n", *ch_ptr);
1003  }
1004  state = si_invalid;
1005 
1006  }
1007  break;
1008  case si_end:
1009  if (buffer_str == "")
1010  {
1011  state = si_invalid;
1012  } // Else, we can convert the token.
1013  // Do nothing, and allow the while loop exit condition to trigger
1014  break;
1015 
1016  case si_prefix:
1017  state = dc_parse_long_prefix(ch_ptr, buffer_str, base);
1018  break;
1019 
1020  case si_numeral_bin:
1021  state = dc_parse_long_numeral_bin(ch_ptr, buffer_str);
1022  break;
1023 
1024  case si_numeral_octal:
1025  state = dc_parse_long_numeral_octal(ch_ptr, buffer_str);
1026  break;
1027 
1028  case si_numeral_hex:
1029  state = dc_parse_long_numeral_hex(ch_ptr, buffer_str);
1030  break;
1031 
1032  case si_numeral:
1033  state = dc_parse_long_numeral(ch_ptr, buffer_str);
1034  break;
1035 
1036  case si_invalid:
1037  default:
1038  throw errParse(ch, type);
1039  }
1040  } while (state != si_end);
1041 
1042  ret = strtoul(buffer_str.c_str(), &end_ptr, base);
1043 
1044  // This last check can be omitted once I can verify the operation of strtol in this sense
1045  if (end_ptr != ch_ptr) {
1046  dc_printf("Error: Could not convert all of the buffer '%s'.\n", buffer_str.c_str());
1047  if (Dc_debug_on) {
1048  dc_printf("<debug> Buffer value: %s\n", buffer_str.c_str());
1049  dc_printf("<debug> Return value: %i", ret);
1050  }
1051  throw errParse(ch, type);
1052  }
1053 
1054  return ret;
1055 }
1056 
1057 void dc_stuff_float(float *f)
1058 {
1059  double value_d;
1060  SCP_string token;
1061 
1063 
1064  dc_get_token(token); // Grab the token
1065  value_d = dc_parse_double(token.c_str(), DCT_FLOAT); // Parse and convert
1066 
1067  // Stuff value if within bounds
1068  if ((std::abs(value_d) < FLT_MAX) && (std::abs(value_d) > FLT_MIN)) {
1069  *f = static_cast<float>(value_d);
1070  } else {
1071  throw errParse(token.c_str(), DCT_FLOAT);
1072  }
1073 }
1074 
1075 void dc_stuff_int(int *i)
1076 {
1077  long value_l;
1078  SCP_string token;
1079 
1081 
1082  dc_get_token(token);
1083  value_l = dc_parse_long(token.c_str(), DCT_INT);
1084 
1085  if ((value_l < INT_MAX) && (value_l > INT_MIN)) {
1086  *i = value_l;
1087 
1088  } else {
1089  throw errParse(token.c_str(), DCT_INT);
1090  }
1091 }
1092 
1094 {
1095  ulong value_l;
1096  SCP_string token;
1097 
1099 
1100  dc_get_token(token);
1101  value_l = dc_parse_long(Cp, DCT_INT);
1102 
1103  if (value_l < UINT_MAX) {
1104  *i = value_l;
1105 
1106  } else {
1107  throw errParse(token.c_str(), DCT_INT);
1108  }
1109 }
1110 
1112 {
1113  ulong value_ul;
1114  SCP_string token;
1115 
1117 
1118  dc_get_token(token);
1119  value_ul = dc_parse_ulong(Cp, DCT_UBYTE);
1120 
1121  // Since some system's chars may be greater than 1 byte, we can't use UCHAR_MAX for a UBYTE
1122  if (value_ul <= 255) {
1123  *i = static_cast<ubyte>(value_ul);
1124 
1125  } else {
1126  throw errParse(token.c_str(), DCT_UBYTE);
1127  }
1128 }
1129 
1130 void dc_stuff_boolean(bool *b)
1131 {
1132  SCP_string token;
1133 
1134  dc_get_token(token);
1135 
1136  if ((token == "yes")
1137  || (token == "true")
1138  || (token == "ja") // German
1139  || (token == "Oui") // French
1140  || (token == "si") // Spanish
1141 // || (token == "ita vero") // Latin, not supported
1142  || (token == "HIja") || (token == "HISLaH") // Klingon
1143  || (token == "1"))
1144  {
1145  *b = true;
1146 
1147  } else if ((token == "no")
1148  || (token == "false")
1149  || (token == "nein") // German
1150  || (token == "Non") // French
1151 // || (token == "no") // Spanish, redundant with English "no"
1152 // || (token == "minime") // Latin, not supported
1153  || (token == "ghobe'") // Klingon
1154  || (token == "0"))
1155  {
1156  *b = false;
1157 
1158  } else {
1159  throw errParse(token.c_str(), DCT_BOOL);
1160  }
1161 }
1162 
1164 {
1165  bool value_b;
1166 
1167  dc_stuff_boolean(&value_b);
1168 
1169  value_b ? *i = 1 : *i = 0;
1170 }
1171 
1172 void dc_stuff_string(char *out_str, size_t maxlen = MAX_TOKEN_LENGTH)
1173 {
1174  size_t count = 0;
1175  char *c_ptr = Cp;
1176  SCP_string token;
1177 
1178  Assert(Cp);
1179  Assert(out_str);
1180 
1182 
1183  // Bail if we're at the terminator
1184  if (*Cp == '\0') {
1185  throw errParse("Nothing!", DCT_STRING);
1186  }
1187 
1188  // Scan the string, stopping at null terminator, or before we overflow
1189  c_ptr = Cp;
1190  while ((*c_ptr != '\0') && (count < maxlen)) {
1191  count++;
1192  c_ptr++;
1193  }
1194 
1195  // Bail if overflow
1196  if (count == maxlen) {
1197  token.assign(Cp, maxlen);
1198  throw errParseOverflow(token.c_str(), maxlen);
1199  }
1200 
1201  // Copy string into out_str
1202  strncpy(out_str, Cp, count);
1203 
1204  // Advance the parser pointer past what we copied
1205  Cp = c_ptr;
1206 }
1207 
1209 {
1210  size_t count = 0;
1211  char *c_ptr = Cp;
1212 
1213  Assert(Cp);
1214 
1216 
1217  // Bail if we're at the terminator
1218  if (*Cp == '\0') {
1219  throw errParse("Nothing!", DCT_STRING);
1220  }
1221 
1222  // Scan the string, stopping at null terminator, or before we overflow
1223  c_ptr = Cp;
1224  while ((*c_ptr != '\0') && (count < out_str.max_size())) {
1225  count++;
1226  c_ptr++;
1227  }
1228 
1229  // Bail if overflow
1230  if ((count == out_str.max_size()) && (*c_ptr != '\0')) {
1231  throw errParse("SCP_string overflow!", DCT_STRING);
1232  }
1233 
1234  // Copy string into out_str
1235  out_str.assign(Cp, count);
1236 
1237  // Advance the parser pointer past what we copied
1238  Cp = c_ptr;
1239 }
1240 
1241 void dc_stuff_string_white(char *out_str, size_t maxlen)
1242 {
1243  size_t count = 0;
1244  char *c_ptr = Cp;
1245 
1246  Assert(Cp);
1247  Assert(out_str);
1248 
1250 
1251  // Bail if we're at the terminator
1252  if (*Cp == '\0') {
1253  throw errParse("Nothing!", DCT_STRING);
1254  }
1255 
1256  // Scan the string, stopping at grayspace, null terminator, or before we overflow
1257  c_ptr = Cp;
1258  while (!is_gray_space(*c_ptr) && (*c_ptr != '\0') && (count < maxlen)) {
1259  count++;
1260  c_ptr++;
1261  }
1262 
1263  // Bail if overflow
1264  if (count == maxlen) {
1265  throw errParse("", DCT_STRING);
1266  }
1267 
1268  // Copy string into out_str
1269  strncpy(out_str, Cp, count);
1270 
1271  // Advance the parser pointer past what we copied
1272  Cp = c_ptr;
1273 }
1274 
1276 {
1277  size_t count = 0;
1278  char *c_ptr;
1279 
1280  Assert(Cp);
1281 
1283 
1284  // Bail if we're at the terminator
1285  if (*Cp == '\0') {
1286  throw errParse("Nothing!", DCT_STRING);
1287  }
1288 
1289  // Scan the string, stopping at grayspace, null terminator, or before we overflow
1290  c_ptr = Cp;
1291  while (!is_gray_space(*c_ptr) && (*c_ptr != '\0') && (count < out_str.max_size())) {
1292  count++;
1293  c_ptr++;
1294  }
1295 
1296  // Bail if overflow
1297  if (count == out_str.max_size()) {
1298  throw errParse("", DCT_STRING);
1299  }
1300 
1301  // Copy string into out_str
1302  out_str.assign(Cp, count);
1303 
1304  // Advance the parser pointer past what we copied
1305  Cp = c_ptr;
1306 }
1307 
1308 inline
1309 state_int dc_parse_long_prefix(const char* &ch_ptr, SCP_string &buffer_str, int &base) {
1310  state_int state = si_invalid;
1311 
1312  if (ch_is_binary_prefix(*ch_ptr)) {
1313  state = si_numeral_bin;
1314  base = 2;
1315  ch_ptr++;
1316 
1317  } else if (ch_is_octal_prefix(*ch_ptr)) {
1318  state = si_numeral_octal;
1319  base = 8;
1320  ch_ptr++;
1321 
1322  } else if (ch_is_hex_prefix(*ch_ptr)) {
1323  state = si_numeral_hex;
1324  base = 16;
1325  ch_ptr++;
1326 
1327  } else if (ch_is_numeral(*ch_ptr)) {
1328  // User passed something like 0123
1329  // Just ignore the first 0, if the user passed something like 00001 then state si_numeral can handle it
1330  state = si_numeral;
1331  ch_ptr++;
1332 
1333  } else if ((*ch_ptr == '\0') || is_white_space(*ch_ptr)) {
1334  // Just a 0 was passed.
1335  buffer_str.push_back('0');
1336  state = si_end;
1337 
1338  } else {
1339  if (Dc_debug_on) {
1340  dc_printf("<debug> [parse_long] Invalid character '%c' found in si_prefix\n", *ch_ptr);
1341  }
1342  state = si_invalid;
1343 
1344  }
1345  return state;
1346 }
1347 
1348 inline
1349 state_int dc_parse_long_sign(const char* &ch_ptr, SCP_string &buffer_str) {
1350  state_int state;
1351  if (ch_is_numeral(*ch_ptr)) {
1352  state = si_numeral;
1353  buffer_str.push_back(*ch_ptr);
1354  ch_ptr++;
1355 
1356  } else if (ch_is_prefix(*ch_ptr)) {
1357  state = si_prefix;
1358  ch_ptr++;
1359 
1360  } else if ((*ch_ptr == '\0') || is_white_space(*ch_ptr)) {
1361  // Error, no value found
1362  state = si_invalid;
1363 
1364  } else {
1365  if (Dc_debug_on) {
1366  dc_printf("<debug> [parse_long] Invalid character '%c' found in si_sign\n", *ch_ptr);
1367  }
1368  state = si_invalid;
1369 
1370  }
1371  return state;
1372 }
1373 
1374 inline
1375 state_int dc_parse_long_numeral(const char* &ch_ptr, SCP_string &buffer_str) {
1376  state_int state = si_numeral;
1377 
1378  if (ch_is_numeral(*ch_ptr)) {
1379  buffer_str.push_back(*ch_ptr);
1380  ch_ptr++;
1381 
1382  } else if ((*ch_ptr == '\0') || is_white_space(*ch_ptr)) {
1383  state = si_end;
1384 
1385  } else {
1386  // Invalid character, throw and bail
1387  if (Dc_debug_on) {
1388  dc_printf("<debug> [parse_long] Invalid character '%c' found in si_numeral\n", *ch_ptr);
1389  }
1390  state = si_invalid;
1391 
1392  }
1393  return state;
1394 }
1395 
1396 inline
1397 state_int dc_parse_long_numeral_bin(const char* &ch_ptr, SCP_string &buffer_str) {
1398  state_int state = si_numeral_bin;
1399 
1400  if (ch_is_binary(*ch_ptr)) {
1401  buffer_str.push_back(*ch_ptr);
1402  ch_ptr++;
1403 
1404  } else if ((*ch_ptr == '\0') || is_white_space(*ch_ptr)) {
1405  state = si_end;
1406 
1407  } else {
1408  if (Dc_debug_on) {
1409  dc_printf("<debug> [parse_long] Invalid character '%c' found in si_numeral_bin\n", *ch_ptr);
1410  }
1411  state = si_invalid;
1412 
1413  }
1414  return state;
1415 }
1416 
1417 inline
1418 state_int dc_parse_long_numeral_hex(const char* &ch_ptr, SCP_string &buffer_str) {
1419  state_int state = si_numeral_hex;
1420 
1421  if (ch_is_hex(*ch_ptr)) {
1422  buffer_str.push_back(*ch_ptr);
1423  ch_ptr++;
1424 
1425  } else if ((*ch_ptr == '\0') || is_white_space(*ch_ptr)) {
1426  state = si_end;
1427 
1428  } else {
1429  if (Dc_debug_on) {
1430  dc_printf("<debug> [parse_long] Invalid character '%c' found in si_numeral_hex\n", *ch_ptr);
1431  }
1432  state = si_invalid;
1433  }
1434  return state;
1435 }
1436 
1437 inline
1438 state_int dc_parse_long_numeral_octal(const char* &ch_ptr, SCP_string &buffer_str) {
1439  state_int state = si_numeral_octal;
1440 
1441  if (ch_is_octal(*ch_ptr)) {
1442  buffer_str.push_back(*ch_ptr);
1443  ch_ptr++;
1444 
1445  } else if ((*ch_ptr == '\0') || is_white_space(*ch_ptr)) {
1446  state = si_end;
1447 
1448  } else {
1449  // Invalid character, throw and bail
1450  if (Dc_debug_on) {
1451  dc_printf("<debug> [parse_long] Invalid character '%c' found in si_numeral_octal\n", *ch_ptr);
1452  }
1453  state = si_invalid;
1454  }
1455  return state;
1456 }
int i
Definition: multi_pxo.cpp:466
char * Cp
Pointer to the commant string.
String.
Definition: consoleparse.h:27
Numeral altstate, 0 - 7.
char Command_string[MAX_CLI_LEN]
Command string buffer.
#define MAX_CLI_LEN
Definition: consoleparse.h:22
state_float dc_parse_double_expsign(const char *&ch_ptr, SCP_string &buffer_str)
Exponent sign.
prefix character sequence, 0b, 0o, or 0x
state_float dc_parse_double_exponent(const char *&ch_ptr, SCP_string &buffer_str)
Assert(pm!=NULL)
state_int dc_parse_long_numeral(const char *&ch_ptr, SCP_string &buffer_str)
bool dc_maybe_stuff_int(int *i)
Tries to stuff an int from the Command_string.
GLclampf f
Definition: Glext.h:7097
bool ch_is_decimal(char ch)
state_int dc_parse_long_prefix(const char *&ch_ptr, SCP_string &buffer_str, int &base)
state_int dc_parse_long_numeral_octal(const char *&ch_ptr, SCP_string &buffer_str)
Class thrown when the parsed string or token could not be stuffed into the smaller destination contai...
Definition: consoleparse.h:120
state_float dc_parse_double_decimal(const char *&ch_ptr, SCP_string &buffer_str)
state_float dc_parse_double_expprefix(const char *&ch_ptr, SCP_string &buffer_str)
Integral or string evaluated as a boolean.
Definition: consoleparse.h:33
bool ch_is_hex(char ch)
Class thrown when a required token is not found.
Definition: consoleparse.h:49
Exponent prefix, 'e', 'E'.
std::basic_string< char, std::char_traits< char >, std::allocator< char > > SCP_string
Definition: vmallocator.h:21
state_int dc_parse_long_numeral_hex(const char *&ch_ptr, SCP_string &buffer_str)
state_float dc_parse_double_fraction(const char *&ch_ptr, SCP_string &buffer_str)
state_float dc_parse_double_whole(const char *&ch_ptr, SCP_string &buffer_str)
state_int
GLenum type
Definition: Gl.h:1492
Exponent value numeral.
uint dc_required_string_any(const uint n,...)
Searches for specified required strings.
void dc_stuff_string(char *out_str, size_t maxlen=MAX_TOKEN_LENGTH)
Stuffs a string to out_str from the command line, stopping at the end of the command line...
Sign character, '-' '+'.
void dc_stuff_uint(uint *i)
Stuffs an unsigned int to the given variable. Supports binary (0b), hexadecimal (0x), and octal (0o) formats.
state_int dc_parse_long_numeral_bin(const char *&ch_ptr, SCP_string &buffer_str)
bool ch_is_octal(char ch)
unsigned int uint
Definition: pstypes.h:64
bool ch_is_binary(char ch)
long dc_parse_long(const char *ch, dc_token type)
Parses a long integral type. Supports decimal, binary, octal, and hexidecimal strings.
void dc_get_token_no_advance(SCP_string &out_str)
Returns a single token, but does not advances Cp.
state_float dc_parse_double_sign(const char *&ch_ptr, SCP_string &buffer_str)
Whole value numeral.
ulong dc_parse_ulong(const char *ch, dc_token type)
Parses an unsigned long integral type. Supports decimal, binary, octal, and hexidecimal strings...
bool dc_maybe_stuff_boolean(bool *b)
Tries to stuff a bool from the Command_string.
bool dc_optional_string_either(const char *str1, const char *str2)
Searches for an optional string and it's alias.
int dc_required_string_either(char *str1, char *str2)
Searchs for either of the specified required strings, throwing an errParse if neither are found...
bool dc_maybe_stuff_ubyte(ubyte *i)
Tries to stuff an ubyte from the Command_string.
bool dc_maybe_stuff_string(char *out_str, size_t maxlen)
Tries to stuff a string to out_str from the command line, stopping at the end of the command line...
void dc_ignore_white_space(void)
Advances the parser past whitespace characters.
unsigned long ulong
Definition: pstypes.h:65
Decimal character.
bool ch_is_octal_prefix(char ch)
void dc_stuff_ubyte(ubyte *i)
Stuffs an unsigned byte to the given variable. Supports binary (0b), hexadecimal (0x), and octal (0o) formats.
GLclampd n
Definition: Glext.h:7286
unsigned char ubyte
Definition: pstypes.h:62
bool ch_is_sign(char ch)
Integral with values between 0 and 255.
Definition: consoleparse.h:32
#define MAX_TOKEN_LENGTH
Definition: consoleparse.h:23
dc_token
Definition: consoleparse.h:25
Class thrown when an expected string was not found. Can/should contain all of the expected strings...
Definition: consoleparse.h:70
void dc_stuff_float(float *f)
Stuffs a float to the given variable.
Floating point.
Definition: consoleparse.h:28
void dc_stuff_int(int *i)
Stuffs an int to the given variable. Supports binary (0b), hexadecimal (0x), and octal (0o) formats...
Numeral altstate, 0 - 9 and 'a' - 'f'.
void dc_stuff_string_white(char *out_str, size_t maxlen)
Stuffs a whitespace delimited string to out_str from the command line, stopping at the end of the com...
GLboolean GLboolean GLboolean b
Definition: Glext.h:5781
void dc_stuff_boolean(bool *b)
stuffs a boolean evaluated integer or string into the given variable.
state_int dc_parse_long_sign(const char *&ch_ptr, SCP_string &buffer_str)
void dc_parse_init(SCP_string &str)
Initializes the DC command line parser.
Fractional value numeral.
int is_gray_space(char ch)
Definition: parselo.cpp:65
bool ch_is_prefix(char ch)
bool Dc_debug_on
Flag used to print console and command debugging strings.
Definition: console.cpp:24
bool ch_is_binary_prefix(char ch)
GLint GLsizei count
Definition: Gl.h:1491
bool dc_maybe_stuff_uint(uint *i)
Tries to stuff an uint from the Command_string.
void dc_ignore_gray_space(void)
Advances the parser past grayspace characters.
bool dc_optional_string(const char *pstr)
Searches for an optional string.
GLenum GLsizei len
Definition: Glext.h:6283
void dc_printf(const char *format,...)
Prints the given char string to the debug console.
Definition: console.cpp:358
GLsizei const GLchar ** strings
Definition: Glext.h:7179
double dc_parse_double(const char *ch, dc_token type)
Parses a double-precision floating point type. Supports, Whole, Fractional, and Mixed numbers...
int is_white_space(char ch)
Definition: parselo.cpp:59
state_float
Integral.
Definition: consoleparse.h:29
Parsing functions for the command line. Previously known as the command line scanner.
bool ch_is_hex_prefix(char ch)
bool ch_is_numeral(char ch)
bool dc_maybe_stuff_float(float *f)
Tries to stuff a float from the Command_string.
void dc_get_token(SCP_string &out_str)
Returns/Advances past a single token.
bool ch_is_exp_prefix(char ch)
Numeral state, 0 - 9.
void dc_required_string(char *pstr)
Searches for a specified required string, throwing an errParse if not found.
Numeral altstate, 0, 1.
Sign character for mantessa.
bool dc_maybe_stuff_string_white(char *str, size_t len)
Tries to stuff a whitespace delimited string to out_str from the command line, stopping at the end of...
#define strcpy_s(...)
Definition: safe_strings.h:67