• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2009, The Android Open Source Project
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *  * Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  *  * Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 
26 #include <map>
27 #include <string>
28 #include <vector>
29 #include <cstdio>
30 #include <stdlib.h>
31 #include <string.h>
32 
33 using namespace std;
34 
35 string WEBKITLIB = "external/webkit";
36 
37 string oldBaseStr;
38 string oldCmdStr;
39 string newBaseStr;
40 string newCmdStr;
41 string sandboxBaseStr;
42 string sandboxCmdStr;
43 string outputDir;
44 string scratchDir;
45 
46 const char* oldBase;
47 const char* oldCmd;
48 const char* newBase;
49 const char* newCmd;
50 const char* sandboxBase;
51 const char* sandboxCmd;
52 
53 bool assert_debug;
54 
55 #define myassert(a) do { \
56     if (!(a)) { \
57         fprintf(stderr, "%s %d %s\n", __FUNCTION__, __LINE__, #a); \
58         fflush(stderr); \
59         if (assert_debug) for(;;); else exit(0); \
60     } \
61 } while(false)
62 
63 class Options {
64 public:
Options()65     Options() : emitGitCommands(false), emitPerforceCommands(false),
66         mergeMake(true), copyOther(true), mergeCore(true),
67         removeEmptyDirs(true), removeSVNDirs(true), debug(false),
68         execute(false), verbose(false), cleared(false)
69     {
70     }
71 
72     bool finish();
clearOnce()73     void clearOnce()
74     {
75         if (cleared)
76             return;
77         mergeMake = copyOther = mergeCore = removeEmptyDirs = removeSVNDirs = false;
78         cleared = true;
79     }
80     string androidWebKit;
81     string baseWebKit;
82     string newWebKit;
83     bool emitGitCommands;
84     bool emitPerforceCommands;
85     bool mergeMake;
86     bool copyOther;
87     bool mergeCore;
88     bool removeEmptyDirs;
89     bool removeSVNDirs;
90     bool debug;
91     bool execute;
92     bool verbose;
93 private:
94     bool cleared;
95 };
96 
97 Options options;
98 
GetFile(string fileNameStr,size_t * sizePtr=NULL,int * lines=NULL)99 char* GetFile(string fileNameStr, size_t* sizePtr = NULL, int* lines = NULL)
100 {
101     const char* fileName = fileNameStr.c_str();
102     FILE* file = fopen(fileName, "r");
103     if (file == NULL)
104     {
105         fprintf(stderr, "can't read %s\n", fileName);
106         myassert(0);
107         return 0;
108     }
109     fseek(file, 0, SEEK_END);
110     size_t size = ftell(file);
111     if (sizePtr)
112         *sizePtr = size;
113     fseek(file, 0, SEEK_SET);
114     char* buffer = new char[size + 2];
115     fread(buffer, size, 1, file);
116     buffer[size] = buffer[size + 1] = '\0';
117     int lineCount = 0;
118     for (size_t index = 0; index < size; index++) {
119         if (buffer[index] == '\n') {
120             buffer[index] = '\0';
121             lineCount++;
122         }
123     }
124     if (lines)
125         *lines = lineCount;
126     fclose(file);
127     return buffer;
128 }
129 
finish()130 bool Options::finish()
131 {
132     ::assert_debug = options.debug;
133     if (androidWebKit.size() == 0) {
134         fprintf(stderr, "missing --android parameter");
135         return false;
136     }
137     if (baseWebKit.size() == 0) {
138         fprintf(stderr, "missing --basewebkit parameter");
139         return false;
140     }
141     if (newWebKit.size() == 0) {
142         fprintf(stderr, "missing --newwebkit parameter");
143         return false;
144     }
145     sandboxBaseStr = androidWebKit + "/" + WEBKITLIB;
146     sandboxCmdStr = sandboxBaseStr;
147     int err = system("pwd > pwd.txt");
148     myassert(err != -1);
149     outputDir = string(GetFile("pwd.txt"));
150     system("rm pwd.txt");
151     myassert(outputDir.size() > 0);
152     scratchDir = outputDir;
153     outputDir += "/scripts/";
154     string outputMkdir = "test -d " + outputDir + " || mkdir " + outputDir;
155     system(outputMkdir.c_str());
156     scratchDir += "/scratch/";
157     string scratchMkdir = "test -d " + scratchDir + " || mkdir " + scratchDir;
158     system(scratchMkdir.c_str());
159     oldBaseStr = baseWebKit;
160     oldCmdStr = oldBaseStr;
161     newBaseStr = newWebKit;
162     newCmdStr = newBaseStr;
163     oldBase = oldBaseStr.c_str();
164     oldCmd = oldCmdStr.c_str();
165     newBase = newBaseStr.c_str();
166     newCmd = newCmdStr.c_str();
167     sandboxBase = sandboxBaseStr.c_str();
168     sandboxCmd = sandboxCmdStr.c_str();
169     return true;
170 }
171 
172 // scratch files
ScratchFile(const char * name)173 string ScratchFile(const char* name)
174 {
175     return scratchDir + name + ".txt";
176 }
177 
178 FILE* commandFile;
179 FILE* copyDirFile;
180 FILE* oopsFile;
181 
SedEscape(const char * str)182 string SedEscape(const char* str)
183 {
184     string result;
185     char ch;
186     while ((ch = *str++) != '\0') {
187         if (ch == '/' || ch == '\\' || ch == '$')
188             result += '\\';
189         result += ch;
190     }
191     return result;
192 }
193 
List(const char * base,char * name,const char * workingDir)194 char* List(const char* base, char* name, const char* workingDir)
195 {
196     string listStr = "ls -F \"";
197     listStr += string(base) + "/" + workingDir + "\" > " + ScratchFile(name);
198     int err = system(listStr.c_str());
199     myassert(err == 0);
200     return GetFile(ScratchFile(name));
201 }
202 
Merge(const char * oldDir,const char * oldFile,const char * newDir,const char * newFile,const char * outFile)203 bool Merge(const char* oldDir, const char* oldFile, const char* newDir, const char* newFile,
204     const char* outFile)
205 {
206     char scratch[2048];
207 
208     sprintf(scratch, "merge -p -q \"%s/%s/%s\" \"%s/%s/%s\"  \"%s/%s/%s\" > %s",
209             sandboxBase, oldDir, oldFile, oldBase, oldDir, oldFile, newBase, newDir, newFile, outFile);
210     int err = system(scratch);
211     myassert(err == 0 || err ==1 || err == 256);
212     return err == 0;
213 }
214 
Merge(const char * dir,const char * file)215 bool Merge(const char* dir, const char* file)
216 {
217     return Merge(dir, file, dir, file, "/dev/null");
218 }
219 
220 /*
221 static const char* skipNonSpace(char** linePtr) {
222     char* line = *linePtr;
223     while (line[0] && isspace(line[0]) == false)
224         line++;
225     *linePtr = line;
226     return line;
227 }
228 */
229 
endsWith(const char * str,const char * end)230 static bool endsWith(const char* str, const char* end) {
231 	size_t endLen = strlen(end);
232 	const char* endStr = str + strlen(str) - endLen;
233 	return endStr >= str && strcmp(endStr, end) == 0;
234 }
235 
skipSpace(char ** linePtr)236 static void skipSpace(char** linePtr) {
237     char* line = *linePtr;
238     while (isspace(line[0]))
239         line++;
240     *linePtr = line;
241 }
242 
243 /*
244 static void setTrimmed(string& str, char* loc, int len) {
245     char* start = loc;
246     skipSpace(&loc);
247     len -= loc - start;
248     while (len > 0 && isspace(loc[len - 1]))
249         len--;
250     str = string(loc, len);
251 }
252 */
253 
skipText(char ** linePtr,const char * text)254 static bool skipText(char** linePtr, const char* text) {
255     skipSpace(linePtr);
256     size_t length = strlen(text);
257     bool result = strncmp(*linePtr, text, length) == 0;
258     if (result)
259         *linePtr += length;
260     skipSpace(linePtr);
261     return result;
262 }
263 
isTokenChar(char ch)264 static bool isTokenChar(char ch) {
265     return isalnum(ch) || ch == '_';
266 }
267 
268 struct Pair {
269     char* name;
270     int brace;
271 };
272 
273 class Parse {
274 public:
275     char* m_text;
276     bool m_inComment;
277     bool m_inFunction;
278     bool m_inFindFunctionType;
279     vector<Pair> m_classes;
280     vector<Pair> m_namespaces;
281     vector<Pair> m_preprocessorConditions;
282     string m_functionName;
283     string m_functionDeclaration;
284     string m_classDeclaration;
285     int m_braceLevel;
286     int m_functionBrace;
287 
Parse(char * text)288     Parse(char* text) : m_text(text), m_inComment(false), m_inFunction(false), m_inFindFunctionType(false),
289         m_braceLevel(0), m_functionBrace(0) {}
290 
CheckForBrace()291     int CheckForBrace()
292     {
293         int indent = 0;
294         // don't count braces in strings, chars, comments
295         do {
296             char* openBrace = strchr(m_text, '{');
297             char* closeBrace = strchr(m_text, '}');
298             if (openBrace == NULL && closeBrace == NULL)
299                 break;
300             char* brace = openBrace == NULL ? closeBrace : closeBrace == NULL ? openBrace :
301                 openBrace < closeBrace ? openBrace : closeBrace;
302             char* doubleQ = strchr(m_text, '"');
303             char* singleQ = strchr(m_text, '\'');
304             char* quote = doubleQ == NULL ? singleQ : singleQ == NULL ? doubleQ :
305                 doubleQ < singleQ ? doubleQ : singleQ;
306             char quoteMark = quote == doubleQ ? '"' : '\'';
307             if (quote && quote < brace) {
308                 myassert(quote[-1] != '\\');
309                 do {
310                     quote = strchr(quote + 1, quoteMark);
311                     myassert(doubleQ);
312                 } while (quote[-1] == '\\');
313                 m_text = quote + 1;
314                 continue;
315             }
316             indent += openBrace != NULL ? 1 : -1;
317             m_text = openBrace + 1;
318         } while (m_text[0] != '\0');
319         return indent;
320     }
321 
ParseLine()322 int ParseLine()
323 {
324     size_t textLen = strlen(m_text);
325     char* lineStart = m_text;
326     char* commentStart;
327     if (m_text[0] == '\0')
328         goto nextLine;
329     if (m_inComment == false && m_text[0] == '/') {
330         m_inComment = m_text[1] == '*';
331         if (m_text[1] == '/' || m_text[1] == '*')
332             goto nextLine;
333     }
334     commentStart = m_text; // before anything else, turn embedded comments into their own lines
335     if (m_inComment == false && skipText(&commentStart, "//")) {
336         if (commentStart < lineStart + textLen)
337             commentStart[0] = '/';
338         else
339             commentStart[-1] = ' ';
340         commentStart -= 2;
341         commentStart[0] = '\0';
342        textLen = commentStart - lineStart;
343        goto nextLine;
344     }
345     if (m_inComment || skipText(&commentStart, "/*")) {
346         char* commentEnd = commentStart;
347         if (skipText(&commentEnd, "*/")) {
348             if (commentEnd < lineStart + textLen) {
349                 commentEnd[-1] = '\0';
350                 textLen = commentEnd - lineStart - 2;
351             }
352             if (m_inComment) {
353                 m_inComment = false;
354                 goto nextLine;
355             }
356         }
357          if (m_inComment)
358             goto nextLine;
359         memcpy(commentStart - 2, "\0/*", 3);
360         textLen = commentStart - lineStart - 2;
361    }
362     if (skipText(&m_text, "#include"))
363         goto nextLine;
364     if (skipText(&m_text, "#if") || skipText(&m_text, "#else")) {
365         Pair condition = { lineStart, m_braceLevel };
366         m_preprocessorConditions.push_back(condition);
367         goto nextLine;
368     }
369     {
370         bool is_endif = false;
371         if (skipText(&m_text, "#elif") || (is_endif = skipText(&m_text, "#endif")) != false) { // pop prior elif, if
372             char* lastText;
373             do {
374                 int last = m_preprocessorConditions.size() - 1;
375                 myassert(last >= 0);
376                 lastText = m_preprocessorConditions[last].name;
377                 m_preprocessorConditions.pop_back();
378             } while (is_endif && skipText(&lastText, "#else") == true);
379             goto nextLine;
380         }
381     }
382     if (skipText(&m_text, "namespace")) {
383         Pair space = { lineStart, m_braceLevel };
384         m_namespaces.push_back(space);
385         goto checkForBrace;
386     }
387     if (m_inFunction)
388         goto checkForBrace;
389     // detect functions by looking for token preceding open-paren.
390     if (m_inFindFunctionType == false) {
391         char* openParen = strchr(m_text, '(');
392         if (openParen) {
393             char* last = openParen;
394             while (last > m_text && isspace(last[-1]))
395                 --last;
396             while (last > m_text && ((isTokenChar(last[-1]) || last[-1] == ':') && last[-2] == ':'))
397                 --last;
398             myassert(isdigit(last[0]) == false);
399             if (isTokenChar(last[0])) {
400                 m_inFindFunctionType = true;
401                 m_functionName = string(last);
402             }
403         }
404     }
405     {
406         char* openBrace = strchr(m_text, '{');
407         char* semiColon = strchr(m_text, ';');
408         if  (semiColon != NULL && semiColon < openBrace)
409             openBrace = NULL;
410     // functions are of the form: type (class::)*function(parameter-list) {
411         // all of which may be on separate lines
412         // so keep track of returntype, class, function, paramlist, openbrace separately
413         if (m_inFindFunctionType == true) { // look ahead to see which comes first, a semicolon or an open brace
414             if (openBrace) {
415                 m_functionBrace = ++m_braceLevel;
416                 m_inFunction = true;
417                 m_inFindFunctionType = false;
418                 m_text = openBrace + 1;
419                 goto checkForBrace;
420             }
421             if (semiColon != NULL) { // a function declaration
422                 m_inFindFunctionType = false;
423                 m_functionDeclaration = m_functionName;
424                 m_functionName.erase(0, m_functionName.length());
425             } else
426                 goto nextLine;
427         }
428         // FIXME what if class line has neither brace nor semi?
429         if (skipText(&m_text, "class")) {
430             if (openBrace > m_text) {
431                 Pair _class = { lineStart, m_braceLevel };
432                 m_classes.push_back(_class);
433             } else if (semiColon != NULL) {
434                 m_classDeclaration = lineStart; // !!! FIXME should have function form as above
435             }
436         }
437     }
438 checkForBrace:
439     m_braceLevel += CheckForBrace();
440     if (m_functionBrace > 0 && m_braceLevel <= m_functionBrace) {
441         m_functionName.erase(0, m_functionName.length());
442         m_functionBrace = 0;
443     }
444 nextLine:
445     return textLen;
446 }
447 
448 };
449 
GetAndroidDiffs(const char * dir,const char * filename)450 char* const GetAndroidDiffs(const char* dir, const char* filename)
451 {
452     char scratch[2048];
453     string diffsFile = ScratchFile(__FUNCTION__);
454     sprintf(scratch, "diff \"%s/%s/%s\"  \"%s/%s/%s\" > %s", sandboxBase, dir,
455         filename, oldBase, dir, filename, diffsFile.c_str());
456     int err = system(scratch);
457     myassert(err == 0 || err == 256);
458     char* const diffs = GetFile(diffsFile);
459     return diffs;
460 }
461 
CheckForExec(const char * base1,const char * dir1,const char * file1,const char * base2,const char * dir2,const char * file2,bool * ex1,bool * ex2)462 void CheckForExec(const char* base1, const char* dir1, const char* file1,
463     const char* base2, const char* dir2, const char* file2, bool* ex1, bool* ex2)
464 {
465     size_t file1Len = strlen(file1);
466     size_t file2Len = strlen(file2);
467     bool file1Ex = file1[file1Len - 1] == '*';
468     bool file2Ex = file2[file2Len - 1] == '*';
469     if (file1Ex != file2Ex) {
470         fprintf(stderr, "warning: %s/%s/%s has %sexec bit set while"
471             " %s/%s/%s has %sexec bit set\n",
472             base1, dir1, file1, file1Ex ? "" : "no ",
473             base2, dir2, file2, file2Ex ? "" : "no ");
474     }
475     if (ex1) *ex1 = file1Ex;
476     if (ex2) *ex2 = file2Ex;
477 }
478 
CompareFiles(const char * base1,const char * dir1,const char * file1,const char * base2,const char * dir2,const char * file2)479 bool CompareFiles(const char* base1, const char* dir1, const char* file1,
480      const char* base2, const char* dir2, const char* file2)
481 {
482     char scratch[2048];
483     bool file1Ex, file2Ex;
484     string compareFileStr = ScratchFile(__FUNCTION__);
485     CheckForExec(base1, dir1, file1, base2, dir2, file2, &file1Ex, &file2Ex);
486     sprintf(scratch, "diff --brief \"%s/%s/%.*s\" \"%s/%s/%.*s\" > %s",
487         base1, dir1, (int) strlen(file1) - (int) file1Ex, file1,
488         base2, dir2, (int) strlen(file2) - (int) file2Ex, file2,
489         compareFileStr.c_str());
490     int err = system(scratch);
491     myassert(err == 0 || err == 256);
492     char* scratchText = GetFile(compareFileStr);
493     size_t len = strlen(scratchText);
494     delete[] scratchText;
495     return len > 0;
496 }
497 
CompareFiles(const char * base1,const char * base2,const char * dir,const char * file)498 bool CompareFiles(const char* base1, const char* base2, const char* dir, const char* file)
499 {
500     return CompareFiles(base1, dir, file, base2, dir, file);
501 }
502 
Compare(char * one,size_t len1,char * two,size_t len2)503 int Compare(char* one, size_t len1, char* two, size_t len2)
504 {
505     char* o_end = one + len1;
506     char* t_end = two + len2;
507     do {
508         if (one == o_end)
509             return two == t_end ? 0 : 1;
510         if (two == t_end)
511             return -1;
512         char o = *one++;
513         char t = *two++;
514         if (o == t)
515             continue;
516         if (o == '/')
517             return -1;
518         if (t == '/')
519             return 1;
520         return o < t ? -1 : 1;
521     } while (true);
522     myassert(0);
523     return 0;
524 }
525 
Find(const char * oldList)526 string Find(const char* oldList)
527 {
528     string result;
529     char scratch[2048];
530     // look in WebCore and JavaScriptCore
531     string findWebCore = ScratchFile("FindWebCore");
532     sprintf(scratch, "cd %s%s ;  find . -name \"%s\" > %s",
533             newBase, "/WebCore", oldList, findWebCore.c_str());
534     int err = system(scratch);
535     myassert(err == 0 || err == 256);
536     int webCount;
537     char* foundInWebCore = GetFile(findWebCore, NULL, &webCount);
538     char* originalFoundInWebCore = foundInWebCore;
539     string findJavaScriptCore = ScratchFile("FindJavaScriptCore");
540     sprintf(scratch, "cd %s%s ;  find . -name \"%s\" > %s",
541             newBase, "/JavaScriptCore", oldList, findJavaScriptCore.c_str());
542     err = system(scratch);
543     myassert(err == 0 || err == 256);
544     int javaScriptCount;
545     char* foundInJavaScriptCore = GetFile(findJavaScriptCore, NULL, &javaScriptCount);
546     char* originalFoundInJavaScriptCore = foundInJavaScriptCore;
547     if (webCount == 1 && javaScriptCount == 0) {
548         result = "WebCore/" + string(&foundInWebCore[2]);
549     } else if (webCount == 0 && javaScriptCount == 1) {
550         result = "JavaScriptCore/" + string(&foundInJavaScriptCore[2]);
551     } else if (webCount == 1 && javaScriptCount == 1 &&
552             strncmp(&foundInWebCore[2], "ForwardingHeaders/", 18) == 0) {
553         result = "JavaScriptCore/" + string(&foundInJavaScriptCore[2]);
554     } else if (webCount == 1 && javaScriptCount == 1 &&
555             strncmp(&foundInJavaScriptCore[2], "API/tests/", 10) == 0) {
556         result = "JavaScriptCore/" + string(&foundInJavaScriptCore[2]);
557     } else if (webCount + javaScriptCount > 0) {
558         fprintf(stderr, "deleted file \"%s\" has more than one possible rename:\n", oldList);
559         int index;
560         for (index = 0; index < webCount; index++) {
561             fprintf(stderr, "WebCore/%s\n", &foundInWebCore[2]);
562             foundInWebCore += strlen(foundInWebCore) + 1;
563         }
564         for (index = 0; index < javaScriptCount; index++) {
565             fprintf(stderr, "JavaScriptCore/%s\n", &foundInJavaScriptCore[2]);
566             foundInJavaScriptCore += strlen(foundInJavaScriptCore) + 1;
567         }
568     }
569     delete[] originalFoundInWebCore;
570     delete[] originalFoundInJavaScriptCore;
571     return result;
572 }
573 
GetMakeAndExceptions(const char * dir,const char * filename,size_t * makeSize,string * excludedFilesPtr,string * excludedGeneratedPtr,string * excludedDirsPtr,string * androidFilesPtr,char ** startPtr,char ** localStartPtr)574 char* GetMakeAndExceptions(const char* dir, const char* filename, size_t* makeSize,
575     string* excludedFilesPtr, string* excludedGeneratedPtr,
576     string* excludedDirsPtr, string* androidFilesPtr,
577     char** startPtr, char** localStartPtr)
578 {
579     char scratch[1024];
580     sprintf(scratch, "%s/%s/%s", sandboxBase, dir, filename);
581     char* makeFile = GetFile(scratch, makeSize);
582     char* start = makeFile;
583     do { // find first filename in makefile
584         if (strncmp(start, "# LOCAL_SRC_FILES_EXCLUDED := \\", 30) == 0)
585             break;
586         start += strlen(start) + 1;
587     } while (start < makeFile + *makeSize);
588     myassert(start[0] != '\0');
589     start += strlen(start) + 1;
590     // construct one very large regular expression that looks like:
591     // echo '%s' | grep -v -E 'DerivedSources.cpp|WebCorePrefix.cpp...'
592     // to filter out matches that aren't allowed
593     // wildcards '*' in the original need to be expanded to '.*'
594     string excludedFiles = "grep -v -E '";
595     while (strncmp(start, "#\t", 2) == 0) {
596         start += 2;
597         char ch;
598         while ((ch = *start++) != ' ') {
599             if (ch == '*')
600                 excludedFiles += '.';
601             else if (ch == '.')
602                 excludedFiles += '\\';
603             excludedFiles += ch;
604         }
605         excludedFiles += "|";
606         myassert(*start == '\\');
607         start += 2;
608     }
609     excludedFiles[excludedFiles.size() - 1] = '\'';
610     *excludedFilesPtr = excludedFiles;
611     do {
612         if (strncmp(start, "# LOCAL_GENERATED_FILES_EXCLUDED := \\", 37) == 0 ||
613                 strncmp(start, "# LOCAL_DIR_WILDCARD_EXCLUDED := \\", 34) == 0)
614             break;
615         start += strlen(start) + 1;
616     } while (start < makeFile + *makeSize);
617     if (strncmp(start, "# LOCAL_GENERATED_FILES_EXCLUDED := \\", 37) == 0) {
618         string excludedGenerated = "grep -v -E '";
619         start += strlen(start) + 1;
620         while (strncmp(start, "#\t", 2) == 0) {
621             start += 2;
622             char ch;
623             while ((ch = *start++) != ' ') {
624                 if (ch == '*')
625                     excludedGenerated += '.';
626                 else if (ch == '.')
627                     excludedGenerated += '\\';
628                 excludedGenerated += ch;
629             }
630             excludedGenerated += "|";
631             myassert(*start == '\\');
632             start += 2;
633         }
634         myassert(excludedGeneratedPtr);
635         excludedGenerated[excludedGenerated.size() - 1] = '\'';
636         *excludedGeneratedPtr = excludedGenerated;
637     }
638     do { // find first filename in makefile
639         if (strncmp(start, "# LOCAL_DIR_WILDCARD_EXCLUDED := \\", 34) == 0)
640             break;
641         start += strlen(start) + 1;
642     } while (start < makeFile + *makeSize);
643     if (start[0] != '\0') {
644         string excludedDirs = "-e '/\\.vcproj\\// d' -e '/\\.svn\\// d' ";
645         do {
646             start += strlen(start) + 1;
647             char* exceptionDirStart = start;
648             if (strncmp(exceptionDirStart, "#\t", 2) != 0) {
649                 myassert(exceptionDirStart[0] == '\0');
650                 break;
651             }
652             exceptionDirStart += 2;
653             char* exceptionDirEnd = exceptionDirStart;
654             do {
655                 exceptionDirEnd = strchr(exceptionDirEnd, '\\');
656             } while (exceptionDirEnd && *++exceptionDirEnd == '/');
657             myassert(exceptionDirEnd);
658             --exceptionDirEnd;
659             myassert(exceptionDirEnd[-1] == ' ');
660             myassert(exceptionDirEnd[-2] == '*');
661             myassert(exceptionDirEnd[-3] == '/');
662             exceptionDirEnd[-3] = '\0';
663             excludedDirs += "-e '/";
664             if (exceptionDirStart[0] == '/')
665                 excludedDirs += "\\";
666             excludedDirs += exceptionDirStart;
667             excludedDirs += "\\// d' ";
668             start = exceptionDirEnd;
669         } while (true);
670         *excludedDirsPtr = excludedDirs;
671     }
672     *startPtr = start;
673     // optionally look for android-specific files
674     char* makeEnd = makeFile + *makeSize;
675     do { // find first filename in makefile
676         if (strcmp(start, "# LOCAL_ANDROID_SRC_FILES_INCLUDED := \\") == 0)
677             break;
678     } while ((start += strlen(start) + 1), start < makeEnd);
679     if (start >= makeEnd)
680         return makeFile;
681     start += strlen(start) + 1;
682     string androidFiles = "grep -v -E '";
683     do {
684         myassert(strncmp(start, "#\t", 2) == 0);
685         start += 2;
686         char ch;
687         bool isIdl = strstr(start, "idl \\") != 0;
688         char* lastSlash = strrchr(start, '/') + 1;
689         while ((ch = *start++) != ' ') {
690             if (ch == '*')
691                 androidFiles += '.';
692             else if (ch == '.')
693                 androidFiles += '\\';
694             androidFiles += ch;
695             if (!isIdl)
696                 continue;
697             if (ch == '/' && start == lastSlash)
698                 androidFiles += "JS";
699             if (ch == '.') {
700                 myassert(strcmp(start, "idl \\") == 0);
701                 start += 4;
702                 androidFiles += 'h';
703                 break;
704             }
705         }
706         androidFiles += "|";
707         myassert(*start == '\\');
708         start += 2;
709     } while (start[0] == '#');
710     androidFiles[androidFiles.size() - 1] = '\'';
711     *androidFilesPtr = androidFiles;
712     return makeFile;
713 }
714 
GetDerivedSourcesMake(const char * dir)715 vector<char*> GetDerivedSourcesMake(const char* dir)
716 {
717     vector<char*> result;
718     char scratch[1024];
719     sprintf(scratch, "%s/%s/%s", newBase, dir, "DerivedSources.make");
720     size_t fileSize;
721     char* file = GetFile(scratch, &fileSize);
722     char* fileEnd = file + fileSize;
723     myassert(file);
724     size_t len;
725     do { // find first filename in makefile
726         len = strlen(file);
727         if (strcmp(file, "all : \\") == 0)
728             break;
729         file += len + 1;
730     } while (file < fileEnd);
731     myassert(strcmp(file, "all : \\") == 0);
732     file += len + 1;
733     while (file[0] != '#') {
734         len = strlen(file);
735         char* st = file;
736         skipSpace(&st);
737         if (st[0] != '\\' && st[0] != '$')
738             result.push_back(st);
739         file += len + 1;
740     }
741     return result;
742 }
743 
MarkDerivedFound(vector<char * > & derived,char * check,size_t len)744 bool MarkDerivedFound(vector<char*>& derived, char* check, size_t len)
745 {
746     bool found = false;
747     for (unsigned index = 0; index < derived.size(); index++) {
748         char* der = derived[index];
749         if (strncmp(der, check, len) == 0) {
750             der[0] = '\0';
751             found = true;
752         }
753     }
754     return found;
755 }
756 
UpdateDerivedMake()757 void UpdateDerivedMake()
758 {
759     const char* dir = "WebCore";
760     int err;
761     vector<char*> derived = GetDerivedSourcesMake(dir);
762     size_t makeSize;
763     char* start, * localStart;
764     string excludedDirs, excludedFiles, excludedGenerated, androidFiles;
765     char* makeFile = GetMakeAndExceptions(dir, "Android.derived.mk", &makeSize,
766         &excludedFiles, &excludedGenerated, &excludedDirs, &androidFiles,
767         &start, &localStart);
768     if (options.emitPerforceCommands)
769         fprintf(commandFile, "p4 edit %s/%s/%s\n", sandboxCmd, dir, "Android.derived.mk");
770     fprintf(commandFile, "cat %s/%s/%s | sed \\\n", sandboxCmd, dir, "Android.derived.mk");
771     string updateDerivedMake = ScratchFile(__FUNCTION__);
772     string filelist = string("cd ") + newBase + "/" + dir +
773         " ;  find . -name '*.idl' | " + excludedFiles +
774         " | sed -e 's/.\\///' " + excludedDirs +
775         " | sed 's@\\(.*\\)/\\(.*\\)\\.idl@    $(intermediates)/\\1/JS\\2.h@' "
776         " | sort -o " + updateDerivedMake;
777     err = system(filelist.c_str());
778     myassert(err == 0 || err == 256);
779     char* bindings = GetFile(updateDerivedMake);
780     bool inGen = false;
781     char* fileEnd = makeFile + makeSize;
782     char* nextStart;
783     do {
784         size_t startLen = strlen(start);
785         nextStart = start + startLen + 1;
786         bool onGen = false;
787         char* st = start;
788         if (inGen == false) {
789             if (strncmp(st, "GEN", 3) != 0)
790                 continue;
791             st += 3;
792             skipSpace(&st);
793             if (strncmp(st, ":=", 2) != 0)
794                 continue;
795             st += 2;
796             onGen = true;
797         }
798         skipSpace(&st);
799         inGen = start[startLen - 1] == '\\';
800         if (inGen) {
801             if (st[0] == '\\' && st[1] == '\0')
802                 continue;
803             if (strcmp(st, "$(addprefix $(intermediates)/, \\") == 0)
804                 continue;
805         } else if (st[0] == ')' && st[1] == '\0')
806             continue;
807         static const char bindHead[] = "bindings/js/";
808         const size_t bindLen = sizeof(bindHead) - 1;
809         string escaped;
810         if (strncmp(st, bindHead, bindLen) == 0) {
811             st += bindLen;
812             if (MarkDerivedFound(derived, st, strlen(st)) == false) {
813                 fprintf(stderr, "*** webkit removed js binding: %s"
814                     " (must be removed manually)\n", st);
815                 escaped = SedEscape(st);
816                 fprintf(commandFile, "-e '/%s/ d' ", escaped.c_str());
817             }
818             continue;
819         }
820         myassert(strncmp(st, "$(intermediates)", 16) == 0);
821         if (onGen && inGen == false) { // no continuation
822             char* lastSlash;
823             myassert(strrchr(st, '/') != NULL);
824             while ((lastSlash = strrchr(st, '/')) != NULL) {
825                 char* lastEnd = strchr(lastSlash, ' ');
826                 if (lastEnd == NULL)
827                     lastEnd = lastSlash + strlen(lastSlash);
828                 myassert(lastSlash != 0);
829                 lastSlash++;
830                 size_t lastLen = lastEnd - lastSlash;
831                 if (MarkDerivedFound(derived, lastSlash, lastLen) == false) {
832                     fprintf(stderr, "*** webkit removed generated file:"
833                         " %.*s (must be removed manually)\n", (int) lastLen,
834                         lastSlash);
835               //      escaped = SedEscape(st);
836               //      fprintf(commandFile, "-e '/%s/ d' \\\n", escaped.c_str());
837                 }
838                 char* priorDollar = strrchr(st, '$');
839                 myassert(priorDollar != NULL);
840                 char* nextDollar = strchr(st, '$');
841                 if (nextDollar == priorDollar)
842                     break;
843                 priorDollar[0] = '\0';
844             }
845             continue;
846         }
847         char* nextSt = nextStart;
848         skipSpace(&nextSt);
849         myassert(strncmp(nextSt, "$(intermediates)", 16) != 0 || strcmp(st, nextSt) < 0);
850    //     do {
851         char* bind = bindings;
852         myassert(bind);
853         skipSpace(&bind);
854         int compare = strncmp(bind, st, strlen(bind) - 2);
855         if (compare < 0) { // add a file
856             escaped = SedEscape(st);
857             char* filename = strrchr(bindings, '/');
858             myassert(filename);
859             filename += 3;
860             // FIX ME: exclude items in DerivedSources.make all : $(filter-out ...
861             char* bi = bindings;
862             skipSpace(&bi);
863             char* bindName = strrchr(bi, '/');
864             myassert(bindName != NULL);
865             bindName++;
866             string biStr = SedEscape(bi);
867             fprintf(commandFile, "-e '/%s/ i\\\n_TAB_%s \\\\\n' ",
868                 escaped.c_str(), biStr.c_str());
869             MarkDerivedFound(derived, bindName, strlen(bindName));
870             nextStart = start;
871             bindings += strlen(bindings) + 1;
872             inGen = true;
873         } else if (compare > 0) {
874             // if file to be deleted is locally added by android, leave it alone
875             myassert(strncmp(st, "$(intermediates)/", 17) == 0);
876             string subst = string(st).substr(17, strlen(st) - 17 - (inGen ? 2 : 0));
877             string localDerivedStr = ScratchFile("LocalDerived");
878             string filter = string("echo '") + subst + "' | " + androidFiles +
879                 " > " + localDerivedStr;
880             if (options.debug)
881                 fprintf(stderr, "LocalDerived.txt : %s\n", filter.c_str());
882             err = system(filter.c_str());
883             myassert(err == 0 || err == 256);
884             char* localDerived = GetFile(localDerivedStr);
885             if (localDerived[0] != '\0') {
886                 escaped = SedEscape(st);
887                 fprintf(commandFile, "-e '/%s/ d' ", escaped.c_str());
888             }
889         } else {
890             char* stName = strrchr(st, '/');
891             myassert(stName);
892             stName++;
893             MarkDerivedFound(derived, stName, strlen(stName));
894             bindings += strlen(bindings) + 1;
895         }
896      //   } while (strstr(start, "$(intermediates)") != NULL);
897         // if changing directories, add any new files to the end of this directory first
898         if (bindings[0] != '\0' && strstr(nextStart, "$(intermediates)") == NULL) {
899             st = start;
900             skipSpace(&st);
901             escaped = SedEscape(st);
902             st = strchr(st, '/');
903             char* stDirEnd = strchr(st + 1, '/');
904             do {
905                 bind = strchr(bindings, '/');
906                 if (!bind)
907                     break;
908                 char* bindEnd = strchr(bind + 1, '/');
909                 if (!bindEnd)
910                     break;
911                 if (bindEnd - bind != stDirEnd - st)
912                     break;
913                 if (strncmp(st, bind, stDirEnd - st) != 0)
914                     break;
915                 if (inGen == false)
916                     fprintf(commandFile, "-e '/%s/ s/$/ \\\\/' ", escaped.c_str());
917                 char* bi = bindings;
918                 skipSpace(&bi);
919                 string biStr = SedEscape(bi);
920                 fprintf(commandFile, "-e '/%s/ a\\\n_TAB_%s\n' ",
921                     escaped.c_str(), biStr.c_str());
922                 MarkDerivedFound(derived, bindEnd + 1, strlen(bindEnd + 1));
923                 escaped = biStr;
924                 inGen = false;
925                 bindings += strlen(bindings) + 1;
926             } while (true);
927         }
928     } while (start = nextStart, start < fileEnd);
929     for (unsigned index = 0; index < derived.size(); index++) {
930         char* der = derived[index];
931         if (der[0] == '\0')
932             continue;
933         string excludedGeneratedStr = ScratchFile("ExcludedGenerated");
934         string filter = string("echo '") + der + "' | " + excludedGenerated +
935             " > " + excludedGeneratedStr;
936         err = system(filter.c_str());
937         myassert(err == 0 || err == 256);
938         char* excluded = GetFile(excludedGeneratedStr);
939         if (excluded[0] != '\0')
940             fprintf(stderr, "*** missing rule to generate %s\n", der);
941     }
942     fprintf(commandFile, " | sed 's/^_TAB_/\t/' > %s/%s/%s\n", sandboxCmd, dir, "xAndroid.derived.mk");
943     fprintf(commandFile, "mv  %s/%s/%s %s/%s/%s\n",
944         sandboxCmd, dir, "xAndroid.derived.mk", sandboxCmd, dir, "Android.derived.mk");
945     if (options.emitGitCommands)
946         fprintf(commandFile, "git add %s/%s\n", dir, "Android.derived.mk");
947 }
948 
MatchLen(const char * one,const char * two,size_t len)949 int MatchLen(const char* one, const char* two, size_t len)
950 {
951     bool svgIn1 = strstr(one, "svg") || strstr(one, "SVG");
952     bool svgIn2 = strstr(two, "svg") || strstr(two, "SVG");
953     if (svgIn1 != svgIn2)
954         return 0;
955     int signedLen = (int) len;
956     int original = signedLen;
957     while (*one++ == *two++ && --signedLen >= 0)
958         ;
959     return original - signedLen;
960 }
961 
962 // create the list of sed commands to update the WebCore Make file
UpdateMake(const char * dir)963 void UpdateMake(const char* dir)
964 {
965     // read in the makefile
966     size_t makeSize;
967     char* start, * localStart = NULL;
968     string excludedDirs, excludedFiles, androidFiles;
969     char* makeFile = GetMakeAndExceptions(dir, "Android.mk", &makeSize,
970         &excludedFiles, NULL, &excludedDirs, &androidFiles, &start, &localStart);
971     char* lastFileName = NULL;
972     size_t lastFileNameLen = 0;
973     int lastLineNumber = -1;
974     // get the actual list of files
975     string updateMakeStr = ScratchFile(__FUNCTION__);
976     string filelist = string("cd ") + newBase + "/" + dir + " ;"
977         "  find . -name '*.cpp' -or -name '*.c' -or -name '*.y' | " +
978         excludedFiles + " |  sed -e 's/.\\///' " + excludedDirs +
979         " | sort -o " + updateMakeStr;
980     if (options.debug)
981         fprintf(stderr, "make %s/%s filter: %s\n", dir, "Android.mk", filelist.c_str());
982     int err = system(filelist.c_str());
983     myassert(err == 0 || err == 256);
984     char* newList = GetFile(updateMakeStr);
985     do { // find first filename in makefile
986         if (strncmp(start, "LOCAL_SRC_FILES := \\", 20) == 0)
987             break;
988         start += strlen(start) + 1;
989     } while (start < makeFile + makeSize);
990     myassert(start[0] != '\0');
991     if (options.emitPerforceCommands)
992         fprintf(commandFile, "p4 edit %s/%s/%s\n", sandboxCmd, dir, "Android.mk");
993     fprintf(commandFile, "cat %s/%s/%s | sed ", sandboxCmd, dir, "Android.mk");
994     int lineNumber = 0;
995     do {
996         start += strlen(start) + 1;
997         lineNumber++;
998         if (start - makeFile >= makeSize || start[0] == '$')
999             break;
1000         if (start[0] == '\0' || !isspace(start[0]))
1001             continue;
1002         skipSpace(&start);
1003         if (start[0] == '\0' || start[0] == '\\')
1004             continue;
1005         size_t startLen = strlen(start);
1006         if (start[startLen - 1] == '\\')
1007             --startLen;
1008         while (isspace(start[startLen - 1]))
1009             --startLen;
1010         size_t newListLen = strlen(newList);
1011         if (lastFileName != NULL) {
1012             myassert(strncmp(start, lastFileName, startLen) > 0 ||
1013                 startLen > lastFileNameLen);
1014         }
1015         if (strstr(start, "android") != NULL || strstr(start, "Android") != NULL) {
1016             if (startLen == newListLen && strncmp(newList, start, startLen) == 0)
1017                 newList += newListLen + 1;
1018             lastFileName = start;
1019             lastFileNameLen = startLen;
1020             lastLineNumber = lineNumber;
1021             continue;
1022         }
1023         int compare;
1024         bool backslash = lastFileName &&
1025             lastFileName[strlen(lastFileName) - 1] == '\\';
1026         do {
1027             compare = strncmp(newList, start, startLen);
1028             if (compare == 0 && startLen != newListLen)
1029                 compare = newListLen < startLen ? -1 : 1;
1030             if (newList[0] == '\0' || compare >= 0)
1031                 break;
1032             // add a file
1033             if (lastFileName && lineNumber - lastLineNumber > 1 &&
1034                     MatchLen(lastFileName, newList, lastFileNameLen) >
1035                     MatchLen(start, newList, startLen)) {
1036                 string escaped = SedEscape(lastFileName);
1037                 if (!backslash)
1038                     fprintf(commandFile, "-e '/%s/ s/$/ \\\\/' ", escaped.c_str());
1039                 fprintf(commandFile, "-e '/%s/ a\\\n_TAB_%s%s\n' ",
1040                     SedEscape(lastFileName).c_str(), newList,
1041                     backslash ? " \\\\" : "");
1042                 lastFileName = newList;
1043                 lastFileNameLen = newListLen;
1044             } else {
1045                 fprintf(commandFile, "-e '/%s/ i\\\n_TAB_%s \\\\\n' ",
1046                     SedEscape(start).c_str(), newList);
1047             }
1048             newList += newListLen + 1;
1049             newListLen = strlen(newList);
1050         } while (true);
1051         if (newList[0] == '\0' || compare > 0) {
1052             // don't delete files added by Android
1053             string localMakeStr = ScratchFile("LocalMake");
1054             string filter = "echo '" + string(start).substr(0, startLen) +
1055                 "' | " + androidFiles + " > " + localMakeStr;
1056             int err = system(filter.c_str());
1057             myassert(err == 0 || err == 256);
1058             char* localMake = GetFile(localMakeStr);
1059             if (localMake[0] != '\0') {
1060                 string escaped = SedEscape(start);
1061                 fprintf(commandFile, "-e '/%s/ d' ", escaped.c_str());
1062             }
1063         } else
1064             newList += newListLen + 1;
1065         lastFileName = start;
1066         lastFileNameLen = startLen;
1067         lastLineNumber = lineNumber;
1068     } while (true);
1069     fprintf(commandFile, " | sed 's/^_TAB_/\t/' > %s/%s/%s\n", sandboxCmd, dir, "xAndroid.mk");
1070     fprintf(commandFile, "mv  %s/%s/%s %s/%s/%s\n",
1071         sandboxCmd, dir, "xAndroid.mk", sandboxCmd, dir, "Android.mk");
1072     if (options.emitGitCommands)
1073         fprintf(commandFile, "git add %s/%s\n", dir, "Android.mk");
1074 }
1075 
emptyDirectory(const char * base,const char * work,const char * dir)1076 static bool emptyDirectory(const char* base, const char* work, const char* dir) {
1077     string findEmptyStr = "find \"";
1078     string emptyDirStr = ScratchFile("emptyDirectory");
1079     if (base[0] != '\0')
1080         findEmptyStr += string(base) + "/" + work + "/" + dir + "\"";
1081     else
1082         findEmptyStr += string(work) + "/" + dir + "\"";
1083     findEmptyStr += " -type f -print > " + emptyDirStr;
1084     int err = system(findEmptyStr.c_str());
1085     if (err != 0)
1086         return true;
1087     FILE* file = fopen(emptyDirStr.c_str(), "r");
1088     if (file == NULL)
1089     {
1090         fprintf(stderr, "can't read %s\n", emptyDirStr.c_str());
1091         myassert(0);
1092         return true;
1093     }
1094     fseek(file, 0, SEEK_END);
1095     size_t size = ftell(file);
1096     fclose(file);
1097     return size == 0;
1098 }
1099 
emptyDirectory(const char * work,const char * dir)1100 static bool emptyDirectory(const char* work, const char* dir) {
1101     return emptyDirectory("", work, dir);
1102 }
1103 
CompareDirs(const char * workingDir,bool renamePass)1104 void CompareDirs(const char* workingDir, bool renamePass)
1105 {
1106     map<string, string> renameMap;
1107     char* oldList = List(oldBase, "old", workingDir);
1108     char* newList = List(newBase, "new", workingDir);
1109     char* sandList = List(sandboxBase, "sandbox", workingDir);
1110     char* oldMem = oldList;
1111     char* newMem = newList;
1112     char* sandboxMem = sandList;
1113     // identify files to be added, removed by comparing old, new lists
1114     do {
1115         size_t oldLen = strlen(oldList);
1116         size_t newLen = strlen(newList);
1117         size_t sandLen = strlen(sandList);
1118         if (oldLen == 0 && newLen == 0 && sandLen == 0)
1119             break;
1120         bool oldDir = false;
1121         bool oldExecutable = false;
1122         if (oldLen > 0) {
1123             char last = oldList[oldLen - 1];
1124             oldDir = last ==  '/';
1125             oldExecutable = last ==  '*';
1126             if (oldDir || oldExecutable)
1127                 --oldLen;
1128         }
1129         bool newDir = false;
1130         bool newExecutable = false;
1131         if (newLen > 0) {
1132             char last = newList[newLen - 1];
1133             newDir = last ==  '/';
1134             newExecutable = last ==  '*';
1135             if (newDir || newExecutable)
1136                 --newLen;
1137         }
1138         bool sandDir = false;
1139         bool sandExecutable = false;
1140         if (sandLen > 0) {
1141             char last = sandList[sandLen - 1];
1142             sandDir = last ==  '/';
1143             sandExecutable = last ==  '*';
1144             if (sandDir || sandExecutable)
1145                 --sandLen;
1146         }
1147         string oldFileStr = string(oldList).substr(0, oldLen);
1148         const char* oldFile = oldFileStr.c_str();
1149         string newFileStr = string(newList).substr(0, newLen);
1150         const char* newFile = newFileStr.c_str();
1151         string sandFileStr = string(sandList).substr(0, sandLen);
1152         const char* sandFile = sandFileStr.c_str();
1153         int order = Compare(oldList, oldLen, newList, newLen);
1154         int sandOrder = 0;
1155         if ((oldLen > 0 || sandLen > 0) && order <= 0) {
1156             sandOrder = Compare(sandList, sandLen, oldList, oldLen);
1157             if (sandOrder > 0 && renamePass == false)
1158                 fprintf(stderr, "error: file in old webkit missing from sandbox: %s/%s\n",
1159                         workingDir, oldFile);
1160             if (sandOrder < 0 && renamePass == false) {
1161                 // file added by android -- should always have name 'android?'
1162                 const char* android = strstr(sandFile, "ndroid");
1163                 if (android == NULL)
1164                     fprintf(stderr, "warning: expect added %s to contain 'android': %s/%s\n",
1165                             sandDir ? "directory" : "file" , workingDir, sandFile);
1166             }
1167             if (sandOrder == 0) {
1168                 myassert(oldDir == sandDir);
1169                 if (oldExecutable != sandExecutable)
1170                     CheckForExec(oldBase, workingDir, oldList,
1171                         sandboxBase, workingDir, sandList, 0, 0);
1172             }
1173             if (sandOrder <= 0)
1174                 sandList += strlen(sandList) + 1;
1175             if (sandOrder < 0)
1176                 continue;
1177         }
1178         if (order < 0) { // file in old list is not in new
1179             // check to see if file is read only ; if so, call p4 delete -- otherwise, just call delete
1180             if (oldDir == false) {
1181                 bool modifiedFile = false;
1182                 // check to see if android modified deleted file
1183                 if (sandOrder == 0) {
1184                     string rename(workingDir);
1185                     rename.append("/");
1186                     rename.append(oldFile);
1187                     if (renamePass) {
1188                         string newName = Find(oldFile);
1189                         if (newName.length() > 0) {
1190                             map<string, string>::iterator iter = renameMap.find(rename);
1191                             myassert(iter == renameMap.end()); // if I see the same file twice, must be a bug
1192                             renameMap[rename] = newName;
1193                             myassert(rename != newName);
1194                             if (options.debug)
1195                                 fprintf(stderr, "map %s to %s\n", rename.c_str(), newName.c_str());
1196                         }
1197                     }
1198                     if (renamePass == false) {
1199                         bool oldSandboxDiff = CompareFiles(oldBase, sandboxBase, workingDir, oldList);
1200                         const char* renamedDir = workingDir;
1201                         map<string, string>::iterator iter = renameMap.find(rename);
1202                         if (iter != renameMap.end()) {
1203                             string newName = renameMap[rename];
1204                             renamedDir = newName.c_str();
1205                             char* renamed = (char*) strrchr(renamedDir, '/');
1206                             *renamed++ = '\0'; // splits rename into two strings
1207                             if (options.emitPerforceCommands) {
1208                                 fprintf(commandFile, "p4 integrate \"%s/%s/%s\" \"%s/%s/%s\"\n", sandboxCmd, workingDir, oldFile,
1209                                     sandboxCmd, renamedDir, renamed);
1210                                 fprintf(commandFile, "p4 resolve \"%s/%s/%s\"\n", sandboxCmd, renamedDir, renamed);
1211                             } else if (options.emitGitCommands) {
1212                                 fprintf(commandFile, "git mv \"%s/%s\" \"%s/%s\"\n", workingDir, oldFile,
1213                                     renamedDir, renamed);
1214                             }
1215                             if (oldSandboxDiff) {
1216                                 if (options.emitPerforceCommands)
1217                                     fprintf(commandFile, "p4 open \"%s/%s/%s\"\n", sandboxCmd, renamedDir, renamed);
1218                                 fprintf(commandFile,  "merge -q \"%s/%s/%s\" \"%s/%s/%s\" \"%s/%s/%s\"\n",
1219                                     sandboxCmd, renamedDir, renamed, oldCmd, workingDir, oldFile, newCmd, renamedDir, renamed);
1220                                 bool success = Merge(workingDir, oldFile, renamedDir, renamed, "/dev/null");
1221                                 if (success == false) {
1222 									fprintf(stderr, "*** Manual merge required: %s/%s\n", renamedDir, renamed);
1223 									fprintf(commandFile, "cat \"%s/%s/%s\" | sed -e 's/^<<<<<<<.*$/#ifdef MANUAL_MERGE_REQUIRED/' "
1224 										"-e 's/^=======$/#else \\/\\/ MANUAL_MERGE_REQUIRED/' "
1225 										"-e 's/^>>>>>>>.*$/#endif \\/\\/ MANUAL_MERGE_REQUIRED/' > \"%s/%s/x%s\"\n",
1226 										sandboxCmd, renamedDir, renamed, sandboxCmd, renamedDir, renamed);
1227 									fprintf(commandFile, "mv \"%s/%s/x%s\" \"%s/%s/%s\"\n",
1228 										sandboxCmd, renamedDir, renamed, sandboxCmd, renamedDir, renamed);
1229                                 }
1230                                 if (options.emitGitCommands)
1231                                     fprintf(commandFile, "git add \"%s/%s\"\n", renamedDir, renamed);
1232                             } else {
1233                                 bool oldNewDiff = CompareFiles(oldBase, workingDir, oldList, newBase, renamedDir, renamed);
1234                                 if (oldNewDiff) {
1235                                     if (options.emitPerforceCommands)
1236                                         fprintf(oopsFile, "p4 open \"%s/%s/%s\"\n", sandboxCmd, renamedDir, renamed);
1237                                     fprintf(oopsFile, "cp \"%s/%s/%s\" \"%s/%s/%s\"\n",
1238                                             newCmd, renamedDir, renamed, sandboxCmd, renamedDir, renamed);
1239                                     if (options.emitGitCommands)
1240                                         fprintf(oopsFile, "git add \"%s/%s\"\n", renamedDir, renamed);
1241                                 }
1242                             }
1243                         } else if (oldSandboxDiff) {
1244                             modifiedFile = true;
1245                             fprintf(stderr, "*** Modified file deleted: %s/%s\n", workingDir, oldFile);
1246 //                                FindDeletedAndroidChanges(workingDir, oldFile);
1247                         }
1248                     } // if renamePass == false
1249                 } // if sandOrder == 0
1250                 if (modifiedFile) {
1251                     fprintf(commandFile, "cat \"%s/%s/%s\" | sed -e '1 i\\\n#ifdef MANUAL_MERGE_REQUIRED\n' "
1252                         "-e '$ a\\\n#endif \\/\\/ MANUAL_MERGE_REQUIRED\n' > \"%s/%s/x%s\"\n",
1253                         sandboxCmd, workingDir, oldFile, sandboxCmd, workingDir, oldFile);
1254                     fprintf(commandFile, "mv \"%s/%s/x%s\" \"%s/%s/%s\"\n",
1255                         sandboxCmd, workingDir, oldFile, sandboxCmd, workingDir, oldFile);
1256                 } else if (options.emitPerforceCommands)
1257                     fprintf(commandFile, "p4 delete \"%s/%s/%s\"\n", sandboxCmd, workingDir, oldFile);
1258                 else if (options.emitGitCommands)
1259                     fprintf(commandFile, "git rm \"%s/%s\"\n", workingDir, oldFile);
1260                 else
1261                     fprintf(commandFile, "rm \"%s/%s/%s\"\n", sandboxCmd, workingDir, oldFile);
1262             } else { // if oldDir != false
1263  // !!! FIXME               start here;
1264                     // check to see if old directory is empty ... (e.g., WebCore/doc)
1265                     // ... and/or isn't in sandbox anyway (e.g., WebCore/LayoutTests)
1266                         // if old directory is in sandbox (e.g. WebCore/kcanvas) that should work
1267                 if (options.emitPerforceCommands)
1268                     fprintf(commandFile, "p4 delete \"%s/%s/%s/...\"\n", sandboxCmd, workingDir, oldFile);
1269                 else if (options.emitGitCommands)
1270                     fprintf(commandFile, "git rm \"%s/%s/...\"\n", workingDir, oldFile);
1271                 else
1272                     fprintf(commandFile, "rm \"%s/%s/%s/...\"\n", sandboxCmd, workingDir, oldFile);
1273                 if (renamePass == false)
1274                     fprintf(stderr, "*** Directory deleted: %s/%s\n", workingDir, oldFile);
1275             }
1276             oldList += strlen(oldList) + 1;
1277             continue;
1278         }
1279         if (order > 0) {
1280              if (renamePass == false) {
1281                 string rename(workingDir);
1282                 rename.append("/");
1283                 rename.append(newFile);
1284                 bool skip = false;
1285                 for (map<string, string>::iterator iter = renameMap.begin(); iter != renameMap.end(); iter++) {
1286                     if (iter->second == rename) {
1287                         skip = true;
1288                         break;
1289                     }
1290                 }
1291                 if (skip == false) {
1292                     if (newDir) {
1293                         if (strcmp(sandFile, newFile) != 0 &&
1294                                 emptyDirectory(newBase, workingDir, newFile) == false) {
1295                             fprintf(copyDirFile, "find \"%s/%s/%s\" -type d -print | "
1296                                 "sed 's@%s/\\(.*\\)@mkdir %s/\\1@' | bash -s\n",
1297                                 newCmd, workingDir, newFile, newCmd, sandboxCmd);
1298                             fprintf(copyDirFile, "find \"%s/%s/%s\" -type f -print | "
1299                                 "sed 's@%s/\\(.*\\)@cp %s/\\1 %s/\\1@' | bash -s\n",
1300                                 newCmd, workingDir, newFile, newCmd, newCmd, sandboxCmd);
1301                             if (options.emitPerforceCommands)
1302                                 fprintf(copyDirFile, "find \"%s/%s/%s\" -type f -print | "
1303                                     "p4 -x - add\n",
1304                                     sandboxCmd, workingDir, newFile);
1305                             else if (options.emitGitCommands)
1306                                 fprintf(copyDirFile, "git add \"%s/%s\"\n",
1307                                     workingDir, newFile);
1308                         }
1309                     } else {
1310 //                        if (emptyDirectory(sandboxBase, workingDir)) {
1311 //                            fprintf(commandFile, "mkdir \"%s/%s\"\n", sandboxCmd, workingDir);
1312 //                        }
1313                         bool edit = false;
1314                         size_t newLen1 = strlen(newFile);
1315                         for (map<string, string>::iterator iter = renameMap.begin(); iter != renameMap.end(); iter++) {
1316                             if (strcmp(iter->second.c_str(), workingDir) == 0) {
1317                                 const char* first = iter->first.c_str();
1318                                 size_t firstLen = strlen(first);
1319                                 if (firstLen > newLen1 && strcmp(newFile,
1320                                         &first[firstLen - newLen1]) == 0) {
1321                                     edit = true;
1322                                     break;
1323                                 }
1324                             }
1325                         }
1326                         if (edit == false) {
1327                             fprintf(commandFile, "cp \"%s/%s/%s\" \"%s/%s/%s\"\n",
1328                                 newCmd, workingDir, newFile, sandboxCmd, workingDir, newFile);
1329                                 if (options.emitPerforceCommands)
1330                                     fprintf(commandFile, "p4 add \"%s/%s/%s\"\n", sandboxCmd, workingDir, newFile);
1331                                 else if (options.emitGitCommands)
1332                                     fprintf(commandFile, "git add \"%s/%s\"\n", workingDir, newFile);
1333                         }
1334                     }
1335                 }
1336             }
1337             newList += strlen(newList) + 1;
1338             continue;
1339         }
1340         if (oldDir) {
1341             myassert(newDir);
1342             size_t newLen1 = strlen(workingDir) + strlen(oldList);
1343             char* newFile = new char[newLen1 + 1];
1344             sprintf(newFile, "%s/%.*s", workingDir, (int) strlen(oldList) - 1,
1345                 oldList);
1346             if (sandOrder > 0) { // file is on old and new but not sandbox
1347                 if (emptyDirectory(newBase, newFile) == false) {
1348                     fprintf(copyDirFile, "find \"%s/%s\" -type d -print | "
1349                         "sed 's@%s/\\(.*\\)@mkdir %s/\\1@' | bash -s\n",
1350                         newCmd, newFile, newCmd, sandboxCmd);
1351                     fprintf(copyDirFile, "find \"%s/%s\" -type f -print | "
1352                         "sed 's@%s/\\(.*\\)@cp %s/\\1 %s/\\1@' | bash -s\n",
1353                         newCmd, newFile, newCmd, newCmd, sandboxCmd);
1354                     if (options.emitPerforceCommands)
1355                         fprintf(copyDirFile, "find \"%s/%s\" -type f -print | "
1356                             "p4 -x - add\n",
1357                             sandboxCmd, newFile);
1358                     else if (options.emitGitCommands)
1359                         fprintf(copyDirFile, "git add \"%s\"", newFile);
1360                 }
1361              } else
1362                 CompareDirs(newFile, renamePass);
1363             delete[] newFile;
1364         } else {
1365             // at this point, the file is in both old and new webkits; see if it changed
1366                // ignore executables, different or not (or always copy, or do text compare? or find binary compare? )
1367             if (oldExecutable != newExecutable)
1368                 fprintf(stderr, "*** %s/%s differs in the execute bit (may cause problems for perforce)\n", workingDir, oldFile);
1369         //            myassert(sandOrder != 0 || sandFile[sandLen - 1] == '*');
1370         //    Diff(oldBase, sandboxBase, workingDir, oldFile);
1371             bool oldNewDiff = CompareFiles(oldBase, newBase, workingDir, oldList);
1372             if (oldNewDiff && sandOrder == 0 && renamePass == false) { // if it changed, see if android also changed it
1373                 if (options.emitPerforceCommands)
1374                     fprintf(commandFile, "p4 edit \"%s/%s/%s\"\n", sandboxCmd, workingDir, oldFile);
1375                 bool oldSandboxDiff = CompareFiles(oldBase, sandboxBase, workingDir, oldFile);
1376                 if (oldSandboxDiff) {
1377                     fprintf(commandFile,  "merge -q \"%s/%s/%s\" \"%s/%s/%s\" \"%s/%s/%s\"\n",
1378                         sandboxCmd, workingDir, oldFile, oldCmd, workingDir, oldFile, newCmd, workingDir, oldFile);
1379                     bool success = Merge(workingDir, oldFile);
1380                     if (success == false) {
1381 						fprintf(stderr, "*** Manual merge required: %s/%s\n", workingDir, oldFile);
1382 						fprintf(commandFile, "cat \"%s/%s/%s\" | sed -e 's/^<<<<<<<.*$/#ifdef MANUAL_MERGE_REQUIRED/' "
1383 							"-e 's/^=======$/#else \\/\\/ MANUAL_MERGE_REQUIRED/' -e 's/^>>>>>>>.*$/#endif \\/\\/ MANUAL_MERGE_REQUIRED/' > \"%s/%s/x%s\"\n",
1384 							sandboxCmd, workingDir, oldFile, sandboxCmd, workingDir, oldFile);
1385 						fprintf(commandFile, "mv \"%s/%s/x%s\" \"%s/%s/%s\"\n",
1386 							sandboxCmd, workingDir, oldFile, sandboxCmd, workingDir, oldFile);
1387                     }
1388                 } else fprintf(commandFile, "cp \"%s/%s/%s\" \"%s/%s/%s\"\n", newCmd, workingDir, oldFile ,
1389                     sandboxCmd, workingDir, oldFile);
1390                 if (options.emitGitCommands)
1391                     fprintf(commandFile, "git add \"%s/%s\"\n", workingDir, oldFile);
1392             }
1393         }
1394         myassert(oldLen == newLen);
1395         newList += strlen(newList) + 1;
1396         oldList += strlen(oldList) + 1;
1397     } while (true);
1398     delete[] oldMem;
1399     delete[] newMem;
1400     delete[] sandboxMem;
1401 }
1402 
Ignore(char * fileName,size_t len)1403 bool Ignore(char* fileName, size_t len)
1404 {
1405     if (len == 0)
1406         return true;
1407     if (fileName[len - 1] =='/')
1408         return true;
1409     if (strcmp(fileName, ".DS_Store") == 0)
1410         return true;
1411     if (strcmp(fileName, ".ignoreSVN") == 0)
1412         return true;
1413     return false;
1414 }
1415 
FixStar(char * fileName,size_t len)1416 void FixStar(char* fileName, size_t len)
1417 {
1418     if (fileName[len - 1] =='*')
1419         fileName[len - 1] = '\0';
1420 }
1421 
FixColon(char ** fileNamePtr,size_t * lenPtr)1422 void FixColon(char** fileNamePtr, size_t* lenPtr)
1423 {
1424     char* fileName = *fileNamePtr;
1425     size_t len = *lenPtr;
1426     if (fileName[len - 1] !=':')
1427         return;
1428     fileName[len - 1] = '\0';
1429     if (strncmp(fileName ,"./", 2) != 0)
1430         return;
1431     fileName += 2;
1432     *fileNamePtr = fileName;
1433     len -= 2;
1434     *lenPtr = len;
1435 }
1436 
IgnoreDirectory(const char * dir,const char ** dirList)1437 bool IgnoreDirectory(const char* dir, const char** dirList)
1438 {
1439     if (dirList == NULL)
1440         return false;
1441     const char* test;
1442     while ((test = *dirList++) != NULL) {
1443         if (strncmp(dir, test, strlen(test)) == 0)
1444             return true;
1445     }
1446     return false;
1447 }
1448 
doSystem(char * scratch)1449 static void doSystem(char* scratch)
1450 {
1451     if (false) printf("%s\n", scratch);
1452     int err = system(scratch);
1453     myassert(err == 0);
1454 }
1455 
copyToCommand(char * scratch,string file)1456 static void copyToCommand(char* scratch, string file)
1457 {
1458     doSystem(scratch);
1459     char* diff = GetFile(file.c_str());
1460     while (*diff) {
1461         fprintf(commandFile, "%s\n", diff);
1462         diff += strlen(diff) + 1;
1463     }
1464 }
1465 
1466 #define WEBKIT_EXCLUDED_DIRECTORIES \
1467         "-not -path \"*Tests\" " /* includes LayoutTests, PageLoadTests */ \
1468         "-not -path \"*Tests/*\" " /* includes LayoutTests, PageLoadTests */ \
1469         "-not -path \"*Site\" " /* includes BugsSite, WebKitSite */ \
1470         "-not -path \"*Site/*\" " /* includes BugsSite, WebKitSite */ \
1471         "-not -path \"./PlanetWebKit/*\" " \
1472         "-not -path \"./PlanetWebKit\" "
1473 
1474 #define ANDROID_EXCLUDED_FILES \
1475         "-e '/^Files .* differ/ d' " \
1476         "-e '/^Only in .*/ d' " \
1477         "-e '/Android.mk/ d' " \
1478         "-e '/android$/ d' "
1479 
1480 #define ANDROID_EXCLUDED_DIRS \
1481         "-e '/\\/JavaScriptCore\\// d' " \
1482         "-e '/\\/WebCore\\// d' "
1483 
1484 #define ANDROID_EXCLUDED_DIRS_GIT \
1485         "-e '/ JavaScriptCore\\// d' " \
1486         "-e '/ WebCore\\// d' "
1487 
CopyOther()1488 void CopyOther()
1489 {
1490     string excludedFiles = ANDROID_EXCLUDED_FILES;
1491     if (options.emitGitCommands)
1492         excludedFiles += ANDROID_EXCLUDED_DIRS_GIT;
1493     else
1494         excludedFiles += ANDROID_EXCLUDED_DIRS;
1495     char scratch[1024];
1496     // directories to ignore in webkit
1497     string copyOtherWebKit = ScratchFile("CopyOtherWebKit");
1498     sprintf(scratch, "cd %s ;  find . -type d -not -empty "
1499         WEBKIT_EXCLUDED_DIRECTORIES
1500         " > %s", newBase, copyOtherWebKit.c_str());
1501     doSystem(scratch);
1502     // directories to ignore in android
1503     string copyOtherAndroid = ScratchFile("CopyOtherAndroid");
1504     sprintf(scratch, "cd %s ;  find . -type d -not -empty "
1505         "-not -path \"*.git*\" "
1506         "-not -path \"*android*\" "
1507         " > %s", sandboxBase, copyOtherAndroid.c_str());
1508     doSystem(scratch);
1509     if (0) {
1510         string copyOtherMkDir = ScratchFile("CopyOtherMkDir");
1511         sprintf(scratch, "diff %s %s | sed -e 's@< \\./\\(.*\\)$"
1512             "@mkdir %s/\\1@' "
1513             "-e '/^[0-9].*/ d' "
1514             "-e '/>.*/ d' "
1515             "-e '/---/ d' "
1516             "-e '/\\/JavaScriptCore\\// d' "
1517             "-e '/\\/WebCore\\// d' "
1518             "> %s", copyOtherWebKit.c_str(), copyOtherAndroid.c_str(), sandboxCmd,
1519             copyOtherMkDir.c_str());
1520         if (options.debug)
1521             fprintf(stderr, "%s\n", scratch);
1522         copyToCommand(scratch, copyOtherMkDir);
1523     }
1524     string copyOtherDiff = ScratchFile("CopyOtherDiff");
1525     int scratchLen = sprintf(scratch, "diff %s %s | sed -e 's@< \\./\\(.*\\)$"
1526         "@mkdir -p -v %s/\\1 ; find %s/\\1 -type f -depth 1 -exec cp {} %s/\\1 \";\"",
1527         copyOtherWebKit.c_str(), copyOtherAndroid.c_str(), sandboxCmd, newCmd,
1528         sandboxCmd);
1529     if (options.emitGitCommands)
1530         scratchLen += sprintf(&scratch[scratchLen], " ; cd %s ; find ", sandboxCmd);
1531     else
1532         scratchLen += sprintf(&scratch[scratchLen], " ; find %s/", sandboxCmd);
1533     scratchLen += sprintf(&scratch[scratchLen], "\\1 -type f -depth 1 | ");
1534     if (options.emitPerforceCommands)
1535         scratchLen += sprintf(&scratch[scratchLen], "p4 -x - add ");
1536     else if (options.emitGitCommands)
1537         scratchLen += sprintf(&scratch[scratchLen], "xargs git add ");
1538     scratchLen += sprintf(&scratch[scratchLen],
1539         "@' -e '/^[0-9].*/ d' "
1540         "-e '/>.*/ d' "
1541         "-e '/---/ d' "
1542         "-e '/\\/JavaScriptCore\\// d' "
1543         "-e '/\\/WebCore\\// d' "
1544         "> %s", copyOtherDiff.c_str());
1545     if (options.debug)
1546         fprintf(stderr, "%s\n", scratch);
1547     copyToCommand(scratch, copyOtherDiff);
1548     string deleteOtherDiff = ScratchFile("DeleteOtherDiff");
1549     scratchLen = sprintf(scratch, "diff -r -q %s %s | sed -e "
1550         "'s@Only in %s/\\(.*\\)\\: \\(.*\\)@",
1551         newBase, sandboxBase, sandboxBase);
1552     if (options.emitPerforceCommands)
1553         scratchLen += sprintf(&scratch[scratchLen], "p4 delete %s/", sandboxCmd);
1554     else if (options.emitGitCommands)
1555         scratchLen += sprintf(&scratch[scratchLen], "git rm ");
1556     else
1557         scratchLen += sprintf(&scratch[scratchLen], "rm %s/", sandboxCmd);
1558     scratchLen += sprintf(&scratch[scratchLen], "\\1/\\2@' %s > %s",
1559         excludedFiles.c_str(), deleteOtherDiff.c_str());
1560     if (options.debug)
1561         fprintf(stderr, "%s\n", scratch);
1562     copyToCommand(scratch, deleteOtherDiff);
1563     string addOtherDiff = ScratchFile("AddOtherDiff");
1564     scratchLen = sprintf(scratch, "diff -r -q %s %s | sed -e "
1565         "'s@Only in %s/\\(.*\\)\\: \\(.*\\)"
1566             "@mkdir -p -v %s/\\1 ; cp %s/\\1/\\2 %s/\\1/\\2 ; ",
1567             newBase, sandboxBase, newBase, sandboxCmd, newCmd, sandboxCmd);
1568     if (options.emitPerforceCommands)
1569         scratchLen += sprintf(&scratch[scratchLen],
1570             "p4 add %s/\\1/\\2", sandboxCmd);
1571     else if (options.emitGitCommands)
1572         scratchLen += sprintf(&scratch[scratchLen],
1573             "git add \\1/\\2");
1574     scratchLen += sprintf(&scratch[scratchLen], "@' %s > %s",
1575         excludedFiles.c_str(), addOtherDiff.c_str());
1576     if (options.debug)
1577         fprintf(stderr, "%s\n", scratch);
1578     copyToCommand(scratch, addOtherDiff);
1579     string editOtherDiff = ScratchFile("EditOtherDiff");
1580     scratchLen = sprintf(scratch, "diff -r -q %s %s | sed -e "
1581         "'s@Files %s/\\(.*\\) and %s/\\(.*\\) differ@",
1582         newBase, sandboxBase, newBase, sandboxBase);
1583     if (options.emitPerforceCommands)
1584         scratchLen += sprintf(&scratch[scratchLen],
1585             "p4 edit %s/\\2 ; ", sandboxCmd);
1586     scratchLen += sprintf(&scratch[scratchLen], "cp %s/\\1 %s/\\2 ",
1587        newCmd, sandboxCmd);
1588     if (options.emitGitCommands)
1589         scratchLen += sprintf(&scratch[scratchLen],
1590             " ; git add \\2");
1591     scratchLen += sprintf(&scratch[scratchLen], "@' %s > %s",
1592         excludedFiles.c_str(), editOtherDiff.c_str());
1593     if (options.debug)
1594         fprintf(stderr, "%s\n", scratch);
1595     copyToCommand(scratch, editOtherDiff);
1596 }
1597 
MakeExecutable(const string & filename)1598 void MakeExecutable(const string& filename)
1599 {
1600     string makeExScript = "chmod +x ";
1601     makeExScript += filename;
1602     int err = system(makeExScript.c_str());
1603     myassert(err == 0);
1604 }
1605 
ReadArgs(char * const args[],int argCount)1606 bool ReadArgs(char* const args[], int argCount)
1607 {
1608     int index = 0;
1609     const char* toolpath = args[index++];
1610     // first arg is path to this executable
1611     // use this to build default paths
1612 
1613     for (; index < argCount; index++) {
1614         const char* arg = args[index];
1615         if (strncmp(arg, "-a", 2) == 0 || strcmp(arg, "--android") == 0) {
1616             index++;
1617             options.androidWebKit = args[index];
1618             continue;
1619         }
1620         if (strncmp(arg, "-b", 2) == 0 || strcmp(arg, "--basewebkit") == 0) {
1621             index++;
1622             options.baseWebKit = args[index];
1623             continue;
1624         }
1625         if (strncmp(arg, "-c", 2) == 0 || strcmp(arg, "--mergecore") == 0) {
1626             options.clearOnce();
1627             options.mergeCore = true;
1628             continue;
1629         }
1630         if (strncmp(arg, "-d", 2) == 0 || strcmp(arg, "--debug") == 0) {
1631             options.debug = true;
1632             continue;
1633         }
1634         if (strncmp(arg, "-e", 2) == 0 || strcmp(arg, "--emptydirs") == 0) {
1635             options.clearOnce();
1636             options.removeEmptyDirs = true;
1637             continue;
1638         }
1639         if (strncmp(arg, "-g", 2) == 0 || strcmp(arg, "--git") == 0) {
1640             options.emitGitCommands = true;
1641             if (options.emitPerforceCommands == false)
1642                 continue;
1643         }
1644         if (strncmp(arg, "-m", 2) == 0 || strcmp(arg, "--mergemake") == 0) {
1645             options.clearOnce();
1646             options.mergeMake = true;
1647             continue;
1648         }
1649         if (strncmp(arg, "-n", 2) == 0 || strcmp(arg, "--newwebkit") == 0) {
1650             index++;
1651             options.newWebKit = args[index];
1652             continue;
1653         }
1654         if (strncmp(arg, "-o", 2) == 0 || strcmp(arg, "--copyother") == 0) {
1655             options.clearOnce();
1656             options.copyOther = true;
1657             continue;
1658         }
1659         if (strncmp(arg, "-p", 2) == 0 || strcmp(arg, "--perforce") == 0) {
1660             options.emitPerforceCommands = true;
1661             if (options.emitGitCommands == false)
1662                 continue;
1663         }
1664         if (strncmp(arg, "-s", 2) == 0 || strcmp(arg, "--removesvn") == 0) {
1665             options.clearOnce();
1666             options.removeSVNDirs = true;
1667             continue;
1668         }
1669         if (strncmp(arg, "-v", 2) == 0 || strcmp(arg, "--verbose") == 0) {
1670             options.verbose = true;
1671             fprintf(stderr, "path: %s\n", toolpath);
1672             int err = system("pwd > pwd.txt");
1673             myassert(err != -1);
1674             fprintf(stderr, "pwd: %s\n", GetFile("pwd.txt"));
1675             system("rm pwd.txt");
1676             continue;
1677         }
1678         if (strncmp(arg, "-x", 2) == 0 || strcmp(arg, "--execute") == 0) {
1679             options.execute = true;
1680             continue;
1681         }
1682         if (options.emitGitCommands && options.emitPerforceCommands)
1683             printf("choose one of --git and --perforce\n");
1684         else if (strncmp(arg, "-h", 2) != 0 && strcmp(arg, "--help") != 0 && strcmp(arg, "-?") != 0)
1685             printf("%s not understood\n", args[index]);
1686         printf(
1687 "WebKit Merge for Android version 1.1\n"
1688 "Usage: webkitmerge -a path -b path -n path [-g or -p] [-c -d -e -m -o -s -v -x]\n"
1689 "Options -c -e -m -o -s are set unless one or more are passed.\n"
1690 "Leave -g and -p unset to copy, merge, and delete files outside of source control.\n"
1691 "-a --android path     Set the Android webkit path to merge to.\n"
1692 "-b --basewebkit path  Set the common base for Android and the newer webkit.\n"
1693 "-c --mergecore        Create merge scripts for WebCore, JavaScriptCore .h .cpp.\n"
1694 "-d --debug            Show debugging printfs; loop forever on internal assert.\n"
1695 "-e --emptydirs        Remove empty directories from webkit trees.\n"
1696 "-g --git              Emit git commands.\n"
1697 "-h --help             Show this help.\n"
1698 "-m --mergemake        Create merge scripts for WebCore/Android.mk,\n"
1699 "                      WebCore/Android.derived.mk, and JavaScriptCore/Android.mk.\n"
1700 "-n --newwebkit path   Set the webkit to merge from.\n"
1701 "-o --copyother        Create script to copy other webkit directories.\n"
1702 "-p --perforce         Emit perforce commands.\n"
1703 "-s --removesvn        Remove svn directories from webkit trees.\n"
1704 "-v --verbose          Show status printfs.\n"
1705 "-x --execute          Execute the merge scripts.\n"
1706         );
1707         return false;
1708     }
1709     return options.finish();
1710 }
1711 
main(int argCount,char * const args[])1712 int main (int argCount, char* const args[])
1713 {
1714     if (ReadArgs(args, argCount) == false)
1715         return 0;
1716     int err;
1717     // First remove all .svn directories
1718     if (options.removeSVNDirs) {
1719         if (options.verbose)
1720             fprintf(stderr, "removing svn directories from %s\n", newBase);
1721         string removeSVNStr = string("find ") + newBase +
1722             " -type d -name \".svn\" -print0 | xargs -0 rm -rf";
1723         err = system(removeSVNStr.c_str());
1724         myassert(err == 0);
1725     }
1726     // Remove all empty directories
1727     if (options.removeEmptyDirs) {
1728         if (options.verbose)
1729             fprintf(stderr, "removing empty directories from %s, %s\n",
1730                 oldBase, newBase);
1731         string removeEmpty = string("find ") + oldBase + " " + newBase +
1732             " -type d -empty -delete";
1733         err = system(removeEmpty.c_str());
1734         myassert(err == 0);
1735     }
1736     if (options.mergeCore /* || options.mergeMake */) {
1737         if (options.verbose)
1738             fprintf(stderr, "building rename map\n");
1739         commandFile = fopen("/dev/null", "w");
1740         copyDirFile = fopen("/dev/null", "w");
1741         CompareDirs("WebCore", true); // build rename map
1742         CompareDirs("JavaScriptCore", true);
1743         fclose(copyDirFile);
1744         fclose(commandFile);
1745     }
1746     if (options.mergeMake) {
1747         if (options.verbose)
1748             fprintf(stderr, "building make.sh\n");
1749         string makeShell = outputDir + "make.sh";
1750         commandFile = fopen(makeShell.c_str(), "w");
1751         if (options.emitGitCommands || options.emitPerforceCommands)
1752             fprintf(commandFile, "cd %s\n", sandboxCmd);
1753         UpdateMake("WebCore");
1754         UpdateMake("JavaScriptCore");
1755         UpdateDerivedMake();
1756         fclose(commandFile);
1757         MakeExecutable(makeShell);
1758     }
1759     if (options.copyOther) {
1760         if (options.verbose)
1761             fprintf(stderr, "building copyOther.sh\n");
1762         string copyOtherShell = outputDir + "copyOther.sh";
1763         commandFile = fopen(copyOtherShell.c_str(), "w");
1764         if (options.emitGitCommands || options.emitPerforceCommands)
1765             fprintf(commandFile, "cd %s\n", sandboxCmd);
1766         CopyOther();
1767         fclose(commandFile);
1768         MakeExecutable(copyOtherShell);
1769     }
1770     if (options.mergeCore) {
1771         if (options.verbose)
1772             fprintf(stderr, "building command.sh copyDir.sh oops.sh\n");
1773         string commandShell = outputDir + "command.sh";
1774         commandFile = fopen(commandShell.c_str(), "w");
1775         if (options.emitGitCommands || options.emitPerforceCommands)
1776             fprintf(commandFile, "cd %s\n", sandboxCmd);
1777         string copyDirShell = outputDir + "copyDir.sh";
1778         copyDirFile = fopen(copyDirShell.c_str(), "w");
1779         if (options.emitGitCommands || options.emitPerforceCommands)
1780             fprintf(copyDirFile, "cd %s\n", sandboxCmd);
1781         string oopsShell = outputDir + "oops.sh";
1782         oopsFile = fopen(oopsShell.c_str(), "w");
1783         if (options.emitGitCommands || options.emitPerforceCommands)
1784             fprintf(oopsFile, "cd %s\n", sandboxCmd);
1785         CompareDirs("WebCore", false); // generate command script
1786         CompareDirs("JavaScriptCore", false);
1787         fclose(oopsFile);
1788         fclose(copyDirFile);
1789         fclose(commandFile);
1790         MakeExecutable(oopsShell);
1791         MakeExecutable(copyDirShell);
1792         MakeExecutable(commandShell);
1793     }
1794     if (options.execute) {
1795         if (options.mergeCore) {
1796             if (options.verbose)
1797                 fprintf(stderr, "executing command.sh\n");
1798             string execCommand = "cd " + options.androidWebKit + "; . " + outputDir + "command.sh";
1799             err = system(execCommand.c_str());
1800             myassert(err == 0);
1801             if (options.verbose)
1802                 fprintf(stderr, "executing copyDir.sh\n");
1803             string execCopy = "cd " + options.androidWebKit + "; . " + outputDir + "copyDir.sh";
1804             err = system(execCopy.c_str());
1805             myassert(err == 0);
1806         }
1807         if (options.mergeMake) {
1808             if (options.verbose)
1809                 fprintf(stderr, "executing make.sh\n");
1810             string execMake = "cd " + options.androidWebKit + "; . " + outputDir + "make.sh";
1811             err = system(execMake.c_str());
1812             myassert(err == 0);
1813         }
1814         if (options.copyOther) {
1815             if (options.verbose)
1816                 fprintf(stderr, "executing copyOther.sh\n");
1817             string execCopyOther = "cd " + options.androidWebKit + "; . " + outputDir + "copyOther.sh";
1818             err = system(execCopyOther.c_str());
1819             myassert(err == 0);
1820         }
1821     }
1822     if (options.verbose)
1823         fprintf(stderr, "done!\n");
1824     else {
1825         string rmAllCmd = "rm " + scratchDir + "* ; rmdir " + scratchDir;
1826         err = system(rmAllCmd.c_str());
1827         myassert(err == 0);
1828     }
1829     return 0;
1830 }
1831 
1832 /* things to do:
1833     when inserting MANUAL_MERGE_REQUIRED, if contents is #preprocessor, balance first?
1834 */
1835