Changeset 3192 for trunk/src/kmk/kmkbuiltin/test.c
- Timestamp:
- Mar 26, 2018, 10:25:56 PM (7 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/kmk/kmkbuiltin/test.c
r3065 r3192 16 16 #endif*/ 17 17 18 19 /********************************************************************************************************************************* 20 * Header Files * 21 *********************************************************************************************************************************/ 18 22 #include "config.h" 19 23 #include <sys/stat.h> … … 32 36 # include <process.h> 33 37 # include "mscfakes.h" 38 # include "quote_argv.h" 34 39 #else 35 40 # include <unistd.h> … … 40 45 #include "kmkbuiltin.h" 41 46 47 48 /********************************************************************************************************************************* 49 * Defined Constants And Macros * 50 *********************************************************************************************************************************/ 42 51 #ifndef __arraycount 43 52 # define __arraycount(a) ( sizeof(a) / sizeof(a[0]) ) … … 45 54 46 55 56 /********************************************************************************************************************************* 57 * Structures and Typedefs * 58 *********************************************************************************************************************************/ 47 59 /* test(1) accepts the following grammar: 48 60 oexpr ::= aexpr | aexpr "-o" oexpr ; … … 118 130 }; 119 131 132 /** kmk_test instance data. */ 133 typedef struct TESTINSTANCE 134 { 135 PKMKBUILTINCTX pCtx; 136 char **t_wp; 137 struct t_op const *t_wp_op; 138 } TESTINSTANCE; 139 typedef TESTINSTANCE *PTESTINSTANCE; 140 141 142 /********************************************************************************************************************************* 143 * Global Variables * 144 *********************************************************************************************************************************/ 120 145 static const struct t_op cop[] = { 121 146 {"!", UNOT, BUNOP}, … … 169 194 }; 170 195 171 static char **t_wp; 172 static struct t_op const *t_wp_op; 173 174 static int syntax(const char *, const char *); 175 static int oexpr(enum token); 176 static int aexpr(enum token); 177 static int nexpr(enum token); 178 static int primary(enum token); 179 static int binop(void); 196 197 /********************************************************************************************************************************* 198 * Internal Functions * 199 *********************************************************************************************************************************/ 200 static int syntax(PTESTINSTANCE, const char *, const char *); 201 static int oexpr(PTESTINSTANCE, enum token); 202 static int aexpr(PTESTINSTANCE, enum token); 203 static int nexpr(PTESTINSTANCE, enum token); 204 static int primary(PTESTINSTANCE, enum token); 205 static int binop(PTESTINSTANCE); 180 206 static int test_access(struct stat *, mode_t); 181 207 static int filstat(char *, enum token); 182 static enum token t_lex( char *);183 static int isoperand( void);184 static int getn( const char *);208 static enum token t_lex(PTESTINSTANCE, char *); 209 static int isoperand(PTESTINSTANCE); 210 static int getn(PTESTINSTANCE, const char *); 185 211 static int newerf(const char *, const char *); 186 212 static int olderf(const char *, const char *); 187 213 static int equalf(const char *, const char *); 188 static int usage( const char *);189 190 #if !defined( kmk_builtin_test) || defined(ELECTRIC_HEAP)214 static int usage(PKMKBUILTINCTX, int); 215 216 #if !defined(KMK_BUILTIN_STANDALONE) || defined(ELECTRIC_HEAP) 191 217 extern void *xmalloc(unsigned int); 192 218 #else … … 195 221 void *p = malloc(sz); 196 222 if (!p) { 197 fprintf(stderr, " %s: malloc(%u) failed\n", g_progname, sz);223 fprintf(stderr, "kmk_test: malloc(%u) failed\n", sz); 198 224 exit(1); 199 225 } … … 202 228 #endif 203 229 204 int kmk_builtin_test(int argc, char **argv, char **envp 205 #ifndef kmk_builtin_test 206 , char ***ppapszArgvSpawn 207 #endif 208 ) 209 { 230 231 232 int kmk_builtin_test(int argc, char **argv, char **envp, PKMKBUILTINCTX pCtx, char ***ppapszArgvSpawn) 233 { 234 TESTINSTANCE This; 210 235 int res; 211 236 char **argv_spawn; 212 237 int i; 213 238 214 g_progname = argv[0]; 239 This.pCtx = pCtx; 240 This.t_wp = NULL; 241 This.t_wp_op = NULL; 215 242 216 243 /* look for the '--', '--help' and '--version'. */ … … 235 262 } 236 263 if (!strcmp(argv[i], "--help")) 237 return usage( argv[0]);264 return usage(pCtx, 0); 238 265 if (!strcmp(argv[i], "--version")) 239 266 return kbuild_version(argv[0]); … … 242 269 243 270 /* are we '['? then check for ']'. */ 244 if (strcmp( g_progname, "[") == 0) { /** @todo should skip the path in g_progname */271 if (strcmp(argv[0], "[") == 0) { /** @todo should skip the path in g_progname */ 245 272 if (strcmp(argv[--argc], "]")) 246 return errx( 1, "missing ]");273 return errx(pCtx, 1, "missing ]"); 247 274 argv[argc] = NULL; 248 275 } … … 252 279 res = 1; 253 280 else { 254 t_wp = &argv[1];255 res = oexpr( t_lex(*t_wp));256 if (res != -42 && * t_wp != NULL && *++t_wp != NULL)257 res = syntax( *t_wp, "unexpected operator");281 This.t_wp = &argv[1]; 282 res = oexpr(&This, t_lex(&This, *This.t_wp)); 283 if (res != -42 && *This.t_wp != NULL && *++This.t_wp != NULL) 284 res = syntax(&This, *This.t_wp, "unexpected operator"); 258 285 if (res == -42) 259 286 return 1; /* don't mix syntax errors with the argv_spawn ignore */ … … 266 293 res = 0; /* ignored */ 267 294 else { 268 #ifdef kmk_builtin_test295 #ifdef KMK_BUILTIN_STANDALONE 269 296 /* try exec the specified process */ 270 297 # if defined(_MSC_VER) 271 res = _spawnvp(_P_WAIT, argv_spawn[0], argv_spawn); 272 if (res == -1) 273 res = err(1, "_spawnvp(_P_WAIT,%s,..)", argv_spawn[0]); 298 int argc_spawn = 0; 299 while (argv_spawn[argc_spawn]) 300 argc_spawn++; 301 if (quote_argv(argc, argv_spawn, 0 /*fWatcomBrainDamage*/, 0/*fFreeOrLeak*/) != -1) 302 { 303 res = _spawnvp(_P_WAIT, argv_spawn[0], argv_spawn); 304 if (res == -1) 305 res = err(pCtx, 1, "_spawnvp(_P_WAIT,%s,..)", argv_spawn[0]); 306 } 307 else 308 res = err(pCtx, 1, "quote_argv: out of memory"); 274 309 # else 275 310 execvp(argv_spawn[0], argv_spawn); … … 305 340 } 306 341 307 static int 308 syntax(const char *op, const char *msg) 342 #ifdef KMK_BUILTIN_STANDALONE 343 int main(int argc, char **argv, char **envp) 344 { 345 KMKBUILTINCTX Ctx = { "kmk_test", NULL }; 346 return kmk_builtin_test(argc, argv, envp, &Ctx, NULL); 347 } 348 #endif 349 350 static int 351 syntax(PTESTINSTANCE pThis, const char *op, const char *msg) 309 352 { 310 353 311 354 if (op && *op) 312 errx( 1, "%s: %s", op, msg);355 errx(pThis->pCtx, 1, "%s: %s", op, msg); 313 356 else 314 errx( 1, "%s", msg);357 errx(pThis->pCtx, 1, "%s", msg); 315 358 return -42; 316 359 } 317 360 318 361 static int 319 oexpr( enum token n)362 oexpr(PTESTINSTANCE pThis, enum token n) 320 363 { 321 364 int res; 322 365 323 res = aexpr( n);324 if (res == -42 || * t_wp == NULL)366 res = aexpr(pThis, n); 367 if (res == -42 || *pThis->t_wp == NULL) 325 368 return res; 326 if (t_lex( *++t_wp) == BOR) {327 int res2 = oexpr( t_lex(*++t_wp));369 if (t_lex(pThis, *++(pThis->t_wp)) == BOR) { 370 int res2 = oexpr(pThis, t_lex(pThis, *++(pThis->t_wp))); 328 371 return res2 != -42 ? res2 || res : res2; 329 372 } 330 t_wp--;373 pThis->t_wp--; 331 374 return res; 332 375 } 333 376 334 377 static int 335 aexpr( enum token n)378 aexpr(PTESTINSTANCE pThis, enum token n) 336 379 { 337 380 int res; 338 381 339 res = nexpr( n);340 if (res == -42 || * t_wp == NULL)382 res = nexpr(pThis, n); 383 if (res == -42 || *pThis->t_wp == NULL) 341 384 return res; 342 if (t_lex( *++t_wp) == BAND) {343 int res2 = aexpr( t_lex(*++t_wp));385 if (t_lex(pThis, *++(pThis->t_wp)) == BAND) { 386 int res2 = aexpr(pThis, t_lex(pThis, *++(pThis->t_wp))); 344 387 return res2 != -42 ? res2 && res : res2; 345 388 } 346 t_wp--;389 pThis->t_wp--; 347 390 return res; 348 391 } 349 392 350 393 static int 351 nexpr( enum token n)394 nexpr(PTESTINSTANCE pThis, enum token n) 352 395 { 353 396 if (n == UNOT) { 354 int res = nexpr( t_lex(*++t_wp));397 int res = nexpr(pThis, t_lex(pThis, *++(pThis->t_wp))); 355 398 return res != -42 ? !res : res; 356 399 } 357 return primary( n);358 } 359 360 static int 361 primary( enum token n)400 return primary(pThis, n); 401 } 402 403 static int 404 primary(PTESTINSTANCE pThis, enum token n) 362 405 { 363 406 enum token nn; … … 367 410 return 0; /* missing expression */ 368 411 if (n == LPAREN) { 369 if ((nn = t_lex( *++t_wp)) == RPAREN)412 if ((nn = t_lex(pThis, *++(pThis->t_wp))) == RPAREN) 370 413 return 0; /* missing expression */ 371 res = oexpr( nn);372 if (res != -42 && t_lex( *++t_wp) != RPAREN)373 return syntax( NULL, "closing paren expected");414 res = oexpr(pThis, nn); 415 if (res != -42 && t_lex(pThis, *++(pThis->t_wp)) != RPAREN) 416 return syntax(pThis, NULL, "closing paren expected"); 374 417 return res; 375 418 } 376 if ( t_wp_op &&t_wp_op->op_type == UNOP) {419 if (pThis->t_wp_op && pThis->t_wp_op->op_type == UNOP) { 377 420 /* unary expression */ 378 if (*++ t_wp== NULL)379 return syntax( t_wp_op->op_text, "argument expected");421 if (*++(pThis->t_wp) == NULL) 422 return syntax(pThis, pThis->t_wp_op->op_text, "argument expected"); 380 423 switch (n) { 381 424 case STREZ: 382 return strlen(* t_wp) == 0;425 return strlen(*pThis->t_wp) == 0; 383 426 case STRNZ: 384 return strlen(* t_wp) != 0;427 return strlen(*pThis->t_wp) != 0; 385 428 case FILTT: 386 return isatty(getn( *t_wp));429 return isatty(getn(pThis, *pThis->t_wp)); 387 430 default: 388 return filstat(* t_wp, n);431 return filstat(*pThis->t_wp, n); 389 432 } 390 433 } 391 434 392 if (t_lex( t_wp[1]), t_wp_op &&t_wp_op->op_type == BINOP) {393 return binop( );394 } 395 396 return strlen(* t_wp) > 0;397 } 398 399 static int 400 binop( void)435 if (t_lex(pThis, pThis->t_wp[1]), pThis->t_wp_op && pThis->t_wp_op->op_type == BINOP) { 436 return binop(pThis); 437 } 438 439 return strlen(*pThis->t_wp) > 0; 440 } 441 442 static int 443 binop(PTESTINSTANCE pThis) 401 444 { 402 445 const char *opnd1, *opnd2; 403 446 struct t_op const *op; 404 447 405 opnd1 = * t_wp;406 (void) t_lex( *++t_wp);407 op = t_wp_op;408 409 if ((opnd2 = *++ t_wp) == NULL)410 return syntax( op->op_text, "argument expected");448 opnd1 = *pThis->t_wp; 449 (void) t_lex(pThis, *++(pThis->t_wp)); 450 op = pThis->t_wp_op; 451 452 if ((opnd2 = *++(pThis->t_wp)) == NULL) 453 return syntax(pThis, op->op_text, "argument expected"); 411 454 412 455 switch (op->op_num) { … … 420 463 return strcmp(opnd1, opnd2) > 0; 421 464 case INTEQ: 422 return getn( opnd1) == getn(opnd2);465 return getn(pThis, opnd1) == getn(pThis, opnd2); 423 466 case INTNE: 424 return getn( opnd1) != getn(opnd2);467 return getn(pThis, opnd1) != getn(pThis, opnd2); 425 468 case INTGE: 426 return getn( opnd1) >= getn(opnd2);469 return getn(pThis, opnd1) >= getn(pThis, opnd2); 427 470 case INTGT: 428 return getn( opnd1) > getn(opnd2);471 return getn(pThis, opnd1) > getn(pThis, opnd2); 429 472 case INTLE: 430 return getn( opnd1) <= getn(opnd2);473 return getn(pThis, opnd1) <= getn(pThis, opnd2); 431 474 case INTLT: 432 return getn( opnd1) < getn(opnd2);475 return getn(pThis, opnd1) < getn(pThis, opnd2); 433 476 case FILNT: 434 477 return newerf(opnd1, opnd2); … … 714 757 return NULL; 715 758 if (s[2] == '\0') 716 return bsearch(s + 1, mop2, __arraycount(mop2), 717 sizeof(*mop2), compare1); 759 return bsearch(s + 1, mop2, __arraycount(mop2), sizeof(*mop2), compare1); 718 760 else if (s[3] != '\0') 719 761 return NULL; 720 762 else 721 return bsearch(s + 1, mop3, __arraycount(mop3), 722 sizeof(*mop3), compare2); 763 return bsearch(s + 1, mop3, __arraycount(mop3), sizeof(*mop3), compare2); 723 764 } else { 724 765 if (s[1] == '\0') 725 return bsearch(s, cop, __arraycount(cop), sizeof(*cop), 726 compare1); 766 return bsearch(s, cop, __arraycount(cop), sizeof(*cop), compare1); 727 767 else if (strcmp(s, cop2[0].op_text) == 0) 728 768 return cop2; … … 733 773 734 774 static enum token 735 t_lex( char *s)775 t_lex(PTESTINSTANCE pThis, char *s) 736 776 { 737 777 struct t_op const *op; 738 778 739 779 if (s == NULL) { 740 t_wp_op = NULL;780 pThis->t_wp_op = NULL; 741 781 return EOI; 742 782 } 743 783 744 784 if ((op = findop(s)) != NULL) { 745 if (!((op->op_type == UNOP && isoperand( )) ||746 (op->op_num == LPAREN && *( t_wp+1) == 0))) {747 t_wp_op = op;785 if (!((op->op_type == UNOP && isoperand(pThis)) || 786 (op->op_num == LPAREN && *(pThis->t_wp+1) == 0))) { 787 pThis->t_wp_op = op; 748 788 return op->op_num; 749 789 } 750 790 } 751 t_wp_op = NULL;791 pThis->t_wp_op = NULL; 752 792 return OPERAND; 753 793 } 754 794 755 795 static int 756 isoperand( void)796 isoperand(PTESTINSTANCE pThis) 757 797 { 758 798 struct t_op const *op; 759 799 char *s, *t; 760 800 761 if ((s = *( t_wp+1)) == 0)801 if ((s = *(pThis->t_wp+1)) == 0) 762 802 return 1; 763 if ((t = *( t_wp+2)) == 0)803 if ((t = *(pThis->t_wp+2)) == 0) 764 804 return 0; 765 805 if ((op = findop(s)) != NULL) … … 770 810 /* atoi with error detection */ 771 811 static int 772 getn( const char *s)812 getn(PTESTINSTANCE pThis, const char *s) 773 813 { 774 814 char *p; … … 779 819 780 820 if (errno != 0) 781 return errx( -42, "%s: out of range", s);821 return errx(pThis->pCtx, -42, "%s: out of range", s); 782 822 783 823 while (isspace((unsigned char)*p)) … … 785 825 786 826 if (*p) 787 return errx( -42, "%s: bad number", s);827 return errx(pThis->pCtx, -42, "%s: bad number", s); 788 828 789 829 return (int) r; … … 822 862 823 863 static int 824 usage(const char *argv0) 825 { 826 fprintf(stdout, 827 "usage: %s expression [-- <prog> [args]]\n", argv0); 864 usage(PKMKBUILTINCTX pCtx, int fIsErr) 865 { 866 kmk_builtin_ctx_printf(pCtx, fIsErr, "usage: %s expression [-- <prog> [args]]\n", pCtx->pszProgName); 828 867 return 0; /* only used in --help. */ 829 868 } 869
Note:
See TracChangeset
for help on using the changeset viewer.