xref: /aosp_15_r20/external/compiler-rt/test/BlocksRuntime/testfilerunner.m (revision 7c3d14c8b49c529e04be81a3ce6f5cc23712e4c6)
1*7c3d14c8STreehugger Robot//
2*7c3d14c8STreehugger Robot//                     The LLVM Compiler Infrastructure
3*7c3d14c8STreehugger Robot//
4*7c3d14c8STreehugger Robot// This file is distributed under the University of Illinois Open Source
5*7c3d14c8STreehugger Robot// License. See LICENSE.TXT for details.
6*7c3d14c8STreehugger Robot
7*7c3d14c8STreehugger Robot//
8*7c3d14c8STreehugger Robot//  testfilerunner.m
9*7c3d14c8STreehugger Robot//  testObjects
10*7c3d14c8STreehugger Robot//
11*7c3d14c8STreehugger Robot//  Created by Blaine Garst on 9/24/08.
12*7c3d14c8STreehugger Robot//
13*7c3d14c8STreehugger Robot
14*7c3d14c8STreehugger Robot#import "testfilerunner.h"
15*7c3d14c8STreehugger Robot#import <Foundation/Foundation.h>
16*7c3d14c8STreehugger Robot#include <stdio.h>
17*7c3d14c8STreehugger Robot#include <unistd.h>
18*7c3d14c8STreehugger Robot#include <fcntl.h>
19*7c3d14c8STreehugger Robot#include <string.h>
20*7c3d14c8STreehugger Robot#include <stdlib.h>
21*7c3d14c8STreehugger Robot#include <stdbool.h>
22*7c3d14c8STreehugger Robot
23*7c3d14c8STreehugger Robotbool Everything = false; // do it also with 3 levels of optimization
24*7c3d14c8STreehugger Robotbool DoClang = false;
25*7c3d14c8STreehugger Robot
26*7c3d14c8STreehugger Robotstatic bool isDirectory(char *path);
27*7c3d14c8STreehugger Robotstatic bool isExecutable(char *path);
28*7c3d14c8STreehugger Robotstatic bool isYounger(char *source, char *binary);
29*7c3d14c8STreehugger Robotstatic bool readErrorFile(char *buffer, const char *from);
30*7c3d14c8STreehugger Robot
31*7c3d14c8STreehugger Robot__strong char *gcstrcpy2(__strong const char *arg, char *endp) {
32*7c3d14c8STreehugger Robot    unsigned size = endp - arg + 1;
33*7c3d14c8STreehugger Robot    __strong char *result = NSAllocateCollectable(size, 0);
34*7c3d14c8STreehugger Robot    strncpy(result, arg, size);
35*7c3d14c8STreehugger Robot    result[size-1] = 0;
36*7c3d14c8STreehugger Robot    return result;
37*7c3d14c8STreehugger Robot}
38*7c3d14c8STreehugger Robot__strong char *gcstrcpy1(__strong char *arg) {
39*7c3d14c8STreehugger Robot    unsigned size = strlen(arg) + 1;
40*7c3d14c8STreehugger Robot    __strong char *result = NSAllocateCollectable(size, 0);
41*7c3d14c8STreehugger Robot    strncpy(result, arg, size);
42*7c3d14c8STreehugger Robot    result[size-1] = 0;
43*7c3d14c8STreehugger Robot    return result;
44*7c3d14c8STreehugger Robot}
45*7c3d14c8STreehugger Robot
46*7c3d14c8STreehugger Robot@implementation TestFileExe
47*7c3d14c8STreehugger Robot
48*7c3d14c8STreehugger Robot@synthesize options, compileLine, shouldFail, binaryName, sourceName;
49*7c3d14c8STreehugger Robot@synthesize generator;
50*7c3d14c8STreehugger Robot@synthesize libraryPath, frameworkPath;
51*7c3d14c8STreehugger Robot
52*7c3d14c8STreehugger Robot- (NSString *)description {
53*7c3d14c8STreehugger Robot    NSMutableString *result = [NSMutableString new];
54*7c3d14c8STreehugger Robot    if (shouldFail) [result appendString:@"fail"];
55*7c3d14c8STreehugger Robot    for (id x  in compileLine) {
56*7c3d14c8STreehugger Robot        [result appendString:[NSString stringWithFormat:@" %s", (char *)x]];
57*7c3d14c8STreehugger Robot    }
58*7c3d14c8STreehugger Robot    return result;
59*7c3d14c8STreehugger Robot}
60*7c3d14c8STreehugger Robot
61*7c3d14c8STreehugger Robot- (__strong char *)radar {
62*7c3d14c8STreehugger Robot    return generator.radar;
63*7c3d14c8STreehugger Robot}
64*7c3d14c8STreehugger Robot
65*7c3d14c8STreehugger Robot- (bool) compileUnlessExists:(bool)skip {
66*7c3d14c8STreehugger Robot    if (shouldFail) {
67*7c3d14c8STreehugger Robot        printf("don't use this to compile anymore!\n");
68*7c3d14c8STreehugger Robot        return false;
69*7c3d14c8STreehugger Robot    }
70*7c3d14c8STreehugger Robot    if (skip && isExecutable(binaryName) && !isYounger(sourceName, binaryName)) return true;
71*7c3d14c8STreehugger Robot    int argc = [compileLine count];
72*7c3d14c8STreehugger Robot    char *argv[argc+1];
73*7c3d14c8STreehugger Robot    for (int i = 0; i < argc; ++i)
74*7c3d14c8STreehugger Robot        argv[i] = (char *)[compileLine pointerAtIndex:i];
75*7c3d14c8STreehugger Robot    argv[argc] = NULL;
76*7c3d14c8STreehugger Robot    pid_t child = fork();
77*7c3d14c8STreehugger Robot    if (child == 0) {
78*7c3d14c8STreehugger Robot        execv(argv[0], argv);
79*7c3d14c8STreehugger Robot        exit(10); // shouldn't happen
80*7c3d14c8STreehugger Robot    }
81*7c3d14c8STreehugger Robot    if (child < 0) {
82*7c3d14c8STreehugger Robot        printf("fork failed\n");
83*7c3d14c8STreehugger Robot        return false;
84*7c3d14c8STreehugger Robot    }
85*7c3d14c8STreehugger Robot    int status = 0;
86*7c3d14c8STreehugger Robot    pid_t deadchild = wait(&status);
87*7c3d14c8STreehugger Robot    if (deadchild != child) {
88*7c3d14c8STreehugger Robot        printf("wait got %d instead of %d\n", deadchild, child);
89*7c3d14c8STreehugger Robot        exit(1);
90*7c3d14c8STreehugger Robot    }
91*7c3d14c8STreehugger Robot    if (WEXITSTATUS(status) == 0) {
92*7c3d14c8STreehugger Robot        return true;
93*7c3d14c8STreehugger Robot    }
94*7c3d14c8STreehugger Robot    printf("run failed\n");
95*7c3d14c8STreehugger Robot    return false;
96*7c3d14c8STreehugger Robot}
97*7c3d14c8STreehugger Robot
98*7c3d14c8STreehugger Robotbool lookforIn(char *lookfor, const char *format, pid_t child) {
99*7c3d14c8STreehugger Robot    char buffer[512];
100*7c3d14c8STreehugger Robot    char got[512];
101*7c3d14c8STreehugger Robot    sprintf(buffer, format, child);
102*7c3d14c8STreehugger Robot    bool gotOutput = readErrorFile(got, buffer);
103*7c3d14c8STreehugger Robot    if (!gotOutput) {
104*7c3d14c8STreehugger Robot        printf("**** didn't get an output file %s to analyze!!??\n", buffer);
105*7c3d14c8STreehugger Robot        return false;
106*7c3d14c8STreehugger Robot    }
107*7c3d14c8STreehugger Robot    char *where = strstr(got, lookfor);
108*7c3d14c8STreehugger Robot    if (!where) {
109*7c3d14c8STreehugger Robot        printf("didn't find '%s' in output file %s\n", lookfor, buffer);
110*7c3d14c8STreehugger Robot        return false;
111*7c3d14c8STreehugger Robot    }
112*7c3d14c8STreehugger Robot    unlink(buffer);
113*7c3d14c8STreehugger Robot    return true;
114*7c3d14c8STreehugger Robot}
115*7c3d14c8STreehugger Robot
116*7c3d14c8STreehugger Robot- (bool) compileWithExpectedFailure {
117*7c3d14c8STreehugger Robot    if (!shouldFail) {
118*7c3d14c8STreehugger Robot        printf("Why am I being called?\n");
119*7c3d14c8STreehugger Robot        return false;
120*7c3d14c8STreehugger Robot    }
121*7c3d14c8STreehugger Robot    int argc = [compileLine count];
122*7c3d14c8STreehugger Robot    char *argv[argc+1];
123*7c3d14c8STreehugger Robot    for (int i = 0; i < argc; ++i)
124*7c3d14c8STreehugger Robot        argv[i] = (char *)[compileLine pointerAtIndex:i];
125*7c3d14c8STreehugger Robot    argv[argc] = NULL;
126*7c3d14c8STreehugger Robot    pid_t child = fork();
127*7c3d14c8STreehugger Robot    char buffer[512];
128*7c3d14c8STreehugger Robot    if (child == 0) {
129*7c3d14c8STreehugger Robot        // in child
130*7c3d14c8STreehugger Robot        sprintf(buffer, "/tmp/errorfile_%d", getpid());
131*7c3d14c8STreehugger Robot        close(1);
132*7c3d14c8STreehugger Robot        int fd = creat(buffer, 0777);
133*7c3d14c8STreehugger Robot        if (fd != 1) {
134*7c3d14c8STreehugger Robot            fprintf(stderr, "didn't open custom error file %s as 1, got %d\n", buffer, fd);
135*7c3d14c8STreehugger Robot            exit(1);
136*7c3d14c8STreehugger Robot        }
137*7c3d14c8STreehugger Robot        close(2);
138*7c3d14c8STreehugger Robot        dup(1);
139*7c3d14c8STreehugger Robot        int result = execv(argv[0], argv);
140*7c3d14c8STreehugger Robot        exit(10);
141*7c3d14c8STreehugger Robot    }
142*7c3d14c8STreehugger Robot    if (child < 0) {
143*7c3d14c8STreehugger Robot        printf("fork failed\n");
144*7c3d14c8STreehugger Robot        return false;
145*7c3d14c8STreehugger Robot    }
146*7c3d14c8STreehugger Robot    int status = 0;
147*7c3d14c8STreehugger Robot    pid_t deadchild = wait(&status);
148*7c3d14c8STreehugger Robot    if (deadchild != child) {
149*7c3d14c8STreehugger Robot        printf("wait got %d instead of %d\n", deadchild, child);
150*7c3d14c8STreehugger Robot        exit(11);
151*7c3d14c8STreehugger Robot    }
152*7c3d14c8STreehugger Robot    if (WIFEXITED(status)) {
153*7c3d14c8STreehugger Robot        if (WEXITSTATUS(status) == 0) {
154*7c3d14c8STreehugger Robot            return false;
155*7c3d14c8STreehugger Robot        }
156*7c3d14c8STreehugger Robot    }
157*7c3d14c8STreehugger Robot    else {
158*7c3d14c8STreehugger Robot        printf("***** compiler borked/ICEd/died unexpectedly (status %x)\n", status);
159*7c3d14c8STreehugger Robot        return false;
160*7c3d14c8STreehugger Robot    }
161*7c3d14c8STreehugger Robot    char *error = generator.errorString;
162*7c3d14c8STreehugger Robot
163*7c3d14c8STreehugger Robot    if (!error) return true;
164*7c3d14c8STreehugger Robot#if 0
165*7c3d14c8STreehugger Robot    char got[512];
166*7c3d14c8STreehugger Robot    sprintf(buffer, "/tmp/errorfile_%d", child);
167*7c3d14c8STreehugger Robot    bool gotOutput = readErrorFile(got, buffer);
168*7c3d14c8STreehugger Robot    if (!gotOutput) {
169*7c3d14c8STreehugger Robot        printf("**** didn't get an error file %s to analyze!!??\n", buffer);
170*7c3d14c8STreehugger Robot        return false;
171*7c3d14c8STreehugger Robot    }
172*7c3d14c8STreehugger Robot    char *where = strstr(got, error);
173*7c3d14c8STreehugger Robot    if (!where) {
174*7c3d14c8STreehugger Robot        printf("didn't find '%s' in error file %s\n", error, buffer);
175*7c3d14c8STreehugger Robot        return false;
176*7c3d14c8STreehugger Robot    }
177*7c3d14c8STreehugger Robot    unlink(buffer);
178*7c3d14c8STreehugger Robot#else
179*7c3d14c8STreehugger Robot    if (!lookforIn(error, "/tmp/errorfile_%d", child)) return false;
180*7c3d14c8STreehugger Robot#endif
181*7c3d14c8STreehugger Robot    return true;
182*7c3d14c8STreehugger Robot}
183*7c3d14c8STreehugger Robot
184*7c3d14c8STreehugger Robot- (bool) run {
185*7c3d14c8STreehugger Robot    if (shouldFail) return true;
186*7c3d14c8STreehugger Robot    if (sizeof(long) == 4 && options & Do64) {
187*7c3d14c8STreehugger Robot        return true;    // skip 64-bit tests
188*7c3d14c8STreehugger Robot    }
189*7c3d14c8STreehugger Robot    int argc = 1;
190*7c3d14c8STreehugger Robot    char *argv[argc+1];
191*7c3d14c8STreehugger Robot    argv[0] = binaryName;
192*7c3d14c8STreehugger Robot    argv[argc] = NULL;
193*7c3d14c8STreehugger Robot    pid_t child = fork();
194*7c3d14c8STreehugger Robot    if (child == 0) {
195*7c3d14c8STreehugger Robot        // set up environment
196*7c3d14c8STreehugger Robot        char lpath[1024];
197*7c3d14c8STreehugger Robot        char fpath[1024];
198*7c3d14c8STreehugger Robot        char *myenv[3];
199*7c3d14c8STreehugger Robot        int counter = 0;
200*7c3d14c8STreehugger Robot        if (libraryPath) {
201*7c3d14c8STreehugger Robot            sprintf(lpath, "DYLD_LIBRARY_PATH=%s", libraryPath);
202*7c3d14c8STreehugger Robot            myenv[counter++] = lpath;
203*7c3d14c8STreehugger Robot        }
204*7c3d14c8STreehugger Robot        if (frameworkPath) {
205*7c3d14c8STreehugger Robot            sprintf(fpath, "DYLD_FRAMEWORK_PATH=%s", frameworkPath);
206*7c3d14c8STreehugger Robot            myenv[counter++] = fpath;
207*7c3d14c8STreehugger Robot        }
208*7c3d14c8STreehugger Robot        myenv[counter] = NULL;
209*7c3d14c8STreehugger Robot        if (generator.warningString) {
210*7c3d14c8STreehugger Robot            // set up stdout/stderr
211*7c3d14c8STreehugger Robot            char outfile[1024];
212*7c3d14c8STreehugger Robot            sprintf(outfile, "/tmp/stdout_%d", getpid());
213*7c3d14c8STreehugger Robot            close(2);
214*7c3d14c8STreehugger Robot            close(1);
215*7c3d14c8STreehugger Robot            creat(outfile, 0700);
216*7c3d14c8STreehugger Robot            dup(1);
217*7c3d14c8STreehugger Robot        }
218*7c3d14c8STreehugger Robot        execve(argv[0], argv, myenv);
219*7c3d14c8STreehugger Robot        exit(10); // shouldn't happen
220*7c3d14c8STreehugger Robot    }
221*7c3d14c8STreehugger Robot    if (child < 0) {
222*7c3d14c8STreehugger Robot        printf("fork failed\n");
223*7c3d14c8STreehugger Robot        return false;
224*7c3d14c8STreehugger Robot    }
225*7c3d14c8STreehugger Robot    int status = 0;
226*7c3d14c8STreehugger Robot    pid_t deadchild = wait(&status);
227*7c3d14c8STreehugger Robot    if (deadchild != child) {
228*7c3d14c8STreehugger Robot        printf("wait got %d instead of %d\n", deadchild, child);
229*7c3d14c8STreehugger Robot        exit(1);
230*7c3d14c8STreehugger Robot    }
231*7c3d14c8STreehugger Robot    if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
232*7c3d14c8STreehugger Robot        if (generator.warningString) {
233*7c3d14c8STreehugger Robot            if (!lookforIn(generator.warningString, "/tmp/stdout_%d", child)) return false;
234*7c3d14c8STreehugger Robot        }
235*7c3d14c8STreehugger Robot        return true;
236*7c3d14c8STreehugger Robot    }
237*7c3d14c8STreehugger Robot    printf("**** run failed for %s\n", binaryName);
238*7c3d14c8STreehugger Robot    return false;
239*7c3d14c8STreehugger Robot}
240*7c3d14c8STreehugger Robot
241*7c3d14c8STreehugger Robot@end
242*7c3d14c8STreehugger Robot
243*7c3d14c8STreehugger Robot@implementation TestFileExeGenerator
244*7c3d14c8STreehugger Robot@synthesize filename, compilerPath, errorString;
245*7c3d14c8STreehugger Robot@synthesize hasObjC, hasRR, hasGC, hasCPlusPlus, wantsC99, supposedToNotCompile, open, wants32, wants64;
246*7c3d14c8STreehugger Robot@synthesize radar;
247*7c3d14c8STreehugger Robot@synthesize warningString;
248*7c3d14c8STreehugger Robot
249*7c3d14c8STreehugger Robot- (void)setFilename:(__strong char *)name {
250*7c3d14c8STreehugger Robot    filename = gcstrcpy1(name);
251*7c3d14c8STreehugger Robot}
252*7c3d14c8STreehugger Robot- (void)setCompilerPath:(__strong char *)name {
253*7c3d14c8STreehugger Robot    compilerPath = gcstrcpy1(name);
254*7c3d14c8STreehugger Robot}
255*7c3d14c8STreehugger Robot
256*7c3d14c8STreehugger Robot- (void)forMostThings:(NSMutableArray *)lines options:(int)options {
257*7c3d14c8STreehugger Robot    TestFileExe *item = nil;
258*7c3d14c8STreehugger Robot    item = [self lineForOptions:options];
259*7c3d14c8STreehugger Robot    if (item) [lines addObject:item];
260*7c3d14c8STreehugger Robot    item = [self lineForOptions:options|Do64];
261*7c3d14c8STreehugger Robot    if (item) [lines addObject:item];
262*7c3d14c8STreehugger Robot    item = [self lineForOptions:options|DoCPP];
263*7c3d14c8STreehugger Robot    if (item) [lines addObject:item];
264*7c3d14c8STreehugger Robot    item = [self lineForOptions:options|Do64|DoCPP];
265*7c3d14c8STreehugger Robot    if (item) [lines addObject:item];
266*7c3d14c8STreehugger Robot}
267*7c3d14c8STreehugger Robot
268*7c3d14c8STreehugger Robot/*
269*7c3d14c8STreehugger Robot    DoDashG = (1 << 8),
270*7c3d14c8STreehugger Robot    DoDashO = (1 << 9),
271*7c3d14c8STreehugger Robot    DoDashOs = (1 << 10),
272*7c3d14c8STreehugger Robot    DoDashO2 = (1 << 11),
273*7c3d14c8STreehugger Robot*/
274*7c3d14c8STreehugger Robot
275*7c3d14c8STreehugger Robot- (void)forAllThings:(NSMutableArray *)lines options:(int)options {
276*7c3d14c8STreehugger Robot    [self forMostThings:lines options:options];
277*7c3d14c8STreehugger Robot    if (!Everything) {
278*7c3d14c8STreehugger Robot        return;
279*7c3d14c8STreehugger Robot    }
280*7c3d14c8STreehugger Robot    // now do it with three explicit optimization flags
281*7c3d14c8STreehugger Robot    [self forMostThings:lines options:options | DoDashO];
282*7c3d14c8STreehugger Robot    [self forMostThings:lines options:options | DoDashOs];
283*7c3d14c8STreehugger Robot    [self forMostThings:lines options:options | DoDashO2];
284*7c3d14c8STreehugger Robot}
285*7c3d14c8STreehugger Robot
286*7c3d14c8STreehugger Robot- (NSArray *)allLines {
287*7c3d14c8STreehugger Robot    NSMutableArray *result = [NSMutableArray new];
288*7c3d14c8STreehugger Robot    TestFileExe *item = nil;
289*7c3d14c8STreehugger Robot
290*7c3d14c8STreehugger Robot    int options = 0;
291*7c3d14c8STreehugger Robot    [self forAllThings:result options:0];
292*7c3d14c8STreehugger Robot    [self forAllThings:result options:DoOBJC | DoRR];
293*7c3d14c8STreehugger Robot    [self forAllThings:result options:DoOBJC | DoGC];
294*7c3d14c8STreehugger Robot    [self forAllThings:result options:DoOBJC | DoGCRR];
295*7c3d14c8STreehugger Robot    //[self forAllThings:result options:DoOBJC | DoRRGC];
296*7c3d14c8STreehugger Robot
297*7c3d14c8STreehugger Robot    return result;
298*7c3d14c8STreehugger Robot}
299*7c3d14c8STreehugger Robot
300*7c3d14c8STreehugger Robot- (void)addLibrary:(const char *)dashLSomething {
301*7c3d14c8STreehugger Robot    if (!extraLibraries) {
302*7c3d14c8STreehugger Robot        extraLibraries = [NSPointerArray pointerArrayWithOptions:
303*7c3d14c8STreehugger Robot            NSPointerFunctionsStrongMemory |
304*7c3d14c8STreehugger Robot            NSPointerFunctionsCStringPersonality];
305*7c3d14c8STreehugger Robot    }
306*7c3d14c8STreehugger Robot    [extraLibraries addPointer:(void *)dashLSomething];
307*7c3d14c8STreehugger Robot}
308*7c3d14c8STreehugger Robot
309*7c3d14c8STreehugger Robot- (TestFileExe *)lineForOptions:(int)options { // nil if no can do
310*7c3d14c8STreehugger Robot    if (hasObjC && !(options & DoOBJC)) return nil;
311*7c3d14c8STreehugger Robot    if (hasCPlusPlus && !(options & DoCPP)) return nil;
312*7c3d14c8STreehugger Robot    if (hasObjC) {
313*7c3d14c8STreehugger Robot        if (!hasGC && (options & (DoGC|DoGCRR))) return nil; // not smart enough
314*7c3d14c8STreehugger Robot        if (!hasRR && (options & (DoRR|DoRRGC))) return nil;
315*7c3d14c8STreehugger Robot    }
316*7c3d14c8STreehugger Robot    NSPointerArray *pa = [NSPointerArray pointerArrayWithOptions:
317*7c3d14c8STreehugger Robot        NSPointerFunctionsStrongMemory |
318*7c3d14c8STreehugger Robot        NSPointerFunctionsCStringPersonality];
319*7c3d14c8STreehugger Robot    // construct path
320*7c3d14c8STreehugger Robot    char path[512];
321*7c3d14c8STreehugger Robot    path[0] = 0;
322*7c3d14c8STreehugger Robot    if (!compilerPath) compilerPath = "/usr/bin";
323*7c3d14c8STreehugger Robot    if (compilerPath) {
324*7c3d14c8STreehugger Robot        strcat(path, compilerPath);
325*7c3d14c8STreehugger Robot        strcat(path, "/");
326*7c3d14c8STreehugger Robot    }
327*7c3d14c8STreehugger Robot    if (options & DoCPP) {
328*7c3d14c8STreehugger Robot        strcat(path, DoClang ? "clang++" : "g++-4.2");
329*7c3d14c8STreehugger Robot    }
330*7c3d14c8STreehugger Robot    else {
331*7c3d14c8STreehugger Robot        strcat(path, DoClang ? "clang" : "gcc-4.2");
332*7c3d14c8STreehugger Robot    }
333*7c3d14c8STreehugger Robot    [pa addPointer:gcstrcpy1(path)];
334*7c3d14c8STreehugger Robot    if (options & DoOBJC) {
335*7c3d14c8STreehugger Robot        if (options & DoCPP) {
336*7c3d14c8STreehugger Robot            [pa addPointer:"-ObjC++"];
337*7c3d14c8STreehugger Robot        }
338*7c3d14c8STreehugger Robot        else {
339*7c3d14c8STreehugger Robot            [pa addPointer:"-ObjC"];
340*7c3d14c8STreehugger Robot        }
341*7c3d14c8STreehugger Robot    }
342*7c3d14c8STreehugger Robot    [pa addPointer:"-g"];
343*7c3d14c8STreehugger Robot    if (options & DoDashO) [pa addPointer:"-O"];
344*7c3d14c8STreehugger Robot    else if (options & DoDashO2) [pa addPointer:"-O2"];
345*7c3d14c8STreehugger Robot    else if (options & DoDashOs) [pa addPointer:"-Os"];
346*7c3d14c8STreehugger Robot    if (wantsC99 && (! (options & DoCPP))) {
347*7c3d14c8STreehugger Robot        [pa addPointer:"-std=c99"];
348*7c3d14c8STreehugger Robot        [pa addPointer:"-fblocks"];
349*7c3d14c8STreehugger Robot    }
350*7c3d14c8STreehugger Robot    [pa addPointer:"-arch"];
351*7c3d14c8STreehugger Robot    [pa addPointer: (options & Do64) ? "x86_64" : "i386"];
352*7c3d14c8STreehugger Robot
353*7c3d14c8STreehugger Robot    if (options & DoOBJC) {
354*7c3d14c8STreehugger Robot        switch (options & (DoRR|DoGC|DoGCRR|DoRRGC)) {
355*7c3d14c8STreehugger Robot        case DoRR:
356*7c3d14c8STreehugger Robot            break;
357*7c3d14c8STreehugger Robot        case DoGC:
358*7c3d14c8STreehugger Robot            [pa addPointer:"-fobjc-gc-only"];
359*7c3d14c8STreehugger Robot            break;
360*7c3d14c8STreehugger Robot        case DoGCRR:
361*7c3d14c8STreehugger Robot            [pa addPointer:"-fobjc-gc"];
362*7c3d14c8STreehugger Robot            break;
363*7c3d14c8STreehugger Robot        case DoRRGC:
364*7c3d14c8STreehugger Robot            printf("DoRRGC unsupported right now\n");
365*7c3d14c8STreehugger Robot            [pa addPointer:"-c"];
366*7c3d14c8STreehugger Robot            return nil;
367*7c3d14c8STreehugger Robot        }
368*7c3d14c8STreehugger Robot        [pa addPointer:"-framework"];
369*7c3d14c8STreehugger Robot        [pa addPointer:"Foundation"];
370*7c3d14c8STreehugger Robot    }
371*7c3d14c8STreehugger Robot    [pa addPointer:gcstrcpy1(filename)];
372*7c3d14c8STreehugger Robot    [pa addPointer:"-o"];
373*7c3d14c8STreehugger Robot
374*7c3d14c8STreehugger Robot    path[0] = 0;
375*7c3d14c8STreehugger Robot    strcat(path, filename);
376*7c3d14c8STreehugger Robot    strcat(path, ".");
377*7c3d14c8STreehugger Robot    strcat(path, (options & Do64) ? "64" : "32");
378*7c3d14c8STreehugger Robot    if (options & DoOBJC) {
379*7c3d14c8STreehugger Robot        switch (options & (DoRR|DoGC|DoGCRR|DoRRGC)) {
380*7c3d14c8STreehugger Robot        case DoRR: strcat(path, "-rr"); break;
381*7c3d14c8STreehugger Robot        case DoGC: strcat(path, "-gconly"); break;
382*7c3d14c8STreehugger Robot        case DoGCRR: strcat(path, "-gcrr"); break;
383*7c3d14c8STreehugger Robot        case DoRRGC: strcat(path, "-rrgc"); break;
384*7c3d14c8STreehugger Robot        }
385*7c3d14c8STreehugger Robot    }
386*7c3d14c8STreehugger Robot    if (options & DoCPP) strcat(path, "++");
387*7c3d14c8STreehugger Robot    if (options & DoDashO) strcat(path, "-O");
388*7c3d14c8STreehugger Robot    else if (options & DoDashO2) strcat(path, "-O2");
389*7c3d14c8STreehugger Robot    else if (options & DoDashOs) strcat(path, "-Os");
390*7c3d14c8STreehugger Robot    if (wantsC99) strcat(path, "-C99");
391*7c3d14c8STreehugger Robot    strcat(path, DoClang ? "-clang" : "-gcc");
392*7c3d14c8STreehugger Robot    strcat(path, "-bin");
393*7c3d14c8STreehugger Robot    TestFileExe *result = [TestFileExe new];
394*7c3d14c8STreehugger Robot    result.binaryName = gcstrcpy1(path); // could snarf copy in pa
395*7c3d14c8STreehugger Robot    [pa addPointer:result.binaryName];
396*7c3d14c8STreehugger Robot    for (id cString in extraLibraries) {
397*7c3d14c8STreehugger Robot        [pa addPointer:cString];
398*7c3d14c8STreehugger Robot    }
399*7c3d14c8STreehugger Robot
400*7c3d14c8STreehugger Robot    result.sourceName = gcstrcpy1(filename); // could snarf copy in pa
401*7c3d14c8STreehugger Robot    result.compileLine = pa;
402*7c3d14c8STreehugger Robot    result.options = options;
403*7c3d14c8STreehugger Robot    result.shouldFail = supposedToNotCompile;
404*7c3d14c8STreehugger Robot    result.generator = self;
405*7c3d14c8STreehugger Robot    return result;
406*7c3d14c8STreehugger Robot}
407*7c3d14c8STreehugger Robot
408*7c3d14c8STreehugger Robot+ (NSArray *)generatorsFromPath:(NSString *)path {
409*7c3d14c8STreehugger Robot    FILE *fp = fopen([path fileSystemRepresentation], "r");
410*7c3d14c8STreehugger Robot    if (fp == NULL) return nil;
411*7c3d14c8STreehugger Robot    NSArray *result = [self generatorsFromFILE:fp];
412*7c3d14c8STreehugger Robot    fclose(fp);
413*7c3d14c8STreehugger Robot    return result;
414*7c3d14c8STreehugger Robot}
415*7c3d14c8STreehugger Robot
416*7c3d14c8STreehugger Robot#define LOOKFOR "CON" "FIG"
417*7c3d14c8STreehugger Robot
418*7c3d14c8STreehugger Robotchar *__strong parseRadar(char *line) {
419*7c3d14c8STreehugger Robot    line = strstr(line, "rdar:");   // returns beginning
420*7c3d14c8STreehugger Robot    char *endp = line + strlen("rdar:");
421*7c3d14c8STreehugger Robot    while (*endp && *endp != ' ' && *endp != '\n')
422*7c3d14c8STreehugger Robot        ++endp;
423*7c3d14c8STreehugger Robot    return gcstrcpy2(line, endp);
424*7c3d14c8STreehugger Robot}
425*7c3d14c8STreehugger Robot
426*7c3d14c8STreehugger Robot- (void)parseLibraries:(const char *)line {
427*7c3d14c8STreehugger Robot  start:
428*7c3d14c8STreehugger Robot    line = strstr(line, "-l");
429*7c3d14c8STreehugger Robot    char *endp = (char *)line + 2;
430*7c3d14c8STreehugger Robot    while (*endp && *endp != ' ' && *endp != '\n')
431*7c3d14c8STreehugger Robot        ++endp;
432*7c3d14c8STreehugger Robot    [self addLibrary:gcstrcpy2(line, endp)];
433*7c3d14c8STreehugger Robot    if (strstr(endp, "-l")) {
434*7c3d14c8STreehugger Robot        line = endp;
435*7c3d14c8STreehugger Robot        goto start;
436*7c3d14c8STreehugger Robot    }
437*7c3d14c8STreehugger Robot}
438*7c3d14c8STreehugger Robot
439*7c3d14c8STreehugger Robot+ (TestFileExeGenerator *)generatorFromLine:(char *)line filename:(char *)filename {
440*7c3d14c8STreehugger Robot    TestFileExeGenerator *item = [TestFileExeGenerator new];
441*7c3d14c8STreehugger Robot    item.filename = gcstrcpy1(filename);
442*7c3d14c8STreehugger Robot    if (strstr(line, "GC")) item.hasGC = true;
443*7c3d14c8STreehugger Robot    if (strstr(line, "RR")) item.hasRR = true;
444*7c3d14c8STreehugger Robot    if (strstr(line, "C++")) item.hasCPlusPlus = true;
445*7c3d14c8STreehugger Robot    if (strstr(line, "-C99")) {
446*7c3d14c8STreehugger Robot        item.wantsC99 = true;
447*7c3d14c8STreehugger Robot    }
448*7c3d14c8STreehugger Robot    if (strstr(line, "64")) item.wants64 = true;
449*7c3d14c8STreehugger Robot    if (strstr(line, "32")) item.wants32 = true;
450*7c3d14c8STreehugger Robot    if (strstr(line, "-l")) [item parseLibraries:line];
451*7c3d14c8STreehugger Robot    if (strstr(line, "open")) item.open = true;
452*7c3d14c8STreehugger Robot    if (strstr(line, "FAIL")) item.supposedToNotCompile = true; // old
453*7c3d14c8STreehugger Robot    // compile time error
454*7c3d14c8STreehugger Robot    if (strstr(line, "error:")) {
455*7c3d14c8STreehugger Robot        item.supposedToNotCompile = true;
456*7c3d14c8STreehugger Robot        // zap newline
457*7c3d14c8STreehugger Robot        char *error = strstr(line, "error:") + strlen("error:");
458*7c3d14c8STreehugger Robot        // make sure we have something before the newline
459*7c3d14c8STreehugger Robot        char *newline = strstr(error, "\n");
460*7c3d14c8STreehugger Robot        if (newline && ((newline-error) > 1)) {
461*7c3d14c8STreehugger Robot            *newline = 0;
462*7c3d14c8STreehugger Robot            item.errorString = gcstrcpy1(strstr(line, "error:") + strlen("error: "));
463*7c3d14c8STreehugger Robot        }
464*7c3d14c8STreehugger Robot    }
465*7c3d14c8STreehugger Robot    // run time warning
466*7c3d14c8STreehugger Robot    if (strstr(line, "runtime:")) {
467*7c3d14c8STreehugger Robot        // zap newline
468*7c3d14c8STreehugger Robot        char *error = strstr(line, "runtime:") + strlen("runtime:");
469*7c3d14c8STreehugger Robot        // make sure we have something before the newline
470*7c3d14c8STreehugger Robot        char *newline = strstr(error, "\n");
471*7c3d14c8STreehugger Robot        if (newline && ((newline-error) > 1)) {
472*7c3d14c8STreehugger Robot            *newline = 0;
473*7c3d14c8STreehugger Robot            item.warningString = gcstrcpy1(strstr(line, "runtime:") + strlen("runtime:"));
474*7c3d14c8STreehugger Robot        }
475*7c3d14c8STreehugger Robot    }
476*7c3d14c8STreehugger Robot    if (strstr(line, "rdar:")) item.radar = parseRadar(line);
477*7c3d14c8STreehugger Robot    if (item.hasGC || item.hasRR) item.hasObjC = true;
478*7c3d14c8STreehugger Robot    if (!item.wants32 && !item.wants64) { // give them both if they ask for neither
479*7c3d14c8STreehugger Robot        item.wants32 = item.wants64 = true;
480*7c3d14c8STreehugger Robot    }
481*7c3d14c8STreehugger Robot    return item;
482*7c3d14c8STreehugger Robot}
483*7c3d14c8STreehugger Robot
484*7c3d14c8STreehugger Robot+ (NSArray *)generatorsFromFILE:(FILE *)fp {
485*7c3d14c8STreehugger Robot    NSMutableArray *result = [NSMutableArray new];
486*7c3d14c8STreehugger Robot    // pretend this is a grep LOOKFOR *.[cmCM][cmCM] input
487*7c3d14c8STreehugger Robot    // look for
488*7c3d14c8STreehugger Robot    // filename: ... LOOKFOR [GC] [RR] [C++] [FAIL ...]
489*7c3d14c8STreehugger Robot    char buf[512];
490*7c3d14c8STreehugger Robot    while (fgets(buf, 512, fp)) {
491*7c3d14c8STreehugger Robot        char *config = strstr(buf, LOOKFOR);
492*7c3d14c8STreehugger Robot        if (!config) continue;
493*7c3d14c8STreehugger Robot        char *filename = buf;
494*7c3d14c8STreehugger Robot        char *end = strchr(buf, ':');
495*7c3d14c8STreehugger Robot        *end = 0;
496*7c3d14c8STreehugger Robot        [result addObject:[self generatorFromLine:config filename:filename]];
497*7c3d14c8STreehugger Robot    }
498*7c3d14c8STreehugger Robot    return result;
499*7c3d14c8STreehugger Robot}
500*7c3d14c8STreehugger Robot
501*7c3d14c8STreehugger Robot+ (TestFileExeGenerator *)generatorFromFilename:(char *)filename {
502*7c3d14c8STreehugger Robot    FILE *fp = fopen(filename, "r");
503*7c3d14c8STreehugger Robot    if (!fp) {
504*7c3d14c8STreehugger Robot        printf("didn't open %s!!\n", filename);
505*7c3d14c8STreehugger Robot        return nil;
506*7c3d14c8STreehugger Robot    }
507*7c3d14c8STreehugger Robot    char buf[512];
508*7c3d14c8STreehugger Robot    while (fgets(buf, 512, fp)) {
509*7c3d14c8STreehugger Robot        char *config = strstr(buf, LOOKFOR);
510*7c3d14c8STreehugger Robot        if (!config) continue;
511*7c3d14c8STreehugger Robot        fclose(fp);
512*7c3d14c8STreehugger Robot        return [self generatorFromLine:config filename:filename];
513*7c3d14c8STreehugger Robot    }
514*7c3d14c8STreehugger Robot    fclose(fp);
515*7c3d14c8STreehugger Robot    // guess from filename
516*7c3d14c8STreehugger Robot    char *ext = strrchr(filename, '.');
517*7c3d14c8STreehugger Robot    if (!ext) return nil;
518*7c3d14c8STreehugger Robot    TestFileExeGenerator *result = [TestFileExeGenerator new];
519*7c3d14c8STreehugger Robot    result.filename = gcstrcpy1(filename);
520*7c3d14c8STreehugger Robot    if (!strncmp(ext, ".m", 2)) {
521*7c3d14c8STreehugger Robot        result.hasObjC = true;
522*7c3d14c8STreehugger Robot        result.hasRR = true;
523*7c3d14c8STreehugger Robot        result.hasGC = true;
524*7c3d14c8STreehugger Robot    }
525*7c3d14c8STreehugger Robot    else if (!strcmp(ext, ".c")) {
526*7c3d14c8STreehugger Robot        ;
527*7c3d14c8STreehugger Robot    }
528*7c3d14c8STreehugger Robot    else if (!strcmp(ext, ".M") || !strcmp(ext, ".mm")) {
529*7c3d14c8STreehugger Robot        result.hasObjC = true;
530*7c3d14c8STreehugger Robot        result.hasRR = true;
531*7c3d14c8STreehugger Robot        result.hasGC = true;
532*7c3d14c8STreehugger Robot        result.hasCPlusPlus = true;
533*7c3d14c8STreehugger Robot    }
534*7c3d14c8STreehugger Robot    else if (!strcmp(ext, ".cc")
535*7c3d14c8STreehugger Robot        || !strcmp(ext, ".cp")
536*7c3d14c8STreehugger Robot        || !strcmp(ext, ".cxx")
537*7c3d14c8STreehugger Robot        || !strcmp(ext, ".cpp")
538*7c3d14c8STreehugger Robot        || !strcmp(ext, ".CPP")
539*7c3d14c8STreehugger Robot        || !strcmp(ext, ".c++")
540*7c3d14c8STreehugger Robot        || !strcmp(ext, ".C")) {
541*7c3d14c8STreehugger Robot        result.hasCPlusPlus = true;
542*7c3d14c8STreehugger Robot    }
543*7c3d14c8STreehugger Robot    else {
544*7c3d14c8STreehugger Robot        printf("unknown extension, file %s ignored\n", filename);
545*7c3d14c8STreehugger Robot        result = nil;
546*7c3d14c8STreehugger Robot    }
547*7c3d14c8STreehugger Robot    return result;
548*7c3d14c8STreehugger Robot
549*7c3d14c8STreehugger Robot}
550*7c3d14c8STreehugger Robot
551*7c3d14c8STreehugger Robot- (NSString *)description {
552*7c3d14c8STreehugger Robot    return [NSString stringWithFormat:@"%s: %s%s%s%s%s%s",
553*7c3d14c8STreehugger Robot        filename,
554*7c3d14c8STreehugger Robot        LOOKFOR,
555*7c3d14c8STreehugger Robot        hasGC ? " GC" : "",
556*7c3d14c8STreehugger Robot        hasRR ? " RR" : "",
557*7c3d14c8STreehugger Robot        hasCPlusPlus ? " C++" : "",
558*7c3d14c8STreehugger Robot        wantsC99 ? "C99" : "",
559*7c3d14c8STreehugger Robot        supposedToNotCompile ? " FAIL" : ""];
560*7c3d14c8STreehugger Robot}
561*7c3d14c8STreehugger Robot
562*7c3d14c8STreehugger Robot@end
563*7c3d14c8STreehugger Robot
564*7c3d14c8STreehugger Robotvoid printDetails(NSArray *failures, const char *whatAreThey) {
565*7c3d14c8STreehugger Robot    if ([failures count]) {
566*7c3d14c8STreehugger Robot        NSMutableString *output = [NSMutableString new];
567*7c3d14c8STreehugger Robot        printf("%s:\n", whatAreThey);
568*7c3d14c8STreehugger Robot        for (TestFileExe *line in failures) {
569*7c3d14c8STreehugger Robot            printf("%s", line.binaryName);
570*7c3d14c8STreehugger Robot            char *radar = line.generator.radar;
571*7c3d14c8STreehugger Robot            if (radar)
572*7c3d14c8STreehugger Robot                printf(" (due to %s?),", radar);
573*7c3d14c8STreehugger Robot            printf(" recompile via:\n%s\n\n", line.description.UTF8String);
574*7c3d14c8STreehugger Robot        }
575*7c3d14c8STreehugger Robot        printf("\n");
576*7c3d14c8STreehugger Robot    }
577*7c3d14c8STreehugger Robot}
578*7c3d14c8STreehugger Robot
579*7c3d14c8STreehugger Robotvoid help(const char *whoami) {
580*7c3d14c8STreehugger Robot    printf("Usage: %s [-fast] [-e] [-dyld librarypath] [gcc4.2dir] [-- | source1 ...]\n", whoami);
581*7c3d14c8STreehugger Robot    printf("     -fast              don't recompile if binary younger than source\n");
582*7c3d14c8STreehugger Robot    printf("     -open              only run tests that are thought to still be unresolved\n");
583*7c3d14c8STreehugger Robot    printf("     -clang             use the clang and clang++ compilers\n");
584*7c3d14c8STreehugger Robot    printf("     -e                 compile all variations also with -Os, -O2, -O3\n");
585*7c3d14c8STreehugger Robot    printf("     -dyld p            override DYLD_LIBRARY_PATH and DYLD_FRAMEWORK_PATH to p when running tests\n");
586*7c3d14c8STreehugger Robot    printf("     <compilerpath>     directory containing gcc-4.2 (or clang) that you wish to use to compile the tests\n");
587*7c3d14c8STreehugger Robot    printf("     --                 assume stdin is a grep CON" "FIG across the test sources\n");
588*7c3d14c8STreehugger Robot    printf("     otherwise treat each remaining argument as a single test file source\n");
589*7c3d14c8STreehugger Robot    printf("%s will compile and run individual test files under a variety of compilers, c, obj-c, c++, and objc++\n", whoami);
590*7c3d14c8STreehugger Robot    printf("  .c files are compiled with all four compilers\n");
591*7c3d14c8STreehugger Robot    printf("  .m files are compiled with objc and objc++ compilers\n");
592*7c3d14c8STreehugger Robot    printf("  .C files are compiled with c++ and objc++ compilers\n");
593*7c3d14c8STreehugger Robot    printf("  .M files are compiled only with the objc++ compiler\n");
594*7c3d14c8STreehugger Robot    printf("(actually all forms of extensions recognized by the compilers are honored, .cc, .c++ etc.)\n");
595*7c3d14c8STreehugger Robot    printf("\nTest files should run to completion with no output and exit (return) 0 on success.\n");
596*7c3d14c8STreehugger Robot    printf("Further they should be able to be compiled and run with GC on or off and by the C++ compilers\n");
597*7c3d14c8STreehugger Robot    printf("A line containing the string CON" "FIG within the source enables restrictions to the above assumptions\n");
598*7c3d14c8STreehugger Robot    printf("and other options.\n");
599*7c3d14c8STreehugger Robot    printf("Following CON" "FIG the string\n");
600*7c3d14c8STreehugger Robot    printf("    C++ restricts the test to only be run by c++ and objc++ compilers\n");
601*7c3d14c8STreehugger Robot    printf("    GC  restricts the test to only be compiled and run with GC on\n");
602*7c3d14c8STreehugger Robot    printf("    RR  (retain/release) restricts the test to only be compiled and run with GC off\n");
603*7c3d14c8STreehugger Robot    printf("Additionally,\n");
604*7c3d14c8STreehugger Robot    printf("    -C99 restricts the C versions of the test to -fstd=c99 -fblocks\n");
605*7c3d14c8STreehugger Robot    printf("    -O   adds the -O optimization level\n");
606*7c3d14c8STreehugger Robot    printf("    -O2  adds the -O2 optimization level\n");
607*7c3d14c8STreehugger Robot    printf("    -Os  adds the -Os optimization level\n");
608*7c3d14c8STreehugger Robot    printf("Files that are known to exhibit unresolved problems can provide the term \"open\" and this can");
609*7c3d14c8STreehugger Robot    printf("in turn allow highlighting of fixes that have regressed as well as identify that fixes are now available.\n");
610*7c3d14c8STreehugger Robot    printf("Files that exhibit known bugs may provide\n");
611*7c3d14c8STreehugger Robot    printf("    rdar://whatever such that if they fail the rdar will get cited\n");
612*7c3d14c8STreehugger Robot    printf("Files that are expected to fail to compile should provide, as their last token sequence,\n");
613*7c3d14c8STreehugger Robot    printf("    error:\n");
614*7c3d14c8STreehugger Robot    printf(" or error: substring to match.\n");
615*7c3d14c8STreehugger Robot    printf("Files that are expected to produce a runtime error message should provide, as their last token sequence,\n");
616*7c3d14c8STreehugger Robot    printf("    warning: string to match\n");
617*7c3d14c8STreehugger Robot    printf("\n%s will compile and run all configurations of the test files and report a summary at the end. Good luck.\n", whoami);
618*7c3d14c8STreehugger Robot    printf("       Blaine Garst [email protected]\n");
619*7c3d14c8STreehugger Robot}
620*7c3d14c8STreehugger Robot
621*7c3d14c8STreehugger Robotint main(int argc, char *argv[]) {
622*7c3d14c8STreehugger Robot    printf("running on %s-bit architecture\n", sizeof(long) == 4 ? "32" : "64");
623*7c3d14c8STreehugger Robot    char *compilerDir = "/usr/bin";
624*7c3d14c8STreehugger Robot    NSMutableArray *generators = [NSMutableArray new];
625*7c3d14c8STreehugger Robot    bool doFast = false;
626*7c3d14c8STreehugger Robot    bool doStdin = false;
627*7c3d14c8STreehugger Robot    bool onlyOpen = false;
628*7c3d14c8STreehugger Robot    char *libraryPath = getenv("DYLD_LIBRARY_PATH");
629*7c3d14c8STreehugger Robot    char *frameworkPath = getenv("DYLD_FRAMEWORK_PATH");
630*7c3d14c8STreehugger Robot    // process options
631*7c3d14c8STreehugger Robot    while (argc > 1) {
632*7c3d14c8STreehugger Robot        if (!strcmp(argv[1], "-fast")) {
633*7c3d14c8STreehugger Robot            doFast = true;
634*7c3d14c8STreehugger Robot            --argc;
635*7c3d14c8STreehugger Robot            ++argv;
636*7c3d14c8STreehugger Robot        }
637*7c3d14c8STreehugger Robot        else if (!strcmp(argv[1], "-dyld")) {
638*7c3d14c8STreehugger Robot            doFast = true;
639*7c3d14c8STreehugger Robot            --argc;
640*7c3d14c8STreehugger Robot            ++argv;
641*7c3d14c8STreehugger Robot            frameworkPath = argv[1];
642*7c3d14c8STreehugger Robot            libraryPath = argv[1];
643*7c3d14c8STreehugger Robot            --argc;
644*7c3d14c8STreehugger Robot            ++argv;
645*7c3d14c8STreehugger Robot        }
646*7c3d14c8STreehugger Robot        else if (!strcmp(argv[1], "-open")) {
647*7c3d14c8STreehugger Robot            onlyOpen = true;
648*7c3d14c8STreehugger Robot            --argc;
649*7c3d14c8STreehugger Robot            ++argv;
650*7c3d14c8STreehugger Robot        }
651*7c3d14c8STreehugger Robot        else if (!strcmp(argv[1], "-clang")) {
652*7c3d14c8STreehugger Robot            DoClang = true;
653*7c3d14c8STreehugger Robot            --argc;
654*7c3d14c8STreehugger Robot            ++argv;
655*7c3d14c8STreehugger Robot        }
656*7c3d14c8STreehugger Robot        else if (!strcmp(argv[1], "-e")) {
657*7c3d14c8STreehugger Robot            Everything = true;
658*7c3d14c8STreehugger Robot            --argc;
659*7c3d14c8STreehugger Robot            ++argv;
660*7c3d14c8STreehugger Robot        }
661*7c3d14c8STreehugger Robot        else if (!strcmp(argv[1], "--")) {
662*7c3d14c8STreehugger Robot            doStdin = true;
663*7c3d14c8STreehugger Robot            --argc;
664*7c3d14c8STreehugger Robot            ++argv;
665*7c3d14c8STreehugger Robot        }
666*7c3d14c8STreehugger Robot        else if (!strcmp(argv[1], "-")) {
667*7c3d14c8STreehugger Robot            help(argv[0]);
668*7c3d14c8STreehugger Robot            return 1;
669*7c3d14c8STreehugger Robot        }
670*7c3d14c8STreehugger Robot        else if (argc > 1 && isDirectory(argv[1])) {
671*7c3d14c8STreehugger Robot            compilerDir = argv[1];
672*7c3d14c8STreehugger Robot            ++argv;
673*7c3d14c8STreehugger Robot            --argc;
674*7c3d14c8STreehugger Robot        }
675*7c3d14c8STreehugger Robot        else
676*7c3d14c8STreehugger Robot            break;
677*7c3d14c8STreehugger Robot    }
678*7c3d14c8STreehugger Robot    // process remaining arguments, or stdin
679*7c3d14c8STreehugger Robot    if (argc == 1) {
680*7c3d14c8STreehugger Robot        if (doStdin)
681*7c3d14c8STreehugger Robot            generators = (NSMutableArray *)[TestFileExeGenerator generatorsFromFILE:stdin];
682*7c3d14c8STreehugger Robot        else {
683*7c3d14c8STreehugger Robot            help(argv[0]);
684*7c3d14c8STreehugger Robot            return 1;
685*7c3d14c8STreehugger Robot        }
686*7c3d14c8STreehugger Robot    }
687*7c3d14c8STreehugger Robot    else while (argc > 1) {
688*7c3d14c8STreehugger Robot        TestFileExeGenerator *generator = [TestFileExeGenerator generatorFromFilename:argv[1]];
689*7c3d14c8STreehugger Robot        if (generator) [generators addObject:generator];
690*7c3d14c8STreehugger Robot        ++argv;
691*7c3d14c8STreehugger Robot        --argc;
692*7c3d14c8STreehugger Robot    }
693*7c3d14c8STreehugger Robot    // see if we can generate all possibilities
694*7c3d14c8STreehugger Robot    NSMutableArray *failureToCompile = [NSMutableArray new];
695*7c3d14c8STreehugger Robot    NSMutableArray *failureToFailToCompile = [NSMutableArray new];
696*7c3d14c8STreehugger Robot    NSMutableArray *failureToRun = [NSMutableArray new];
697*7c3d14c8STreehugger Robot    NSMutableArray *successes = [NSMutableArray new];
698*7c3d14c8STreehugger Robot    for (TestFileExeGenerator *generator in generators) {
699*7c3d14c8STreehugger Robot        //NSLog(@"got %@", generator);
700*7c3d14c8STreehugger Robot        if (onlyOpen && !generator.open) {
701*7c3d14c8STreehugger Robot            //printf("skipping resolved test %s\n", generator.filename);
702*7c3d14c8STreehugger Robot            continue;  // skip closed if onlyOpen
703*7c3d14c8STreehugger Robot        }
704*7c3d14c8STreehugger Robot        if (!onlyOpen && generator.open) {
705*7c3d14c8STreehugger Robot            //printf("skipping open test %s\n", generator.filename);
706*7c3d14c8STreehugger Robot            continue;  // skip open if not asked for onlyOpen
707*7c3d14c8STreehugger Robot        }
708*7c3d14c8STreehugger Robot        generator.compilerPath = compilerDir;
709*7c3d14c8STreehugger Robot        NSArray *tests = [generator allLines];
710*7c3d14c8STreehugger Robot        for (TestFileExe *line in tests) {
711*7c3d14c8STreehugger Robot            line.frameworkPath = frameworkPath;   // tell generators about it instead XXX
712*7c3d14c8STreehugger Robot            line.libraryPath = libraryPath;   // tell generators about it instead XXX
713*7c3d14c8STreehugger Robot            if ([line shouldFail]) {
714*7c3d14c8STreehugger Robot                if (doFast) continue; // don't recompile & don't count as success
715*7c3d14c8STreehugger Robot                if ([line compileWithExpectedFailure]) {
716*7c3d14c8STreehugger Robot                    [successes addObject:line];
717*7c3d14c8STreehugger Robot                }
718*7c3d14c8STreehugger Robot                else
719*7c3d14c8STreehugger Robot                    [failureToFailToCompile addObject:line];
720*7c3d14c8STreehugger Robot            }
721*7c3d14c8STreehugger Robot            else if ([line compileUnlessExists:doFast]) {
722*7c3d14c8STreehugger Robot                if ([line run]) {
723*7c3d14c8STreehugger Robot                    printf("%s ran successfully\n", line.binaryName);
724*7c3d14c8STreehugger Robot                    [successes addObject:line];
725*7c3d14c8STreehugger Robot                }
726*7c3d14c8STreehugger Robot                else {
727*7c3d14c8STreehugger Robot                    [failureToRun addObject:line];
728*7c3d14c8STreehugger Robot                }
729*7c3d14c8STreehugger Robot            }
730*7c3d14c8STreehugger Robot            else {
731*7c3d14c8STreehugger Robot                [failureToCompile addObject:line];
732*7c3d14c8STreehugger Robot            }
733*7c3d14c8STreehugger Robot        }
734*7c3d14c8STreehugger Robot    }
735*7c3d14c8STreehugger Robot    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",
736*7c3d14c8STreehugger Robot        [successes count], [failureToCompile count], [failureToFailToCompile count], [failureToRun count]);
737*7c3d14c8STreehugger Robot    printDetails(failureToCompile, "unexpected compile failures");
738*7c3d14c8STreehugger Robot    printDetails(failureToFailToCompile, "should have failed to compile but didn't failures");
739*7c3d14c8STreehugger Robot    printDetails(failureToRun, "run failures");
740*7c3d14c8STreehugger Robot
741*7c3d14c8STreehugger Robot    if (onlyOpen && [successes count]) {
742*7c3d14c8STreehugger Robot        NSMutableSet *radars = [NSMutableSet new];
743*7c3d14c8STreehugger Robot        printf("The following tests ran successfully suggesting that they are now resolved:\n");
744*7c3d14c8STreehugger Robot        for (TestFileExe *line in successes) {
745*7c3d14c8STreehugger Robot            printf("%s\n", line.binaryName);
746*7c3d14c8STreehugger Robot            if (line.radar) [radars addObject:line.generator];
747*7c3d14c8STreehugger Robot        }
748*7c3d14c8STreehugger Robot        if ([radars count]) {
749*7c3d14c8STreehugger Robot            printf("The following radars may be resolved:\n");
750*7c3d14c8STreehugger Robot            for (TestFileExeGenerator *line in radars) {
751*7c3d14c8STreehugger Robot                printf("%s\n", line.radar);
752*7c3d14c8STreehugger Robot            }
753*7c3d14c8STreehugger Robot        }
754*7c3d14c8STreehugger Robot    }
755*7c3d14c8STreehugger Robot
756*7c3d14c8STreehugger Robot    return [failureToCompile count] + [failureToRun count];
757*7c3d14c8STreehugger Robot}
758*7c3d14c8STreehugger Robot
759*7c3d14c8STreehugger Robot#include <sys/stat.h>
760*7c3d14c8STreehugger Robot
761*7c3d14c8STreehugger Robotstatic bool isDirectory(char *path) {
762*7c3d14c8STreehugger Robot    struct stat statb;
763*7c3d14c8STreehugger Robot    int retval = stat(path, &statb);
764*7c3d14c8STreehugger Robot    if (retval != 0) return false;
765*7c3d14c8STreehugger Robot    if (statb.st_mode & S_IFDIR) return true;
766*7c3d14c8STreehugger Robot    return false;
767*7c3d14c8STreehugger Robot}
768*7c3d14c8STreehugger Robot
769*7c3d14c8STreehugger Robotstatic bool isExecutable(char *path) {
770*7c3d14c8STreehugger Robot    struct stat statb;
771*7c3d14c8STreehugger Robot    int retval = stat(path, &statb);
772*7c3d14c8STreehugger Robot    if (retval != 0) return false;
773*7c3d14c8STreehugger Robot    if (!(statb.st_mode & S_IFREG)) return false;
774*7c3d14c8STreehugger Robot    if (statb.st_mode & S_IXUSR) return true;
775*7c3d14c8STreehugger Robot    return false;
776*7c3d14c8STreehugger Robot}
777*7c3d14c8STreehugger Robot
778*7c3d14c8STreehugger Robotstatic bool isYounger(char *source, char *binary) {
779*7c3d14c8STreehugger Robot    struct stat statb;
780*7c3d14c8STreehugger Robot    int retval = stat(binary, &statb);
781*7c3d14c8STreehugger Robot    if (retval != 0) return true;  // if doesn't exit, lie
782*7c3d14c8STreehugger Robot
783*7c3d14c8STreehugger Robot    struct stat stata;
784*7c3d14c8STreehugger Robot    retval = stat(source, &stata);
785*7c3d14c8STreehugger Robot    if (retval != 0) return true; // we're hosed
786*7c3d14c8STreehugger Robot    // the greater the timeval the younger it is
787*7c3d14c8STreehugger Robot    if (stata.st_mtimespec.tv_sec > statb.st_mtimespec.tv_sec) return true;
788*7c3d14c8STreehugger Robot    if (stata.st_mtimespec.tv_nsec > statb.st_mtimespec.tv_nsec) return true;
789*7c3d14c8STreehugger Robot    return false;
790*7c3d14c8STreehugger Robot}
791*7c3d14c8STreehugger Robot
792*7c3d14c8STreehugger Robotstatic bool readErrorFile(char *buffer, const char *from) {
793*7c3d14c8STreehugger Robot    int fd = open(from, 0);
794*7c3d14c8STreehugger Robot    if (fd < 0) {
795*7c3d14c8STreehugger Robot        printf("didn't open %s, (might not have been created?)\n", buffer);
796*7c3d14c8STreehugger Robot        return false;
797*7c3d14c8STreehugger Robot    }
798*7c3d14c8STreehugger Robot    int count = read(fd, buffer, 512);
799*7c3d14c8STreehugger Robot    if (count < 1) {
800*7c3d14c8STreehugger Robot        printf("read error on %s\n", buffer);
801*7c3d14c8STreehugger Robot        return false;
802*7c3d14c8STreehugger Robot    }
803*7c3d14c8STreehugger Robot    buffer[count-1] = 0; // zap newline
804*7c3d14c8STreehugger Robot    return true;
805*7c3d14c8STreehugger Robot}
806