summaryrefslogtreecommitdiff
path: root/Build/source/texk/xdvik/pagehist.c
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2006-01-17 21:41:51 +0000
committerKarl Berry <karl@freefriends.org>2006-01-17 21:41:51 +0000
commit487ca4806cc046076293cf6cc5fbba0db282bac7 (patch)
tree847b412ab5158dd7bdd7ed7e5a4cc3fbca94be32 /Build/source/texk/xdvik/pagehist.c
parenta3d3111bfe26b8e5f5bc6049dfb2a4ca2edc7881 (diff)
texk 1
git-svn-id: svn://tug.org/texlive/trunk@1485 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/texk/xdvik/pagehist.c')
-rw-r--r--Build/source/texk/xdvik/pagehist.c547
1 files changed, 547 insertions, 0 deletions
diff --git a/Build/source/texk/xdvik/pagehist.c b/Build/source/texk/xdvik/pagehist.c
new file mode 100644
index 00000000000..e3ba0e7e0de
--- /dev/null
+++ b/Build/source/texk/xdvik/pagehist.c
@@ -0,0 +1,547 @@
+/*
+ * Copyright (c) 2004 Stefan Ulrich
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+/*
+ Very simple page history (i.e. stack of visited pages) for xdvik
+*/
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+#include "util.h"
+#include "string-utils.h"
+#include "events.h"
+#include "dvi-init.h"
+#include "statusline.h"
+#include "message-window.h"
+#include "xm_toolbar.h"
+#include "pagehist.h"
+
+/****************************************************************************
+ *
+ * File-scope globals
+ *
+ ****************************************************************************/
+
+/* maximum number of items to print before truncating (10 left and right) */
+static const int HISTORY_MAX_CONTEXT = 21;
+
+/* list of pages in history */
+static struct dl_list *m_page_history = NULL;
+
+/* pointer to the head of the list, which only gets changed when
+ truncating the head (when list has reached its max size). */
+static struct dl_list *m_page_history_head = NULL;
+
+/* current size of the list */
+static int m_page_history_length = 0;
+
+/* current position in the list */
+static int m_page_history_currpos = 0;
+
+/* lookup table of filenames visited so far */
+static char **m_filename_list = NULL;
+static size_t m_filename_size = 0;
+
+/* item in above list */
+struct page_history {
+ int pageno;
+ int file_idx; /* index in file_list */
+};
+
+#define DEBUG 0
+
+/****************************************************************************
+ *
+ * Private functions
+ *
+ ****************************************************************************/
+
+static void
+page_history_show(struct dl_list *head, const struct dl_list *curr)
+{
+#if DEBUG
+ int n;
+ for (n = 0; head != NULL; head = head->next, n++) {
+ struct page_history *item = (struct page_history *)(head->item);
+ if (head == curr) {
+ fprintf(stderr, "item %d: <%d>\n", n, item->pageno);
+ }
+ else {
+ fprintf(stderr, "item %d: %d\n", n, item->pageno);
+ }
+ }
+#else
+ UNUSED(head);
+ UNUSED(curr);
+#endif /* DEBUG */
+}
+
+/* like above, but output goes to the statusline, and it prints only up to HISTORY_MAX_CONTEXT
+ items around the current one.
+*/
+static void
+page_history_show_statusline(struct dl_list *head,
+ const struct dl_list *curr,
+ const char *msg)
+{
+#define HIST_LEN 1024 /* should be ample since statusline is limited to 512 MAX_LEN */
+
+ int file_idx = 0;
+
+ int n;
+ char history[HIST_LEN];
+ char *ptr = history;
+ int tot_len = m_page_history_length;
+ int curr_pos = m_page_history_currpos;
+ int initial_offset = 0;
+ int printed_len = 0;
+
+#if DEBUG
+ fprintf(stderr, "tot_len: %d, curr_pos: %d\n", tot_len, curr_pos);
+#endif
+
+ if (head == NULL){
+ strcpy(ptr, "Page history empty.");
+ ptr += strlen("Page history empty.");
+ }
+ else {
+ strcpy(ptr, "Page history:");
+ ptr += strlen("Page history:");
+ }
+
+ /* check if we need to truncate at the beginning or end */
+ if (tot_len > HISTORY_MAX_CONTEXT) {
+ /* need to truncate, try to make first and second chunk around current position of same length */
+ int good_pos = HISTORY_MAX_CONTEXT / 2.0 + 0.5;
+ while (curr_pos > good_pos /* && */
+/* m_page_history_length - m_page_history_currpos > good_pos */) {
+#if DEBUG
+ fprintf(stderr, "%d > %d; %d > %d\n", curr_pos, good_pos,
+ m_page_history_length - m_page_history_currpos, good_pos);
+#endif
+ curr_pos--;
+ initial_offset++;
+ }
+#if DEBUG
+ fprintf(stderr, "initial offset: %d\n", initial_offset);
+#endif
+ /* if we're more to the end, adjust good_pos and initial_offset */
+ while (good_pos - 1 > m_page_history_length - m_page_history_currpos) {
+#if DEBUG
+ fprintf(stderr, "%d > %d\n", m_page_history_length - m_page_history_currpos, good_pos);
+#endif
+ initial_offset--;
+ good_pos--;
+ }
+#if DEBUG
+ fprintf(stderr, "initial offset adjusted: %d\n", initial_offset);
+#endif
+ }
+
+ for (n = 0; head != NULL; head = head->next, n++) {
+ struct page_history *item;
+ /* skip initial offset, and insert truncation marker at beginning/end */
+ if (initial_offset == 1 || printed_len >= HISTORY_MAX_CONTEXT) {
+ strcpy(ptr, " ...");
+ ptr += strlen(" ...");
+ if (printed_len >= HISTORY_MAX_CONTEXT)
+ break;
+ }
+ if (initial_offset > 0) {
+ initial_offset--;
+ continue;
+ }
+
+ printed_len++;
+
+ item = (struct page_history *)(head->item);
+
+ /* insert a marker if item is in different file ... */
+ if (item->file_idx != file_idx) {
+ if (n > 0) { /* ... but only if we're not at the beginning of the list */
+#if 1
+ strcpy(ptr, " -");
+ ptr += 2;
+#else
+ char *fname = m_filename_list[item->file_idx];
+ char *tmp;
+ if ((tmp = strrchr(m_filename_list[item->file_idx], '/')) != NULL)
+ fname = tmp + 1;
+ strcpy(ptr, " [");
+ ptr += 2;
+ strcpy(ptr, fname);
+ ptr += strlen(fname);
+ strcpy(ptr, "]");
+ ptr++;
+#endif
+ }
+ file_idx = item->file_idx;
+ }
+
+ if (head == curr) {
+ ASSERT(m_page_history_currpos == n + 1, "Consistency check for pagelist position failed!");
+ sprintf(ptr, " [%d]", item->pageno + 1);
+ ptr += 3 + length_of_int(item->pageno + 1);
+ }
+ else {
+ sprintf(ptr, " %d", item->pageno + 1);
+ ptr += 1 + length_of_int(item->pageno + 1);
+ }
+ }
+#if DEBUG
+ fprintf(stderr, "Statusline string: |%s|; printed len: %d\n", history, printed_len);
+#endif
+ statusline_print(STATUS_LONG, "%s %s", history, msg ? msg : "");
+#undef HIST_LEN
+}
+
+static void
+goto_location(const char *filename, int pageno)
+{
+#if DEBUG
+ fprintf(stderr, "going to page %d of file %s\n", pageno, filename);
+#endif
+ if (strcmp(globals.dvi_name, filename) != 0) { /* it's a different file */
+ Boolean tried_dvi_ext = True;
+ char *new_dvi_name;
+#if DEBUG
+ fprintf(stderr, "different file: |%s|\n", filename);
+#endif
+ if ((new_dvi_name = open_dvi_file_wrapper(filename, True, False,
+ &tried_dvi_ext, True)) == NULL) {
+ statusline_append(STATUS_MEDIUM,
+ "Re-opening file",
+ "Re-opening file \"%s\" failed!", filename);
+#if DEBUG
+ fprintf(stderr, "Re-opening file \"%s\" failed!\n", filename);
+#endif
+ page_history_delete(1);
+ return;
+ }
+ else {
+ dviErrFlagT errflag;
+ if (load_dvi_file(True, &errflag)) {
+ set_dvi_name(new_dvi_name);
+
+ globals.ev.flags |= EV_NEWDOC;
+#if DEBUG
+ fprintf(stderr, "Back to file: \"%s\"\n", globals.dvi_name);
+#endif
+ }
+ else { /* re-open old file */
+ popup_message(globals.widgets.top_level,
+ MSG_ERR,
+ NULL,
+ "Could not open `%s': %s.\n"
+ /* "Removing this file from the history." */,
+ globals.dvi_name, get_dvi_error(errflag));
+
+ if (!internal_open_dvi(globals.dvi_name, &errflag, True)) {
+ popup_message(globals.widgets.top_level,
+ MSG_ERR,
+ NULL,
+ "Couldn't reopen `%s': %s.\n"
+ /* "Removing this file from the history." */,
+ globals.dvi_name, get_dvi_error(errflag));
+ }
+ else {
+ globals.ev.flags |= EV_NEWPAGE;
+ }
+ page_history_delete(1);
+ }
+ }
+ }
+ if (pageno != current_page) {
+ if (pageno < total_pages) {
+ goto_page(pageno, resource.keep_flag ? NULL : home, False);
+ }
+ else {
+ XDVI_WARNING((stderr, "Could not go to page %d (file has shrunken)", pageno));
+ statusline_print(STATUS_MEDIUM,
+ "Could not go to page %d (file has shrunken)", pageno);
+ }
+ }
+}
+
+/****************************************************************************
+ *
+ * Exported functions
+ *
+ ****************************************************************************/
+
+/*
+ Move n elements in page history; n == 0 doesn't move,
+ n < 0 moves n items back, n > 0 moves n items forward.
+*/
+void page_history_move(int n)
+{
+ struct dl_list *pos;
+ struct page_history *item;
+ const char *msg = NULL;
+
+ page_history_show(m_page_history_head, m_page_history);
+
+ if (resource.page_history_size == 0)
+ return;
+
+ if (m_page_history_head == NULL)
+ m_page_history_head = m_page_history;
+
+ if (n < 0) { /* move backwards */
+ for (pos = NULL; n < 0; n++) {
+ if (m_page_history != NULL)
+ pos = m_page_history->prev;
+ if (pos == NULL) {
+ XBell(DISP, 0);
+ msg = " - at begin of page history.";
+ break;
+ }
+ else {
+ m_page_history = pos;
+ m_page_history_currpos--;
+ }
+ }
+ }
+ else { /* move forward */
+ for (pos = NULL; n > 0; n--) {
+ if (m_page_history != NULL)
+ pos = m_page_history->next;
+ if (pos == NULL) {
+ XBell(DISP, 0);
+ msg = " - at end of page history.";
+ break;
+ }
+ else {
+ m_page_history = pos;
+ m_page_history_currpos++;
+ }
+ }
+ }
+ item = (struct page_history *)m_page_history->item;
+#if DEBUG
+ fprintf(stderr, "going to page %d\n", item->pageno);
+#endif
+ goto_location(m_filename_list[item->file_idx], item->pageno);
+
+#if defined(MOTIF) && HAVE_XPM
+ tb_set_pagehist_back_sensitivity(m_page_history->prev != NULL);
+ tb_set_pagehist_forward_sensitivity(m_page_history->next != NULL);
+#endif
+
+ page_history_show(m_page_history_head, m_page_history);
+ page_history_show_statusline(m_page_history_head, m_page_history, msg);
+ page_history_update_toolbar_navigation();
+}
+
+/* add page n to the page history */
+void page_history_insert(int n)
+{
+ struct page_history *item = NULL;
+ static char *current_filename = NULL;
+ static size_t filename_idx = 0; /* index of current filename */
+
+#if DEBUG
+ fprintf(stderr, "inserting into history: %d\n", n);
+#endif
+ page_history_show(m_page_history_head, m_page_history);
+ /* do nothing if no history is used */
+ if (resource.page_history_size == 0)
+ return;
+
+ if (m_page_history_head == NULL)
+ m_page_history_head = m_page_history;
+
+ item = xmalloc(sizeof *item);
+ /* first call, or filename changed -> update file_list */
+ if (current_filename == NULL || strcmp(current_filename, globals.dvi_name) != 0) {
+ size_t i;
+ current_filename = xstrdup(globals.dvi_name);
+
+ for (i = 0; i < m_filename_size; i++) {
+#if DEBUG
+ fprintf(stderr, "comparing %d: |%s|%s|\n", i, current_filename, m_filename_list[i]);
+#endif
+ if (strcmp(current_filename, m_filename_list[i]) == 0) { /* found */
+ filename_idx = i;
+ break;
+ }
+ }
+
+ if (i >= m_filename_size) { /* not found, insert into file list */
+ m_filename_list = xrealloc(m_filename_list, (m_filename_size + 1) * sizeof *m_filename_list);
+ m_filename_list[m_filename_size] = filename_append_dvi(current_filename);
+ filename_idx = m_filename_size++;
+#if DEBUG
+ fprintf(stderr, "NEW file %d: %s\n", filename_idx, current_filename);
+#endif
+ }
+ }
+
+#if DEBUG
+ fprintf(stderr, "-------- %d >= %d?\n", m_page_history_length, resource.page_history_size - 1);
+#endif
+ if (m_page_history_length >= resource.page_history_size - 1) { /* truncate history */
+ free(m_page_history_head->item);
+ m_page_history_head = dl_list_truncate_head(m_page_history_head);
+ }
+ else {
+ m_page_history_length++;
+ }
+
+ item->pageno = n;
+ item->file_idx = filename_idx;
+
+#if DEBUG
+ fprintf(stderr, "inserting %d\n", item->pageno);
+#endif
+ m_page_history = dl_list_insert(m_page_history, item);
+ m_page_history_currpos++;
+
+#if DEBUG
+ fprintf(stderr, "head: %p, curr: %p\n", (void *)m_page_history_head, (void *)m_page_history);
+#endif
+ page_history_show(m_page_history_head, m_page_history);
+ page_history_update_toolbar_navigation();
+}
+
+void
+page_history_update_toolbar_navigation(void)
+{
+#if defined(MOTIF) && HAVE_XPM
+ tb_set_htex_back_sensitivity(m_page_history->prev != NULL);
+ tb_set_htex_forward_sensitivity(m_page_history->next != NULL);
+#endif
+}
+
+void
+page_history_clear()
+{
+ struct dl_list *pos, *curr;
+
+ if (resource.page_history_size == 0)
+ return;
+
+ m_page_history_head = m_page_history;
+
+ for (curr = m_page_history; curr != NULL && curr->prev != NULL; curr = pos) {
+ pos = curr->prev;
+ free(curr->item);
+ (void)dl_list_remove_item(&curr);
+ m_page_history_length--;
+ page_history_show(m_page_history_head, m_page_history);
+ page_history_show_statusline(m_page_history_head, m_page_history, NULL);
+ }
+
+/* for (curr = m_page_history; curr != NULL && curr->next != NULL; curr = pos) { */
+/* pos = curr->next; */
+/* free(curr->item); */
+/* (void)dl_list_remove_item(&curr); */
+/* m_page_history_length--; */
+/* page_history_show(m_page_history_head, m_page_history); */
+/* } */
+
+
+}
+
+/*
+ Delete n elements from the page history.
+ If n < 0, delete current and n-1 previous items and move to the item before them.
+ If n > 0, delete current and n-1 next items and move to the item after them.
+ E.g. (with current position marked by `<>'):
+
+ a b <c> d e
+ -> page_history_delete(-2)
+ -> <a> d e
+
+ a b <c> d e
+ -> page_history_delete(2)
+ -> a b <e>
+
+ Prints an error to the statusline if number of deletions exceeds the limits
+ of the list.
+*/
+void page_history_delete(int n)
+{
+ struct dl_list *pos;
+ struct page_history *item;
+ const char *msg = NULL;
+
+ if (resource.page_history_size == 0)
+ return;
+
+ if (m_page_history_head == NULL)
+ m_page_history_head = m_page_history;
+
+ /* fprintf(stderr, "deleting items: |%d|\n", n); */
+
+ if (n < 0) { /* delete backwards */
+ for (pos = NULL; n < 0; n++) {
+ if (m_page_history != NULL)
+ pos = m_page_history->prev;
+ if (pos == NULL) {
+ XBell(DISP, 0);
+ msg = " - at begin of page history.";
+ break;
+ }
+ else {
+ /* remove item */
+ free(m_page_history->item);
+ (void)dl_list_remove_item(&m_page_history);
+ m_page_history = pos;
+ m_page_history_currpos--;
+ m_page_history_length--;
+ }
+ }
+ }
+ else { /* delete forward */
+ for (pos = NULL; n > 0; n--) {
+ if (m_page_history != NULL)
+ pos = m_page_history->next;
+ if (pos == NULL) {
+ XBell(DISP, 0);
+ msg = " - at end of page history.";
+ break;
+ }
+ else {
+ /* remove item */
+ free(m_page_history->item);
+ if (m_page_history->prev == NULL) { /* at head */
+ m_page_history_head = m_page_history = dl_list_truncate_head(m_page_history);
+ }
+ else {
+ (void)dl_list_remove_item(&m_page_history);
+ m_page_history = pos;
+ }
+ /* Note: m_page_history_currpos remains unchanged here */
+ m_page_history_length--;
+ }
+ }
+ }
+ item = (struct page_history *)m_page_history->item;
+#if DEBUG
+ fprintf(stderr, "going to page %d\n", item->pageno);
+#endif
+ goto_location(m_filename_list[item->file_idx], item->pageno);
+ page_history_show(m_page_history_head, m_page_history);
+ page_history_show_statusline(m_page_history_head, m_page_history, msg);
+}
+