/* Generate a file notification event. */ static void kqueue_generate_event (Lisp_Object watch_object, Lisp_Object actions, Lisp_Object file, Lisp_Object file1) { Lisp_Object flags, action, entry; struct input_event event; /* Check, whether all actions shall be monitored. */ flags = Fnth (make_number (2), watch_object); action = actions; do { if (NILP (action)) break; entry = XCAR (action); if (NILP (Fmember (entry, flags))) { action = XCDR (action); actions = Fdelq (entry, actions); } else action = XCDR (action); } while (1); /* Store it into the input event queue. */ if (! NILP (actions)) { EVENT_INIT (event); event.kind = FILE_NOTIFY_EVENT; event.frame_or_window = Qnil; event.arg = list2 (Fcons (XCAR (watch_object), Fcons (actions, NILP (file1) ? Fcons (file, Qnil) : list2 (file, file1))), Fnth (make_number (3), watch_object)); kbd_buffer_store_event (&event); } }
static rep_struct_node * lookup_or_add (rep_struct *s, repv var) { rep_struct_node *n = lookup (s, var); if (n == 0) { if (s->total_buckets == 0) { s->total_buckets = MIN_BUCKETS; s->buckets = rep_alloc (sizeof (rep_struct_node *) * s->total_buckets); memset (s->buckets, 0, sizeof (rep_struct_node *) * s->total_buckets); rep_data_after_gc += sizeof (rep_struct_node *) * s->total_buckets; } if (s->total_bindings > s->total_buckets * MAX_MULTIPLIER) { int new_total = s->total_buckets * 2; rep_struct_node **buckets = rep_alloc (new_total * sizeof (rep_struct_node *)); int i; memset (buckets, 0, new_total * sizeof (rep_struct_node *)); rep_data_after_gc += new_total * sizeof (rep_struct_node *); for (i = 0; i < s->total_buckets; i++) { rep_struct_node *next; for (n = s->buckets[i]; n != 0; n = next) { next = n->next; n->next = buckets[rep_STRUCT_HASH (n->symbol, new_total)]; buckets[rep_STRUCT_HASH (n->symbol, new_total)] = n; } } s->total_buckets = new_total; rep_free (s->buckets); s->buckets = buckets; } n = rep_alloc (sizeof (rep_struct_node)); rep_data_after_gc += sizeof (rep_struct_node); n->symbol = var; n->is_constant = 0; n->is_exported = (s->car & rep_STF_EXPORT_ALL) != 0; n->next = s->buckets[rep_STRUCT_HASH (var, s->total_buckets)]; s->buckets[rep_STRUCT_HASH (var, s->total_buckets)] = n; s->total_bindings++; if (structure_exports_inherited_p (s, var)) { n->is_exported = 1; s->inherited = Fdelq (var, s->inherited); } cache_invalidate_symbol (var); } return n; }
/* This compares two directory listings in case of a `write' event for a directory. Generate resulting file notification events. The old directory listing is retrieved from watch_object, it will be replaced by the new directory listing at the end of this function. */ static void kqueue_compare_dir_list (Lisp_Object watch_object) { Lisp_Object dir, pending_dl, deleted_dl; Lisp_Object old_directory_files, old_dl, new_directory_files, new_dl, dl; dir = XCAR (XCDR (watch_object)); pending_dl = Qnil; deleted_dl = Qnil; old_directory_files = Fnth (make_number (4), watch_object); old_dl = kqueue_directory_listing (old_directory_files); /* When the directory is not accessible anymore, it has been deleted. */ if (NILP (Ffile_directory_p (dir))) { kqueue_generate_event (watch_object, Fcons (Qdelete, Qnil), dir, Qnil); return; } new_directory_files = directory_files_internal (dir, Qnil, Qnil, Qnil, 1, Qnil); new_dl = kqueue_directory_listing (new_directory_files); /* Parse through the old list. */ dl = old_dl; while (1) { Lisp_Object old_entry, new_entry, dl1; if (NILP (dl)) break; /* Search for an entry with the same inode. */ old_entry = XCAR (dl); new_entry = assq_no_quit (XCAR (old_entry), new_dl); if (! NILP (Fequal (old_entry, new_entry))) { /* Both entries are identical. Nothing to do. */ new_dl = Fdelq (new_entry, new_dl); goto the_end; } /* Both entries have the same inode. */ if (! NILP (new_entry)) { /* Both entries have the same file name. */ if (strcmp (SSDATA (XCAR (XCDR (old_entry))), SSDATA (XCAR (XCDR (new_entry)))) == 0) { /* Modification time has been changed, the file has been written. */ if (NILP (Fequal (Fnth (make_number (2), old_entry), Fnth (make_number (2), new_entry)))) kqueue_generate_event (watch_object, Fcons (Qwrite, Qnil), XCAR (XCDR (old_entry)), Qnil); /* Status change time has been changed, the file attributes have changed. */ if (NILP (Fequal (Fnth (make_number (3), old_entry), Fnth (make_number (3), new_entry)))) kqueue_generate_event (watch_object, Fcons (Qattrib, Qnil), XCAR (XCDR (old_entry)), Qnil); } else { /* The file has been renamed. */ kqueue_generate_event (watch_object, Fcons (Qrename, Qnil), XCAR (XCDR (old_entry)), XCAR (XCDR (new_entry))); deleted_dl = Fcons (new_entry, deleted_dl); } new_dl = Fdelq (new_entry, new_dl); goto the_end; } /* Search, whether there is a file with the same name but another inode. */ for (dl1 = new_dl; ! NILP (dl1); dl1 = XCDR (dl1)) { new_entry = XCAR (dl1); if (strcmp (SSDATA (XCAR (XCDR (old_entry))), SSDATA (XCAR (XCDR (new_entry)))) == 0) { pending_dl = Fcons (new_entry, pending_dl); new_dl = Fdelq (new_entry, new_dl); goto the_end; } } /* Check, whether this a pending file. */ new_entry = assq_no_quit (XCAR (old_entry), pending_dl); if (NILP (new_entry)) { /* Check, whether this is an already deleted file (by rename). */ for (dl1 = deleted_dl; ! NILP (dl1); dl1 = XCDR (dl1)) { new_entry = XCAR (dl1); if (strcmp (SSDATA (XCAR (XCDR (old_entry))), SSDATA (XCAR (XCDR (new_entry)))) == 0) { deleted_dl = Fdelq (new_entry, deleted_dl); goto the_end; } } /* The file has been deleted. */ kqueue_generate_event (watch_object, Fcons (Qdelete, Qnil), XCAR (XCDR (old_entry)), Qnil); } else { /* The file has been renamed. */ kqueue_generate_event (watch_object, Fcons (Qrename, Qnil), XCAR (XCDR (old_entry)), XCAR (XCDR (new_entry))); pending_dl = Fdelq (new_entry, pending_dl); } the_end: dl = XCDR (dl); old_dl = Fdelq (old_entry, old_dl); } /* Parse through the resulting new list. */ dl = new_dl; while (1) { Lisp_Object entry; if (NILP (dl)) break; /* A new file has appeared. */ entry = XCAR (dl); kqueue_generate_event (watch_object, Fcons (Qcreate, Qnil), XCAR (XCDR (entry)), Qnil); /* Check size of that file. */ Lisp_Object size = Fnth (make_number (4), entry); if (FLOATP (size) || (XINT (size) > 0)) kqueue_generate_event (watch_object, Fcons (Qwrite, Qnil), XCAR (XCDR (entry)), Qnil); dl = XCDR (dl); new_dl = Fdelq (entry, new_dl); } /* Parse through the resulting pending_dl list. */ dl = pending_dl; while (1) { Lisp_Object entry; if (NILP (dl)) break; /* A file is still pending. Assume it was a write. */ entry = XCAR (dl); kqueue_generate_event (watch_object, Fcons (Qwrite, Qnil), XCAR (XCDR (entry)), Qnil); dl = XCDR (dl); pending_dl = Fdelq (entry, pending_dl); } /* At this point, old_dl, new_dl and pending_dl shall be empty. deleted_dl might not be empty when there was a rename to a nonexistent file. Let's make a check for this (might be removed once the code is stable). */ if (! NILP (old_dl)) report_file_error ("Old list not empty", old_dl); if (! NILP (new_dl)) report_file_error ("New list not empty", new_dl); if (! NILP (pending_dl)) report_file_error ("Pending events list not empty", pending_dl); // if (! NILP (deleted_dl)) // report_file_error ("Deleted events list not empty", deleted_dl); /* Replace old directory listing with the new one. */ XSETCDR (Fnthcdr (make_number (3), watch_object), Fcons (new_directory_files, Qnil)); return; }