specifiers.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929
  1. /*
  2. * Version: MPL 1.1
  3. *
  4. * The contents of this file are subject to the Mozilla Public License Version
  5. * 1.1 (the "License"); you may not use this file except in compliance with
  6. * the License. You may obtain a copy of the License at
  7. * http://www.mozilla.org/MPL/
  8. *
  9. * Software distributed under the License is distributed on an "AS IS" basis,
  10. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11. * for the specific language governing rights and limitations under the
  12. * License.
  13. *
  14. * The Original Code is the sscanf 2.0 SA:MP plugin.
  15. *
  16. * The Initial Developer of the Original Code is Alex "Y_Less" Cole.
  17. * Portions created by the Initial Developer are Copyright (C) 2010
  18. * the Initial Developer. All Rights Reserved.
  19. *
  20. * Contributor(s):
  21. *
  22. * Special Thanks to:
  23. *
  24. * SA:MP Team past, present and future
  25. */
  26. #include <string.h>
  27. #include <stdlib.h>
  28. #include "sscanf.h"
  29. #include "utils.h"
  30. #include "data.h"
  31. #include "specifiers.h"
  32. extern logprintf_t
  33. logprintf;
  34. extern int
  35. gOptions;
  36. extern unsigned int
  37. g_iTrueMax,
  38. g_iInvalid,
  39. g_iMaxPlayerName;
  40. //extern int
  41. // g_iServerVersion;
  42. bool
  43. DoI(char ** input, int * ret)
  44. {
  45. *ret = GetDec(input);
  46. return GetReturn(input);
  47. }
  48. bool
  49. DoN(char ** input, int * ret)
  50. {
  51. *ret = GetNumber(input);
  52. return GetReturn(input);
  53. }
  54. bool
  55. DoH(char ** input, int * ret)
  56. {
  57. *ret = GetHex(input);
  58. return GetReturn(input);
  59. }
  60. bool
  61. DoO(char ** input, int * ret)
  62. {
  63. *ret = GetOct(input);
  64. return GetReturn(input);
  65. }
  66. bool
  67. DoF(char ** input, double * ret)
  68. {
  69. *ret = strtod(*input, input);
  70. return GetReturn(input);
  71. }
  72. bool
  73. DoC(char ** input, char * ret)
  74. {
  75. *ret = **input;
  76. ++(*input);
  77. if (*ret == '\\')
  78. {
  79. if (IsSpacer(**input))
  80. {
  81. // '\ '
  82. *ret = **input;
  83. ++(*input);
  84. }
  85. else if (**input == '\\')
  86. {
  87. // '\\'
  88. ++(*input);
  89. }
  90. }
  91. return GetReturn(input);
  92. }
  93. bool
  94. DoL(char ** input, bool * ret)
  95. {
  96. *ret = GetLogical(input);
  97. return true;
  98. }
  99. bool
  100. DoB(char ** input, int * ret)
  101. {
  102. *ret = (int)GetBool(input);
  103. return GetReturn(input);
  104. }
  105. bool
  106. DoG(char ** input, double * ret)
  107. {
  108. char *
  109. string = *input;
  110. int
  111. temp = 0;
  112. switch (*string)
  113. {
  114. case 'N':
  115. case 'n':
  116. if (strichecks(string, "NAN_E"))
  117. {
  118. *input += 5;
  119. temp = FLOAT_NAN_E;
  120. }
  121. else if (strichecks(string, "NAN"))
  122. {
  123. *input += 3;
  124. temp = FLOAT_NAN;
  125. }
  126. else if (strichecks(string, "NEG_INFINITY"))
  127. {
  128. *input += 12;
  129. temp = FLOAT_NEG_INFINITY;
  130. }
  131. else if (strichecks(string, "NEGATIVE_INFINITY"))
  132. {
  133. *input += 17;
  134. temp = FLOAT_NEG_INFINITY;
  135. }
  136. *ret = (double)(*((float *)&temp));
  137. break;
  138. case 'I':
  139. case 'i':
  140. if (strichecks(string, "INFINITY"))
  141. {
  142. *input += 8;
  143. temp = FLOAT_INFINITY;
  144. *ret = (double)(*((float *)&temp));
  145. }
  146. break;
  147. case '-':
  148. if (strichecks(string + 1, "INFINITY"))
  149. {
  150. *input += 9;
  151. temp = FLOAT_NEG_INFINITY;
  152. *ret = (double)(*((float *)&temp));
  153. break;
  154. }
  155. // FALLTHROUGH
  156. default:
  157. // Read in the value and save the pointer - may as well use
  158. // existing, pre set up variables.
  159. *ret = strtod(string, input);
  160. break;
  161. }
  162. return GetReturn(input);
  163. }
  164. bool
  165. DoS(char ** input, char ** ret, int length, bool all)
  166. {
  167. // Don't reallocate the memory, just set pointers to the current data and
  168. // add nulls to terminate.
  169. int
  170. i = 0;
  171. // Save the pointer to the start of the data.
  172. *ret = *input;
  173. // Check if we want the whole remaining string or just the next word.
  174. char
  175. * string = *input,
  176. * outp = string;
  177. if (all)
  178. {
  179. // Everything.
  180. while (!IsEnd(*string))
  181. {
  182. ++i;
  183. // Cap at "length" characters long.
  184. if (i == length)
  185. {
  186. // Could let the loop exit properly as it would next time, but
  187. // there's no point - it's just extra work and we know it's OK.
  188. // We set the null before incrementing to ensure it's included
  189. // in the output.
  190. logprintf("sscanf warning: String buffer overflow.");
  191. // Removed the break - discard the rest of the string.
  192. //break;
  193. }
  194. else if (i < length)
  195. {
  196. if (*string == '\\')
  197. {
  198. if (IsEnd(*(string + 1)))
  199. {
  200. ++string;
  201. break;
  202. }
  203. // You can only escape the escape character or spaces.
  204. // Spaces aren't technically used here, but they COULD be
  205. // used in the current string in other circumstances, so
  206. // they may be present even when not needed.
  207. if (*(string + 1) == '\\' || IsSpacer(*(string + 1)))
  208. {
  209. ++string;
  210. }
  211. }
  212. if (outp != string)
  213. {
  214. // Compress the string only if we have a discrepancy
  215. // between input and output pos.
  216. *outp = *string;
  217. }
  218. ++outp;
  219. }
  220. ++string;
  221. }
  222. }
  223. else if (IsDefaultDelimiter())
  224. {
  225. while (!IsWhitespace(*string))
  226. {
  227. ++i;
  228. if (i == length)
  229. {
  230. logprintf("sscanf warning: String buffer overflow.");
  231. }
  232. else if (i < length)
  233. {
  234. if (*string == '\\')
  235. {
  236. if (IsEnd(*(string + 1)))
  237. {
  238. ++string;
  239. break;
  240. }
  241. if (*(string + 1) == '\\' || IsWhitespace(*(string + 1)))
  242. {
  243. ++string;
  244. }
  245. }
  246. if (outp != string)
  247. {
  248. *outp = *string;
  249. }
  250. ++outp;
  251. }
  252. ++string;
  253. }
  254. }
  255. else
  256. {
  257. // Just a single word. Note that if your delimiter is a backslash you
  258. // can't escape it - this is not a bug, just don't try use it as a
  259. // delimiter and still expect to be able to use it in a string.
  260. while (!IsEnd(*string) && !IsDelimiter(*string))
  261. {
  262. ++i;
  263. if (i == length)
  264. {
  265. logprintf("sscanf warning: String buffer overflow.");
  266. }
  267. else if (i < length)
  268. {
  269. if (*string == '\\')
  270. {
  271. if (IsEnd(*(string + 1)))
  272. {
  273. ++string;
  274. break;
  275. }
  276. // Escape spaces, backspace and delimiters - this code is
  277. // context independent so you can use a string with or
  278. // without a delimiter and can still escape spaces.
  279. if (*(string + 1) == '\\' || IsSpacer(*(string + 1)))
  280. {
  281. ++string;
  282. }
  283. }
  284. if (outp != string)
  285. {
  286. *outp = *string;
  287. }
  288. ++outp;
  289. }
  290. ++string;
  291. }
  292. }
  293. if (!IsEnd(*string))
  294. {
  295. // Skip the final character.
  296. *input = string + 1;
  297. }
  298. else
  299. {
  300. // Save the return.
  301. *input = string;
  302. }
  303. // Add a null terminator.
  304. *outp = '\0';
  305. // Can't really fail on a string as everything goes!
  306. return true;
  307. }
  308. bool
  309. DoU(char ** input, int * ret, unsigned int start)
  310. {
  311. char
  312. * end = NULL,
  313. * string = *input;
  314. unsigned int
  315. val = GetUserString(string, &end);
  316. if (val < g_iTrueMax && IsPlayerConnected(val))
  317. {
  318. *input = end;
  319. *ret = val;
  320. return false;
  321. }
  322. else
  323. {
  324. *ret = g_iInvalid;
  325. int
  326. * conn = GetConnected(),
  327. len = end - string;
  328. val = start;
  329. conn += start;
  330. char
  331. tmp = *end,
  332. * name = GetNames();
  333. *end = '\0';
  334. switch (gOptions & 6)
  335. {
  336. case 0:
  337. // Original.
  338. while (val < g_iTrueMax)
  339. {
  340. if (*conn++ && !strincmp(name, string, len))
  341. {
  342. break;
  343. }
  344. name += g_iMaxPlayerName;
  345. ++val;
  346. }
  347. break;
  348. case 2:
  349. // Partial matches.
  350. while (val < g_iTrueMax)
  351. {
  352. if (*conn++ && strstrin(name, string, len))
  353. {
  354. break;
  355. }
  356. name += g_iMaxPlayerName;
  357. ++val;
  358. }
  359. break;
  360. case 4:
  361. // Multiple matches.
  362. while (val < g_iTrueMax)
  363. {
  364. if (*conn++ && !strincmp(name, string, len))
  365. {
  366. if (*ret != g_iInvalid)
  367. {
  368. val = 0x80000000;
  369. break;
  370. }
  371. *ret = val;
  372. }
  373. name += g_iMaxPlayerName;
  374. ++val;
  375. }
  376. break;
  377. case 6:
  378. // Both.
  379. while (val < g_iTrueMax)
  380. {
  381. if (*conn++ && strstrin(name, string, len))
  382. {
  383. if (*ret != g_iInvalid)
  384. {
  385. val = 0x80000000;
  386. break;
  387. }
  388. *ret = val;
  389. }
  390. name += g_iMaxPlayerName;
  391. ++val;
  392. }
  393. break;
  394. }
  395. *end = tmp;
  396. }
  397. *input = end;
  398. if (val != g_iTrueMax)
  399. {
  400. *ret = val;
  401. }
  402. return true;
  403. }
  404. bool
  405. DoQ(char ** input, int * ret, unsigned int start)
  406. {
  407. char
  408. * end = NULL,
  409. * string = *input;
  410. // Get the string.
  411. unsigned int
  412. val = GetUserString(string, &end);
  413. // We only have a less than check here as valid IDs start at 0, and
  414. // GetUserString can't return numbers less than 0, it's physically
  415. // impossible for it to do so as there's no code there for it to happen.
  416. // Check that the player is a valid ID, connected and a non-player
  417. // character, and if one of those checks FAILS, do the code below. We
  418. // could attempt to write a C++ equivalent to foreach here, but this should
  419. // be pretty fast anyway as it uses direct memory access.
  420. if (val < g_iTrueMax && IsPlayerConnected(val) && IsPlayerNPC(val))
  421. {
  422. *input = end;
  423. *ret = val;
  424. return false;
  425. }
  426. else
  427. {
  428. *ret = g_iInvalid;
  429. // Find the NPC by name.
  430. int
  431. * conn = GetConnected(),
  432. * npc = GetNPCs(),
  433. len = end - string;
  434. val = start;
  435. conn += start;
  436. npc += start;
  437. // Save the end character for the name.
  438. char
  439. tmp = *end,
  440. * name = GetNames();
  441. // Make the input string shorter for comparison.
  442. *end = '\0';
  443. switch (gOptions & 6)
  444. {
  445. case 0:
  446. // Original.
  447. while (val < g_iTrueMax)
  448. {
  449. if (*conn && *npc && !strincmp(name, string, len))
  450. {
  451. break;
  452. }
  453. ++conn;
  454. ++npc;
  455. name += g_iMaxPlayerName;
  456. ++val;
  457. }
  458. break;
  459. case 2:
  460. // Partial matches.
  461. while (val < g_iTrueMax)
  462. {
  463. if (*conn && *npc && strstrin(name, string, len))
  464. {
  465. break;
  466. }
  467. ++conn;
  468. ++npc;
  469. name += g_iMaxPlayerName;
  470. ++val;
  471. }
  472. break;
  473. case 4:
  474. // Multiple matches.
  475. while (val < g_iTrueMax)
  476. {
  477. if (*conn && *npc && !strincmp(name, string, len))
  478. {
  479. if (*ret != g_iInvalid)
  480. {
  481. val = 0x80000000;
  482. break;
  483. }
  484. *ret = val;
  485. }
  486. ++conn;
  487. ++npc;
  488. name += g_iMaxPlayerName;
  489. ++val;
  490. }
  491. break;
  492. case 6:
  493. // Both.
  494. // Loop through all the players and check that they're
  495. // connected, an NPC, and that their name is correct.
  496. while (val < g_iTrueMax)
  497. {
  498. if (*conn && *npc && strstrin(name, string, len))
  499. {
  500. if (*ret != g_iInvalid)
  501. {
  502. val = 0x80000000;
  503. break;
  504. }
  505. *ret = val;
  506. }
  507. // Can't do *npc++ above as it's not always reached and we
  508. // need it to be incremented (short circuiting).
  509. ++conn;
  510. ++npc;
  511. name += g_iMaxPlayerName;
  512. ++val;
  513. }
  514. break;
  515. }
  516. *end = tmp;
  517. }
  518. // Save the pointer to the end of the name.
  519. *input = end;
  520. // Optimised from the PAWN version. If it gets to here without having
  521. // found a valid player then 'val' will be g_iTrueMax.
  522. if (val != g_iTrueMax)
  523. {
  524. *ret = val;
  525. }
  526. return true;
  527. }
  528. bool
  529. DoR(char ** input, int * ret, unsigned int start)
  530. {
  531. char
  532. * end = NULL,
  533. * string = *input;
  534. unsigned int
  535. val = GetUserString(string, &end);
  536. if (val < g_iTrueMax && IsPlayerConnected(val) && !IsPlayerNPC(val))
  537. {
  538. *input = end;
  539. *ret = val;
  540. return false;
  541. }
  542. else
  543. {
  544. *ret = g_iInvalid;
  545. int
  546. * conn = GetConnected(),
  547. * npc = GetNPCs(),
  548. len = end - string;
  549. val = start;
  550. conn += start;
  551. npc += start;
  552. char
  553. tmp = *end,
  554. * name = GetNames();
  555. *end = '\0';
  556. switch (gOptions & 6)
  557. {
  558. case 0:
  559. // Original.
  560. while (val < g_iTrueMax)
  561. {
  562. if (*conn && !*npc && !strincmp(name, string, len))
  563. {
  564. break;
  565. }
  566. ++conn;
  567. ++npc;
  568. name += g_iMaxPlayerName;
  569. ++val;
  570. }
  571. break;
  572. case 2:
  573. // Partial matches.
  574. while (val < g_iTrueMax)
  575. {
  576. if (*conn && !*npc && strstrin(name, string, len))
  577. {
  578. break;
  579. }
  580. ++conn;
  581. ++npc;
  582. name += g_iMaxPlayerName;
  583. ++val;
  584. }
  585. break;
  586. case 4:
  587. // Multiple matches.
  588. while (val < g_iTrueMax)
  589. {
  590. if (*conn && !*npc && !strincmp(name, string, len))
  591. {
  592. if (*ret != g_iInvalid)
  593. {
  594. val = 0x80000000;
  595. break;
  596. }
  597. *ret = val;
  598. }
  599. ++conn;
  600. ++npc;
  601. name += g_iMaxPlayerName;
  602. ++val;
  603. }
  604. break;
  605. case 6:
  606. // Both.
  607. // Loop through all the players and check that they're
  608. // connected, an NPC, and that their name is correct.
  609. while (val < g_iTrueMax)
  610. {
  611. if (*conn && !*npc && strstrin(name, string, len))
  612. {
  613. if (*ret != g_iInvalid)
  614. {
  615. val = 0x80000000;
  616. break;
  617. }
  618. *ret = val;
  619. }
  620. // Can't do *npc++ above as it's not always reached and we
  621. // need it to be incremented (short circuiting).
  622. ++conn;
  623. ++npc;
  624. name += g_iMaxPlayerName;
  625. ++val;
  626. }
  627. break;
  628. }
  629. *end = tmp;
  630. }
  631. *input = end;
  632. if (val != g_iTrueMax)
  633. {
  634. *ret = val;
  635. }
  636. return true;
  637. }
  638. bool
  639. DoID(char ** input, int * ret)
  640. {
  641. if (!FindDefaultStart(input))
  642. {
  643. return false;
  644. }
  645. *ret = GetDec(input);
  646. return GetReturnDefault(input);
  647. }
  648. bool
  649. DoND(char ** input, int * ret)
  650. {
  651. if (!FindDefaultStart(input))
  652. {
  653. return false;
  654. }
  655. *ret = GetNumber(input);
  656. return GetReturnDefault(input);
  657. }
  658. bool
  659. DoHD(char ** input, int * ret)
  660. {
  661. if (!FindDefaultStart(input))
  662. {
  663. return false;
  664. }
  665. *ret = GetHex(input);
  666. return GetReturnDefault(input);
  667. }
  668. bool
  669. DoOD(char ** input, int * ret)
  670. {
  671. if (!FindDefaultStart(input))
  672. {
  673. return false;
  674. }
  675. *ret = GetOct(input);
  676. return GetReturnDefault(input);
  677. }
  678. bool
  679. DoFD(char ** input, double * ret)
  680. {
  681. if (!FindDefaultStart(input))
  682. {
  683. return false;
  684. }
  685. *ret = strtod(*input, input);
  686. return GetReturnDefault(input);
  687. }
  688. bool
  689. DoCD(char ** input, char * ret)
  690. {
  691. if (!FindDefaultStart(input))
  692. {
  693. return false;
  694. }
  695. *ret = **input;
  696. ++(*input);
  697. if (*ret == '\\')
  698. {
  699. if (IsSpacer(**input))
  700. {
  701. // '\ '
  702. *ret = **input;
  703. ++(*input);
  704. }
  705. else if (**input == '\\')
  706. {
  707. // '\\'
  708. ++(*input);
  709. }
  710. }
  711. return GetReturnDefault(input);
  712. }
  713. bool
  714. DoBD(char ** input, int * ret)
  715. {
  716. if (!FindDefaultStart(input))
  717. {
  718. return false;
  719. }
  720. *ret = (int)GetBool(input);
  721. return GetReturnDefault(input);
  722. }
  723. bool
  724. DoGD(char ** input, double * ret)
  725. {
  726. if (!FindDefaultStart(input))
  727. {
  728. return false;
  729. }
  730. char *
  731. string = *input;
  732. int
  733. temp = 0;
  734. switch (*string)
  735. {
  736. case 'N':
  737. case 'n':
  738. if (strichecks(string, "NAN_E"))
  739. {
  740. *input += 5;
  741. temp = FLOAT_NAN_E;
  742. }
  743. else if (strichecks(string, "NAN"))
  744. {
  745. *input += 3;
  746. temp = FLOAT_NAN;
  747. }
  748. else if (strichecks(string, "NEG_INFINITY"))
  749. {
  750. *input += 12;
  751. temp = FLOAT_NEG_INFINITY;
  752. }
  753. else if (strichecks(string, "NEGATIVE_INFINITY"))
  754. {
  755. *input += 17;
  756. temp = FLOAT_NEG_INFINITY;
  757. }
  758. *ret = (double)(*((float *)&temp));
  759. break;
  760. case 'I':
  761. case 'i':
  762. if (strichecks(string, "INFINITY"))
  763. {
  764. *input += 8;
  765. temp = FLOAT_INFINITY;
  766. *ret = (double)(*((float *)&temp));
  767. }
  768. break;
  769. case '-':
  770. if (strichecks(string + 1, "INFINITY"))
  771. {
  772. *input += 9;
  773. temp = FLOAT_NEG_INFINITY;
  774. *ret = (double)(*((float *)&temp));
  775. break;
  776. }
  777. // FALLTHROUGH
  778. default:
  779. // Read in the value and save the pointer - may as well use
  780. // existing, pre set up variables.
  781. *ret = strtod(string, input);
  782. break;
  783. }
  784. return GetReturnDefault(input);
  785. }
  786. bool
  787. DoSD(char ** input, char ** ret, int * length)
  788. {
  789. if (!FindDefaultStart(input))
  790. {
  791. return false;
  792. }
  793. // Don't reallocate the memory, just set pointers to the current data and
  794. // add nulls to terminate.
  795. int
  796. i = 0;
  797. // Save the pointer to the start of the data.
  798. *ret = *input;
  799. // Check if we want the whole remaining string or just the next word.
  800. char
  801. * string = *input,
  802. * outp = string;
  803. while (!IsEnd(*string) && !IsDelimiter(*string))
  804. {
  805. ++i;
  806. if (*string == '\\')
  807. {
  808. if (IsEnd(*(string + 1)))
  809. {
  810. ++string;
  811. break;
  812. }
  813. // Escape spaces, backspace and delimiters - this code is
  814. // context independent so you can use a string with or
  815. // without a delimiter and can still escape spaces.
  816. if (*(string + 1) == '\\' || IsWhitespace(*(string + 1)) || IsDelimiter(*(string + 1)))
  817. {
  818. ++string;
  819. }
  820. }
  821. if (outp != string)
  822. {
  823. *outp = *string;
  824. }
  825. ++outp;
  826. ++string;
  827. }
  828. if (IsDelimiter(*string))
  829. {
  830. // Skip the final character.
  831. *input = string + 1;
  832. // NOW get the length.
  833. *length = GetLength(input, false);
  834. }
  835. else
  836. {
  837. logprintf("sscanf warning: Unclosed default value.");
  838. // Save the return.
  839. *input = string;
  840. logprintf("sscanf warning: Strings without a length are deprecated, please add a destination size.");
  841. *length = SSCANF_MAX_LENGTH;
  842. }
  843. // Add a null terminator.
  844. if (i >= *length)
  845. {
  846. logprintf("sscanf warning: String buffer overflow.");
  847. *(ret + (*length - 1)) = '\0';
  848. }
  849. else
  850. {
  851. *outp = '\0';
  852. }
  853. return true;
  854. }
  855. bool
  856. DoUD(char ** input, int * ret)
  857. {
  858. if (!FindDefaultStart(input))
  859. {
  860. return false;
  861. }
  862. if (gOptions & 1) DoU(input, ret, 0);
  863. else DoN(input, ret);
  864. return GetReturnDefault(input);
  865. }
  866. bool
  867. DoQD(char ** input, int * ret)
  868. {
  869. if (!FindDefaultStart(input))
  870. {
  871. return false;
  872. }
  873. if (gOptions & 1) DoQ(input, ret, 0);
  874. else DoN(input, ret);
  875. return GetReturnDefault(input);
  876. }
  877. bool
  878. DoRD(char ** input, int * ret)
  879. {
  880. if (!FindDefaultStart(input))
  881. {
  882. return false;
  883. }
  884. if (gOptions & 1) DoR(input, ret, 0);
  885. else DoN(input, ret);
  886. return GetReturnDefault(input);
  887. }
  888. bool
  889. DoLD(char ** input, bool * ret)
  890. {
  891. if (!FindDefaultStart(input))
  892. {
  893. return false;
  894. }
  895. DoL(input, ret);
  896. return GetReturnDefault(input);
  897. }