test.c 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884
  1. /*++
  2. Copyright (c) 2013 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. test.c
  5. Abstract:
  6. This module implements the test (aka left square bracket [) program.
  7. Author:
  8. Evan Green 15-Jun-2013
  9. Environment:
  10. POSIX
  11. --*/
  12. //
  13. // ------------------------------------------------------------------- Includes
  14. //
  15. #include <minoca/lib/types.h>
  16. #include <assert.h>
  17. #include <errno.h>
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include <sys/stat.h>
  21. #include "swlib.h"
  22. //
  23. // ---------------------------------------------------------------- Definitions
  24. //
  25. #define TEST_VERSION_MAJOR 1
  26. #define TEST_VERSION_MINOR 0
  27. #define TEST_USAGE \
  28. "usage: test [<test>]\n" \
  29. " [ <test> ]\n" \
  30. "The test utility performs basic file, integer, and string tests to \n" \
  31. "augment the shell's functionality. Options are: \n" \
  32. " --help -- Show this help and exit.\n" \
  33. " --version -- Show the application version and exit.\n\n" \
  34. "Valid tests are:\n" \
  35. " -b file -- The file exists and is a block device.\n" \
  36. " -c file -- The file exists and is a character device.\n" \
  37. " -d file -- The file exists and is a directory.\n" \
  38. " -f file -- The file exists and is a regular file.\n" \
  39. " -g file -- The file exists and has its set-group-ID flag set.\n" \
  40. " -h file -- The file exists and is a symbolic link.\n" \
  41. " -L file -- The file exists and is a symbolic link (same as -h).\n" \
  42. " -p file -- The file exists and is a FIFO.\n" \
  43. " -r file -- The file exists and is readable.\n" \
  44. " -S file -- The file exists and is a socket.\n" \
  45. " -s file -- The file exists and has a size greater than zero.\n" \
  46. " -t file_descriptor -- The file descriptor is valid and points to a \n" \
  47. " terminal device.\n" \
  48. " -u file -- The file exists and has its set-user-ID flag set.\n" \
  49. " -w file -- The file exists and is writable.\n" \
  50. " -x file -- The file exists and is executable.\n" \
  51. " file1 -fe file2 -- True if file1 and file2 have the same device and \n" \
  52. " file serial numbers.\n" \
  53. " file1 -nt file2 -- True if file1 has a later modification date than \n" \
  54. " file2.\n" \
  55. " file1 -ot file2 -- True if file1 has an earlier modification date \n" \
  56. " than file2.\n" \
  57. " -n string -- True if the length of the given string is non-zero.\n" \
  58. " -z string -- True if the length of the string is zero.\n" \
  59. " string -- True if the string is not the null string.\n" \
  60. " string1 = string2 -- True if the two strings are identical.\n" \
  61. " string1 != string2 -- True if the two strings are not identical.\n" \
  62. " number1 -eq number2 -- True if the two numbers are equal.\n" \
  63. " number1 -ne number2 -- True if the two numbers are not equal.\n" \
  64. " number1 -gt number2 -- True if number1 is greater than number2.\n" \
  65. " number1 -ge number2 -- True if number1 is greater than or equal to \n" \
  66. " number2.\n" \
  67. " number1 -lt number2 -- True if number1 is less than number2.\n" \
  68. " number1 -le number2 -- True if number1 is less than or equal to " \
  69. "number2.\n\n" \
  70. "Additionally, tests can be combined in the following ways:\n" \
  71. " expression1 -a expression2 -- True if both expression1 and \n" \
  72. " expression2 are true. This has a higher precedence than -o.\n" \
  73. " expression1 -o expression2 -- True if either expression1 or \n" \
  74. " expression2 are true.\n" \
  75. " ! expression - True if the expression is false.\n" \
  76. " ( expression ) - True if the inner expression is True. Parentheses \n" \
  77. " can be used to alter the normal associativity and precedence.\n\n" \
  78. //
  79. // Define away the test utility return values since they're backwards and
  80. // therefore a little tough to look at.
  81. //
  82. #define TEST_UTILITY_FALSE 1
  83. #define TEST_UTILITY_TRUE 0
  84. #define TEST_UTILITY_ERROR 2
  85. //
  86. // ------------------------------------------------------ Data Type Definitions
  87. //
  88. typedef enum _TEST_UTILITY_TEST {
  89. TestUtilityInvalid,
  90. TestUtilityBang,
  91. TestUtilityOpenParentheses,
  92. TestUtilityCloseParentheses,
  93. TestUtilityAnd,
  94. TestUtilityOr,
  95. TestFileMinValue,
  96. TestFileIsBlockDevice,
  97. TestFileIsCharacterDevice,
  98. TestFileIsDirectory,
  99. TestFileExists,
  100. TestFileIsRegularFile,
  101. TestFileHasSetGroupId,
  102. TestFileIsSymbolicLink,
  103. TestFileIsFifo,
  104. TestFileCanRead,
  105. TestFileIsSocket,
  106. TestFileIsNonEmpty,
  107. TestFileDescriptorIsTerminal,
  108. TestFileHasSetUserId,
  109. TestFileCanWrite,
  110. TestFileCanExecute,
  111. TestFileEqual,
  112. TestFileNewer,
  113. TestFileOlder,
  114. TestFileMaxValue,
  115. TestStringMinValue,
  116. TestStringNonZeroLength,
  117. TestStringZeroLength,
  118. TestStringEquals,
  119. TestStringNotEquals,
  120. TestStringMaxValue,
  121. TestIntegerMinValue,
  122. TestIntegerEquals,
  123. TestIntegerNotEquals,
  124. TestIntegerGreaterThan,
  125. TestIntegerGreaterThanOrEqualTo,
  126. TestIntegerLessThan,
  127. TestIntegerLessThanOrEqualTo,
  128. TestIntegerMaxValue,
  129. } TEST_UTILITY_TEST, *PTEST_UTILITY_TEST;
  130. typedef enum _TEST_PARSE_ELEMENT_TYPE {
  131. TestParseElementInvalid,
  132. TestParseElementOperator,
  133. TestParseElementToken,
  134. TestParseElementResult,
  135. TestParseElementEnd,
  136. } TEST_PARSE_ELEMENT_TYPE, *PTEST_PARSE_ELEMENT_TYPE;
  137. typedef struct _TEST_PARSE_ELEMENT {
  138. TEST_PARSE_ELEMENT_TYPE Type;
  139. PSTR Token;
  140. TEST_UTILITY_TEST Operator;
  141. INT Result;
  142. } TEST_PARSE_ELEMENT, *PTEST_PARSE_ELEMENT;
  143. //
  144. // ----------------------------------------------- Internal Function Prototypes
  145. //
  146. INT
  147. TestEvaluateExpression (
  148. INT ArgumentCount,
  149. CHAR **Arguments
  150. );
  151. BOOL
  152. TestShiftOrReduce (
  153. PTEST_PARSE_ELEMENT Stack,
  154. ULONG StackSize,
  155. PTEST_PARSE_ELEMENT NextElement,
  156. PBOOL Shift
  157. );
  158. BOOL
  159. TestReduce (
  160. PTEST_PARSE_ELEMENT Stack,
  161. PULONG StackSize
  162. );
  163. TEST_UTILITY_TEST
  164. TestGetOperator (
  165. PSTR String
  166. );
  167. ULONG
  168. TestGetOperandCount (
  169. TEST_UTILITY_TEST Operator
  170. );
  171. ULONG
  172. TestGetOperatorPrecedence (
  173. TEST_UTILITY_TEST Operator
  174. );
  175. INT
  176. TestEvaluateUnaryOperator (
  177. TEST_UTILITY_TEST Operator,
  178. PSTR Operand
  179. );
  180. INT
  181. TestEvaluateBinaryOperator (
  182. TEST_UTILITY_TEST Operator,
  183. PSTR LeftOperand,
  184. PSTR RightOperand
  185. );
  186. INT
  187. TestEvaluateStringTest (
  188. TEST_UTILITY_TEST Operator,
  189. PSTR String1,
  190. PSTR String2
  191. );
  192. INT
  193. TestEvaluateIntegerTest (
  194. TEST_UTILITY_TEST Operator,
  195. PSTR LeftIntegerString,
  196. PSTR RightIntegerString
  197. );
  198. INT
  199. TestEvaluateAndOr (
  200. TEST_UTILITY_TEST Operator,
  201. INT Left,
  202. INT Right
  203. );
  204. VOID
  205. TestConvertTokenToResult (
  206. PTEST_PARSE_ELEMENT Element
  207. );
  208. //
  209. // -------------------------------------------------------------------- Globals
  210. //
  211. PSTR TestOperatorStrings[] = {
  212. NULL,
  213. "!",
  214. "(",
  215. ")",
  216. "-a",
  217. "-o",
  218. NULL,
  219. "-b",
  220. "-c",
  221. "-d",
  222. "-e",
  223. "-f",
  224. "-g",
  225. "-h",
  226. "-p",
  227. "-r",
  228. "-S",
  229. "-s",
  230. "-t",
  231. "-u",
  232. "-w",
  233. "-x",
  234. "-fe",
  235. "-nt",
  236. "-ot",
  237. NULL,
  238. NULL,
  239. "-n",
  240. "-z",
  241. "=",
  242. "!=",
  243. NULL,
  244. NULL,
  245. "-eq",
  246. "-ne",
  247. "-gt",
  248. "-ge",
  249. "-lt",
  250. "-le",
  251. NULL,
  252. };
  253. BOOL TestDebugPrintEvaluations = FALSE;
  254. //
  255. // ------------------------------------------------------------------ Functions
  256. //
  257. INT
  258. TestMain (
  259. INT ArgumentCount,
  260. CHAR **Arguments
  261. )
  262. /*++
  263. Routine Description:
  264. This routine implements the test application entry point.
  265. Arguments:
  266. ArgumentCount - Supplies the number of arguments on the command line.
  267. Arguments - Supplies an array of pointers to strings representing the
  268. arguments.
  269. Return Value:
  270. 0 or 1 if the evaluation succeeds.
  271. >1 on failure.
  272. --*/
  273. {
  274. PSTR LastSlash;
  275. INT Result;
  276. //
  277. // Look for --help or --version as the only argument.
  278. //
  279. if (ArgumentCount == 2) {
  280. if (strcmp(Arguments[1], "--help") == 0) {
  281. printf(TEST_USAGE);
  282. return TEST_UTILITY_ERROR;
  283. } else if (strcmp(Arguments[1], "--version") == 0) {
  284. SwPrintVersion(TEST_VERSION_MAJOR, TEST_VERSION_MINOR);
  285. return TEST_UTILITY_ERROR;
  286. }
  287. }
  288. //
  289. // Look for an open bracket.
  290. //
  291. if (ArgumentCount == 0) {
  292. return TEST_UTILITY_ERROR;
  293. }
  294. LastSlash = strrchr(Arguments[0], '/');
  295. if (LastSlash == NULL) {
  296. LastSlash = Arguments[0];
  297. } else {
  298. LastSlash += 1;
  299. }
  300. if (strchr(LastSlash, '[') != NULL) {
  301. //
  302. // There had better be a closing bracket.
  303. //
  304. if (strcmp(Arguments[ArgumentCount - 1], "]") != 0) {
  305. SwPrintError(0, Arguments[ArgumentCount - 1], "Expected ']'");
  306. return TEST_UTILITY_ERROR;
  307. }
  308. ArgumentCount -= 1;
  309. }
  310. if (ArgumentCount == 0) {
  311. return TEST_UTILITY_FALSE;
  312. }
  313. Result = TestEvaluateExpression(ArgumentCount - 1, Arguments + 1);
  314. return Result;
  315. }
  316. //
  317. // --------------------------------------------------------- Internal Functions
  318. //
  319. INT
  320. TestEvaluateExpression (
  321. INT ArgumentCount,
  322. CHAR **Arguments
  323. )
  324. /*++
  325. Routine Description:
  326. This routine evaluates an expression for the test application.
  327. Arguments:
  328. ArgumentCount - Supplies the number of remaining arguments on the command
  329. line.
  330. Arguments - Supplies an array of pointers to strings representing the
  331. arguments.
  332. ArgumentsConsumed - Supplies a pointer where the number of arguments
  333. consumed will be returned.
  334. Return Value:
  335. 0 or 1 if the evaluation succeeds.
  336. >1 on failure.
  337. --*/
  338. {
  339. ULONG ArgumentIndex;
  340. TEST_PARSE_ELEMENT NextElement;
  341. TEST_UTILITY_TEST Operator;
  342. PTEST_PARSE_ELEMENT ParseStack;
  343. BOOL Result;
  344. INT ReturnValue;
  345. BOOL Shift;
  346. ULONG StackIndex;
  347. ParseStack = NULL;
  348. //
  349. // Zero arguments represents an implicit test for a non-null string
  350. // failing.
  351. //
  352. if (ArgumentCount == 0) {
  353. return TEST_UTILITY_FALSE;
  354. //
  355. // For a single argument test to see if it's non-null.
  356. //
  357. } else if (ArgumentCount == 1) {
  358. if (strlen(Arguments[0]) != 0) {
  359. return TEST_UTILITY_TRUE;
  360. } else {
  361. return TEST_UTILITY_FALSE;
  362. }
  363. //
  364. // For two arguments, process a unary operator or a bang plus an implicit
  365. // non-null test.
  366. //
  367. } else if (ArgumentCount == 2) {
  368. Operator = TestGetOperator(Arguments[0]);
  369. if (Operator == TestUtilityBang) {
  370. if (strlen(Arguments[1]) != 0) {
  371. return TEST_UTILITY_FALSE;
  372. } else {
  373. return TEST_UTILITY_TRUE;
  374. }
  375. }
  376. if ((Operator == TestUtilityInvalid) ||
  377. (TestGetOperandCount(Operator) != 1)) {
  378. SwPrintError(0, NULL, "%s: Unary operator expected", Arguments[0]);
  379. return TEST_UTILITY_ERROR;
  380. }
  381. return TestEvaluateUnaryOperator(Operator, Arguments[1]);
  382. //
  383. // For three arguments:
  384. // * If $2 is a binary primary, perform the binary test of $1 and $3.
  385. // * If $1 is '!', negate the two-argument test of $2 and $3.
  386. // * If $1 is '(' and $3 is ')', perfomr the unary test of $2.
  387. //
  388. } else if (ArgumentCount == 3) {
  389. Operator = TestGetOperator(Arguments[1]);
  390. if ((Operator != TestUtilityInvalid) &&
  391. (TestGetOperandCount(Operator) == 2)) {
  392. ReturnValue = TestEvaluateBinaryOperator(Operator,
  393. Arguments[0],
  394. Arguments[2]);
  395. return ReturnValue;
  396. } else {
  397. Operator = TestGetOperator(Arguments[0]);
  398. if (Operator == TestUtilityBang) {
  399. ReturnValue = TestEvaluateExpression(ArgumentCount - 1,
  400. Arguments + 1);
  401. if (ReturnValue == TEST_UTILITY_FALSE) {
  402. return TEST_UTILITY_TRUE;
  403. } else if (ReturnValue == TEST_UTILITY_TRUE) {
  404. return TEST_UTILITY_FALSE;
  405. } else {
  406. return ReturnValue;
  407. }
  408. } else if (Operator == TestUtilityOpenParentheses) {
  409. Operator = TestGetOperator(Arguments[2]);
  410. if (Operator != TestUtilityCloseParentheses) {
  411. SwPrintError(0,
  412. NULL,
  413. "%s: Close parentheses expected",
  414. Arguments[2]);
  415. return TEST_UTILITY_ERROR;
  416. }
  417. ReturnValue = TestEvaluateExpression(ArgumentCount - 2,
  418. Arguments + 1);
  419. return ReturnValue;
  420. }
  421. }
  422. //
  423. // For four arguments:
  424. // * If $1 is '!', negate the three-argument test of $2, $3, and $4.
  425. // * If $1 is '(' and $4 is ')', perform the two argument test of $2 and $3.
  426. //
  427. } else if (ArgumentCount == 4) {
  428. Operator = TestGetOperator(Arguments[0]);
  429. if (Operator == TestUtilityBang) {
  430. ReturnValue = TestEvaluateExpression(ArgumentCount - 1,
  431. Arguments + 1);
  432. if (ReturnValue == TEST_UTILITY_FALSE) {
  433. return TEST_UTILITY_TRUE;
  434. } else if (ReturnValue == TEST_UTILITY_TRUE) {
  435. return TEST_UTILITY_FALSE;
  436. } else {
  437. return ReturnValue;
  438. }
  439. } else if (Operator == TestUtilityOpenParentheses) {
  440. Operator = TestGetOperator(Arguments[3]);
  441. if (Operator == TestUtilityCloseParentheses) {
  442. ReturnValue = TestEvaluateExpression(ArgumentCount - 2,
  443. Arguments + 1);
  444. return ReturnValue;
  445. }
  446. }
  447. }
  448. //
  449. // Allocate the space for a basic parse stack.
  450. //
  451. ParseStack = malloc(sizeof(TEST_PARSE_ELEMENT) * ArgumentCount);
  452. if (ParseStack == NULL) {
  453. SwPrintError(errno, NULL, "Failed to allocate");
  454. return TEST_UTILITY_ERROR;
  455. }
  456. memset(ParseStack, 0, sizeof(TEST_PARSE_ELEMENT) * ArgumentCount);
  457. ArgumentIndex = 0;
  458. StackIndex = 0;
  459. while (TRUE) {
  460. if (ArgumentIndex == ArgumentCount) {
  461. NextElement.Type = TestParseElementEnd;
  462. } else {
  463. //
  464. // Get the next parse stack element.
  465. //
  466. Operator = TestGetOperator(Arguments[ArgumentIndex]);
  467. if (Operator != TestUtilityInvalid) {
  468. NextElement.Type = TestParseElementOperator;
  469. NextElement.Operator = Operator;
  470. } else {
  471. NextElement.Type = TestParseElementToken;
  472. }
  473. NextElement.Token = Arguments[ArgumentIndex];
  474. //
  475. // Ensure that if this is a binary operator, there is a token
  476. // before it.
  477. //
  478. if ((Operator != TestUtilityInvalid) &&
  479. (TestGetOperandCount(Operator) == 2)) {
  480. if ((StackIndex == 0) ||
  481. (ParseStack[StackIndex - 1].Type !=
  482. TestParseElementToken)) {
  483. SwPrintError(0,
  484. Arguments[ArgumentIndex],
  485. "Binary operator used without left argument");
  486. ReturnValue = TEST_UTILITY_ERROR;
  487. goto EvaluateExpressionEnd;
  488. }
  489. }
  490. }
  491. while (TRUE) {
  492. Result = TestShiftOrReduce(ParseStack,
  493. StackIndex,
  494. &NextElement,
  495. &Shift);
  496. if (Result == FALSE) {
  497. ReturnValue = TEST_UTILITY_ERROR;
  498. goto EvaluateExpressionEnd;
  499. }
  500. if (Shift != FALSE) {
  501. break;
  502. }
  503. Result = TestReduce(ParseStack, &StackIndex);
  504. if (Result == FALSE) {
  505. ReturnValue = TEST_UTILITY_ERROR;
  506. goto EvaluateExpressionEnd;
  507. }
  508. if ((NextElement.Type == TestParseElementEnd) &&
  509. (StackIndex == 1) &&
  510. (ParseStack[0].Type == TestParseElementResult)) {
  511. ReturnValue = ParseStack[0].Result;
  512. goto EvaluateExpressionEnd;
  513. }
  514. }
  515. //
  516. // Shift this next element onto the stack.
  517. //
  518. memcpy(&(ParseStack[StackIndex]),
  519. &NextElement,
  520. sizeof(TEST_PARSE_ELEMENT));
  521. StackIndex += 1;
  522. ArgumentIndex += 1;
  523. }
  524. EvaluateExpressionEnd:
  525. if (ParseStack != NULL) {
  526. free(ParseStack);
  527. }
  528. return ReturnValue;
  529. }
  530. BOOL
  531. TestShiftOrReduce (
  532. PTEST_PARSE_ELEMENT Stack,
  533. ULONG StackSize,
  534. PTEST_PARSE_ELEMENT NextElement,
  535. PBOOL Shift
  536. )
  537. /*++
  538. Routine Description:
  539. This routine determines whether the test parser should shift another
  540. element onto the stack or reduce what it's got.
  541. Arguments:
  542. Stack - Supplies a pointer to the parse stack.
  543. StackSize - Supplies the number of elements on the stack.
  544. NextElement - Supplies a pointer to the next element that would be
  545. shifted onto the stack.
  546. Shift - Supplies a pointer where a boolean will be returned indicating
  547. whether or not to shift (TRUE) or reduce (FALSE).
  548. Return Value:
  549. TRUE on success.
  550. FALSE if there was a parsing error.
  551. --*/
  552. {
  553. TEST_UTILITY_TEST NextOperator;
  554. TEST_UTILITY_TEST Operator;
  555. if (StackSize == 0) {
  556. *Shift = TRUE;
  557. return TRUE;
  558. }
  559. if (NextElement->Type == TestParseElementEnd) {
  560. *Shift = FALSE;
  561. return TRUE;
  562. }
  563. switch (Stack[StackSize - 1].Type) {
  564. case TestParseElementOperator:
  565. Operator = Stack[StackSize - 1].Operator;
  566. if (Operator == TestUtilityOpenParentheses) {
  567. *Shift = TRUE;
  568. return TRUE;
  569. }
  570. if (Operator == TestUtilityCloseParentheses) {
  571. *Shift = FALSE;
  572. return TRUE;
  573. }
  574. //
  575. // If it's an and, or, or bang, just shift.
  576. //
  577. if ((Operator == TestUtilityAnd) || (Operator == TestUtilityOr) ||
  578. (Operator == TestUtilityBang)) {
  579. *Shift = TRUE;
  580. return TRUE;
  581. }
  582. //
  583. // If it's an operator, then all other operators are turned off
  584. // except for bang.
  585. //
  586. if ((NextElement->Type == TestParseElementOperator) &&
  587. (NextElement->Operator == TestUtilityBang)) {
  588. *Shift = TRUE;
  589. return TRUE;
  590. }
  591. NextElement->Type = TestParseElementToken;
  592. *Shift = TRUE;
  593. return TRUE;
  594. case TestParseElementToken:
  595. //
  596. // If the next thing isn't an operator this is an error.
  597. //
  598. if (NextElement->Type != TestParseElementOperator) {
  599. SwPrintError(0,
  600. NULL,
  601. "Expected an operator, got %s",
  602. NextElement->Token);
  603. return FALSE;
  604. }
  605. //
  606. // If there's only one element on the stack just shift. That next
  607. // argument had better be a binary argument.
  608. //
  609. NextOperator = NextElement->Operator;
  610. if (StackSize == 1) {
  611. if (TestGetOperandCount(NextOperator) != 2) {
  612. SwPrintError(0, NULL, "Expected a binary operator");
  613. }
  614. *Shift = TRUE;
  615. return TRUE;
  616. }
  617. //
  618. // There's more than one element on the stack, so get the operator
  619. // back there and compare with this upcoming operator.
  620. //
  621. assert(Stack[StackSize - 2].Type == TestParseElementOperator);
  622. Operator = Stack[StackSize - 2].Operator;
  623. if (Operator == TestUtilityOpenParentheses) {
  624. *Shift = TRUE;
  625. } else if (TestGetOperatorPrecedence(Operator) >=
  626. TestGetOperatorPrecedence(NextOperator)) {
  627. *Shift = FALSE;
  628. } else {
  629. *Shift = TRUE;
  630. }
  631. return TRUE;
  632. case TestParseElementResult:
  633. //
  634. // If the next thing isn't an operator this is an error.
  635. //
  636. if (NextElement->Type != TestParseElementOperator) {
  637. SwPrintError(0,
  638. NULL,
  639. "Expected an operator, got %s",
  640. NextElement->Token);
  641. return FALSE;
  642. }
  643. //
  644. // The upcoming operator had better be an and or an or.
  645. //
  646. NextOperator = NextElement->Operator;
  647. if ((NextOperator != TestUtilityAnd) &&
  648. (NextOperator != TestUtilityOr) &&
  649. (NextOperator != TestUtilityCloseParentheses)) {
  650. SwPrintError(0, NULL, "Expected end of expression");
  651. return FALSE;
  652. }
  653. if (StackSize == 1) {
  654. *Shift = TRUE;
  655. return TRUE;
  656. }
  657. //
  658. // The operator back there had better be an and, or, or bang.
  659. //
  660. Operator = Stack[StackSize - 2].Operator;
  661. assert((Operator == TestUtilityAnd) || (Operator == TestUtilityOr) ||
  662. (Operator == TestUtilityBang) ||
  663. (Operator == TestUtilityOpenParentheses));
  664. //
  665. // Figure out which is more important and shift or reduce.
  666. //
  667. if (Operator == TestUtilityOpenParentheses) {
  668. *Shift = TRUE;
  669. } else if (TestGetOperatorPrecedence(Operator) >=
  670. TestGetOperatorPrecedence(NextOperator)) {
  671. *Shift = FALSE;
  672. } else {
  673. *Shift = TRUE;
  674. }
  675. return TRUE;
  676. default:
  677. break;
  678. }
  679. assert(FALSE);
  680. return FALSE;
  681. }
  682. BOOL
  683. TestReduce (
  684. PTEST_PARSE_ELEMENT Stack,
  685. PULONG StackSize
  686. )
  687. /*++
  688. Routine Description:
  689. This routine attempts to reduce the stack by performing the topmost
  690. operation.
  691. Arguments:
  692. Stack - Supplies a pointer to the parse stack.
  693. StackSize - Supplies the number of elements on the stack.
  694. Return Value:
  695. TRUE on success.
  696. FALSE on failure.
  697. --*/
  698. {
  699. ULONG OperandCount;
  700. TEST_UTILITY_TEST Operator;
  701. BOOL Result;
  702. INT ReturnValue;
  703. assert(*StackSize != 0);
  704. //
  705. // If there's a single element on the stack or the stack looks like
  706. // ( something, then just evaluate the top item.
  707. //
  708. if ((*StackSize == 1) ||
  709. ((Stack[*StackSize - 1].Type == TestParseElementToken) &&
  710. (Stack[*StackSize - 2].Type == TestParseElementOperator) &&
  711. (Stack[*StackSize - 2].Operator == TestUtilityOpenParentheses))) {
  712. if (Stack[0].Type != TestParseElementToken) {
  713. SwPrintError(0, NULL, "Expected token");
  714. return FALSE;
  715. }
  716. TestConvertTokenToResult(&(Stack[0]));
  717. }
  718. //
  719. // If the topmost thing is a close parentheses, reduce until finding the
  720. // corresponding open parentheses.
  721. //
  722. if (Stack[*StackSize - 1].Type == TestParseElementOperator) {
  723. if (Stack[*StackSize - 1].Operator != TestUtilityCloseParentheses) {
  724. SwPrintError(0, NULL, "Argument expected");
  725. return FALSE;
  726. }
  727. *StackSize -= 1;
  728. while (TRUE) {
  729. if (*StackSize < 2) {
  730. SwPrintError(0, NULL, "Unexpected close parentheses");
  731. return FALSE;
  732. }
  733. if ((Stack[*StackSize - 1].Type == TestParseElementResult) &&
  734. (Stack[*StackSize - 2].Type == TestParseElementOperator) &&
  735. (Stack[*StackSize - 2].Operator ==
  736. TestUtilityOpenParentheses)) {
  737. *StackSize -= 1;
  738. Stack[*StackSize - 1].Type = TestParseElementResult;
  739. Stack[*StackSize - 1].Result = Stack[*StackSize].Result;
  740. return TRUE;
  741. }
  742. Result = TestReduce(Stack, StackSize);
  743. if (Result == FALSE) {
  744. return FALSE;
  745. }
  746. }
  747. }
  748. assert(Stack[*StackSize - 2].Type == TestParseElementOperator);
  749. //
  750. // Handle the logical operators !, AND, and OR right here.
  751. //
  752. Operator = Stack[*StackSize - 2].Operator;
  753. if (Operator == TestUtilityBang) {
  754. assert(Stack[*StackSize - 1].Type == TestParseElementResult);
  755. ReturnValue = Stack[*StackSize - 1].Result;
  756. if (ReturnValue == TEST_UTILITY_TRUE) {
  757. ReturnValue = TEST_UTILITY_FALSE;
  758. } else if (ReturnValue == TEST_UTILITY_FALSE) {
  759. ReturnValue = TEST_UTILITY_TRUE;
  760. }
  761. if (TestDebugPrintEvaluations != FALSE) {
  762. SwPrintError(0,
  763. NULL,
  764. "%d <== [!] %d\n",
  765. ReturnValue,
  766. Stack[*StackSize - 1].Result);
  767. }
  768. *StackSize -= 1;
  769. Stack[*StackSize - 1].Result = ReturnValue;
  770. Stack[*StackSize - 1].Type = TestParseElementResult;
  771. return TRUE;
  772. } else if ((Operator == TestUtilityAnd) || (Operator == TestUtilityOr)) {
  773. TestConvertTokenToResult(&(Stack[*StackSize - 3]));
  774. TestConvertTokenToResult(&(Stack[*StackSize - 1]));
  775. assert(Stack[*StackSize - 3].Type == TestParseElementResult);
  776. assert(Stack[*StackSize - 1].Type == TestParseElementResult);
  777. ReturnValue = TestEvaluateAndOr(Operator,
  778. Stack[*StackSize - 3].Result,
  779. Stack[*StackSize - 1].Result);
  780. *StackSize -= 2;
  781. Stack[*StackSize - 1].Result = ReturnValue;
  782. Stack[*StackSize - 1].Type = TestParseElementResult;
  783. return TRUE;
  784. }
  785. //
  786. // It's not logical, it must be an expression with tokens.
  787. //
  788. assert(Stack[*StackSize - 1].Type == TestParseElementToken);
  789. //
  790. // Try for a unary operator.
  791. //
  792. OperandCount = TestGetOperandCount(Operator);
  793. if (OperandCount == 1) {
  794. ReturnValue = TestEvaluateUnaryOperator(Operator,
  795. Stack[*StackSize - 1].Token);
  796. *StackSize -= 1;
  797. //
  798. // Process a binary operator.
  799. //
  800. } else {
  801. assert(OperandCount == 2);
  802. ReturnValue = TestEvaluateBinaryOperator(Operator,
  803. Stack[*StackSize - 3].Token,
  804. Stack[*StackSize - 1].Token);
  805. *StackSize -= 2;
  806. }
  807. Stack[*StackSize - 1].Result = ReturnValue;
  808. Stack[*StackSize - 1].Type = TestParseElementResult;
  809. return TRUE;
  810. }
  811. TEST_UTILITY_TEST
  812. TestGetOperator (
  813. PSTR String
  814. )
  815. /*++
  816. Routine Description:
  817. This routine converts the given string into an operator.
  818. Arguments:
  819. String - Supplies the argument string.
  820. Return Value:
  821. 0 or 1 if the evaluation succeeds.
  822. >1 on failure.
  823. --*/
  824. {
  825. if (String[0] == '\0') {
  826. return TestUtilityInvalid;
  827. }
  828. if ((strcmp(String, "=") == 0) || (strcmp(String, "==") == 0)) {
  829. return TestStringEquals;
  830. }
  831. if (strcmp(String, "(") == 0) {
  832. return TestUtilityOpenParentheses;
  833. }
  834. if (strcmp(String, ")") == 0) {
  835. return TestUtilityCloseParentheses;
  836. }
  837. if (strcmp(String, "!") == 0) {
  838. return TestUtilityBang;
  839. }
  840. if (strcmp(String, "!=") == 0) {
  841. return TestStringNotEquals;
  842. }
  843. //
  844. // All others start with a -.
  845. //
  846. if (String[0] != '-') {
  847. return TestUtilityInvalid;
  848. }
  849. String += 1;
  850. if (strcmp(String, "a") == 0) {
  851. return TestUtilityAnd;
  852. }
  853. if (strcmp(String, "b") == 0) {
  854. return TestFileIsBlockDevice;
  855. }
  856. if (strcmp(String, "c") == 0) {
  857. return TestFileIsCharacterDevice;
  858. }
  859. if (strcmp(String, "d") == 0) {
  860. return TestFileIsDirectory;
  861. }
  862. if (strcmp(String, "e") == 0) {
  863. return TestFileExists;
  864. }
  865. if (strcmp(String, "f") == 0) {
  866. return TestFileIsRegularFile;
  867. }
  868. if (strcmp(String, "g") == 0) {
  869. return TestFileHasSetGroupId;
  870. }
  871. if (strcmp(String, "h") == 0) {
  872. return TestFileIsSymbolicLink;
  873. }
  874. if (strcmp(String, "L") == 0) {
  875. return TestFileIsSymbolicLink;
  876. }
  877. if (strcmp(String, "o") == 0) {
  878. return TestUtilityOr;
  879. }
  880. if (strcmp(String, "p") == 0) {
  881. return TestFileIsFifo;
  882. }
  883. if (strcmp(String, "r") == 0) {
  884. return TestFileCanRead;
  885. }
  886. if (strcmp(String, "S") == 0) {
  887. return TestFileIsSocket;
  888. }
  889. if (strcmp(String, "s") == 0) {
  890. return TestFileIsNonEmpty;
  891. }
  892. if (strcmp(String, "t") == 0) {
  893. return TestFileDescriptorIsTerminal;
  894. }
  895. if (strcmp(String, "u") == 0) {
  896. return TestFileHasSetUserId;
  897. }
  898. if (strcmp(String, "w") == 0) {
  899. return TestFileCanWrite;
  900. }
  901. if (strcmp(String, "x") == 0) {
  902. return TestFileCanExecute;
  903. }
  904. if (strcmp(String, "fe") == 0) {
  905. return TestFileEqual;
  906. }
  907. if (strcmp(String, "nt") == 0) {
  908. return TestFileNewer;
  909. }
  910. if (strcmp(String, "ot") == 0) {
  911. return TestFileOlder;
  912. }
  913. if (strcmp(String, "n") == 0) {
  914. return TestStringNonZeroLength;
  915. }
  916. if (strcmp(String, "z") == 0) {
  917. return TestStringZeroLength;
  918. }
  919. if (strcmp(String, "eq") == 0) {
  920. return TestIntegerEquals;
  921. }
  922. if (strcmp(String, "ne") == 0) {
  923. return TestIntegerNotEquals;
  924. }
  925. if (strcmp(String, "gt") == 0) {
  926. return TestIntegerGreaterThan;
  927. }
  928. if (strcmp(String, "ge") == 0) {
  929. return TestIntegerGreaterThanOrEqualTo;
  930. }
  931. if (strcmp(String, "lt") == 0) {
  932. return TestIntegerLessThan;
  933. }
  934. if (strcmp(String, "le") == 0) {
  935. return TestIntegerLessThanOrEqualTo;
  936. }
  937. return TestUtilityInvalid;
  938. }
  939. ULONG
  940. TestGetOperandCount (
  941. TEST_UTILITY_TEST Operator
  942. )
  943. /*++
  944. Routine Description:
  945. This routine returns the number of operands needed for the given operator.
  946. Arguments:
  947. Operator - Supplies the operator.
  948. Return Value:
  949. 0 on failure.
  950. 1 or 2 for unary and binary operators.
  951. --*/
  952. {
  953. if ((Operator > TestIntegerMinValue) && (Operator < TestIntegerMaxValue)) {
  954. return 2;
  955. }
  956. if ((Operator == TestStringEquals) || (Operator == TestStringNotEquals) ||
  957. (Operator == TestUtilityAnd) || (Operator == TestUtilityOr)) {
  958. return 2;
  959. }
  960. if ((Operator > TestFileMinValue) && (Operator < TestFileMaxValue)) {
  961. if ((Operator == TestFileEqual) || (Operator == TestFileNewer) ||
  962. (Operator == TestFileOlder)) {
  963. return 2;
  964. }
  965. return 1;
  966. }
  967. if ((Operator == TestStringZeroLength) ||
  968. (Operator == TestStringNonZeroLength) ||
  969. (Operator == TestUtilityBang)) {
  970. return 1;
  971. }
  972. return 0;
  973. }
  974. ULONG
  975. TestGetOperatorPrecedence (
  976. TEST_UTILITY_TEST Operator
  977. )
  978. /*++
  979. Routine Description:
  980. This routine returns precedence of the given operator.
  981. Arguments:
  982. Operator - Supplies the operator.
  983. Return Value:
  984. Returns the precedence. Higher values are higher precedence.
  985. --*/
  986. {
  987. if (Operator == TestUtilityCloseParentheses) {
  988. return 0;
  989. }
  990. if (Operator == TestUtilityOr) {
  991. return 1;
  992. }
  993. if (Operator == TestUtilityAnd) {
  994. return 2;
  995. }
  996. if (Operator == TestUtilityBang) {
  997. return 3;
  998. }
  999. if ((Operator == TestStringEquals) || (Operator == TestStringNotEquals)) {
  1000. return 6;
  1001. }
  1002. if (Operator == TestUtilityOpenParentheses) {
  1003. return 7;
  1004. }
  1005. if (TestGetOperandCount(Operator) == 2) {
  1006. return 4;
  1007. }
  1008. return 5;
  1009. }
  1010. INT
  1011. TestEvaluateUnaryOperator (
  1012. TEST_UTILITY_TEST Operator,
  1013. PSTR Operand
  1014. )
  1015. /*++
  1016. Routine Description:
  1017. This routine evaluates a unary operator.
  1018. Arguments:
  1019. Operator - Supplies the operator.
  1020. Operand - Supplies the operand.
  1021. Return Value:
  1022. Returns the result of the operation.
  1023. --*/
  1024. {
  1025. INT Error;
  1026. SWISS_FILE_TEST FileTest;
  1027. INT Result;
  1028. INT ReturnValue;
  1029. if ((Operator > TestFileMinValue) && (Operator < TestFileMaxValue)) {
  1030. switch (Operator) {
  1031. case TestFileIsBlockDevice:
  1032. FileTest = FileTestIsBlockDevice;
  1033. break;
  1034. case TestFileIsCharacterDevice:
  1035. FileTest = FileTestIsCharacterDevice;
  1036. break;
  1037. case TestFileIsDirectory:
  1038. FileTest = FileTestIsDirectory;
  1039. break;
  1040. case TestFileExists:
  1041. FileTest = FileTestExists;
  1042. break;
  1043. case TestFileIsRegularFile:
  1044. FileTest = FileTestIsRegularFile;
  1045. break;
  1046. case TestFileHasSetGroupId:
  1047. FileTest = FileTestHasSetGroupId;
  1048. break;
  1049. case TestFileIsSymbolicLink:
  1050. FileTest = FileTestIsSymbolicLink;
  1051. break;
  1052. case TestFileIsFifo:
  1053. FileTest = FileTestIsFifo;
  1054. break;
  1055. case TestFileCanRead:
  1056. FileTest = FileTestCanRead;
  1057. break;
  1058. case TestFileIsSocket:
  1059. FileTest = FileTestIsSocket;
  1060. break;
  1061. case TestFileIsNonEmpty:
  1062. FileTest = FileTestIsNonEmpty;
  1063. break;
  1064. case TestFileDescriptorIsTerminal:
  1065. FileTest = FileTestDescriptorIsTerminal;
  1066. break;
  1067. case TestFileHasSetUserId:
  1068. FileTest = FileTestHasSetUserId;
  1069. break;
  1070. case TestFileCanWrite:
  1071. FileTest = FileTestCanWrite;
  1072. break;
  1073. case TestFileCanExecute:
  1074. FileTest = FileTestCanExecute;
  1075. break;
  1076. default:
  1077. assert(FALSE);
  1078. return TEST_UTILITY_ERROR;
  1079. }
  1080. ReturnValue = TEST_UTILITY_FALSE;
  1081. Result = SwEvaluateFileTest(FileTest, Operand, &Error);
  1082. if (Error != 0) {
  1083. ReturnValue = TEST_UTILITY_ERROR;
  1084. } else if (Result != FALSE) {
  1085. ReturnValue = TEST_UTILITY_TRUE;
  1086. }
  1087. } else if ((Operator == TestStringZeroLength) ||
  1088. (Operator == TestStringNonZeroLength)) {
  1089. ReturnValue = TestEvaluateStringTest(Operator, Operand, NULL);
  1090. } else {
  1091. assert(FALSE);
  1092. ReturnValue = TEST_UTILITY_ERROR;
  1093. }
  1094. if (TestDebugPrintEvaluations != FALSE) {
  1095. SwPrintError(0,
  1096. NULL,
  1097. "%d <== [%s] \"%s\"\n",
  1098. ReturnValue,
  1099. TestOperatorStrings[Operator],
  1100. Operand);
  1101. }
  1102. return ReturnValue;
  1103. }
  1104. INT
  1105. TestEvaluateBinaryOperator (
  1106. TEST_UTILITY_TEST Operator,
  1107. PSTR LeftOperand,
  1108. PSTR RightOperand
  1109. )
  1110. /*++
  1111. Routine Description:
  1112. This routine evaluates a binary operator.
  1113. Arguments:
  1114. Operator - Supplies the operator.
  1115. LeftOperand - Supplies the left operand.
  1116. RightOperand - Supplies the right operand.
  1117. Return Value:
  1118. Returns the result of the operation.
  1119. --*/
  1120. {
  1121. INT LeftResult;
  1122. struct stat LeftStat;
  1123. INT ReturnValue;
  1124. INT RightResult;
  1125. struct stat RightStat;
  1126. if ((Operator > TestFileMinValue) && (Operator < TestFileMaxValue)) {
  1127. memset(&LeftStat, 0, sizeof(struct stat));
  1128. memset(&RightStat, 0, sizeof(struct stat));
  1129. SwStat(LeftOperand, TRUE, &LeftStat);
  1130. SwStat(RightOperand, TRUE, &RightStat);
  1131. ReturnValue = TEST_UTILITY_FALSE;
  1132. switch (Operator) {
  1133. case TestFileEqual:
  1134. if ((LeftStat.st_dev == RightStat.st_dev) &&
  1135. (LeftStat.st_ino == RightStat.st_ino)) {
  1136. ReturnValue = TEST_UTILITY_TRUE;
  1137. }
  1138. break;
  1139. case TestFileNewer:
  1140. if (LeftStat.st_mtime > RightStat.st_mtime) {
  1141. ReturnValue = TEST_UTILITY_TRUE;
  1142. }
  1143. break;
  1144. case TestFileOlder:
  1145. if (LeftStat.st_mtime < RightStat.st_mtime) {
  1146. ReturnValue = TEST_UTILITY_TRUE;
  1147. }
  1148. break;
  1149. default:
  1150. assert(FALSE);
  1151. ReturnValue = TEST_UTILITY_ERROR;
  1152. break;
  1153. }
  1154. } else if ((Operator > TestStringMinValue) &&
  1155. (Operator < TestStringMaxValue)) {
  1156. ReturnValue = TestEvaluateStringTest(Operator,
  1157. LeftOperand,
  1158. RightOperand);
  1159. } else if ((Operator > TestIntegerMinValue) &&
  1160. (Operator < TestIntegerMaxValue)) {
  1161. ReturnValue = TestEvaluateIntegerTest(Operator,
  1162. LeftOperand,
  1163. RightOperand);
  1164. } else if ((Operator == TestUtilityAnd) || (Operator == TestUtilityOr)) {
  1165. LeftResult = TEST_UTILITY_FALSE;
  1166. RightResult = TEST_UTILITY_FALSE;
  1167. if (strlen(LeftOperand) != 0) {
  1168. LeftResult = TEST_UTILITY_TRUE;
  1169. }
  1170. if (strlen(RightOperand) != 0) {
  1171. RightResult = TEST_UTILITY_TRUE;
  1172. }
  1173. ReturnValue = TestEvaluateAndOr(Operator, LeftResult, RightResult);
  1174. } else {
  1175. assert(FALSE);
  1176. ReturnValue = TEST_UTILITY_ERROR;
  1177. }
  1178. if (TestDebugPrintEvaluations != FALSE) {
  1179. SwPrintError(0,
  1180. NULL,
  1181. "%d <== \"%s\" [%s] \"%s\"\n",
  1182. ReturnValue,
  1183. LeftOperand,
  1184. TestOperatorStrings[Operator],
  1185. RightOperand);
  1186. }
  1187. return ReturnValue;
  1188. }
  1189. INT
  1190. TestEvaluateStringTest (
  1191. TEST_UTILITY_TEST Operator,
  1192. PSTR String1,
  1193. PSTR String2
  1194. )
  1195. /*++
  1196. Routine Description:
  1197. This routine evaluates a string test.
  1198. Arguments:
  1199. Operator - Supplies the operator.
  1200. String1 - Supplies a pointer to the first string operand.
  1201. String2 - Supplies a pointer to the second string operand. Not all
  1202. operators require a second operand.
  1203. Return Value:
  1204. Returns the result of the operation.
  1205. --*/
  1206. {
  1207. INT ReturnValue;
  1208. ReturnValue = TEST_UTILITY_FALSE;
  1209. switch (Operator) {
  1210. case TestStringNonZeroLength:
  1211. if (strlen(String1) != 0) {
  1212. ReturnValue = TEST_UTILITY_TRUE;
  1213. }
  1214. break;
  1215. case TestStringZeroLength:
  1216. if (strlen(String1) == 0) {
  1217. ReturnValue = TEST_UTILITY_TRUE;
  1218. }
  1219. break;
  1220. case TestStringEquals:
  1221. assert((String1 != NULL) && (String2 != NULL));
  1222. if (strcmp(String1, String2) == 0) {
  1223. ReturnValue = TEST_UTILITY_TRUE;
  1224. }
  1225. break;
  1226. case TestStringNotEquals:
  1227. assert((String1 != NULL) && (String2 != NULL));
  1228. if (strcmp(String1, String2) != 0) {
  1229. ReturnValue = TEST_UTILITY_TRUE;
  1230. }
  1231. break;
  1232. default:
  1233. assert(FALSE);
  1234. break;
  1235. }
  1236. return ReturnValue;
  1237. }
  1238. INT
  1239. TestEvaluateIntegerTest (
  1240. TEST_UTILITY_TEST Operator,
  1241. PSTR LeftIntegerString,
  1242. PSTR RightIntegerString
  1243. )
  1244. /*++
  1245. Routine Description:
  1246. This routine evaluates an integer test.
  1247. Arguments:
  1248. Operator - Supplies the operator.
  1249. LeftIntegerString - Supplies a pointer to the string containing the left
  1250. numeric value.
  1251. RightIntegerString - Supplies a pointer to the string containing the right
  1252. numeric value.
  1253. Return Value:
  1254. Returns the result of the operation.
  1255. --*/
  1256. {
  1257. PSTR AfterScan;
  1258. INT Left;
  1259. INT ReturnValue;
  1260. INT Right;
  1261. //
  1262. // Convert the strings to integers.
  1263. //
  1264. Left = strtol(LeftIntegerString, &AfterScan, 10);
  1265. if ((Left == 0) && (AfterScan == LeftIntegerString)) {
  1266. SwPrintError(0, NULL, "%s: Invalid integer", LeftIntegerString);
  1267. return TEST_UTILITY_ERROR;
  1268. }
  1269. Right = strtol(RightIntegerString, &AfterScan, 10);
  1270. if ((Right == 0) && (AfterScan == RightIntegerString)) {
  1271. SwPrintError(0, NULL, "%s: Invalid integer", RightIntegerString);
  1272. return TEST_UTILITY_ERROR;
  1273. }
  1274. ReturnValue = TEST_UTILITY_FALSE;
  1275. switch (Operator) {
  1276. case TestIntegerEquals:
  1277. if (Left == Right) {
  1278. ReturnValue = TEST_UTILITY_TRUE;
  1279. }
  1280. break;
  1281. case TestIntegerNotEquals:
  1282. if (Left != Right) {
  1283. ReturnValue = TEST_UTILITY_TRUE;
  1284. }
  1285. break;
  1286. case TestIntegerGreaterThan:
  1287. if (Left > Right) {
  1288. ReturnValue = TEST_UTILITY_TRUE;
  1289. }
  1290. break;
  1291. case TestIntegerGreaterThanOrEqualTo:
  1292. if (Left >= Right) {
  1293. ReturnValue = TEST_UTILITY_TRUE;
  1294. }
  1295. break;
  1296. case TestIntegerLessThan:
  1297. if (Left < Right) {
  1298. ReturnValue = TEST_UTILITY_TRUE;
  1299. }
  1300. break;
  1301. case TestIntegerLessThanOrEqualTo:
  1302. if (Left <= Right) {
  1303. ReturnValue = TEST_UTILITY_TRUE;
  1304. }
  1305. break;
  1306. default:
  1307. assert(FALSE);
  1308. break;
  1309. }
  1310. return ReturnValue;
  1311. }
  1312. INT
  1313. TestEvaluateAndOr (
  1314. TEST_UTILITY_TEST Operator,
  1315. INT Left,
  1316. INT Right
  1317. )
  1318. /*++
  1319. Routine Description:
  1320. This routine evaluates and AND (-a) or and OR (-o) operator.
  1321. Arguments:
  1322. Operator - Supplies the operator, which should be AND or OR.
  1323. Left - Supplies the left result, a TEST_UTILITY_* value.
  1324. Right - Supplies the right result, a TEST_UTILITY_* value.
  1325. Return Value:
  1326. Returns the TEST_UTILITY_* result.
  1327. --*/
  1328. {
  1329. INT ReturnValue;
  1330. assert((Operator == TestUtilityAnd) || (Operator == TestUtilityOr));
  1331. ReturnValue = TEST_UTILITY_FALSE;
  1332. if (Operator == TestUtilityAnd) {
  1333. if ((Left == TEST_UTILITY_TRUE) && (Right == TEST_UTILITY_TRUE)) {
  1334. ReturnValue = TEST_UTILITY_TRUE;
  1335. }
  1336. } else {
  1337. if ((Left == TEST_UTILITY_TRUE) || (Right == TEST_UTILITY_TRUE)) {
  1338. ReturnValue = TEST_UTILITY_TRUE;
  1339. }
  1340. }
  1341. if (TestDebugPrintEvaluations != FALSE) {
  1342. SwPrintError(0,
  1343. NULL,
  1344. "%d <== %d [%s] %d\n",
  1345. ReturnValue,
  1346. Left,
  1347. TestOperatorStrings[Operator],
  1348. Right);
  1349. }
  1350. return ReturnValue;
  1351. }
  1352. VOID
  1353. TestConvertTokenToResult (
  1354. PTEST_PARSE_ELEMENT Element
  1355. )
  1356. /*++
  1357. Routine Description:
  1358. This routine converts a token type parse element into a result element,
  1359. which is non-zero if the given token has a non-zero length.
  1360. Arguments:
  1361. Element - Supplies a pointer to the token element to convert into a result.
  1362. Return Value:
  1363. None.
  1364. --*/
  1365. {
  1366. //
  1367. // Skip it if it's already a result.
  1368. //
  1369. if (Element->Type == TestParseElementResult) {
  1370. return;
  1371. }
  1372. //
  1373. // Only tokens are handled here, there's no converting an operator to a
  1374. // result.
  1375. //
  1376. assert(Element->Type == TestParseElementToken);
  1377. if (strlen(Element->Token) != 0) {
  1378. Element->Result = TEST_UTILITY_TRUE;
  1379. } else {
  1380. Element->Result = TEST_UTILITY_FALSE;
  1381. }
  1382. Element->Type = TestParseElementResult;
  1383. return;
  1384. }