void MainWindow::setup_shortcuts(){ static struct Pair{ const char *command; const char *slot; } pairs[] = { #define SETUP_SHORTCUT(command, slot) { command, SLOT(slot)}, SETUP_SHORTCUT(quit_command, quit_slot()) SETUP_SHORTCUT(quit2_command, quit2_slot()) SETUP_SHORTCUT(next_command, next_slot()) SETUP_SHORTCUT(back_command, back_slot()) SETUP_SHORTCUT(background_swap_command, background_swap_slot()) SETUP_SHORTCUT(close_command, close_slot()) SETUP_SHORTCUT(zoom_in_command, zoom_in_slot()) SETUP_SHORTCUT(zoom_out_command, zoom_out_slot()) SETUP_SHORTCUT(reset_zoom_command, reset_zoom_slot()) SETUP_SHORTCUT(up_command, up_slot()) SETUP_SHORTCUT(down_command, down_slot()) SETUP_SHORTCUT(left_command, left_slot()) SETUP_SHORTCUT(right_command, right_slot()) SETUP_SHORTCUT(up_big_command, up_big_slot()) SETUP_SHORTCUT(down_big_command, down_big_slot()) SETUP_SHORTCUT(left_big_command, left_big_slot()) SETUP_SHORTCUT(right_big_command, right_big_slot()) SETUP_SHORTCUT(cycle_zoom_mode_command, cycle_zoom_mode_slot()) SETUP_SHORTCUT(toggle_lock_zoom_command, toggle_lock_zoom_slot()) SETUP_SHORTCUT(go_to_start_command, go_to_start()) SETUP_SHORTCUT(go_to_end_command, go_to_end()) SETUP_SHORTCUT(toggle_fullscreen_command, toggle_fullscreen()) SETUP_SHORTCUT(rotate_left_command, rotate_left()) SETUP_SHORTCUT(rotate_right_command, rotate_right()) SETUP_SHORTCUT(rotate_left_fine_command, rotate_left_fine()) SETUP_SHORTCUT(rotate_right_fine_command, rotate_right_fine()) SETUP_SHORTCUT(flip_h_command, flip_h()) SETUP_SHORTCUT(flip_v_command, flip_v()) SETUP_SHORTCUT(minimize_command, minimize_slot()) SETUP_SHORTCUT(minimize_all_command, minimize_all_slot()) SETUP_SHORTCUT(show_options_command, show_options_dialog()) }; for (auto &c : this->connections) this->disconnect(c); this->connections.clear(); this->shortcuts.clear(); auto &shortcuts = this->app->get_shortcuts(); for (auto &p : pairs){ auto setting = shortcuts.get_shortcut_setting(p.command); if (!setting) continue; for (auto &seq : setting->sequences) this->setup_shortcut(seq, p.slot); } }
int cache_ls(const char *path) { DIR *dir; struct dirent *ent; int err = 0; struct cache_slot slot = { NULL }; struct strbuf fullname = STRBUF_INIT; size_t prefixlen; if (!path) { cache_log("[cgit] cache path not specified\n"); return -1; } dir = opendir(path); if (!dir) { err = errno; cache_log("[cgit] unable to open path %s: %s (%d)\n", path, strerror(err), err); return err; } strbuf_addstr(&fullname, path); strbuf_ensure_end(&fullname, '/'); prefixlen = fullname.len; while ((ent = readdir(dir)) != NULL) { if (strlen(ent->d_name) != 8) continue; strbuf_setlen(&fullname, prefixlen); strbuf_addstr(&fullname, ent->d_name); slot.cache_name = fullname.buf; if ((err = open_slot(&slot)) != 0) { cache_log("[cgit] unable to open path %s: %s (%d)\n", fullname.buf, strerror(err), err); continue; } htmlf("%s %s %10"PRIuMAX" %s\n", fullname.buf, sprintftime("%Y-%m-%d %H:%M:%S", slot.cache_st.st_mtime), (uintmax_t)slot.cache_st.st_size, slot.buf); close_slot(&slot); } closedir(dir); strbuf_release(&fullname); return 0; }
static int process_slot(struct cache_slot *slot) { int err; err = open_slot(slot); if (!err && slot->match) { if (is_expired(slot)) { if (!lock_slot(slot)) { /* If the cachefile has been replaced between * `open_slot` and `lock_slot`, we'll just * serve the stale content from the original * cachefile. This way we avoid pruning the * newly generated slot. The same code-path * is chosen if fill_slot() fails for some * reason. * * TODO? check if the new slot contains the * same key as the old one, since we would * prefer to serve the newest content. * This will require us to open yet another * file-descriptor and read and compare the * key from the new file, so for now we're * lazy and just ignore the new file. */ if (is_modified(slot) || fill_slot(slot)) { unlock_slot(slot, 0); close_lock(slot); } else { close_slot(slot); unlock_slot(slot, 1); slot->cache_fd = slot->lock_fd; } } } if ((err = print_slot(slot)) != 0) { cache_log("[cgit] error printing cache %s: %s (%d)\n", slot->cache_name, strerror(err), err); } close_slot(slot); return err; } /* If the cache slot does not exist (or its key doesn't match the * current key), lets try to create a new cache slot for this * request. If this fails (for whatever reason), lets just generate * the content without caching it and fool the caller to belive * everything worked out (but print a warning on stdout). */ close_slot(slot); if ((err = lock_slot(slot)) != 0) { cache_log("[cgit] Unable to lock slot %s: %s (%d)\n", slot->lock_name, strerror(err), err); slot->fn(); return 0; } if ((err = fill_slot(slot)) != 0) { cache_log("[cgit] Unable to fill slot %s: %s (%d)\n", slot->lock_name, strerror(err), err); unlock_slot(slot, 0); close_lock(slot); slot->fn(); return 0; } // We've got a valid cache slot in the lock file, which // is about to replace the old cache slot. But if we // release the lockfile and then try to open the new cache // slot, we might get a race condition with a concurrent // writer for the same cache slot (with a different key). // Lets avoid such a race by just printing the content of // the lock file. slot->cache_fd = slot->lock_fd; unlock_slot(slot, 1); if ((err = print_slot(slot)) != 0) { cache_log("[cgit] error printing cache %s: %s (%d)\n", slot->cache_name, strerror(err), err); } close_slot(slot); return err; }