xref: /llvm-project/compiler-rt/test/BlocksRuntime/testfilerunner.m (revision 2946cd701067404b99c39fb29dc9c74bd7193eb3)
18c1441f8SAlexey Samsonov//
2*2946cd70SChandler Carruth// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3*2946cd70SChandler Carruth// See https://llvm.org/LICENSE.txt for license information.
4*2946cd70SChandler Carruth// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
58c1441f8SAlexey Samsonov
68c1441f8SAlexey Samsonov//
78c1441f8SAlexey Samsonov//  testfilerunner.m
88c1441f8SAlexey Samsonov//  testObjects
98c1441f8SAlexey Samsonov//
108c1441f8SAlexey Samsonov//  Created by Blaine Garst on 9/24/08.
118c1441f8SAlexey Samsonov//
128c1441f8SAlexey Samsonov
138c1441f8SAlexey Samsonov#import "testfilerunner.h"
148c1441f8SAlexey Samsonov#import <Foundation/Foundation.h>
158c1441f8SAlexey Samsonov#include <stdio.h>
168c1441f8SAlexey Samsonov#include <unistd.h>
178c1441f8SAlexey Samsonov#include <fcntl.h>
188c1441f8SAlexey Samsonov#include <string.h>
198c1441f8SAlexey Samsonov#include <stdlib.h>
208c1441f8SAlexey Samsonov#include <stdbool.h>
218c1441f8SAlexey Samsonov
228c1441f8SAlexey Samsonovbool Everything = false; // do it also with 3 levels of optimization
238c1441f8SAlexey Samsonovbool DoClang = false;
248c1441f8SAlexey Samsonov
258c1441f8SAlexey Samsonovstatic bool isDirectory(char *path);
268c1441f8SAlexey Samsonovstatic bool isExecutable(char *path);
278c1441f8SAlexey Samsonovstatic bool isYounger(char *source, char *binary);
288c1441f8SAlexey Samsonovstatic bool readErrorFile(char *buffer, const char *from);
298c1441f8SAlexey Samsonov
308c1441f8SAlexey Samsonov__strong char *gcstrcpy2(__strong const char *arg, char *endp) {
318c1441f8SAlexey Samsonov    unsigned size = endp - arg + 1;
328c1441f8SAlexey Samsonov    __strong char *result = NSAllocateCollectable(size, 0);
338c1441f8SAlexey Samsonov    strncpy(result, arg, size);
348c1441f8SAlexey Samsonov    result[size-1] = 0;
358c1441f8SAlexey Samsonov    return result;
368c1441f8SAlexey Samsonov}
378c1441f8SAlexey Samsonov__strong char *gcstrcpy1(__strong char *arg) {
388c1441f8SAlexey Samsonov    unsigned size = strlen(arg) + 1;
398c1441f8SAlexey Samsonov    __strong char *result = NSAllocateCollectable(size, 0);
408c1441f8SAlexey Samsonov    strncpy(result, arg, size);
418c1441f8SAlexey Samsonov    result[size-1] = 0;
428c1441f8SAlexey Samsonov    return result;
438c1441f8SAlexey Samsonov}
448c1441f8SAlexey Samsonov
458c1441f8SAlexey Samsonov@implementation TestFileExe
468c1441f8SAlexey Samsonov
478c1441f8SAlexey Samsonov@synthesize options, compileLine, shouldFail, binaryName, sourceName;
488c1441f8SAlexey Samsonov@synthesize generator;
498c1441f8SAlexey Samsonov@synthesize libraryPath, frameworkPath;
508c1441f8SAlexey Samsonov
518c1441f8SAlexey Samsonov- (NSString *)description {
528c1441f8SAlexey Samsonov    NSMutableString *result = [NSMutableString new];
538c1441f8SAlexey Samsonov    if (shouldFail) [result appendString:@"fail"];
548c1441f8SAlexey Samsonov    for (id x  in compileLine) {
558c1441f8SAlexey Samsonov        [result appendString:[NSString stringWithFormat:@" %s", (char *)x]];
568c1441f8SAlexey Samsonov    }
578c1441f8SAlexey Samsonov    return result;
588c1441f8SAlexey Samsonov}
598c1441f8SAlexey Samsonov
608c1441f8SAlexey Samsonov- (__strong char *)radar {
618c1441f8SAlexey Samsonov    return generator.radar;
628c1441f8SAlexey Samsonov}
638c1441f8SAlexey Samsonov
648c1441f8SAlexey Samsonov- (bool) compileUnlessExists:(bool)skip {
658c1441f8SAlexey Samsonov    if (shouldFail) {
668c1441f8SAlexey Samsonov        printf("don't use this to compile anymore!\n");
678c1441f8SAlexey Samsonov        return false;
688c1441f8SAlexey Samsonov    }
698c1441f8SAlexey Samsonov    if (skip && isExecutable(binaryName) && !isYounger(sourceName, binaryName)) return true;
708c1441f8SAlexey Samsonov    int argc = [compileLine count];
718c1441f8SAlexey Samsonov    char *argv[argc+1];
728c1441f8SAlexey Samsonov    for (int i = 0; i < argc; ++i)
738c1441f8SAlexey Samsonov        argv[i] = (char *)[compileLine pointerAtIndex:i];
748c1441f8SAlexey Samsonov    argv[argc] = NULL;
758c1441f8SAlexey Samsonov    pid_t child = fork();
768c1441f8SAlexey Samsonov    if (child == 0) {
778c1441f8SAlexey Samsonov        execv(argv[0], argv);
788c1441f8SAlexey Samsonov        exit(10); // shouldn't happen
798c1441f8SAlexey Samsonov    }
808c1441f8SAlexey Samsonov    if (child < 0) {
818c1441f8SAlexey Samsonov        printf("fork failed\n");
828c1441f8SAlexey Samsonov        return false;
838c1441f8SAlexey Samsonov    }
848c1441f8SAlexey Samsonov    int status = 0;
858c1441f8SAlexey Samsonov    pid_t deadchild = wait(&status);
868c1441f8SAlexey Samsonov    if (deadchild != child) {
878c1441f8SAlexey Samsonov        printf("wait got %d instead of %d\n", deadchild, child);
888c1441f8SAlexey Samsonov        exit(1);
898c1441f8SAlexey Samsonov    }
908c1441f8SAlexey Samsonov    if (WEXITSTATUS(status) == 0) {
918c1441f8SAlexey Samsonov        return true;
928c1441f8SAlexey Samsonov    }
938c1441f8SAlexey Samsonov    printf("run failed\n");
948c1441f8SAlexey Samsonov    return false;
958c1441f8SAlexey Samsonov}
968c1441f8SAlexey Samsonov
978c1441f8SAlexey Samsonovbool lookforIn(char *lookfor, const char *format, pid_t child) {
988c1441f8SAlexey Samsonov    char buffer[512];
998c1441f8SAlexey Samsonov    char got[512];
1008c1441f8SAlexey Samsonov    sprintf(buffer, format, child);
1018c1441f8SAlexey Samsonov    bool gotOutput = readErrorFile(got, buffer);
1028c1441f8SAlexey Samsonov    if (!gotOutput) {
1038c1441f8SAlexey Samsonov        printf("**** didn't get an output file %s to analyze!!??\n", buffer);
1048c1441f8SAlexey Samsonov        return false;
1058c1441f8SAlexey Samsonov    }
1068c1441f8SAlexey Samsonov    char *where = strstr(got, lookfor);
1078c1441f8SAlexey Samsonov    if (!where) {
1088c1441f8SAlexey Samsonov        printf("didn't find '%s' in output file %s\n", lookfor, buffer);
1098c1441f8SAlexey Samsonov        return false;
1108c1441f8SAlexey Samsonov    }
1118c1441f8SAlexey Samsonov    unlink(buffer);
1128c1441f8SAlexey Samsonov    return true;
1138c1441f8SAlexey Samsonov}
1148c1441f8SAlexey Samsonov
1158c1441f8SAlexey Samsonov- (bool) compileWithExpectedFailure {
1168c1441f8SAlexey Samsonov    if (!shouldFail) {
1178c1441f8SAlexey Samsonov        printf("Why am I being called?\n");
1188c1441f8SAlexey Samsonov        return false;
1198c1441f8SAlexey Samsonov    }
1208c1441f8SAlexey Samsonov    int argc = [compileLine count];
1218c1441f8SAlexey Samsonov    char *argv[argc+1];
1228c1441f8SAlexey Samsonov    for (int i = 0; i < argc; ++i)
1238c1441f8SAlexey Samsonov        argv[i] = (char *)[compileLine pointerAtIndex:i];
1248c1441f8SAlexey Samsonov    argv[argc] = NULL;
1258c1441f8SAlexey Samsonov    pid_t child = fork();
1268c1441f8SAlexey Samsonov    char buffer[512];
1278c1441f8SAlexey Samsonov    if (child == 0) {
1288c1441f8SAlexey Samsonov        // in child
1298c1441f8SAlexey Samsonov        sprintf(buffer, "/tmp/errorfile_%d", getpid());
1308c1441f8SAlexey Samsonov        close(1);
1318c1441f8SAlexey Samsonov        int fd = creat(buffer, 0777);
1328c1441f8SAlexey Samsonov        if (fd != 1) {
1338c1441f8SAlexey Samsonov            fprintf(stderr, "didn't open custom error file %s as 1, got %d\n", buffer, fd);
1348c1441f8SAlexey Samsonov            exit(1);
1358c1441f8SAlexey Samsonov        }
1368c1441f8SAlexey Samsonov        close(2);
1378c1441f8SAlexey Samsonov        dup(1);
1388c1441f8SAlexey Samsonov        int result = execv(argv[0], argv);
1398c1441f8SAlexey Samsonov        exit(10);
1408c1441f8SAlexey Samsonov    }
1418c1441f8SAlexey Samsonov    if (child < 0) {
1428c1441f8SAlexey Samsonov        printf("fork failed\n");
1438c1441f8SAlexey Samsonov        return false;
1448c1441f8SAlexey Samsonov    }
1458c1441f8SAlexey Samsonov    int status = 0;
1468c1441f8SAlexey Samsonov    pid_t deadchild = wait(&status);
1478c1441f8SAlexey Samsonov    if (deadchild != child) {
1488c1441f8SAlexey Samsonov        printf("wait got %d instead of %d\n", deadchild, child);
1498c1441f8SAlexey Samsonov        exit(11);
1508c1441f8SAlexey Samsonov    }
1518c1441f8SAlexey Samsonov    if (WIFEXITED(status)) {
1528c1441f8SAlexey Samsonov        if (WEXITSTATUS(status) == 0) {
1538c1441f8SAlexey Samsonov            return false;
1548c1441f8SAlexey Samsonov        }
1558c1441f8SAlexey Samsonov    }
1568c1441f8SAlexey Samsonov    else {
1578c1441f8SAlexey Samsonov        printf("***** compiler borked/ICEd/died unexpectedly (status %x)\n", status);
1588c1441f8SAlexey Samsonov        return false;
1598c1441f8SAlexey Samsonov    }
1608c1441f8SAlexey Samsonov    char *error = generator.errorString;
1618c1441f8SAlexey Samsonov
1628c1441f8SAlexey Samsonov    if (!error) return true;
1638c1441f8SAlexey Samsonov#if 0
1648c1441f8SAlexey Samsonov    char got[512];
1658c1441f8SAlexey Samsonov    sprintf(buffer, "/tmp/errorfile_%d", child);
1668c1441f8SAlexey Samsonov    bool gotOutput = readErrorFile(got, buffer);
1678c1441f8SAlexey Samsonov    if (!gotOutput) {
1688c1441f8SAlexey Samsonov        printf("**** didn't get an error file %s to analyze!!??\n", buffer);
1698c1441f8SAlexey Samsonov        return false;
1708c1441f8SAlexey Samsonov    }
1718c1441f8SAlexey Samsonov    char *where = strstr(got, error);
1728c1441f8SAlexey Samsonov    if (!where) {
1738c1441f8SAlexey Samsonov        printf("didn't find '%s' in error file %s\n", error, buffer);
1748c1441f8SAlexey Samsonov        return false;
1758c1441f8SAlexey Samsonov    }
1768c1441f8SAlexey Samsonov    unlink(buffer);
1778c1441f8SAlexey Samsonov#else
1788c1441f8SAlexey Samsonov    if (!lookforIn(error, "/tmp/errorfile_%d", child)) return false;
1798c1441f8SAlexey Samsonov#endif
1808c1441f8SAlexey Samsonov    return true;
1818c1441f8SAlexey Samsonov}
1828c1441f8SAlexey Samsonov
1838c1441f8SAlexey Samsonov- (bool) run {
1848c1441f8SAlexey Samsonov    if (shouldFail) return true;
1858c1441f8SAlexey Samsonov    if (sizeof(long) == 4 && options & Do64) {
1868c1441f8SAlexey Samsonov        return true;    // skip 64-bit tests
1878c1441f8SAlexey Samsonov    }
1888c1441f8SAlexey Samsonov    int argc = 1;
1898c1441f8SAlexey Samsonov    char *argv[argc+1];
1908c1441f8SAlexey Samsonov    argv[0] = binaryName;
1918c1441f8SAlexey Samsonov    argv[argc] = NULL;
1928c1441f8SAlexey Samsonov    pid_t child = fork();
1938c1441f8SAlexey Samsonov    if (child == 0) {
1948c1441f8SAlexey Samsonov        // set up environment
1958c1441f8SAlexey Samsonov        char lpath[1024];
1968c1441f8SAlexey Samsonov        char fpath[1024];
1978c1441f8SAlexey Samsonov        char *myenv[3];
1988c1441f8SAlexey Samsonov        int counter = 0;
1998c1441f8SAlexey Samsonov        if (libraryPath) {
2008c1441f8SAlexey Samsonov            sprintf(lpath, "DYLD_LIBRARY_PATH=%s", libraryPath);
2018c1441f8SAlexey Samsonov            myenv[counter++] = lpath;
2028c1441f8SAlexey Samsonov        }
2038c1441f8SAlexey Samsonov        if (frameworkPath) {
2048c1441f8SAlexey Samsonov            sprintf(fpath, "DYLD_FRAMEWORK_PATH=%s", frameworkPath);
2058c1441f8SAlexey Samsonov            myenv[counter++] = fpath;
2068c1441f8SAlexey Samsonov        }
2078c1441f8SAlexey Samsonov        myenv[counter] = NULL;
2088c1441f8SAlexey Samsonov        if (generator.warningString) {
2098c1441f8SAlexey Samsonov            // set up stdout/stderr
2108c1441f8SAlexey Samsonov            char outfile[1024];
2118c1441f8SAlexey Samsonov            sprintf(outfile, "/tmp/stdout_%d", getpid());
2128c1441f8SAlexey Samsonov            close(2);
2138c1441f8SAlexey Samsonov            close(1);
2148c1441f8SAlexey Samsonov            creat(outfile, 0700);
2158c1441f8SAlexey Samsonov            dup(1);
2168c1441f8SAlexey Samsonov        }
2178c1441f8SAlexey Samsonov        execve(argv[0], argv, myenv);
2188c1441f8SAlexey Samsonov        exit(10); // shouldn't happen
2198c1441f8SAlexey Samsonov    }
2208c1441f8SAlexey Samsonov    if (child < 0) {
2218c1441f8SAlexey Samsonov        printf("fork failed\n");
2228c1441f8SAlexey Samsonov        return false;
2238c1441f8SAlexey Samsonov    }
2248c1441f8SAlexey Samsonov    int status = 0;
2258c1441f8SAlexey Samsonov    pid_t deadchild = wait(&status);
2268c1441f8SAlexey Samsonov    if (deadchild != child) {
2278c1441f8SAlexey Samsonov        printf("wait got %d instead of %d\n", deadchild, child);
2288c1441f8SAlexey Samsonov        exit(1);
2298c1441f8SAlexey Samsonov    }
2308c1441f8SAlexey Samsonov    if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
2318c1441f8SAlexey Samsonov        if (generator.warningString) {
2328c1441f8SAlexey Samsonov            if (!lookforIn(generator.warningString, "/tmp/stdout_%d", child)) return false;
2338c1441f8SAlexey Samsonov        }
2348c1441f8SAlexey Samsonov        return true;
2358c1441f8SAlexey Samsonov    }
2368c1441f8SAlexey Samsonov    printf("**** run failed for %s\n", binaryName);
2378c1441f8SAlexey Samsonov    return false;
2388c1441f8SAlexey Samsonov}
2398c1441f8SAlexey Samsonov
2408c1441f8SAlexey Samsonov@end
2418c1441f8SAlexey Samsonov
2428c1441f8SAlexey Samsonov@implementation TestFileExeGenerator
2438c1441f8SAlexey Samsonov@synthesize filename, compilerPath, errorString;
2448c1441f8SAlexey Samsonov@synthesize hasObjC, hasRR, hasGC, hasCPlusPlus, wantsC99, supposedToNotCompile, open, wants32, wants64;
2458c1441f8SAlexey Samsonov@synthesize radar;
2468c1441f8SAlexey Samsonov@synthesize warningString;
2478c1441f8SAlexey Samsonov
2488c1441f8SAlexey Samsonov- (void)setFilename:(__strong char *)name {
2498c1441f8SAlexey Samsonov    filename = gcstrcpy1(name);
2508c1441f8SAlexey Samsonov}
2518c1441f8SAlexey Samsonov- (void)setCompilerPath:(__strong char *)name {
2528c1441f8SAlexey Samsonov    compilerPath = gcstrcpy1(name);
2538c1441f8SAlexey Samsonov}
2548c1441f8SAlexey Samsonov
2558c1441f8SAlexey Samsonov- (void)forMostThings:(NSMutableArray *)lines options:(int)options {
2568c1441f8SAlexey Samsonov    TestFileExe *item = nil;
2578c1441f8SAlexey Samsonov    item = [self lineForOptions:options];
2588c1441f8SAlexey Samsonov    if (item) [lines addObject:item];
2598c1441f8SAlexey Samsonov    item = [self lineForOptions:options|Do64];
2608c1441f8SAlexey Samsonov    if (item) [lines addObject:item];
2618c1441f8SAlexey Samsonov    item = [self lineForOptions:options|DoCPP];
2628c1441f8SAlexey Samsonov    if (item) [lines addObject:item];
2638c1441f8SAlexey Samsonov    item = [self lineForOptions:options|Do64|DoCPP];
2648c1441f8SAlexey Samsonov    if (item) [lines addObject:item];
2658c1441f8SAlexey Samsonov}
2668c1441f8SAlexey Samsonov
2678c1441f8SAlexey Samsonov/*
2688c1441f8SAlexey Samsonov    DoDashG = (1 << 8),
2698c1441f8SAlexey Samsonov    DoDashO = (1 << 9),
2708c1441f8SAlexey Samsonov    DoDashOs = (1 << 10),
2718c1441f8SAlexey Samsonov    DoDashO2 = (1 << 11),
2728c1441f8SAlexey Samsonov*/
2738c1441f8SAlexey Samsonov
2748c1441f8SAlexey Samsonov- (void)forAllThings:(NSMutableArray *)lines options:(int)options {
2758c1441f8SAlexey Samsonov    [self forMostThings:lines options:options];
2768c1441f8SAlexey Samsonov    if (!Everything) {
2778c1441f8SAlexey Samsonov        return;
2788c1441f8SAlexey Samsonov    }
2798c1441f8SAlexey Samsonov    // now do it with three explicit optimization flags
2808c1441f8SAlexey Samsonov    [self forMostThings:lines options:options | DoDashO];
2818c1441f8SAlexey Samsonov    [self forMostThings:lines options:options | DoDashOs];
2828c1441f8SAlexey Samsonov    [self forMostThings:lines options:options | DoDashO2];
2838c1441f8SAlexey Samsonov}
2848c1441f8SAlexey Samsonov
2858c1441f8SAlexey Samsonov- (NSArray *)allLines {
2868c1441f8SAlexey Samsonov    NSMutableArray *result = [NSMutableArray new];
2878c1441f8SAlexey Samsonov    TestFileExe *item = nil;
2888c1441f8SAlexey Samsonov
2898c1441f8SAlexey Samsonov    int options = 0;
2908c1441f8SAlexey Samsonov    [self forAllThings:result options:0];
2918c1441f8SAlexey Samsonov    [self forAllThings:result options:DoOBJC | DoRR];
2928c1441f8SAlexey Samsonov    [self forAllThings:result options:DoOBJC | DoGC];
2938c1441f8SAlexey Samsonov    [self forAllThings:result options:DoOBJC | DoGCRR];
2948c1441f8SAlexey Samsonov    //[self forAllThings:result options:DoOBJC | DoRRGC];
2958c1441f8SAlexey Samsonov
2968c1441f8SAlexey Samsonov    return result;
2978c1441f8SAlexey Samsonov}
2988c1441f8SAlexey Samsonov
2998c1441f8SAlexey Samsonov- (void)addLibrary:(const char *)dashLSomething {
3008c1441f8SAlexey Samsonov    if (!extraLibraries) {
3018c1441f8SAlexey Samsonov        extraLibraries = [NSPointerArray pointerArrayWithOptions:
3028c1441f8SAlexey Samsonov            NSPointerFunctionsStrongMemory |
3038c1441f8SAlexey Samsonov            NSPointerFunctionsCStringPersonality];
3048c1441f8SAlexey Samsonov    }
3058c1441f8SAlexey Samsonov    [extraLibraries addPointer:(void *)dashLSomething];
3068c1441f8SAlexey Samsonov}
3078c1441f8SAlexey Samsonov
3088c1441f8SAlexey Samsonov- (TestFileExe *)lineForOptions:(int)options { // nil if no can do
3098c1441f8SAlexey Samsonov    if (hasObjC && !(options & DoOBJC)) return nil;
3108c1441f8SAlexey Samsonov    if (hasCPlusPlus && !(options & DoCPP)) return nil;
3118c1441f8SAlexey Samsonov    if (hasObjC) {
3128c1441f8SAlexey Samsonov        if (!hasGC && (options & (DoGC|DoGCRR))) return nil; // not smart enough
3138c1441f8SAlexey Samsonov        if (!hasRR && (options & (DoRR|DoRRGC))) return nil;
3148c1441f8SAlexey Samsonov    }
3158c1441f8SAlexey Samsonov    NSPointerArray *pa = [NSPointerArray pointerArrayWithOptions:
3168c1441f8SAlexey Samsonov        NSPointerFunctionsStrongMemory |
3178c1441f8SAlexey Samsonov        NSPointerFunctionsCStringPersonality];
3188c1441f8SAlexey Samsonov    // construct path
3198c1441f8SAlexey Samsonov    char path[512];
3208c1441f8SAlexey Samsonov    path[0] = 0;
3218c1441f8SAlexey Samsonov    if (!compilerPath) compilerPath = "/usr/bin";
3228c1441f8SAlexey Samsonov    if (compilerPath) {
3238c1441f8SAlexey Samsonov        strcat(path, compilerPath);
3248c1441f8SAlexey Samsonov        strcat(path, "/");
3258c1441f8SAlexey Samsonov    }
3268c1441f8SAlexey Samsonov    if (options & DoCPP) {
3278c1441f8SAlexey Samsonov        strcat(path, DoClang ? "clang++" : "g++-4.2");
3288c1441f8SAlexey Samsonov    }
3298c1441f8SAlexey Samsonov    else {
3308c1441f8SAlexey Samsonov        strcat(path, DoClang ? "clang" : "gcc-4.2");
3318c1441f8SAlexey Samsonov    }
3328c1441f8SAlexey Samsonov    [pa addPointer:gcstrcpy1(path)];
3338c1441f8SAlexey Samsonov    if (options & DoOBJC) {
3348c1441f8SAlexey Samsonov        if (options & DoCPP) {
3358c1441f8SAlexey Samsonov            [pa addPointer:"-ObjC++"];
3368c1441f8SAlexey Samsonov        }
3378c1441f8SAlexey Samsonov        else {
3388c1441f8SAlexey Samsonov            [pa addPointer:"-ObjC"];
3398c1441f8SAlexey Samsonov        }
3408c1441f8SAlexey Samsonov    }
3418c1441f8SAlexey Samsonov    [pa addPointer:"-g"];
3428c1441f8SAlexey Samsonov    if (options & DoDashO) [pa addPointer:"-O"];
3438c1441f8SAlexey Samsonov    else if (options & DoDashO2) [pa addPointer:"-O2"];
3448c1441f8SAlexey Samsonov    else if (options & DoDashOs) [pa addPointer:"-Os"];
3458c1441f8SAlexey Samsonov    if (wantsC99 && (! (options & DoCPP))) {
3468c1441f8SAlexey Samsonov        [pa addPointer:"-std=c99"];
3478c1441f8SAlexey Samsonov        [pa addPointer:"-fblocks"];
3488c1441f8SAlexey Samsonov    }
3498c1441f8SAlexey Samsonov    [pa addPointer:"-arch"];
3508c1441f8SAlexey Samsonov    [pa addPointer: (options & Do64) ? "x86_64" : "i386"];
3518c1441f8SAlexey Samsonov
3528c1441f8SAlexey Samsonov    if (options & DoOBJC) {
3538c1441f8SAlexey Samsonov        switch (options & (DoRR|DoGC|DoGCRR|DoRRGC)) {
3548c1441f8SAlexey Samsonov        case DoRR:
3558c1441f8SAlexey Samsonov            break;
3568c1441f8SAlexey Samsonov        case DoGC:
3578c1441f8SAlexey Samsonov            [pa addPointer:"-fobjc-gc-only"];
3588c1441f8SAlexey Samsonov            break;
3598c1441f8SAlexey Samsonov        case DoGCRR:
3608c1441f8SAlexey Samsonov            [pa addPointer:"-fobjc-gc"];
3618c1441f8SAlexey Samsonov            break;
3628c1441f8SAlexey Samsonov        case DoRRGC:
3638c1441f8SAlexey Samsonov            printf("DoRRGC unsupported right now\n");
3648c1441f8SAlexey Samsonov            [pa addPointer:"-c"];
3658c1441f8SAlexey Samsonov            return nil;
3668c1441f8SAlexey Samsonov        }
3678c1441f8SAlexey Samsonov        [pa addPointer:"-framework"];
3688c1441f8SAlexey Samsonov        [pa addPointer:"Foundation"];
3698c1441f8SAlexey Samsonov    }
3708c1441f8SAlexey Samsonov    [pa addPointer:gcstrcpy1(filename)];
3718c1441f8SAlexey Samsonov    [pa addPointer:"-o"];
3728c1441f8SAlexey Samsonov
3738c1441f8SAlexey Samsonov    path[0] = 0;
3748c1441f8SAlexey Samsonov    strcat(path, filename);
3758c1441f8SAlexey Samsonov    strcat(path, ".");
3768c1441f8SAlexey Samsonov    strcat(path, (options & Do64) ? "64" : "32");
3778c1441f8SAlexey Samsonov    if (options & DoOBJC) {
3788c1441f8SAlexey Samsonov        switch (options & (DoRR|DoGC|DoGCRR|DoRRGC)) {
3798c1441f8SAlexey Samsonov        case DoRR: strcat(path, "-rr"); break;
3808c1441f8SAlexey Samsonov        case DoGC: strcat(path, "-gconly"); break;
3818c1441f8SAlexey Samsonov        case DoGCRR: strcat(path, "-gcrr"); break;
3828c1441f8SAlexey Samsonov        case DoRRGC: strcat(path, "-rrgc"); break;
3838c1441f8SAlexey Samsonov        }
3848c1441f8SAlexey Samsonov    }
3858c1441f8SAlexey Samsonov    if (options & DoCPP) strcat(path, "++");
3868c1441f8SAlexey Samsonov    if (options & DoDashO) strcat(path, "-O");
3878c1441f8SAlexey Samsonov    else if (options & DoDashO2) strcat(path, "-O2");
3888c1441f8SAlexey Samsonov    else if (options & DoDashOs) strcat(path, "-Os");
3898c1441f8SAlexey Samsonov    if (wantsC99) strcat(path, "-C99");
3908c1441f8SAlexey Samsonov    strcat(path, DoClang ? "-clang" : "-gcc");
3918c1441f8SAlexey Samsonov    strcat(path, "-bin");
3928c1441f8SAlexey Samsonov    TestFileExe *result = [TestFileExe new];
3938c1441f8SAlexey Samsonov    result.binaryName = gcstrcpy1(path); // could snarf copy in pa
3948c1441f8SAlexey Samsonov    [pa addPointer:result.binaryName];
3958c1441f8SAlexey Samsonov    for (id cString in extraLibraries) {
3968c1441f8SAlexey Samsonov        [pa addPointer:cString];
3978c1441f8SAlexey Samsonov    }
3988c1441f8SAlexey Samsonov
3998c1441f8SAlexey Samsonov    result.sourceName = gcstrcpy1(filename); // could snarf copy in pa
4008c1441f8SAlexey Samsonov    result.compileLine = pa;
4018c1441f8SAlexey Samsonov    result.options = options;
4028c1441f8SAlexey Samsonov    result.shouldFail = supposedToNotCompile;
4038c1441f8SAlexey Samsonov    result.generator = self;
4048c1441f8SAlexey Samsonov    return result;
4058c1441f8SAlexey Samsonov}
4068c1441f8SAlexey Samsonov
4078c1441f8SAlexey Samsonov+ (NSArray *)generatorsFromPath:(NSString *)path {
4088c1441f8SAlexey Samsonov    FILE *fp = fopen([path fileSystemRepresentation], "r");
4098c1441f8SAlexey Samsonov    if (fp == NULL) return nil;
4108c1441f8SAlexey Samsonov    NSArray *result = [self generatorsFromFILE:fp];
4118c1441f8SAlexey Samsonov    fclose(fp);
4128c1441f8SAlexey Samsonov    return result;
4138c1441f8SAlexey Samsonov}
4148c1441f8SAlexey Samsonov
4158c1441f8SAlexey Samsonov#define LOOKFOR "CON" "FIG"
4168c1441f8SAlexey Samsonov
4178c1441f8SAlexey Samsonovchar *__strong parseRadar(char *line) {
4188c1441f8SAlexey Samsonov    line = strstr(line, "rdar:");   // returns beginning
4198c1441f8SAlexey Samsonov    char *endp = line + strlen("rdar:");
4208c1441f8SAlexey Samsonov    while (*endp && *endp != ' ' && *endp != '\n')
4218c1441f8SAlexey Samsonov        ++endp;
4228c1441f8SAlexey Samsonov    return gcstrcpy2(line, endp);
4238c1441f8SAlexey Samsonov}
4248c1441f8SAlexey Samsonov
4258c1441f8SAlexey Samsonov- (void)parseLibraries:(const char *)line {
4268c1441f8SAlexey Samsonov  start:
4278c1441f8SAlexey Samsonov    line = strstr(line, "-l");
4288c1441f8SAlexey Samsonov    char *endp = (char *)line + 2;
4298c1441f8SAlexey Samsonov    while (*endp && *endp != ' ' && *endp != '\n')
4308c1441f8SAlexey Samsonov        ++endp;
4318c1441f8SAlexey Samsonov    [self addLibrary:gcstrcpy2(line, endp)];
4328c1441f8SAlexey Samsonov    if (strstr(endp, "-l")) {
4338c1441f8SAlexey Samsonov        line = endp;
4348c1441f8SAlexey Samsonov        goto start;
4358c1441f8SAlexey Samsonov    }
4368c1441f8SAlexey Samsonov}
4378c1441f8SAlexey Samsonov
4388c1441f8SAlexey Samsonov+ (TestFileExeGenerator *)generatorFromLine:(char *)line filename:(char *)filename {
4398c1441f8SAlexey Samsonov    TestFileExeGenerator *item = [TestFileExeGenerator new];
4408c1441f8SAlexey Samsonov    item.filename = gcstrcpy1(filename);
4418c1441f8SAlexey Samsonov    if (strstr(line, "GC")) item.hasGC = true;
4428c1441f8SAlexey Samsonov    if (strstr(line, "RR")) item.hasRR = true;
4438c1441f8SAlexey Samsonov    if (strstr(line, "C++")) item.hasCPlusPlus = true;
4448c1441f8SAlexey Samsonov    if (strstr(line, "-C99")) {
4458c1441f8SAlexey Samsonov        item.wantsC99 = true;
4468c1441f8SAlexey Samsonov    }
4478c1441f8SAlexey Samsonov    if (strstr(line, "64")) item.wants64 = true;
4488c1441f8SAlexey Samsonov    if (strstr(line, "32")) item.wants32 = true;
4498c1441f8SAlexey Samsonov    if (strstr(line, "-l")) [item parseLibraries:line];
4508c1441f8SAlexey Samsonov    if (strstr(line, "open")) item.open = true;
4518c1441f8SAlexey Samsonov    if (strstr(line, "FAIL")) item.supposedToNotCompile = true; // old
4528c1441f8SAlexey Samsonov    // compile time error
4538c1441f8SAlexey Samsonov    if (strstr(line, "error:")) {
4548c1441f8SAlexey Samsonov        item.supposedToNotCompile = true;
4558c1441f8SAlexey Samsonov        // zap newline
4568c1441f8SAlexey Samsonov        char *error = strstr(line, "error:") + strlen("error:");
4578c1441f8SAlexey Samsonov        // make sure we have something before the newline
4588c1441f8SAlexey Samsonov        char *newline = strstr(error, "\n");
4598c1441f8SAlexey Samsonov        if (newline && ((newline-error) > 1)) {
4608c1441f8SAlexey Samsonov            *newline = 0;
4618c1441f8SAlexey Samsonov            item.errorString = gcstrcpy1(strstr(line, "error:") + strlen("error: "));
4628c1441f8SAlexey Samsonov        }
4638c1441f8SAlexey Samsonov    }
4648c1441f8SAlexey Samsonov    // run time warning
4658c1441f8SAlexey Samsonov    if (strstr(line, "runtime:")) {
4668c1441f8SAlexey Samsonov        // zap newline
4678c1441f8SAlexey Samsonov        char *error = strstr(line, "runtime:") + strlen("runtime:");
4688c1441f8SAlexey Samsonov        // make sure we have something before the newline
4698c1441f8SAlexey Samsonov        char *newline = strstr(error, "\n");
4708c1441f8SAlexey Samsonov        if (newline && ((newline-error) > 1)) {
4718c1441f8SAlexey Samsonov            *newline = 0;
4728c1441f8SAlexey Samsonov            item.warningString = gcstrcpy1(strstr(line, "runtime:") + strlen("runtime:"));
4738c1441f8SAlexey Samsonov        }
4748c1441f8SAlexey Samsonov    }
4758c1441f8SAlexey Samsonov    if (strstr(line, "rdar:")) item.radar = parseRadar(line);
4768c1441f8SAlexey Samsonov    if (item.hasGC || item.hasRR) item.hasObjC = true;
4778c1441f8SAlexey Samsonov    if (!item.wants32 && !item.wants64) { // give them both if they ask for neither
4788c1441f8SAlexey Samsonov        item.wants32 = item.wants64 = true;
4798c1441f8SAlexey Samsonov    }
4808c1441f8SAlexey Samsonov    return item;
4818c1441f8SAlexey Samsonov}
4828c1441f8SAlexey Samsonov
4838c1441f8SAlexey Samsonov+ (NSArray *)generatorsFromFILE:(FILE *)fp {
4848c1441f8SAlexey Samsonov    NSMutableArray *result = [NSMutableArray new];
4858c1441f8SAlexey Samsonov    // pretend this is a grep LOOKFOR *.[cmCM][cmCM] input
4868c1441f8SAlexey Samsonov    // look for
4878c1441f8SAlexey Samsonov    // filename: ... LOOKFOR [GC] [RR] [C++] [FAIL ...]
4888c1441f8SAlexey Samsonov    char buf[512];
4898c1441f8SAlexey Samsonov    while (fgets(buf, 512, fp)) {
4908c1441f8SAlexey Samsonov        char *config = strstr(buf, LOOKFOR);
4918c1441f8SAlexey Samsonov        if (!config) continue;
4928c1441f8SAlexey Samsonov        char *filename = buf;
4938c1441f8SAlexey Samsonov        char *end = strchr(buf, ':');
4948c1441f8SAlexey Samsonov        *end = 0;
4958c1441f8SAlexey Samsonov        [result addObject:[self generatorFromLine:config filename:filename]];
4968c1441f8SAlexey Samsonov    }
4978c1441f8SAlexey Samsonov    return result;
4988c1441f8SAlexey Samsonov}
4998c1441f8SAlexey Samsonov
5008c1441f8SAlexey Samsonov+ (TestFileExeGenerator *)generatorFromFilename:(char *)filename {
5018c1441f8SAlexey Samsonov    FILE *fp = fopen(filename, "r");
5028c1441f8SAlexey Samsonov    if (!fp) {
5038c1441f8SAlexey Samsonov        printf("didn't open %s!!\n", filename);
5048c1441f8SAlexey Samsonov        return nil;
5058c1441f8SAlexey Samsonov    }
5068c1441f8SAlexey Samsonov    char buf[512];
5078c1441f8SAlexey Samsonov    while (fgets(buf, 512, fp)) {
5088c1441f8SAlexey Samsonov        char *config = strstr(buf, LOOKFOR);
5098c1441f8SAlexey Samsonov        if (!config) continue;
5108c1441f8SAlexey Samsonov        fclose(fp);
5118c1441f8SAlexey Samsonov        return [self generatorFromLine:config filename:filename];
5128c1441f8SAlexey Samsonov    }
5138c1441f8SAlexey Samsonov    fclose(fp);
5148c1441f8SAlexey Samsonov    // guess from filename
5158c1441f8SAlexey Samsonov    char *ext = strrchr(filename, '.');
5168c1441f8SAlexey Samsonov    if (!ext) return nil;
5178c1441f8SAlexey Samsonov    TestFileExeGenerator *result = [TestFileExeGenerator new];
5188c1441f8SAlexey Samsonov    result.filename = gcstrcpy1(filename);
5198c1441f8SAlexey Samsonov    if (!strncmp(ext, ".m", 2)) {
5208c1441f8SAlexey Samsonov        result.hasObjC = true;
5218c1441f8SAlexey Samsonov        result.hasRR = true;
5228c1441f8SAlexey Samsonov        result.hasGC = true;
5238c1441f8SAlexey Samsonov    }
5248c1441f8SAlexey Samsonov    else if (!strcmp(ext, ".c")) {
5258c1441f8SAlexey Samsonov        ;
5268c1441f8SAlexey Samsonov    }
5278c1441f8SAlexey Samsonov    else if (!strcmp(ext, ".M") || !strcmp(ext, ".mm")) {
5288c1441f8SAlexey Samsonov        result.hasObjC = true;
5298c1441f8SAlexey Samsonov        result.hasRR = true;
5308c1441f8SAlexey Samsonov        result.hasGC = true;
5318c1441f8SAlexey Samsonov        result.hasCPlusPlus = true;
5328c1441f8SAlexey Samsonov    }
5338c1441f8SAlexey Samsonov    else if (!strcmp(ext, ".cc")
5348c1441f8SAlexey Samsonov        || !strcmp(ext, ".cp")
5358c1441f8SAlexey Samsonov        || !strcmp(ext, ".cxx")
5368c1441f8SAlexey Samsonov        || !strcmp(ext, ".cpp")
5378c1441f8SAlexey Samsonov        || !strcmp(ext, ".CPP")
5388c1441f8SAlexey Samsonov        || !strcmp(ext, ".c++")
5398c1441f8SAlexey Samsonov        || !strcmp(ext, ".C")) {
5408c1441f8SAlexey Samsonov        result.hasCPlusPlus = true;
5418c1441f8SAlexey Samsonov    }
5428c1441f8SAlexey Samsonov    else {
5438c1441f8SAlexey Samsonov        printf("unknown extension, file %s ignored\n", filename);
5448c1441f8SAlexey Samsonov        result = nil;
5458c1441f8SAlexey Samsonov    }
5468c1441f8SAlexey Samsonov    return result;
5478c1441f8SAlexey Samsonov
5488c1441f8SAlexey Samsonov}
5498c1441f8SAlexey Samsonov
5508c1441f8SAlexey Samsonov- (NSString *)description {
5518c1441f8SAlexey Samsonov    return [NSString stringWithFormat:@"%s: %s%s%s%s%s%s",
5528c1441f8SAlexey Samsonov        filename,
5538c1441f8SAlexey Samsonov        LOOKFOR,
5548c1441f8SAlexey Samsonov        hasGC ? " GC" : "",
5558c1441f8SAlexey Samsonov        hasRR ? " RR" : "",
5568c1441f8SAlexey Samsonov        hasCPlusPlus ? " C++" : "",
5578c1441f8SAlexey Samsonov        wantsC99 ? "C99" : "",
5588c1441f8SAlexey Samsonov        supposedToNotCompile ? " FAIL" : ""];
5598c1441f8SAlexey Samsonov}
5608c1441f8SAlexey Samsonov
5618c1441f8SAlexey Samsonov@end
5628c1441f8SAlexey Samsonov
5638c1441f8SAlexey Samsonovvoid printDetails(NSArray *failures, const char *whatAreThey) {
5648c1441f8SAlexey Samsonov    if ([failures count]) {
5658c1441f8SAlexey Samsonov        NSMutableString *output = [NSMutableString new];
5668c1441f8SAlexey Samsonov        printf("%s:\n", whatAreThey);
5678c1441f8SAlexey Samsonov        for (TestFileExe *line in failures) {
5688c1441f8SAlexey Samsonov            printf("%s", line.binaryName);
5698c1441f8SAlexey Samsonov            char *radar = line.generator.radar;
5708c1441f8SAlexey Samsonov            if (radar)
5718c1441f8SAlexey Samsonov                printf(" (due to %s?),", radar);
5728c1441f8SAlexey Samsonov            printf(" recompile via:\n%s\n\n", line.description.UTF8String);
5738c1441f8SAlexey Samsonov        }
5748c1441f8SAlexey Samsonov        printf("\n");
5758c1441f8SAlexey Samsonov    }
5768c1441f8SAlexey Samsonov}
5778c1441f8SAlexey Samsonov
5788c1441f8SAlexey Samsonovvoid help(const char *whoami) {
5798c1441f8SAlexey Samsonov    printf("Usage: %s [-fast] [-e] [-dyld librarypath] [gcc4.2dir] [-- | source1 ...]\n", whoami);
5808c1441f8SAlexey Samsonov    printf("     -fast              don't recompile if binary younger than source\n");
5818c1441f8SAlexey Samsonov    printf("     -open              only run tests that are thought to still be unresolved\n");
5828c1441f8SAlexey Samsonov    printf("     -clang             use the clang and clang++ compilers\n");
5838c1441f8SAlexey Samsonov    printf("     -e                 compile all variations also with -Os, -O2, -O3\n");
5848c1441f8SAlexey Samsonov    printf("     -dyld p            override DYLD_LIBRARY_PATH and DYLD_FRAMEWORK_PATH to p when running tests\n");
5858c1441f8SAlexey Samsonov    printf("     <compilerpath>     directory containing gcc-4.2 (or clang) that you wish to use to compile the tests\n");
5868c1441f8SAlexey Samsonov    printf("     --                 assume stdin is a grep CON" "FIG across the test sources\n");
5878c1441f8SAlexey Samsonov    printf("     otherwise treat each remaining argument as a single test file source\n");
5888c1441f8SAlexey Samsonov    printf("%s will compile and run individual test files under a variety of compilers, c, obj-c, c++, and objc++\n", whoami);
5898c1441f8SAlexey Samsonov    printf("  .c files are compiled with all four compilers\n");
5908c1441f8SAlexey Samsonov    printf("  .m files are compiled with objc and objc++ compilers\n");
5918c1441f8SAlexey Samsonov    printf("  .C files are compiled with c++ and objc++ compilers\n");
5928c1441f8SAlexey Samsonov    printf("  .M files are compiled only with the objc++ compiler\n");
5938c1441f8SAlexey Samsonov    printf("(actually all forms of extensions recognized by the compilers are honored, .cc, .c++ etc.)\n");
5948c1441f8SAlexey Samsonov    printf("\nTest files should run to completion with no output and exit (return) 0 on success.\n");
5958c1441f8SAlexey Samsonov    printf("Further they should be able to be compiled and run with GC on or off and by the C++ compilers\n");
5968c1441f8SAlexey Samsonov    printf("A line containing the string CON" "FIG within the source enables restrictions to the above assumptions\n");
5978c1441f8SAlexey Samsonov    printf("and other options.\n");
5988c1441f8SAlexey Samsonov    printf("Following CON" "FIG the string\n");
5998c1441f8SAlexey Samsonov    printf("    C++ restricts the test to only be run by c++ and objc++ compilers\n");
6008c1441f8SAlexey Samsonov    printf("    GC  restricts the test to only be compiled and run with GC on\n");
6018c1441f8SAlexey Samsonov    printf("    RR  (retain/release) restricts the test to only be compiled and run with GC off\n");
6028c1441f8SAlexey Samsonov    printf("Additionally,\n");
6038c1441f8SAlexey Samsonov    printf("    -C99 restricts the C versions of the test to -fstd=c99 -fblocks\n");
6048c1441f8SAlexey Samsonov    printf("    -O   adds the -O optimization level\n");
6058c1441f8SAlexey Samsonov    printf("    -O2  adds the -O2 optimization level\n");
6068c1441f8SAlexey Samsonov    printf("    -Os  adds the -Os optimization level\n");
6078c1441f8SAlexey Samsonov    printf("Files that are known to exhibit unresolved problems can provide the term \"open\" and this can");
6088c1441f8SAlexey Samsonov    printf("in turn allow highlighting of fixes that have regressed as well as identify that fixes are now available.\n");
6098c1441f8SAlexey Samsonov    printf("Files that exhibit known bugs may provide\n");
6108c1441f8SAlexey Samsonov    printf("    rdar://whatever such that if they fail the rdar will get cited\n");
6118c1441f8SAlexey Samsonov    printf("Files that are expected to fail to compile should provide, as their last token sequence,\n");
6128c1441f8SAlexey Samsonov    printf("    error:\n");
6138c1441f8SAlexey Samsonov    printf(" or error: substring to match.\n");
6148c1441f8SAlexey Samsonov    printf("Files that are expected to produce a runtime error message should provide, as their last token sequence,\n");
6158c1441f8SAlexey Samsonov    printf("    warning: string to match\n");
6168c1441f8SAlexey Samsonov    printf("\n%s will compile and run all configurations of the test files and report a summary at the end. Good luck.\n", whoami);
6178c1441f8SAlexey Samsonov    printf("       Blaine Garst blaine@apple.com\n");
6188c1441f8SAlexey Samsonov}
6198c1441f8SAlexey Samsonov
6208c1441f8SAlexey Samsonovint main(int argc, char *argv[]) {
6218c1441f8SAlexey Samsonov    printf("running on %s-bit architecture\n", sizeof(long) == 4 ? "32" : "64");
6228c1441f8SAlexey Samsonov    char *compilerDir = "/usr/bin";
6238c1441f8SAlexey Samsonov    NSMutableArray *generators = [NSMutableArray new];
6248c1441f8SAlexey Samsonov    bool doFast = false;
6258c1441f8SAlexey Samsonov    bool doStdin = false;
6268c1441f8SAlexey Samsonov    bool onlyOpen = false;
6278c1441f8SAlexey Samsonov    char *libraryPath = getenv("DYLD_LIBRARY_PATH");
6288c1441f8SAlexey Samsonov    char *frameworkPath = getenv("DYLD_FRAMEWORK_PATH");
6298c1441f8SAlexey Samsonov    // process options
6308c1441f8SAlexey Samsonov    while (argc > 1) {
6318c1441f8SAlexey Samsonov        if (!strcmp(argv[1], "-fast")) {
6328c1441f8SAlexey Samsonov            doFast = true;
6338c1441f8SAlexey Samsonov            --argc;
6348c1441f8SAlexey Samsonov            ++argv;
6358c1441f8SAlexey Samsonov        }
6368c1441f8SAlexey Samsonov        else if (!strcmp(argv[1], "-dyld")) {
6378c1441f8SAlexey Samsonov            doFast = true;
6388c1441f8SAlexey Samsonov            --argc;
6398c1441f8SAlexey Samsonov            ++argv;
6408c1441f8SAlexey Samsonov            frameworkPath = argv[1];
6418c1441f8SAlexey Samsonov            libraryPath = argv[1];
6428c1441f8SAlexey Samsonov            --argc;
6438c1441f8SAlexey Samsonov            ++argv;
6448c1441f8SAlexey Samsonov        }
6458c1441f8SAlexey Samsonov        else if (!strcmp(argv[1], "-open")) {
6468c1441f8SAlexey Samsonov            onlyOpen = true;
6478c1441f8SAlexey Samsonov            --argc;
6488c1441f8SAlexey Samsonov            ++argv;
6498c1441f8SAlexey Samsonov        }
6508c1441f8SAlexey Samsonov        else if (!strcmp(argv[1], "-clang")) {
6518c1441f8SAlexey Samsonov            DoClang = true;
6528c1441f8SAlexey Samsonov            --argc;
6538c1441f8SAlexey Samsonov            ++argv;
6548c1441f8SAlexey Samsonov        }
6558c1441f8SAlexey Samsonov        else if (!strcmp(argv[1], "-e")) {
6568c1441f8SAlexey Samsonov            Everything = true;
6578c1441f8SAlexey Samsonov            --argc;
6588c1441f8SAlexey Samsonov            ++argv;
6598c1441f8SAlexey Samsonov        }
6608c1441f8SAlexey Samsonov        else if (!strcmp(argv[1], "--")) {
6618c1441f8SAlexey Samsonov            doStdin = true;
6628c1441f8SAlexey Samsonov            --argc;
6638c1441f8SAlexey Samsonov            ++argv;
6648c1441f8SAlexey Samsonov        }
6658c1441f8SAlexey Samsonov        else if (!strcmp(argv[1], "-")) {
6668c1441f8SAlexey Samsonov            help(argv[0]);
6678c1441f8SAlexey Samsonov            return 1;
6688c1441f8SAlexey Samsonov        }
6698c1441f8SAlexey Samsonov        else if (argc > 1 && isDirectory(argv[1])) {
6708c1441f8SAlexey Samsonov            compilerDir = argv[1];
6718c1441f8SAlexey Samsonov            ++argv;
6728c1441f8SAlexey Samsonov            --argc;
6738c1441f8SAlexey Samsonov        }
6748c1441f8SAlexey Samsonov        else
6758c1441f8SAlexey Samsonov            break;
6768c1441f8SAlexey Samsonov    }
6778c1441f8SAlexey Samsonov    // process remaining arguments, or stdin
6788c1441f8SAlexey Samsonov    if (argc == 1) {
6798c1441f8SAlexey Samsonov        if (doStdin)
6808c1441f8SAlexey Samsonov            generators = (NSMutableArray *)[TestFileExeGenerator generatorsFromFILE:stdin];
6818c1441f8SAlexey Samsonov        else {
6828c1441f8SAlexey Samsonov            help(argv[0]);
6838c1441f8SAlexey Samsonov            return 1;
6848c1441f8SAlexey Samsonov        }
6858c1441f8SAlexey Samsonov    }
6868c1441f8SAlexey Samsonov    else while (argc > 1) {
6878c1441f8SAlexey Samsonov        TestFileExeGenerator *generator = [TestFileExeGenerator generatorFromFilename:argv[1]];
6888c1441f8SAlexey Samsonov        if (generator) [generators addObject:generator];
6898c1441f8SAlexey Samsonov        ++argv;
6908c1441f8SAlexey Samsonov        --argc;
6918c1441f8SAlexey Samsonov    }
6928c1441f8SAlexey Samsonov    // see if we can generate all possibilities
6938c1441f8SAlexey Samsonov    NSMutableArray *failureToCompile = [NSMutableArray new];
6948c1441f8SAlexey Samsonov    NSMutableArray *failureToFailToCompile = [NSMutableArray new];
6958c1441f8SAlexey Samsonov    NSMutableArray *failureToRun = [NSMutableArray new];
6968c1441f8SAlexey Samsonov    NSMutableArray *successes = [NSMutableArray new];
6978c1441f8SAlexey Samsonov    for (TestFileExeGenerator *generator in generators) {
6988c1441f8SAlexey Samsonov        //NSLog(@"got %@", generator);
6998c1441f8SAlexey Samsonov        if (onlyOpen && !generator.open) {
7008c1441f8SAlexey Samsonov            //printf("skipping resolved test %s\n", generator.filename);
7018c1441f8SAlexey Samsonov            continue;  // skip closed if onlyOpen
7028c1441f8SAlexey Samsonov        }
7038c1441f8SAlexey Samsonov        if (!onlyOpen && generator.open) {
7048c1441f8SAlexey Samsonov            //printf("skipping open test %s\n", generator.filename);
7058c1441f8SAlexey Samsonov            continue;  // skip open if not asked for onlyOpen
7068c1441f8SAlexey Samsonov        }
7078c1441f8SAlexey Samsonov        generator.compilerPath = compilerDir;
7088c1441f8SAlexey Samsonov        NSArray *tests = [generator allLines];
7098c1441f8SAlexey Samsonov        for (TestFileExe *line in tests) {
7108c1441f8SAlexey Samsonov            line.frameworkPath = frameworkPath;   // tell generators about it instead XXX
7118c1441f8SAlexey Samsonov            line.libraryPath = libraryPath;   // tell generators about it instead XXX
7128c1441f8SAlexey Samsonov            if ([line shouldFail]) {
7138c1441f8SAlexey Samsonov                if (doFast) continue; // don't recompile & don't count as success
7148c1441f8SAlexey Samsonov                if ([line compileWithExpectedFailure]) {
7158c1441f8SAlexey Samsonov                    [successes addObject:line];
7168c1441f8SAlexey Samsonov                }
7178c1441f8SAlexey Samsonov                else
7188c1441f8SAlexey Samsonov                    [failureToFailToCompile addObject:line];
7198c1441f8SAlexey Samsonov            }
7208c1441f8SAlexey Samsonov            else if ([line compileUnlessExists:doFast]) {
7218c1441f8SAlexey Samsonov                if ([line run]) {
7228c1441f8SAlexey Samsonov                    printf("%s ran successfully\n", line.binaryName);
7238c1441f8SAlexey Samsonov                    [successes addObject:line];
7248c1441f8SAlexey Samsonov                }
7258c1441f8SAlexey Samsonov                else {
7268c1441f8SAlexey Samsonov                    [failureToRun addObject:line];
7278c1441f8SAlexey Samsonov                }
7288c1441f8SAlexey Samsonov            }
7298c1441f8SAlexey Samsonov            else {
7308c1441f8SAlexey Samsonov                [failureToCompile addObject:line];
7318c1441f8SAlexey Samsonov            }
7328c1441f8SAlexey Samsonov        }
7338c1441f8SAlexey Samsonov    }
7348c1441f8SAlexey Samsonov    printf("\n--- results ---\n\n%lu successes\n%lu unexpected compile failures\n%lu failure to fail to compile errors\n%lu run failures\n",
7358c1441f8SAlexey Samsonov        [successes count], [failureToCompile count], [failureToFailToCompile count], [failureToRun count]);
7368c1441f8SAlexey Samsonov    printDetails(failureToCompile, "unexpected compile failures");
7378c1441f8SAlexey Samsonov    printDetails(failureToFailToCompile, "should have failed to compile but didn't failures");
7388c1441f8SAlexey Samsonov    printDetails(failureToRun, "run failures");
7398c1441f8SAlexey Samsonov
7408c1441f8SAlexey Samsonov    if (onlyOpen && [successes count]) {
7418c1441f8SAlexey Samsonov        NSMutableSet *radars = [NSMutableSet new];
7428c1441f8SAlexey Samsonov        printf("The following tests ran successfully suggesting that they are now resolved:\n");
7438c1441f8SAlexey Samsonov        for (TestFileExe *line in successes) {
7448c1441f8SAlexey Samsonov            printf("%s\n", line.binaryName);
7458c1441f8SAlexey Samsonov            if (line.radar) [radars addObject:line.generator];
7468c1441f8SAlexey Samsonov        }
7478c1441f8SAlexey Samsonov        if ([radars count]) {
7488c1441f8SAlexey Samsonov            printf("The following radars may be resolved:\n");
7498c1441f8SAlexey Samsonov            for (TestFileExeGenerator *line in radars) {
7508c1441f8SAlexey Samsonov                printf("%s\n", line.radar);
7518c1441f8SAlexey Samsonov            }
7528c1441f8SAlexey Samsonov        }
7538c1441f8SAlexey Samsonov    }
7548c1441f8SAlexey Samsonov
7558c1441f8SAlexey Samsonov    return [failureToCompile count] + [failureToRun count];
7568c1441f8SAlexey Samsonov}
7578c1441f8SAlexey Samsonov
7588c1441f8SAlexey Samsonov#include <sys/stat.h>
7598c1441f8SAlexey Samsonov
7608c1441f8SAlexey Samsonovstatic bool isDirectory(char *path) {
7618c1441f8SAlexey Samsonov    struct stat statb;
7628c1441f8SAlexey Samsonov    int retval = stat(path, &statb);
7638c1441f8SAlexey Samsonov    if (retval != 0) return false;
7648c1441f8SAlexey Samsonov    if (statb.st_mode & S_IFDIR) return true;
7658c1441f8SAlexey Samsonov    return false;
7668c1441f8SAlexey Samsonov}
7678c1441f8SAlexey Samsonov
7688c1441f8SAlexey Samsonovstatic bool isExecutable(char *path) {
7698c1441f8SAlexey Samsonov    struct stat statb;
7708c1441f8SAlexey Samsonov    int retval = stat(path, &statb);
7718c1441f8SAlexey Samsonov    if (retval != 0) return false;
7728c1441f8SAlexey Samsonov    if (!(statb.st_mode & S_IFREG)) return false;
7738c1441f8SAlexey Samsonov    if (statb.st_mode & S_IXUSR) return true;
7748c1441f8SAlexey Samsonov    return false;
7758c1441f8SAlexey Samsonov}
7768c1441f8SAlexey Samsonov
7778c1441f8SAlexey Samsonovstatic bool isYounger(char *source, char *binary) {
7788c1441f8SAlexey Samsonov    struct stat statb;
7798c1441f8SAlexey Samsonov    int retval = stat(binary, &statb);
7808c1441f8SAlexey Samsonov    if (retval != 0) return true;  // if doesn't exit, lie
7818c1441f8SAlexey Samsonov
7828c1441f8SAlexey Samsonov    struct stat stata;
7838c1441f8SAlexey Samsonov    retval = stat(source, &stata);
7848c1441f8SAlexey Samsonov    if (retval != 0) return true; // we're hosed
7858c1441f8SAlexey Samsonov    // the greater the timeval the younger it is
7868c1441f8SAlexey Samsonov    if (stata.st_mtimespec.tv_sec > statb.st_mtimespec.tv_sec) return true;
7878c1441f8SAlexey Samsonov    if (stata.st_mtimespec.tv_nsec > statb.st_mtimespec.tv_nsec) return true;
7888c1441f8SAlexey Samsonov    return false;
7898c1441f8SAlexey Samsonov}
7908c1441f8SAlexey Samsonov
7918c1441f8SAlexey Samsonovstatic bool readErrorFile(char *buffer, const char *from) {
7928c1441f8SAlexey Samsonov    int fd = open(from, 0);
7938c1441f8SAlexey Samsonov    if (fd < 0) {
7948c1441f8SAlexey Samsonov        printf("didn't open %s, (might not have been created?)\n", buffer);
7958c1441f8SAlexey Samsonov        return false;
7968c1441f8SAlexey Samsonov    }
7978c1441f8SAlexey Samsonov    int count = read(fd, buffer, 512);
7988c1441f8SAlexey Samsonov    if (count < 1) {
7998c1441f8SAlexey Samsonov        printf("read error on %s\n", buffer);
8008c1441f8SAlexey Samsonov        return false;
8018c1441f8SAlexey Samsonov    }
8028c1441f8SAlexey Samsonov    buffer[count-1] = 0; // zap newline
8038c1441f8SAlexey Samsonov    return true;
8048c1441f8SAlexey Samsonov}
805