#import <stdlib.h>
#import <sys/types.h>
#import <stdio.h>
#import <string.h>
#import <sys/stat.h>
#import <errno.h>
#ifdef __APPLE__
#import <fts.h>
#else
#import <sys/param.h>
#endif
#ifndef WIN32
#define IS_DIRECTORY(st_mode) (((st_mode) & S_IFMT) == S_IFDIR)
#define IS_LINK(st_mode) (((st_mode) & S_IFMT) == S_IFLNK)
#define IS_REGULAR(st_mode) (((st_mode) & S_IFMT) == S_IFREG)
#ifdef __APPLE__
#import <sys/dir.h>
typedef struct direct DIRENT;
#else
#include <dirent.h>
typedef struct dirent DIRENT;
#endif
#else WIN32
#define IS_DIRECTORY(st_mode) (((st_mode) & S_IFMT) == S_IFDIR)
#define IS_LINK(st_mode) 0
#define IS_REGULAR(st_mode) (((st_mode) & S_IFMT) == S_IFREG)
#define lstat stat
#import <windows.h>
#import <objc/hashtable2.h>
#endif
#ifndef BOOL
#define BOOL char
#endif
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#define PROGRAM_NAME "changes"
#ifdef WIN32
#define MAX_STRING_CHUNK 4096
typedef struct _StringTable {
char strings[MAX_STRING_CHUNK];
struct _StringTable * next;
} StringTable;
static BOOL searchForNewerFiles(char * dir, FILETIME refTime) {
WIN32_FIND_DATA fileData;
HANDLE cursor;
char searchPattern[MAX_PATH];
BOOL newerFiles = FALSE;
StringTable allStrings;
StringTable * stringTab = &allStrings;
char *stringPtr = stringTab->strings;
#ifndef DIVE
NXHashTable *table = NULL;
NXHashState state;
#endif
allStrings.next = NULL;
*stringPtr = '\0';
sprintf(searchPattern, "%s/*", dir);
cursor = FindFirstFileA(searchPattern, &fileData);
do {
if (fileData.cFileName[0] == '.' && (fileData.cFileName[1] == '\0'
|| (fileData.cFileName[1] == '.' && fileData.cFileName[2] == '\0')))
continue;
#ifdef DEBUG
printf("Doing %s",fileData.cFileName);
#endif
if (CompareFileTime(&refTime, &fileData.ftLastWriteTime) == -1) {
#ifdef DEBUG
printf("-- NEWER!\n");
#endif
newerFiles = TRUE;
break;
}
if (fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
#ifdef DIVE
char subdir[MAX_PATH];
sprintf(subdir, "%s/%s", dir, fileData.cFileName);
#ifdef DEBUG
printf(" Diving: doing %s...\n", subdir);
#endif
if (searchForNewerFiles(subdir, refTime)) {
newerFiles = TRUE;
break;
}
#else
if (stringPtr + strlen(fileData.cFileName) + 2 >= &stringTab->strings[MAX_STRING_CHUNK]) {
stringTab->next = (StringTable *) malloc(sizeof(StringTable)); stringTab = stringTab->next;
stringPtr = stringTab->strings;
stringTab->next = NULL;
#ifdef DEBUG
printf(" (reallocating)");
#endif
}
strcpy(stringPtr, fileData.cFileName);
if (!table)
table = NXCreateHashTable(NXStrPrototype, 0, NULL);
NXHashInsert(table, stringPtr);
stringPtr += strlen(fileData.cFileName) + 1;
#ifdef DEBUG
printf(" (saving for later)");
#endif
#endif
}
#ifdef DEBUG
printf("\n");
#endif
} while (!newerFiles && FindNextFileA(cursor, &fileData));
FindClose(cursor);
#ifndef DIVE
if (!newerFiles && table) {
state = NXInitHashState(table);
while (NXNextHashState(table, &state, (void **)&stringPtr)) {
char subdir[MAX_PATH];
sprintf(subdir, "%s/%s", dir, stringPtr);
#ifdef DEBUG
printf(" Later: doing %s...\n", subdir);
#endif
if (searchForNewerFiles(subdir, refTime)) {
newerFiles = TRUE;
break;
}
}
}
#endif
return newerFiles;
}
#else
static BOOL searchForNewerFiles(char * dir, time_t refTime) {
DIRENT *dp;
DIR *dirp;
dirp = opendir(dir);
if (!dirp)
return TRUE;
dp = readdir(dirp);
dp = readdir(dirp);
for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
char dirEntry[FILENAME_MAX+1];
struct stat statbuf;
strcpy(dirEntry, dir); strcat(dirEntry, "/"); strcat(dirEntry, dp->d_name);
if (lstat(dirEntry, &statbuf) || (refTime < statbuf.st_mtime)) {
closedir(dirp);
return TRUE;
}
if ((IS_DIRECTORY(statbuf.st_mode)) &&
searchForNewerFiles(dirEntry, refTime)) {
closedir(dirp);
return TRUE;
}
}
closedir(dirp);
return FALSE;
}
#endif
#ifdef BSD44
static BOOL searchForNewerFiles(char * dir, time_t refTime) {
const char * paths[2];
register FTSENT *entry;
FTS * tree;
paths[0] = dir;
paths[1] = NULL;
if ((tree = fts_open(paths, FTS_PHYSICAL | FTS_COMFOLLOW, (int (*)())NULL)) == NULL) {
perror("fts_open");
return TRUE;
}
while ((entry = fts_read(tree)) != NULL) {
switch (entry->fts_info) {
case FTS_DP:
case FTS_ERR:
case FTS_DNR:
case FTS_DOT:
case FTS_NS:
continue;
}
if (refTime < entry->fts_statp->st_mtime)
return TRUE;
}
if (errno)
perror("fts_read");
fts_close(tree);
return FALSE;
}
#endif BSD44
static void signifyUnknownChanges(char *filelist[], int numFiles) {
int i;
for (i = 0; filelist[i] && (i < numFiles); i++)
printf("%s ",filelist[i]);
printf("\n");
exit(0);
}
void main(int argc, char *argv[]) {
if (argc < 2) {
fprintf(stderr,"Usage: %s <referenceFile> <buildtype> [file1 ... fileN]\n",argv[0]);
fprintf(stderr," (note: <referenceFile> muist contain <buildtype> for no changes to be identified)\n");
exit(1);
} else {
char ** filelist;
int j;
FILE * ref;
char refContents[128];
char * refFile = argv[1];
char * newBuildType = (argc > 2) ? argv[2] : NULL;
int numFiles = argc - 3;
#ifndef WIN32
struct stat refstatbuf, statbuf;
#else
WIN32_FIND_DATA refFileData, fileData;
HANDLE cursor;
#endif
if (numFiles <= 0) {
printf("\n");
exit(0);
}
filelist = &argv[3];
ref = fopen(refFile,"r");
if (!ref)
signifyUnknownChanges(filelist, numFiles);
if (fgets(refContents,127,ref))
refContents[strlen(refContents)-1] = '\0'; if (!newBuildType || strcmp(refContents, newBuildType))
signifyUnknownChanges(filelist, numFiles);
#ifndef WIN32
if (lstat(refFile,&refstatbuf) != 0)
signifyUnknownChanges(filelist, numFiles);
#else // WIN32
cursor = FindFirstFileA(refFile,&refFileData);
if (cursor == INVALID_HANDLE_VALUE)
signifyUnknownChanges(filelist, numFiles);
FindClose(cursor);
#endif
for (j = 0; filelist[j] && (j < numFiles); j++) {
#ifndef WIN32
if ((lstat(filelist[j],&statbuf) != 0) ||
(refstatbuf.st_mtime < statbuf.st_mtime) ) {
printf("%s ",filelist[j]);
continue;
}
if ((IS_DIRECTORY(statbuf.st_mode)) &&
searchForNewerFiles(filelist[j], refstatbuf.st_mtime)) {
printf("%s ",filelist[j]);
}
#else // WIN32
cursor = FindFirstFileA(filelist[j],&fileData);
FindClose(cursor);
if ((cursor == INVALID_HANDLE_VALUE)
|| (CompareFileTime(&refFileData.ftLastWriteTime,
&fileData.ftLastWriteTime) == -1)) {
printf("%s ",filelist[j]);
continue;
}
if ((fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
&& searchForNewerFiles(filelist[j], refFileData.ftLastWriteTime)) {
printf("%s ",filelist[j]);
}
#endif
}
printf("\n");
exit(0);
}
}