wdm 0.0.3 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE CHANGED
@@ -1,22 +1,22 @@
1
- Copyright (c) 2012 Maher Sallam
2
-
3
- MIT License
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining
6
- a copy of this software and associated documentation files (the
7
- "Software"), to deal in the Software without restriction, including
8
- without limitation the rights to use, copy, modify, merge, publish,
9
- distribute, sublicense, and/or sell copies of the Software, and to
10
- permit persons to whom the Software is furnished to do so, subject to
11
- the following conditions:
12
-
13
- The above copyright notice and this permission notice shall be
14
- included in all copies or substantial portions of the Software.
15
-
16
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
1
+ Copyright (c) 2012 Maher Sallam
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
22
  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md CHANGED
@@ -1,25 +1,14 @@
1
1
  # Windows Directory Monitor (WDM)
2
2
 
3
- Windows Directory Monitor (WDM) is a library which can be used to monitor directories for changes.
4
- It's mostly implemented in C and uses the Win32 API for a better performance.
5
-
6
- **Note:** This is still a work in progress, so it's not advisable to use
7
- it yet in anything (unless you are testing it, which is very much appreciated :)).
3
+ Windows Directory Monitor (WDM) is a thread-safe ruby library which can be used to monitor directories for changes on Windows.
8
4
 
9
- TODO:
5
+ It's mostly implemented in C and uses the Win32 API for a better performance.
10
6
 
11
- - Fix all the TODO's in the source.
12
- - ~~Enable watching subdirectories.~~
13
- - ~~Add options to the `watch` method.~~
14
- - ~~Provide info about the change in the callback.~~
15
- - ~~Convert \ to / in paths.~~
16
- - ~~Don't allow directories to be watched while the monitor is running.~~
17
- - ~~Check if the passed direcoty exists.~~
18
- - ~~Convert passed directories to absolute paths.~~
7
+ **Important**: WDM only runs on ruby versions >= *1.9.2*!
19
8
 
20
9
  ## Installation
21
10
 
22
- Add this line to your application's Gemfile:
11
+ If you are using Bundler, add the following line to your application's Gemfile:
23
12
 
24
13
  gem 'wdm'
25
14
 
@@ -31,20 +20,180 @@ Or install it yourself as:
31
20
 
32
21
  $ gem install wdm
33
22
 
