zf

zenflows testing
git clone https://s.sonu.ch/~srfsh/zf.git
Log | Files | Refs | Submodules | README | LICENSE

main.c (7779B)


      1 #include "common.h"
      2 #include "cli.h"
      3 
      4 // TODO: set on fire. cli.{h,c} handle both parsing and defaults, so there's
      5 //       no need to set those here. also, in order to scope metadata by path,
      6 //       each stream will need its own configuration... so this won't work as
      7 //       a global any more. In the end the goal is to make the output format
      8 //       able to declare not just that something happened and what flags were
      9 //       attached, but what path it was watching that caused those events (so
     10 //       that the path itself can be used for routing that information to the
     11 //       relevant callback).
     12 //
     13 // Structure for storing metadata parsed from the commandline
     14 static struct {
     15   FSEventStreamEventId     sinceWhen;
     16   CFTimeInterval           latency;
     17   FSEventStreamCreateFlags flags;
     18   CFMutableArrayRef        paths;
     19   int                      format;
     20 } config = {
     21   (UInt64) kFSEventStreamEventIdSinceNow,
     22   (double) 0.3,
     23   (CFOptionFlags) kFSEventStreamCreateFlagNone,
     24   NULL,
     25   0
     26 };
     27 
     28 // Prototypes
     29 static void         append_path(const char* path);
     30 static inline void  parse_cli_settings(int argc, const char* argv[]);
     31 static void         callback(FSEventStreamRef streamRef,
     32                              void* clientCallBackInfo,
     33                              size_t numEvents,
     34                              void* eventPaths,
     35                              const FSEventStreamEventFlags eventFlags[],
     36                              const FSEventStreamEventId eventIds[]);
     37 
     38 
     39 static void append_path(const char* path)
     40 {
     41   CFStringRef pathRef = CFStringCreateWithCString(kCFAllocatorDefault,
     42                                                   path,
     43                                                   kCFStringEncodingUTF8);
     44   CFArrayAppendValue(config.paths, pathRef);
     45   CFRelease(pathRef);
     46 }
     47 
     48 // Parse commandline settings
     49 static inline void parse_cli_settings(int argc, const char* argv[])
     50 {
     51   // runtime os version detection
     52   SInt32 osMajorVersion, osMinorVersion;
     53   if (!(Gestalt(gestaltSystemVersionMajor, &osMajorVersion) == noErr)) {
     54     osMajorVersion = 0;
     55   }
     56   if (!(Gestalt(gestaltSystemVersionMinor, &osMinorVersion) == noErr)) {
     57     osMinorVersion = 0;
     58   }
     59 
     60   if ((osMajorVersion == 10) & (osMinorVersion < 5)) {
     61     fprintf(stderr, "The FSEvents API is unavailable on this version of macos!\n");
     62     exit(EXIT_FAILURE);
     63   }
     64 
     65   struct cli_info args_info;
     66   cli_parser_init(&args_info);
     67 
     68   if (cli_parser(argc, argv, &args_info) != 0) {
     69     exit(EXIT_FAILURE);
     70   }
     71 
     72   config.paths = CFArrayCreateMutable(NULL,
     73                                       (CFIndex)0,
     74                                       &kCFTypeArrayCallBacks);
     75 
     76   config.sinceWhen = args_info.since_when_arg;
     77   config.latency = args_info.latency_arg;
     78   config.format = args_info.format_arg;
     79 
     80   if (args_info.no_defer_flag) {
     81     config.flags |= kFSEventStreamCreateFlagNoDefer;
     82   }
     83   if (args_info.watch_root_flag) {
     84     config.flags |= kFSEventStreamCreateFlagWatchRoot;
     85   }
     86 
     87   if (args_info.ignore_self_flag) {
     88     if ((osMajorVersion > 10) | ((osMajorVersion == 10) & (osMinorVersion >= 6))) {
     89       config.flags |= kFSEventStreamCreateFlagIgnoreSelf;
     90     } else {
     91       fprintf(stderr, "MacOSX 10.6 or later is required for --ignore-self\n");
     92       exit(EXIT_FAILURE);
     93     }
     94   }
     95 
     96   if (args_info.file_events_flag) {
     97     if ((osMajorVersion > 10) | ((osMajorVersion == 10) & (osMinorVersion >= 7))) {
     98       config.flags |= kFSEventStreamCreateFlagFileEvents;
     99     } else {
    100       fprintf(stderr, "MacOSX 10.7 or later required for --file-events\n");
    101       exit(EXIT_FAILURE);
    102     }
    103   }
    104 
    105   if (args_info.mark_self_flag) {
    106     if ((osMajorVersion > 10) | ((osMajorVersion == 10) & (osMinorVersion >= 9))) {
    107       config.flags |= kFSEventStreamCreateFlagMarkSelf;
    108     } else {
    109       fprintf(stderr, "MacOSX 10.9 or later required for --mark-self\n");
    110       exit(EXIT_FAILURE);
    111     }
    112   }
    113 
    114   if (args_info.inputs_num == 0) {
    115     append_path(".");
    116   } else {
    117     for (unsigned int i=0; i < args_info.inputs_num; ++i) {
    118       append_path(args_info.inputs[i]);
    119     }
    120   }
    121 
    122   cli_parser_free(&args_info);
    123 
    124 #ifdef DEBUG
    125   fprintf(stderr, "config.sinceWhen    %llu\n", config.sinceWhen);
    126   fprintf(stderr, "config.latency      %f\n", config.latency);
    127   fprintf(stderr, "config.flags        %#.8x\n", config.flags);
    128 
    129   FLAG_CHECK_STDERR(config.flags, kFSEventStreamCreateFlagUseCFTypes,
    130                     "  Using CF instead of C types");
    131   FLAG_CHECK_STDERR(config.flags, kFSEventStreamCreateFlagNoDefer,
    132                     "  NoDefer latency modifier enabled");
    133   FLAG_CHECK_STDERR(config.flags, kFSEventStreamCreateFlagWatchRoot,
    134                     "  WatchRoot notifications enabled");
    135   FLAG_CHECK_STDERR(config.flags, kFSEventStreamCreateFlagIgnoreSelf,
    136                     "  IgnoreSelf enabled");
    137   FLAG_CHECK_STDERR(config.flags, kFSEventStreamCreateFlagFileEvents,
    138                     "  FileEvents enabled");
    139 
    140   fprintf(stderr, "config.paths\n");
    141 
    142   long numpaths = CFArrayGetCount(config.paths);
    143 
    144   for (long i = 0; i < numpaths; i++) {
    145     char path[PATH_MAX];
    146     CFStringGetCString(CFArrayGetValueAtIndex(config.paths, i),
    147                        path,
    148                        PATH_MAX,
    149                        kCFStringEncodingUTF8);
    150     fprintf(stderr, "  %s\n", path);
    151   }
    152 
    153   fprintf(stderr, "\n");
    154 #endif
    155 }
    156 
    157 static void callback(__attribute__((unused)) FSEventStreamRef streamRef,
    158                      __attribute__((unused)) void* clientCallBackInfo,
    159                      size_t numEvents,
    160                      void* eventPaths,
    161                      const FSEventStreamEventFlags eventFlags[],
    162                      const FSEventStreamEventId eventIds[])
    163 {
    164   char** paths = eventPaths;
    165   char *buf = calloc(sizeof(FSEVENTSBITS), sizeof(char));
    166 
    167   for (size_t i = 0; i < numEvents; i++) {
    168     sprintb(buf, eventFlags[i], FSEVENTSBITS);
    169     printf("%llu\t%#.8x=[%s]\t%s\n", eventIds[i], eventFlags[i], buf, paths[i]);
    170   }
    171   fflush(stdout);
    172   free(buf);
    173 
    174   if (fcntl(STDIN_FILENO, F_GETFD) == -1) {
    175     CFRunLoopStop(CFRunLoopGetCurrent());
    176   }
    177 }
    178 
    179 static void stdin_callback(CFFileDescriptorRef fdref, CFOptionFlags callBackTypes, void *info)
    180 {
    181   char buf[1024];
    182   int nread;
    183 
    184   do {
    185     nread = read(STDIN_FILENO, buf, sizeof(buf));
    186     if (nread == -1 && errno == EAGAIN) {
    187       CFFileDescriptorEnableCallBacks(fdref, kCFFileDescriptorReadCallBack);
    188       return;
    189     } else if (nread == 0) {
    190       exit(1);
    191       return;
    192     }
    193   } while (nread > 0);
    194 }
    195 
    196 int main(int argc, const char* argv[])
    197 {
    198   parse_cli_settings(argc, argv);
    199 
    200   FSEventStreamContext context = {0, NULL, NULL, NULL, NULL};
    201   FSEventStreamRef stream;
    202   stream = FSEventStreamCreate(kCFAllocatorDefault,
    203                                (FSEventStreamCallback)&callback,
    204                                &context,
    205                                config.paths,
    206                                config.sinceWhen,
    207                                config.latency,
    208                                config.flags);
    209 
    210 #ifdef DEBUG
    211   FSEventStreamShow(stream);
    212   fprintf(stderr, "\n");
    213 #endif
    214 
    215   fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK);
    216 
    217   CFFileDescriptorRef fdref = CFFileDescriptorCreate(kCFAllocatorDefault, STDIN_FILENO, false, stdin_callback, NULL);
    218   CFFileDescriptorEnableCallBacks(fdref, kCFFileDescriptorReadCallBack);
    219   CFRunLoopSourceRef source = CFFileDescriptorCreateRunLoopSource(kCFAllocatorDefault, fdref, 0);
    220   CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode);
    221   CFRelease(source);
    222 
    223   FSEventStreamScheduleWithRunLoop(stream,
    224                                    CFRunLoopGetCurrent(),
    225                                    kCFRunLoopDefaultMode);
    226   FSEventStreamStart(stream);
    227   CFRunLoopRun();
    228   FSEventStreamFlushSync(stream);
    229   FSEventStreamStop(stream);
    230 
    231   return 0;
    232 }
    233 
    234 // vim: ts=2 sts=2 et sw=2