1 2 /* 3 4 Test to see if a particular fix should be applied to a header file. 5 6 Copyright (C) 1997, 1998, 1999, 2000, 2001, 2003, 2004 7 Free Software Foundation, Inc. 8 9 = = = = = = = = = = = = = = = = = = = = = = = = = 10 11 NOTE TO DEVELOPERS 12 13 The routines you write here must work closely with fixincl.c. 14 15 Here are the rules: 16 17 1. Every test procedure name must be suffixed with "_fix". 18 These routines will be referenced from inclhack.def, sans the suffix. 19 20 2. Use the "FIX_PROC_HEAD()" macro _with_ the "_fix" suffix 21 (I cannot use the ## magic from ANSI C) for defining your entry point. 22 23 3. Put your test name into the FIXUP_TABLE. 24 25 4. Do not read anything from stdin. It is closed. 26 27 5. Write to stderr only in the event of a reportable error 28 In such an event, call "exit (EXIT_FAILURE)". 29 30 6. You have access to the fixDescList entry for the fix in question. 31 This may be useful, for example, if there are interesting strings 32 or pre-compiled regular expressions stored there. 33 34 = = = = = = = = = = = = = = = = = = = = = = = = = 35 36 This file is part of GCC. 37 38 GCC is free software; you can redistribute it and/or modify 39 it under the terms of the GNU General Public License as published by 40 the Free Software Foundation; either version 2, or (at your option) 41 any later version. 42 43 GCC is distributed in the hope that it will be useful, 44 but WITHOUT ANY WARRANTY; without even the implied warranty of 45 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 46 GNU General Public License for more details. 47 48 You should have received a copy of the GNU General Public License 49 along with GCC; see the file COPYING. If not, write to 50 the Free Software Foundation, 51 Franklin Street, Fifth Floor, 51 Boston, MA 02110-1301, USA. */ 52 53 #include "fixlib.h" 54 #define GTYPE_SE_CT 1 55 56 #ifdef SEPARATE_FIX_PROC 57 #include "fixincl.x" 58 #endif 59 60 tSCC zNeedsArg[] = "fixincl error: `%s' needs %s argument (c_fix_arg[%d])\n"; 61 62 typedef void t_fix_proc (const char *, const char *, tFixDesc *) ; 63 typedef struct { 64 const char* fix_name; 65 t_fix_proc* fix_proc; 66 } fix_entry_t; 67 68 #define FIXUP_TABLE \ 69 _FT_( "char_macro_def", char_macro_def_fix ) \ 70 _FT_( "char_macro_use", char_macro_use_fix ) \ 71 _FT_( "format", format_fix ) \ 72 _FT_( "machine_name", machine_name_fix ) \ 73 _FT_( "wrap", wrap_fix ) \ 74 _FT_( "gnu_type", gnu_type_fix ) 75 76 77 #define FIX_PROC_HEAD( fix ) \ 78 static void fix (const char* filname ATTRIBUTE_UNUSED , \ 79 const char* text ATTRIBUTE_UNUSED , \ 80 tFixDesc* p_fixd ATTRIBUTE_UNUSED ) 81 82 #ifdef NEED_PRINT_QUOTE 83 /* 84 * Skip over a quoted string. Single quote strings may 85 * contain multiple characters if the first character is 86 * a backslash. Especially a backslash followed by octal digits. 87 * We are not doing a correctness syntax check here. 88 */ 89 static char* 90 print_quote(char q, char* text ) 91 { 92 fputc( q, stdout ); 93 94 for (;;) 95 { 96 char ch = *(text++); 97 fputc( ch, stdout ); 98 99 switch (ch) 100 { 101 case '\\': 102 if (*text == NUL) 103 goto quote_done; 104 105 fputc( *(text++), stdout ); 106 break; 107 108 case '"': 109 case '\'': 110 if (ch != q) 111 break; 112 /*FALLTHROUGH*/ 113 114 case '\n': 115 case NUL: 116 goto quote_done; 117 } 118 } quote_done:; 119 120 return text; 121 } 122 #endif /* NEED_PRINT_QUOTE */ 123 124 125 /* 126 * Emit the GNU standard type wrapped up in such a way that 127 * this thing can be encountered countless times during a compile 128 * and not cause even a warning. 129 */ 130 static const char* 131 emit_gnu_type (const char* text, regmatch_t* rm ) 132 { 133 char z_TYPE[ 64 ]; 134 char z_type[ 64 ]; 135 136 fwrite (text, rm[0].rm_so, 1, stdout); 137 138 { 139 const char* ps = text + rm[1].rm_so; 140 const char* pe = text + rm[1].rm_eo; 141 char* pd = z_type; 142 char* pD = z_TYPE; 143 144 while (ps < pe) 145 *(pD++) = TOUPPER( *(pd++) = *(ps++) ); 146 147 *pD = *pd = NUL; 148 } 149 150 /* 151 * Now print out the reformed typedef, 152 * with a C++ guard for WCHAR 153 */ 154 { 155 tSCC z_fmt[] = "\ 156 #if !defined(_GCC_%s_T)%s\n\ 157 #define _GCC_%s_T\n\ 158 typedef __%s_TYPE__ %s_t;\n\ 159 #endif\n"; 160 161 const char *const pz_guard = (strcmp (z_type, "wchar") == 0) 162 ? " && ! defined(__cplusplus)" : ""; 163 164 printf (z_fmt, z_TYPE, pz_guard, z_TYPE, z_TYPE, z_type); 165 } 166 167 return text += rm[0].rm_eo; 168 } 169 170 171 /* 172 * Copy the `format' string to std out, replacing `%n' expressions 173 * with the matched text from a regular expression evaluation. 174 * Doubled '%' characters will be replaced with a single copy. 175 * '%' characters in other contexts and all other characters are 176 * copied out verbatim. 177 */ 178 static void 179 format_write (tCC* format, tCC* text, regmatch_t av[] ) 180 { 181 int c; 182 183 while ((c = (unsigned)*(format++)) != NUL) { 184 185 if (c != '%') 186 { 187 putchar(c); 188 continue; 189 } 190 191 c = (unsigned)*(format++); 192 193 /* 194 * IF the character following a '%' is not a digit, 195 * THEN we will always emit a '%' and we may or may 196 * not emit the following character. We will end on 197 * a NUL and we will emit only one of a pair of '%'. 198 */ 199 if (! ISDIGIT ( c )) 200 { 201 putchar( '%' ); 202 switch (c) { 203 case NUL: 204 return; 205 case '%': 206 break; 207 default: 208 putchar(c); 209 } 210 } 211 212 /* 213 * Emit the matched subexpression numbered 'c'. 214 * IF, of course, there was such a match... 215 */ 216 else { 217 regmatch_t* pRM = av + (c - (unsigned)'0'); 218 size_t len; 219 220 if (pRM->rm_so < 0) 221 continue; 222 223 len = pRM->rm_eo - pRM->rm_so; 224 if (len > 0) 225 fwrite(text + pRM->rm_so, len, 1, stdout); 226 } 227 } 228 } 229 230 231 /* 232 * Search for multiple copies of a regular expression. Each block 233 * of matched text is replaced with the format string, as described 234 * above in `format_write'. 235 */ 236 FIX_PROC_HEAD( format_fix ) 237 { 238 tCC* pz_pat = p_fixd->patch_args[2]; 239 tCC* pz_fmt = p_fixd->patch_args[1]; 240 regex_t re; 241 regmatch_t rm[10]; 242 IGNORE_ARG(filname); 243 244 /* 245 * We must have a format 246 */ 247 if (pz_fmt == (tCC*)NULL) 248 { 249 fprintf( stderr, zNeedsArg, p_fixd->fix_name, "replacement format", 0 ); 250 exit (EXIT_BROKEN); 251 } 252 253 /* 254 * IF we don't have a search text, then go find the first 255 * regular expression among the tests. 256 */ 257 if (pz_pat == (tCC*)NULL) 258 { 259 tTestDesc* pTD = p_fixd->p_test_desc; 260 int ct = p_fixd->test_ct; 261 for (;;) 262 { 263 if (ct-- <= 0) 264 { 265 fprintf( stderr, zNeedsArg, p_fixd->fix_name, "search text", 1 ); 266 exit (EXIT_BROKEN); 267 } 268 269 if (pTD->type == TT_EGREP) 270 { 271 pz_pat = pTD->pz_test_text; 272 break; 273 } 274 275 pTD++; 276 } 277 } 278 279 /* 280 * Replace every copy of the text we find 281 */ 282 compile_re (pz_pat, &re, 1, "format search-text", "format_fix" ); 283 while (xregexec (&re, text, 10, rm, 0) == 0) 284 { 285 fwrite( text, rm[0].rm_so, 1, stdout ); 286 format_write( pz_fmt, text, rm ); 287 text += rm[0].rm_eo; 288 } 289 290 /* 291 * Dump out the rest of the file 292 */ 293 fputs (text, stdout); 294 } 295 296 297 /* Scan the input file for all occurrences of text like this: 298 299 #define TIOCCONS _IO(T, 12) 300 301 and change them to read like this: 302 303 #define TIOCCONS _IO('T', 12) 304 305 which is the required syntax per the C standard. (The definition of 306 _IO also has to be tweaked - see below.) 'IO' is actually whatever you 307 provide as the `c_fix_arg' argument. */ 308 309 FIX_PROC_HEAD( char_macro_use_fix ) 310 { 311 /* This regexp looks for a traditional-syntax #define (# in column 1) 312 of an object-like macro. */ 313 static const char pat[] = 314 "^#[ \t]*define[ \t]+[_A-Za-z][_A-Za-z0-9]*[ \t]+"; 315 static regex_t re; 316 317 const char* str = p_fixd->patch_args[1]; 318 regmatch_t rm[1]; 319 const char *p, *limit; 320 size_t len; 321 IGNORE_ARG(filname); 322 323 if (str == NULL) 324 { 325 fprintf (stderr, zNeedsArg, p_fixd->fix_name, "ioctl type", 0); 326 exit (EXIT_BROKEN); 327 } 328 329 len = strlen (str); 330 compile_re (pat, &re, 1, "macro pattern", "char_macro_use_fix"); 331 332 for (p = text; 333 xregexec (&re, p, 1, rm, 0) == 0; 334 p = limit + 1) 335 { 336 /* p + rm[0].rm_eo is the first character of the macro replacement. 337 Find the end of the macro replacement, and the STR we were 338 sent to look for within the replacement. */ 339 p += rm[0].rm_eo; 340 limit = p - 1; 341 do 342 { 343 limit = strchr (limit + 1, '\n'); 344 if (!limit) 345 goto done; 346 } 347 while (limit[-1] == '\\'); 348 349 do 350 { 351 if (*p == str[0] && !strncmp (p+1, str+1, len-1)) 352 goto found; 353 } 354 while (++p < limit - len); 355 /* Hit end of line. */ 356 continue; 357 358 found: 359 /* Found STR on this line. If the macro needs fixing, 360 the next few chars will be whitespace or uppercase, 361 then an open paren, then a single letter. */ 362 while ((ISSPACE (*p) || ISUPPER (*p)) && p < limit) p++; 363 if (*p++ != '(') 364 continue; 365 if (!ISALPHA (*p)) 366 continue; 367 if (ISIDNUM (p[1])) 368 continue; 369 370 /* Splat all preceding text into the output buffer, 371 quote the character at p, then proceed. */ 372 fwrite (text, 1, p - text, stdout); 373 putchar ('\''); 374 putchar (*p); 375 putchar ('\''); 376 text = p + 1; 377 } 378 done: 379 fputs (text, stdout); 380 } 381 382 383 /* Scan the input file for all occurrences of text like this: 384 385 #define xxxIOxx(x, y) (....'x'<<16....) 386 387 and change them to read like this: 388 389 #define xxxIOxx(x, y) (....x<<16....) 390 391 which is the required syntax per the C standard. (The uses of _IO 392 also has to be tweaked - see above.) 'IO' is actually whatever 393 you provide as the `c_fix_arg' argument. */ 394 FIX_PROC_HEAD( char_macro_def_fix ) 395 { 396 /* This regexp looks for any traditional-syntax #define (# in column 1). */ 397 static const char pat[] = 398 "^#[ \t]*define[ \t]+"; 399 static regex_t re; 400 401 const char* str = p_fixd->patch_args[1]; 402 regmatch_t rm[1]; 403 const char *p, *limit; 404 char arg; 405 size_t len; 406 IGNORE_ARG(filname); 407 408 if (str == NULL) 409 { 410 fprintf (stderr, zNeedsArg, p_fixd->fix_name, "ioctl type", 0); 411 exit (EXIT_BROKEN); 412 } 413 414 len = strlen (str); 415 compile_re (pat, &re, 1, "macro pattern", "fix_char_macro_defines"); 416 417 for (p = text; 418 xregexec (&re, p, 1, rm, 0) == 0; 419 p = limit + 1) 420 { 421 /* p + rm[0].rm_eo is the first character of the macro name. 422 Find the end of the macro replacement, and the STR we were 423 sent to look for within the name. */ 424 p += rm[0].rm_eo; 425 limit = p - 1; 426 do 427 { 428 limit = strchr (limit + 1, '\n'); 429 if (!limit) 430 goto done; 431 } 432 while (limit[-1] == '\\'); 433 434 do 435 { 436 if (*p == str[0] && !strncmp (p+1, str+1, len-1)) 437 goto found; 438 p++; 439 } 440 while (ISIDNUM (*p)); 441 /* Hit end of macro name without finding the string. */ 442 continue; 443 444 found: 445 /* Found STR in this macro name. If the macro needs fixing, 446 there may be a few uppercase letters, then there will be an 447 open paren with _no_ intervening whitespace, and then a 448 single letter. */ 449 while (ISUPPER (*p) && p < limit) p++; 450 if (*p++ != '(') 451 continue; 452 if (!ISALPHA (*p)) 453 continue; 454 if (ISIDNUM (p[1])) 455 continue; 456 457 /* The character at P is the one to look for in the following 458 text. */ 459 arg = *p; 460 p += 2; 461 462 while (p < limit) 463 { 464 if (p[-1] == '\'' && p[0] == arg && p[1] == '\'') 465 { 466 /* Remove the quotes from this use of ARG. */ 467 p--; 468 fwrite (text, 1, p - text, stdout); 469 putchar (arg); 470 p += 3; 471 text = p; 472 } 473 else 474 p++; 475 } 476 } 477 done: 478 fputs (text, stdout); 479 } 480 481 /* Fix for machine name #ifdefs that are not in the namespace reserved 482 by the C standard. They won't be defined if compiling with -ansi, 483 and the headers will break. We go to some trouble to only change 484 #ifdefs where the macro is defined by GCC in non-ansi mode; this 485 minimizes the number of headers touched. */ 486 487 #define SCRATCHSZ 64 /* hopefully long enough */ 488 489 FIX_PROC_HEAD( machine_name_fix ) 490 { 491 regmatch_t match[2]; 492 const char *line, *base, *limit, *p, *q; 493 regex_t *label_re, *name_re; 494 char scratch[SCRATCHSZ]; 495 size_t len; 496 IGNORE_ARG(filname); 497 IGNORE_ARG(p_fixd); 498 499 if (!mn_get_regexps (&label_re, &name_re, "machine_name_fix")) 500 { 501 fputs( "The target machine has no needed machine name fixes\n", stderr ); 502 goto done; 503 } 504 505 scratch[0] = '_'; 506 scratch[1] = '_'; 507 508 for (base = text; 509 xregexec (label_re, base, 2, match, 0) == 0; 510 base = limit) 511 { 512 base += match[0].rm_eo; 513 /* We're looking at an #if or #ifdef. Scan forward for the 514 next non-escaped newline. */ 515 line = limit = base; 516 do 517 { 518 limit++; 519 limit = strchr (limit, '\n'); 520 if (!limit) 521 goto done; 522 } 523 while (limit[-1] == '\\'); 524 525 /* If the 'name_pat' matches in between base and limit, we have 526 a bogon. It is not worth the hassle of excluding comments 527 because comments on #if/#ifdef lines are rare, and strings on 528 such lines are illegal. 529 530 REG_NOTBOL means 'base' is not at the beginning of a line, which 531 shouldn't matter since the name_re has no ^ anchor, but let's 532 be accurate anyway. */ 533 534 for (;;) 535 { 536 again: 537 if (base == limit) 538 break; 539 540 if (xregexec (name_re, base, 1, match, REG_NOTBOL)) 541 goto done; /* No remaining match in this file */ 542 543 /* Match; is it on the line? */ 544 if (match[0].rm_eo > limit - base) 545 break; 546 547 p = base + match[0].rm_so; 548 base += match[0].rm_eo; 549 550 /* One more test: if on the same line we have the same string 551 with the appropriate underscores, then leave it alone. 552 We want exactly two leading and trailing underscores. */ 553 if (*p == '_') 554 { 555 len = base - p - ((*base == '_') ? 2 : 1); 556 q = p + 1; 557 } 558 else 559 { 560 len = base - p - ((*base == '_') ? 1 : 0); 561 q = p; 562 } 563 if (len + 4 > SCRATCHSZ) 564 abort (); 565 memcpy (&scratch[2], q, len); 566 len += 2; 567 scratch[len++] = '_'; 568 scratch[len++] = '_'; 569 570 for (q = line; q <= limit - len; q++) 571 if (*q == '_' && !strncmp (q, scratch, len)) 572 goto again; 573 574 fwrite (text, 1, p - text, stdout); 575 fwrite (scratch, 1, len, stdout); 576 577 text = base; 578 } 579 } 580 done: 581 fputs (text, stdout); 582 } 583 584 585 FIX_PROC_HEAD( wrap_fix ) 586 { 587 tSCC z_no_wrap_pat[] = "^#if.*__need_"; 588 static regex_t no_wrapping_re; /* assume zeroed data */ 589 590 tCC* pz_name = NULL; 591 592 if (no_wrapping_re.allocated == 0) 593 compile_re( z_no_wrap_pat, &no_wrapping_re, 0, "no-wrap pattern", 594 "wrap-fix" ); 595 596 /* 597 * IF we do *not* match the no-wrap re, then we have a double negative. 598 * A double negative means YES. 599 */ 600 if (xregexec( &no_wrapping_re, text, 0, NULL, 0 ) != 0) 601 { 602 /* 603 * A single file can get wrapped more than once by different fixes. 604 * A single fix can wrap multiple files. Therefore, guard with 605 * *both* the fix name and the file name. 606 */ 607 size_t ln = strlen( filname ) + strlen( p_fixd->fix_name ) + 14; 608 char* pz = XNEWVEC (char, ln); 609 pz_name = pz; 610 sprintf( pz, "FIXINC_WRAP_%s-%s", filname, p_fixd->fix_name ); 611 612 for (pz += 12; 1; pz++) { 613 char ch = *pz; 614 615 if (ch == NUL) 616 break; 617 618 if (! ISALNUM( ch )) { 619 *pz = '_'; 620 } 621 else { 622 *pz = TOUPPER( ch ); 623 } 624 } 625 626 printf( "#ifndef %s\n", pz_name ); 627 printf( "#define %s 1\n\n", pz_name ); 628 } 629 630 if (p_fixd->patch_args[1] == (tCC*)NULL) 631 fputs( text, stdout ); 632 633 else { 634 fputs( p_fixd->patch_args[1], stdout ); 635 fputs( text, stdout ); 636 if (p_fixd->patch_args[2] != (tCC*)NULL) 637 fputs( p_fixd->patch_args[2], stdout ); 638 } 639 640 if (pz_name != NULL) { 641 printf( "\n#endif /* %s */\n", pz_name ); 642 free( (void*)pz_name ); 643 } 644 } 645 646 647 /* 648 * Search for multiple copies of a regular expression. Each block 649 * of matched text is replaced with the format string, as described 650 * above in `format_write'. 651 */ 652 FIX_PROC_HEAD( gnu_type_fix ) 653 { 654 const char* pz_pat; 655 regex_t re; 656 regmatch_t rm[GTYPE_SE_CT+1]; 657 IGNORE_ARG(filname); 658 659 { 660 tTestDesc* pTD = p_fixd->p_test_desc; 661 int ct = p_fixd->test_ct; 662 for (;;) 663 { 664 if (ct-- <= 0) 665 { 666 fprintf (stderr, zNeedsArg, p_fixd->fix_name, "search text", 1); 667 exit (EXIT_BROKEN); 668 } 669 670 if (pTD->type == TT_EGREP) 671 { 672 pz_pat = pTD->pz_test_text; 673 break; 674 } 675 676 pTD++; 677 } 678 } 679 680 compile_re (pz_pat, &re, 1, "gnu type typedef", "gnu_type_fix"); 681 682 while (xregexec (&re, text, GTYPE_SE_CT+1, rm, 0) == 0) 683 { 684 text = emit_gnu_type (text, rm); 685 } 686 687 /* 688 * Dump out the rest of the file 689 */ 690 fputs (text, stdout); 691 } 692 693 694 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = 695 696 test for fix selector 697 698 THIS IS THE ONLY EXPORTED ROUTINE 699 700 */ 701 void 702 apply_fix( tFixDesc* p_fixd, tCC* filname ) 703 { 704 #define _FT_(n,p) { n, p }, 705 static fix_entry_t fix_table[] = { FIXUP_TABLE { NULL, NULL }}; 706 #undef _FT_ 707 #define FIX_TABLE_CT (ARRAY_SIZE (fix_table)-1) 708 709 tCC* fixname = p_fixd->patch_args[0]; 710 char* buf; 711 int ct = FIX_TABLE_CT; 712 fix_entry_t* pfe = fix_table; 713 714 for (;;) 715 { 716 if (strcmp (pfe->fix_name, fixname) == 0) 717 break; 718 if (--ct <= 0) 719 { 720 fprintf (stderr, "fixincl error: the `%s' fix is unknown\n", 721 fixname ); 722 exit (EXIT_BROKEN); 723 } 724 pfe++; 725 } 726 727 buf = load_file_data (stdin); 728 (*pfe->fix_proc)( filname, buf, p_fixd ); 729 } 730 731 #ifdef SEPARATE_FIX_PROC 732 tSCC z_usage[] = 733 "USAGE: applyfix <fix-name> <file-to-fix> <file-source> <file-destination>\n"; 734 tSCC z_reopen[] = 735 "FS error %d (%s) reopening %s as std%s\n"; 736 737 int 738 main( int argc, char** argv ) 739 { 740 tFixDesc* pFix; 741 char* pz_tmptmp; 742 char* pz_tmp_base; 743 char* pz_tmp_dot; 744 745 if (argc != 5) 746 { 747 usage_failure: 748 fputs (z_usage, stderr); 749 return EXIT_FAILURE; 750 } 751 752 initialize_opts (); 753 754 { 755 char* pz = argv[1]; 756 long idx; 757 758 if (! ISDIGIT ( *pz )) 759 goto usage_failure; 760 761 idx = strtol (pz, &pz, 10); 762 if ((*pz != NUL) || ((unsigned)idx >= FIX_COUNT)) 763 goto usage_failure; 764 pFix = fixDescList + idx; 765 } 766 767 if (freopen (argv[3], "r", stdin) != stdin) 768 { 769 fprintf (stderr, z_reopen, errno, strerror( errno ), argv[3], "in"); 770 return EXIT_FAILURE; 771 } 772 773 pz_tmptmp = XNEWVEC (char, strlen (argv[4]) + 5); 774 strcpy( pz_tmptmp, argv[4] ); 775 776 /* Don't lose because "12345678" and "12345678X" map to the same 777 file under DOS restricted 8+3 file namespace. Note that DOS 778 doesn't allow more than one dot in the trunk of a file name. */ 779 pz_tmp_base = basename( pz_tmptmp ); 780 pz_tmp_dot = strchr( pz_tmp_base, '.' ); 781 #ifdef _PC_NAME_MAX 782 if (pathconf( pz_tmptmp, _PC_NAME_MAX ) <= 12 /* is this DOS or Windows9X? */ 783 && pz_tmp_dot != (char*)NULL) 784 strcpy (pz_tmp_dot+1, "X"); /* nuke the original extension */ 785 else 786 #endif /* _PC_NAME_MAX */ 787 strcat (pz_tmptmp, ".X"); 788 if (freopen (pz_tmptmp, "w", stdout) != stdout) 789 { 790 fprintf (stderr, z_reopen, errno, strerror( errno ), pz_tmptmp, "out"); 791 return EXIT_FAILURE; 792 } 793 794 apply_fix (pFix, argv[1]); 795 fclose (stdout); 796 fclose (stdin); 797 unlink (argv[4]); 798 if (rename (pz_tmptmp, argv[4]) != 0) 799 { 800 fprintf (stderr, "error %d (%s) renaming %s to %s\n", errno, 801 strerror( errno ), pz_tmptmp, argv[4]); 802 return EXIT_FAILURE; 803 } 804 805 return EXIT_SUCCESS; 806 } 807 #endif 808