23
+ ## Usage
24
+
25
+ For a simple example on how to use WDM, you can take a look at the `example` directory of the repository.
26
+
27
+ ## Benchmarks
28
+
29
+ You can find a comparison of different ruby libraries for watching directory changes on Windows in the `benchmark` directory of the repository.
30
+
31
+ ## Reference
32
+
33
+ ### `WDM::Monitor`
34
+
35
+ To start watching directories, you need an instance of `WDM::Monitor`:
36
+
37
+ ```ruby
38
+ monitor = WDM::Monitor.new
39
+ ```
40
+
41
+ After that, register a callback for each directory you want to watch:
42
+
43
+ ```ruby
44
+ # Watch a single directory
45
+ monitor.watch('C:\Users\Maher\Desktop') { |change| puts change.path }
46
+
47
+ # Watch a directory with its subdirectories
48
+ monitor.watch_recursively('C:\Users\Maher\Projects\my_project') { |change| puts change.path }
49
+ ```
50
+
51
+ Both `Monitor#watch` and `Monitor#watch_recursively` can take a series of options after the first parameter to specify the watching options:
52
+
53
+ ```ruby
54
+ # Report changes to directories in the watched directory (Ex.: Addition of an empty directory)
55
+ monitor.watch('C:\Users\Maher\Desktop', :default, :directories)
56
+ ```
57
+
58
+ The supported options are:
59
+
60
+ <table>
61
+ <thead>
62
+ <tr>
63
+ <th>Value</th>
64
+ <th>Meaning</th>
65
+ </tr>
66
+ </thead>
67
+ <tbody>
68
+ <tr>
69
+ <td>:default</td>
70
+
71
+ <td>
72
+ The default set of options for watching directories. It's a combination of the :files, :directories and the :last_write options.
73
+ </td>
74
+ </tr>
75
+
76
+ <tr>
77
+ <td>:files</td>
78
+
79
+ <td>
80
+ Any file name change in the watched directory or subtree causes a change
81
+ notification wait operation to return. Changes include renaming, creating, or
82
+ deleting a file.
83
+ </td>
84
+ </tr>
85
+
86
+ <tr>
87
+ <td>:directories</td>
88
+
89
+ <td>
90
+ Any directory-name change in the watched directory or subtree causes a
91
+ change notification wait operation to return. Changes include creating or
92
+ deleting a directory.
93
+ </td>
94
+ </tr>
95
+
96
+ <tr>
97
+ <td>:attributes</td>
98
+
99
+ <td>
100
+ Any attribute change in the watched directory or subtree causes a change
101
+ notification wait operation to return.
102
+ </td>
103
+ </tr>
104
+
105
+ <tr>
106
+ <td>:size</td>
107
+
108
+ <td>
109
+ Any file-size change in the watched directory or subtree causes a change
110
+ notification wait operation to return. The operating system detects a change in
111
+ file size only when the file is written to the disk. For operating systems that
112
+ use extensive caching, detection occurs only when the cache is sufficiently
113
+ flushed.
114
+ </td>
115
+ </tr>
116
+
117
+ <tr>
118
+ <td>:last_write</td>
119
+
120
+ <td>
121
+ Any change to the last write-time of files in the watched directory or
122
+ subtree causes a change notification wait operation to return. The operating
123
+ system detects a change to the last write-time only when the file is written to
124
+ the disk. For operating systems that use extensive caching, detection occurs
125
+ only when the cache is sufficiently flushed.
126
+ </td>
127
+ </tr>
128
+
129
+ <tr>
130
+ <td>:last_access</td>
131
+
132
+ <td>
133
+ Any change to the last access time of files in the watched directory or
134
+ subtree causes a change notification wait operation to return.
135
+ </td>
136
+ </tr>
137
+
138
+ <tr>
139
+ <td>:creation</td>
140
+
141
+ <td>
142
+ Any change to the creation time of files in the watched directory or subtree
143
+ causes a change notification wait operation to return.
144
+ </td>
145
+ </tr>
146
+
147
+ <tr>
148
+ <td>:security</td>
149
+
150
+ <td>
151
+ Any security-descriptor change in the watched directory or subtree causes a
152
+ change notification wait operation to return.
153
+ </td>
154
+ </tr>
155
+ </tbody>
156
+ </table>
157
+
158
+ These options map to the filters that `ReadDirectoryChangesW` takes in its `dwNotifyFilter` parameter. You can find more info on the [docs page](http://msdn.microsoft.com/en-us/library/windows/desktop/aa365465.aspx) of `ReadDirectoryChangesW`.
159
+
160
+ Now all that's left to be done is to run the monitor:
161
+
162
+ ```ruby
163
+ monitor.run!
164
+ ```
165
+
166
+ The `Monitor#run!` method blocks the process. Since monitors are thread-safe, you can run them in a thread if you don't want to block your main one:
167
+
168
+ ```ruby
169
+ worker_thread = Thread.new { monitor.run! }
170
+
171
+ # The process won't block; it will continue with the next line of code...
172
+ ```
173
+
174
+ When you are done with the monitor, don't forget to stop it. Here is a snippet to always stop the monitor when the ruby process exits:
175
+
176
+ ```ruby
177
+ at_exit { monitor.stop }
178
+ ```
179
+
180
+ ### `WDM::Change`
181
+
182
+ The passed argument to the block is an instance of `WDM::Change`. This class has two methods:
183
+
184
+ - `Change#path`: The absolute path to the change.
185
+ - `Change#type`: This can be one of the following values: `:added`, `:modified`, `:removed`, `:renamed_old_file` or `:renamed_new_file`.
186
+
34
187
  ## Compiling the extension for developers
35
188
 
36
189
  Download the source, then run the following:
37
190
 
38
- $ rake compile
191
+ $ bundle exec rake compile
39
192
 
40
193
  To get debug messages, you need to enable them in the `global.h` file:
41
194
 
42
195
  #define WDM_DEBUG_ENABLED TRUE // This is disabled by default
43
196
 
44
- ## Usage
45
-
46
- TODO: Write usage instructions here
47
-
48
197
  ## Contributing
49
198
 
50
199
  1. Fork it
@@ -8,7 +8,8 @@
8
8
  // ---------------------------------------------------------
9
9
 
10
10
  WDM_PEntryUserData
11
- wdm_entry_user_data_new() {
11
+ wdm_entry_user_data_new()
12
+ {
12
13
  WDM_PEntryUserData user_data;
13
14
 
14
15
  user_data = WDM_ALLOC(WDM_EntryUserData);
@@ -20,7 +21,8 @@ wdm_entry_user_data_new() {
20
21
  }
21
22
 
22
23
  void
23
- wdm_entry_user_data_free(WDM_PEntryUserData user_data) {
24
+ wdm_entry_user_data_free(WDM_PEntryUserData user_data)
25
+ {
24
26
  if ( user_data->dir != NULL ) free(user_data->dir);
25
27
  free(user_data);
26
28
  }
@@ -30,7 +32,8 @@ wdm_entry_user_data_free(WDM_PEntryUserData user_data) {
30
32
  // ---------------------------------------------------------
31
33
 
32
34
  WDM_PEntry
33
- wdm_entry_new() {
35
+ wdm_entry_new()
36
+ {
34
37
  WDM_PEntry entry;
35
38
 
36
39
  entry = WDM_ALLOC(WDM_Entry);
@@ -46,7 +49,8 @@ wdm_entry_new() {
46
49
  }
47
50
 
48
51
  void
49
- wdm_entry_free(WDM_PEntry entry) {
52
+ wdm_entry_free(WDM_PEntry entry)
53
+ {
50
54
  if ( entry->dir_handle != INVALID_HANDLE_VALUE ) {
51
55
  CancelIo(entry->dir_handle); // Stop monitoring changes
52
56
  CloseHandle(entry->dir_handle);
@@ -56,7 +60,8 @@ wdm_entry_free(WDM_PEntry entry) {
56
60
  }
57
61
 
58
62
  void
59
- wdm_entry_list_free(WDM_PEntry entry) {
63
+ wdm_entry_list_free(WDM_PEntry entry)
64
+ {
60
65
  WDM_PEntry tmp;
61
66
 
62
67
  while(entry != NULL) {
@@ -1,9 +1,27 @@
1
1
  require 'mkmf'
2
+ require 'rbconfig'
2
3
 
3
- if have_library("kernel32") and
4
+ def generate_makefile
5
+ create_makefile("wdm_ext")
6
+ end
7
+
8
+ def generate_dummy_makefile
9
+ File.open("Makefile", "w") do |f|
10
+ f.puts dummy_makefile('wdm_ext').join
11
+ end
12
+ end
13
+
14
+ def windows?
15
+ RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/
16
+ end
17
+
18
+ if windows? and
19
+ have_library("kernel32") and
4
20
  have_header("windows.h") and
5
21
  have_header("ruby.h") and
6
22
  have_const('HAVE_RUBY_ENCODING_H')
7
23
  then
8
- create_makefile("wdm")
24
+ generate_makefile()
25
+ else
26
+ generate_dummy_makefile()
9
27
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  #include "memory.h"
4
4
 
5
- void *
5
+ void*
6
6
  wdm_memory_malloc (size_t size)
7
7
  {
8
8
  void *memory = malloc(size);
@@ -14,7 +14,7 @@ wdm_memory_malloc (size_t size)
14
14
  return memory;
15
15
  }
16
16
 
17
- void *
17
+ void*
18
18
  wdm_memory_realloc (void *ptr, size_t size)
19
19
  {
20
20
  void *memory = realloc(ptr, size);
@@ -9,11 +9,9 @@ extern "C" {
9
9
  // Prototypes
10
10
  // ---------------------------------------------------------
11
11
 
12
- void *
13
- wdm_memory_malloc (size_t);
12
+ void* wdm_memory_malloc (size_t);
14
13
 
15
- void *
16
- wdm_memory_realloc (void *, size_t);
14
+ void* wdm_memory_realloc (void*, size_t);
17
15
 
18
16
  // ---------------------------------------------------------
19
17
  // Macros
@@ -7,7 +7,8 @@
7
7
  #include "monitor.h"
8
8
 
9
9
  WDM_PMonitor
10
- wdm_monitor_new() {
10
+ wdm_monitor_new()
11
+ {
11
12
  WDM_PMonitor monitor;
12
13
 
13
14
  monitor = WDM_ALLOC(WDM_Monitor);
@@ -32,7 +33,8 @@ wdm_monitor_new() {
32
33
  }
33
34
 
34
35
  void
35
- wdm_monitor_free(WDM_PMonitor monitor) {
36
+ wdm_monitor_free(WDM_PMonitor monitor)
37
+ {
36
38
  if ( monitor->monitoring_thread != INVALID_HANDLE_VALUE ) CloseHandle(monitor->monitoring_thread);
37
39
 
38
40
  wdm_entry_list_free(monitor->head);
@@ -45,7 +47,8 @@ wdm_monitor_free(WDM_PMonitor monitor) {
45
47
  }
46
48
 
47
49
  void
48
- wdm_monitor_update_head(WDM_PMonitor monitor, WDM_PEntry new_head) {
50
+ wdm_monitor_update_head(WDM_PMonitor monitor, WDM_PEntry new_head)
51
+ {
49
52
  EnterCriticalSection(&monitor->lock);
50
53
  new_head->next = monitor->head;
51
54
  monitor->head = new_head;
@@ -53,7 +56,8 @@ wdm_monitor_update_head(WDM_PMonitor monitor, WDM_PEntry new_head) {
53
56
  }
54
57
 
55
58
  WDM_PMonitorCallbackParam
56
- wdm_monitor_callback_param_new(WDM_PMonitor monitor, WDM_PEntry entry) {
59
+ wdm_monitor_callback_param_new(WDM_PMonitor monitor, WDM_PEntry entry)
60
+ {
57
61
  WDM_PMonitorCallbackParam param;
58
62
 
59
63
  param = WDM_ALLOC(WDM_MonitorCallbackParam);
@@ -65,6 +69,7 @@ wdm_monitor_callback_param_new(WDM_PMonitor monitor, WDM_PEntry entry) {
65
69
  }
66
70
 
67
71
  void
68
- wdm_monitor_callback_param_free(WDM_PMonitorCallbackParam param) {
72
+ wdm_monitor_callback_param_free(WDM_PMonitorCallbackParam param)
73
+ {
69
74
  free(param);
70
75
  }
@@ -5,11 +5,19 @@
5
5
  #include "memory.h"
6
6
  #include "queue.h"
7
7
 
8
+ // ---------------------------------------------------------
9
+ // Prototypes of static functions
10
+ // ---------------------------------------------------------
11
+
12
+ static WDM_PQueueItem do_queue_dequeue(WDM_PQueue queue);
13
+
8
14
  // ---------------------------------------------------------
9
15
  // Queue item functions
10
16
  // ---------------------------------------------------------
11
17
 
12
- WDM_PQueueItemError wdm_queue_item_error_new(VALUE exception, LPCSTR format, ...) {
18
+ WDM_PQueueItemError
19
+ wdm_queue_item_error_new(VALUE exception, LPCSTR format, ...)
20
+ {
13
21
  WDM_PQueueItemError error;
14
22
  va_list ap;
15
23
  int length;
@@ -27,15 +35,19 @@ WDM_PQueueItemError wdm_queue_item_error_new(VALUE exception, LPCSTR format, ...
27
35
  return error;
28
36
  }
29
37
 
30
- void wdm_queue_item_error_free(WDM_PQueueItemError error) {
38
+ void
39
+ wdm_queue_item_error_free(WDM_PQueueItemError error)
40
+ {
31
41
  if ( error->message != NULL ) free(error->message);
32
42
  free(error);
33
43
  }
34
44
 
35
- WDM_PQueueItemData wdm_queue_item_data_new() {
45
+ WDM_PQueueItemData
46
+ wdm_queue_item_data_new()
47
+ {
36
48
  WDM_PQueueItemData data;
37
49
 
38
- data = ALLOC(WDM_QueueItemData);
50
+ data = WDM_ALLOC(WDM_QueueItemData);
39
51
  data->user_data = NULL;
40
52
 
41
53
  ZeroMemory(&data->buffer, WDM_BUFFER_SIZE);
@@ -43,12 +55,15 @@ WDM_PQueueItemData wdm_queue_item_data_new() {
43
55
  return data;
44
56
  }
45
57
 
46
- void wdm_queue_item_data_free(WDM_PQueueItemData data) {
58
+ void
59
+ wdm_queue_item_data_free(WDM_PQueueItemData data)
60
+ {
47
61
  free(data);
48
62
  }
49
63
 
50
64
  WDM_PQueueItem
51
- wdm_queue_item_new(WDM_QueueItemType type) {
65
+ wdm_queue_item_new(WDM_QueueItemType type)
66
+ {
52
67
  WDM_PQueueItem item;
53
68
 
54
69
  item = WDM_ALLOC(WDM_QueueItem);
@@ -61,14 +76,14 @@ wdm_queue_item_new(WDM_QueueItemType type) {
61
76
  item->data = NULL;
62
77
  }
63
78
 
64
- item->previous = NULL;
65
79
  item->next = NULL;
66
80
 
67
81
  return item;
68
82
  }
69
83
 
70
84
  void
71
- wdm_queue_item_free(WDM_PQueueItem item) {
85
+ wdm_queue_item_free(WDM_PQueueItem item)
86
+ {
72
87
  if ( item->type == WDM_QUEUE_ITEM_TYPE_ERROR ) {
73
88
  if ( item->error != NULL ) wdm_queue_item_error_free(item->error);
74
89
  }
@@ -76,8 +91,8 @@ wdm_queue_item_free(WDM_PQueueItem item) {
76
91
  if ( item->data != NULL ) wdm_queue_item_data_free(item->data);
77
92
  }
78
93
 
79
- // We can't really do anything to the prev pointer nor the next pointer,
80
- // because we might break any linking the user has established.
94
+ // We can't really do anything to the next pointer because
95
+ // we might break any linking the user has established.
81
96
  free(item);
82
97
  }
83
98
 
@@ -86,7 +101,8 @@ wdm_queue_item_free(WDM_PQueueItem item) {
86
101
  // ---------------------------------------------------------
87
102
 
88
103
  WDM_PQueue
89
- wdm_queue_new() {
104
+ wdm_queue_new()
105
+ {
90
106
  WDM_PQueue queue;
91
107
 
92
108
  queue = WDM_ALLOC(WDM_Queue);
@@ -103,21 +119,22 @@ wdm_queue_new() {
103
119
  }
104
120
 
105
121
  void
106
- wdm_queue_free(WDM_PQueue queue) {
122
+ wdm_queue_free(WDM_PQueue queue)
123
+ {
107
124
  wdm_queue_empty(queue);
108
125
  free(queue);
109
126
  }
110
127
 
111
128
  void
112
- wdm_queue_enqueue(WDM_PQueue queue, WDM_PQueueItem item) {
129
+ wdm_queue_enqueue(WDM_PQueue queue, WDM_PQueueItem item)
130
+ {
113
131
  EnterCriticalSection(&queue->lock);
114
132
 
115
- if ( queue->rear == NULL && queue->front == NULL ) {
133
+ if ( wdm_queue_is_empty(queue) ) {
116
134
  queue->front = queue->rear = item;
117
135
  }
118
136
  else {
119
137
  queue->rear->next = item;
120
- item->previous = queue->rear;
121
138
  queue->rear = item;
122
139
  }
123
140
 
@@ -125,12 +142,11 @@ wdm_queue_enqueue(WDM_PQueue queue, WDM_PQueueItem item) {
125
142
  }
126
143
 
127
144
  WDM_PQueueItem
128
- wdm_queue_dequeue(WDM_PQueue queue) {
145
+ do_queue_dequeue(WDM_PQueue queue)
146
+ {
129
147
  WDM_PQueueItem item;
130
148
 
131
- EnterCriticalSection(&queue->lock);
132
-
133
- if ( queue->rear == NULL && queue->front == NULL ) {
149
+ if ( wdm_queue_is_empty(queue) ) {
134
150
  item = NULL;
135
151
  }
136
152
  else {
@@ -141,21 +157,40 @@ wdm_queue_dequeue(WDM_PQueue queue) {
141
157
  if ( queue->front == NULL ) queue->rear = NULL;
142
158
 
143
159
  // Don't allow the user to mess with the queue
144
- item->previous = item->next = NULL;
160
+ item->next = NULL;
145
161
  }
146
162
 
163
+ return item;
164
+ }
165
+
166
+ WDM_PQueueItem
167
+ wdm_queue_dequeue(WDM_PQueue queue)
168
+ {
169
+ WDM_PQueueItem item;
170
+
171
+ EnterCriticalSection(&queue->lock);
172
+
173
+ item = do_queue_dequeue(queue);
174
+
147
175
  LeaveCriticalSection(&queue->lock);
148
176
 
149
177
  return item;
150
178
  }
151
179
 
152
- void wdm_queue_empty(WDM_PQueue queue) {
180
+ void
181
+ wdm_queue_empty(WDM_PQueue queue)
182
+ {
183
+ EnterCriticalSection(&queue->lock);
184
+
153
185
  while( ! wdm_queue_is_empty(queue) ) {
154
- wdm_queue_item_free(wdm_queue_dequeue(queue));
186
+ wdm_queue_item_free( do_queue_dequeue(queue) );
155
187
  }
188
+
189
+ LeaveCriticalSection(&queue->lock);
156
190
  }
157
191
 
158
- BOOL
159
- wdm_queue_is_empty(WDM_PQueue queue) {
192
+ inline BOOL
193
+ wdm_queue_is_empty(WDM_PQueue queue)
194
+ {
160
195
  return queue->front == NULL && queue->rear == NULL;
161
196
  }
@@ -34,11 +34,10 @@ typedef struct WDM_QueueItem {
34
34
  WDM_PQueueItemData data;
35
35
  WDM_PQueueItemError error;
36
36
  };
37
- struct WDM_QueueItem* previous;
38
37
  struct WDM_QueueItem* next;
39
38
  } WDM_QueueItem, *WDM_PQueueItem;
40
39
 
41
- typedef struct WDM_Queue {
40
+ typedef struct {
42
41
  CRITICAL_SECTION lock;
43
42
  WDM_PQueueItem front;
44
43
  WDM_PQueueItem rear;
@@ -11,7 +11,7 @@
11
11
  // Internal constants
12
12
  // ---------------------------------------------------------
13
13
 
14
- // The _wsplitpat constants account for two NULL chars, so substract 1 because we only need one!
14
+ // The _wsplitpat constants account for two NULL chars, so subtract 1 because we only need one!
15
15
  #define WDM_MAX_FILENAME (_MAX_FNAME + _MAX_EXT - 1)
16
16
 
17
17
  // ----------------------------------------------------------
@@ -38,10 +38,11 @@ static VALUE extract_change_type_from_notification(const PFILE_NOTIFY_INFORMATIO
38
38
  // ----------------------------------------------------------
39
39
 
40
40
  // TODO:
41
- // 1. this function uses a lot of 'alloca' calls, which AFAIK is not recommeneded! Can this be avoided?
41
+ // 1. this function uses a lot of 'alloca' calls, which AFAIK is not recommended! Can this be avoided?
42
42
  // 2. all wcscat calls can be done faster with memcpy, but is it worth sacrificing the readability?
43
43
  static VALUE
44
- extract_absolute_path_from_notification(const LPWSTR base_dir, const PFILE_NOTIFY_INFORMATION info) {
44
+ extract_absolute_path_from_notification(const LPWSTR base_dir, const PFILE_NOTIFY_INFORMATION info)
45
+ {
45
46
  LPWSTR buffer, absolute_filepath;
46
47
  WCHAR file[_MAX_FNAME], ext[_MAX_EXT], filename[WDM_MAX_FILENAME];
47
48
  DWORD filename_len, absolute_filepath_len;
@@ -115,7 +116,7 @@ extract_absolute_path_from_notification(const LPWSTR base_dir, const PFILE_NOTIF
115
116
  }
116
117
  }
117
118
 
118
- // The convention in Ruby is to use forward-slashes to seprarate dirs on all platforms.
119
+ // The convention in Ruby is to use forward-slashes to separate dirs on all platforms.
119
120
  wdm_utils_convert_back_to_forward_slashes(absolute_filepath, absolute_filepath_len + 1);
120
121
 
121
122
  // Convert the path from WCHAR to multibyte CHAR to use it in a ruby string
@@ -141,7 +142,8 @@ extract_absolute_path_from_notification(const LPWSTR base_dir, const PFILE_NOTIF
141
142
  }
142
143
 
143
144
  static VALUE
144
- extract_change_type_from_notification(const PFILE_NOTIFY_INFORMATION info) {
145
+ extract_change_type_from_notification(const PFILE_NOTIFY_INFORMATION info)
146
+ {
145
147
  ID type;
146
148
 
147
149
  switch(info->Action) {
@@ -162,7 +164,8 @@ extract_change_type_from_notification(const PFILE_NOTIFY_INFORMATION info) {
162
164
  }
163
165
 
164
166
  VALUE
165
- wdm_rb_change_new_from_notification(const LPWSTR base_dir, const PFILE_NOTIFY_INFORMATION info) {
167
+ wdm_rb_change_new_from_notification(const LPWSTR base_dir, const PFILE_NOTIFY_INFORMATION info)
168
+ {
166
169
  VALUE change;
167
170
 
168
171
  change = rb_class_new_instance(0, NULL, cWDM_Change);
@@ -177,7 +180,8 @@ wdm_rb_change_new_from_notification(const LPWSTR base_dir, const PFILE_NOTIFY_IN
177
180
  }
178
181
 
179
182
  void
180
- wdm_rb_change_init() {
183
+ wdm_rb_change_init()
184
+ {
181
185
  WDM_DEBUG("Registering WDM::Event with Ruby!");
182
186
 
183
187
  wdm_rb_sym_at_path = rb_intern("@path");
@@ -60,7 +60,8 @@ static VALUE rb_monitor_stop(VALUE);
60
60
  // ----------------------------------------------------------
61
61
 
62
62
  static void
63
- monitor_mark(LPVOID param) {
63
+ monitor_mark(LPVOID param)
64
+ {
64
65
  WDM_PMonitor monitor;
65
66
  WDM_PEntry entry;
66
67
 
@@ -74,7 +75,8 @@ monitor_mark(LPVOID param) {
74
75
  }
75
76
 
76
77
  static void
77
- monitor_free(LPVOID param) {
78
+ monitor_free(LPVOID param)
79
+ {
78
80
  WDM_PMonitor monitor;
79
81
  WDM_PEntry entry;
80
82
 
@@ -98,7 +100,8 @@ monitor_free(LPVOID param) {
98
100
  }
99
101
 
100
102
  static VALUE
101
- rb_monitor_alloc(VALUE self) {
103
+ rb_monitor_alloc(VALUE self)
104
+ {
102
105
  WDM_DEBUG("--------------------------------");
103
106
  WDM_DEBUG("Allocating a new monitor object!");
104
107
  WDM_DEBUG("--------------------------------");
@@ -107,10 +110,11 @@ rb_monitor_alloc(VALUE self) {
107
110
  }
108
111
 
109
112
  static DWORD
110
- id_to_flag(ID id) {
113
+ id_to_flag(ID id)
114
+ {
111
115
  if ( id == wdm_rb_sym_default ) return WDM_MONITOR_FLAGS_DEFAULT;
112
116
 
113
- // TODO: Maybe reorder the if's in the frequentie of use for better performance?
117
+ // TODO: Maybe reorder the if's in the frequency of use for better performance?
114
118
  if ( id == wdm_rb_sym_files ) return FILE_NOTIFY_CHANGE_FILE_NAME;
115
119
  if ( id == wdm_rb_sym_directories ) return FILE_NOTIFY_CHANGE_DIR_NAME;
116
120
  if ( id == wdm_rb_sym_attributes ) return FILE_NOTIFY_CHANGE_ATTRIBUTES;
@@ -124,7 +128,8 @@ id_to_flag(ID id) {
124
128
  }
125
129
 
126
130
  static DWORD
127
- extract_flags_from_rb_array(VALUE flags_array) {
131
+ extract_flags_from_rb_array(VALUE flags_array)
132
+ {
128
133
  VALUE flag_symbol;
129
134
  DWORD flags;
130
135
 
@@ -140,7 +145,8 @@ extract_flags_from_rb_array(VALUE flags_array) {
140
145
  }
141
146
 
142
147
  static VALUE
143
- combined_watch(BOOL recursively, int argc, VALUE *argv, VALUE self) {
148
+ combined_watch(BOOL recursively, int argc, VALUE *argv, VALUE self)
149
+ {
144
150
  WDM_PMonitor monitor;
145
151
  WDM_PEntry entry;
146
152
  int directory_letters_count;
@@ -237,12 +243,14 @@ combined_watch(BOOL recursively, int argc, VALUE *argv, VALUE self) {
237
243
  }
238
244
 
239
245
  static VALUE
240
- rb_monitor_watch(int argc, VALUE *argv, VALUE self) {
246
+ rb_monitor_watch(int argc, VALUE *argv, VALUE self)
247
+ {
241
248
  return combined_watch(FALSE, argc, argv, self);
242
249
  }
243
250
 
244
251
  static VALUE
245
- rb_monitor_watch_recursively(int argc, VALUE *argv, VALUE self) {
252
+ rb_monitor_watch_recursively(int argc, VALUE *argv, VALUE self)
253
+ {
246
254
  return combined_watch(TRUE, argc, argv, self);
247
255
  }
248
256
 
@@ -256,7 +264,7 @@ handle_entry_change(
256
264
  WDM_PQueueItem data_to_process;
257
265
 
258
266
  if ( err_code == ERROR_OPERATION_ABORTED ) {
259
- // Async operation was canceld. This shouldn't happen.
267
+ // Async operation was canceled. This shouldn't happen.
260
268
  // TODO:
261
269
  // 1. Maybe add a union in the queue for errors?
262
270
  // 2. What's the best action when this happens?
@@ -293,7 +301,8 @@ handle_entry_change(
293
301
  }
294
302
 
295
303
  static BOOL
296
- register_monitoring_entry(WDM_PEntry entry) {
304
+ register_monitoring_entry(WDM_PEntry entry)
305
+ {
297
306
  BOOL success;
298
307
  DWORD bytes;
299
308
  bytes = 0; // Not used because the process callback gets passed the written bytes
@@ -318,7 +327,8 @@ register_monitoring_entry(WDM_PEntry entry) {
318
327
  }
319
328
 
320
329
  static DWORD WINAPI
321
- start_monitoring(LPVOID param) {
330
+ start_monitoring(LPVOID param)
331
+ {
322
332
  WDM_PMonitor monitor;
323
333
  WDM_PEntry curr_entry;
324
334
 
@@ -361,7 +371,8 @@ start_monitoring(LPVOID param) {
361
371
  }
362
372
 
363
373
  static VALUE
364
- wait_for_changes(LPVOID param) {
374
+ wait_for_changes(LPVOID param)
375
+ {
365
376
  HANDLE process_event;
366
377
 
367
378
  process_event = (HANDLE)param;
@@ -370,7 +381,8 @@ wait_for_changes(LPVOID param) {
370
381
  }
371
382
 
372
383
  static void
373
- process_changes(WDM_PQueue changes) {
384
+ process_changes(WDM_PQueue changes)
385
+ {
374
386
  WDM_PQueueItem item;
375
387
  LPBYTE current_info_entry_offset;
376
388
  PFILE_NOTIFY_INFORMATION info;
@@ -412,7 +424,8 @@ process_changes(WDM_PQueue changes) {
412
424
  }
413
425
 
414
426
  static void
415
- stop_monitoring(LPVOID param) {
427
+ stop_monitoring(LPVOID param)
428
+ {
416
429
  BOOL already_stopped;
417
430
  WDM_PMonitor monitor;
418
431
  WDM_PEntry entry;
@@ -449,8 +462,8 @@ stop_monitoring(LPVOID param) {
449
462
  }
450
463
 
451
464
  static VALUE
452
- rb_monitor_run_bang(VALUE self) {
453
- DWORD thread_id;
465
+ rb_monitor_run_bang(VALUE self)
466
+ {
454
467
  BOOL already_running,
455
468
  waiting_succeeded;
456
469
  WDM_PMonitor monitor;
@@ -484,7 +497,7 @@ rb_monitor_run_bang(VALUE self) {
484
497
  start_monitoring, // thread function name
485
498
  monitor, // argument to thread function
486
499
  0, // use default creation flags
487
- &thread_id // returns the thread identifier
500
+ NULL // Ignore thread identifier
488
501
  );
489
502
 
490
503
  if ( monitor->monitoring_thread == NULL ) {
@@ -514,7 +527,8 @@ rb_monitor_run_bang(VALUE self) {
514
527
  }
515
528
 
516
529
  static VALUE
517
- rb_monitor_stop(VALUE self) {
530
+ rb_monitor_stop(VALUE self)
531
+ {
518
532
  WDM_PMonitor monitor;
519
533
 
520
534
  Data_Get_Struct(self, WDM_Monitor, monitor);
@@ -527,7 +541,8 @@ rb_monitor_stop(VALUE self) {
527
541
  }
528
542
 
529
543
  void
530
- wdm_rb_monitor_init() {
544
+ wdm_rb_monitor_init()
545
+ {
531
546
  WDM_DEBUG("Registering WDM::Monitor with Ruby!");
532
547
 
533
548
  wdm_rb_sym_call = rb_intern("call");
@@ -8,7 +8,8 @@
8
8
  // ---------------------------------------------------------
9
9
 
10
10
  LPWSTR
11
- wdm_utils_convert_back_to_forward_slashes(LPWSTR path, DWORD path_len) {
11
+ wdm_utils_convert_back_to_forward_slashes(LPWSTR path, DWORD path_len)
12
+ {
12
13
  UINT i;
13
14
 
14
15
  for(i = 0; i < (path_len - 1); ++i) { // path_len-1 because we don't need to check the NULL-char!
@@ -19,7 +20,8 @@ wdm_utils_convert_back_to_forward_slashes(LPWSTR path, DWORD path_len) {
19
20
  }
20
21
 
21
22
  LPWSTR
22
- wdm_utils_full_pathname(const LPWSTR path) {
23
+ wdm_utils_full_pathname(const LPWSTR path)
24
+ {
23
25
  WCHAR maxed_path[WDM_MAX_WCHAR_LONG_PATH];
24
26
  LPWSTR full_path;
25
27
  size_t full_path_len;
@@ -42,7 +44,8 @@ wdm_utils_full_pathname(const LPWSTR path) {
42
44
  }
43
45
 
44
46
  BOOL
45
- wdm_utils_unicode_is_directory(const LPWSTR path) {
47
+ wdm_utils_unicode_is_directory(const LPWSTR path)
48
+ {
46
49
  WCHAR unicode_path[WDM_MAX_WCHAR_LONG_PATH];
47
50
 
48
51
  wcscpy(unicode_path, L"\\\\?\\");
@@ -59,7 +62,8 @@ wdm_utils_unicode_is_directory(const LPWSTR path) {
59
62
  }
60
63
 
61
64
  BOOL
62
- wdm_utils_is_directory(const LPWSTR path) {
65
+ wdm_utils_is_directory(const LPWSTR path)
66
+ {
63
67
  DWORD dwAttrib = GetFileAttributesW(path);
64
68
 
65
69
  return (dwAttrib != INVALID_FILE_ATTRIBUTES &&
@@ -67,6 +71,7 @@ wdm_utils_is_directory(const LPWSTR path) {
67
71
  }
68
72
 
69
73
  BOOL
70
- wdm_utils_is_unc_path(const LPWSTR path) {
74
+ wdm_utils_is_unc_path(const LPWSTR path)
75
+ {
71
76
  return path[0] == path[1] && path[0] == L'\\';
72
77
  }
@@ -32,7 +32,8 @@ rb_encoding *wdm_rb_enc_utf8;
32
32
  // ----------------------------------------------------------
33
33
 
34
34
  void
35
- Init_wdm() {
35
+ Init_wdm_ext()
36
+ {
36
37
  WDM_DEBUG("Registering WDM with Ruby!");
37
38
 
38
39
  wdm_rb_enc_utf8 = rb_utf8_encoding();
@@ -57,6 +57,12 @@ extern VALUE eWDM_Error;
57
57
 
58
58
  extern rb_encoding *wdm_rb_enc_utf8;
59
59
 
60
+ // ---------------------------------------------------------
61
+ // Prototypes
62
+ // ---------------------------------------------------------
63
+
64
+ void Init_wdm_ext();
65
+
60
66
  // ---------------------------------------------------------
61
67
 
62
68
  #ifdef __cplusplus
@@ -20,12 +20,14 @@
20
20
  <ConfigurationType>Application</ConfigurationType>
21
21
  <UseDebugLibraries>true</UseDebugLibraries>
22
22
  <CharacterSet>Unicode</CharacterSet>
23
+ <PlatformToolset>v110</PlatformToolset>
23
24
  </PropertyGroup>
24
25
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
25
26
  <ConfigurationType>Application</ConfigurationType>
26
27
  <UseDebugLibraries>false</UseDebugLibraries>
27
28
  <WholeProgramOptimization>true</WholeProgramOptimization>
28
29
  <CharacterSet>Unicode</CharacterSet>
30
+ <PlatformToolset>v110</PlatformToolset>
29
31
  </PropertyGroup>
30
32
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
31
33
  <ImportGroup Label="ExtensionSettings">
@@ -0,0 +1,10 @@
1
+ begin
2
+ require 'wdm_ext'
3
+ rescue LoadError
4
+ raise LoadError.new(<<-EOS)
5
+ Can't load WDM!
6
+
7
+ WDM is not supported on your system. For a cross-platform alternative,
8
+ we recommend using Listen: http://github.com/guard/listen
9
+ EOS
10
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wdm
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-08-15 00:00:00.000000000 Z
12
+ date: 2013-02-11 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake-compiler
@@ -153,6 +153,7 @@ files:
153
153
  - ext/wdm/wdm.sln
154
154
  - ext/wdm/wdm.vcxproj
155
155
  - ext/wdm/wdm.vcxproj.filters
156
+ - lib/wdm.rb
156
157
  - LICENSE
157
158
  - README.md
158
159
  homepage: https://github.com/Maher4Ever/wdm
@@ -173,9 +174,6 @@ required_rubygems_version: !ruby/object:Gem::Requirement
173
174
  - - ! '>='
174
175
  - !ruby/object:Gem::Version
175
176
  version: '0'
176
- segments:
177
- - 0
178
- hash: 341068911
179
177
  requirements: []
180
178
  rubyforge_project:
181
179
  rubygems_version: 1.8.24