diff options
author | Peter Breitenlohner <peb@mppmu.mpg.de> | 2014-06-18 12:10:20 +0000 |
---|---|---|
committer | Peter Breitenlohner <peb@mppmu.mpg.de> | 2014-06-18 12:10:20 +0000 |
commit | 3e2864914687b1af9d1ce374ee11b3a799e9561a (patch) | |
tree | 8e6911bfef46a6843e977fda8d837bf6425c7481 /Build/source/utils/xpdfopen/pdfopen.c | |
parent | 1c0abb83d537ef1e3b95ebd92c646a5d70793d93 (diff) |
xpdfopen 0.86
git-svn-id: svn://tug.org/texlive/trunk@34291 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/utils/xpdfopen/pdfopen.c')
-rw-r--r-- | Build/source/utils/xpdfopen/pdfopen.c | 540 |
1 files changed, 0 insertions, 540 deletions
diff --git a/Build/source/utils/xpdfopen/pdfopen.c b/Build/source/utils/xpdfopen/pdfopen.c deleted file mode 100644 index 2575e8d4bbf..00000000000 --- a/Build/source/utils/xpdfopen/pdfopen.c +++ /dev/null @@ -1,540 +0,0 @@ -/* - * pdfopen.c. - * - * Heavily modified by Jim Diamond (jim.diamond@acadiau.ca) 2010/04/11 - * to work with AR 9, xpdf and evince. - * (Also some mods by Peter Breitenlohner <tex-live@tug.org> from 2009 - * and suggestions from 2010, and some suggestions from Karl Berry - * (2011).) - * - * Note 1: the calling sequence was changed considerably to match what - * the program actually seemed to do as well as what made sense to me. - * - * Note 2: if there are two instances of acroread displaying that file, - * only one is reloaded. - * - * Further modified 2010/05/03 to work with ar5, and to include some code - * that does *not* work with okular (see note below). - * - * Modified 2014/05/16 (V 0.84) to add capability to open a pdf file - * at a specified page (currently working with AR9, xpdf and evince). - * - * Note 3: Unlike xpdf and AR[5,7,8,9], okular will not accept X events - * from this program unless the okular window has focus. On my system - * (Slackware64 13.0, using fvwm2), the functions I added to sendx.c to try - * to change the focus to the okular window do not work. (See also the - * comments in sendx.c.) If anyone cares to contribute working code, - * please send it to me for inclusion. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <sys/types.h> -#include <sys/wait.h> - -#include "sendx.h" -#include "xpdfopen.h" -#include "utils.h" - -#define DEFINE_EXTERNS -#include "externs.h" - -#define MAX_RELOAD_CMDS 10 -#define MAX_PRE_PAGE_OPTIONS 2 /* See struct defn below */ -#define MAX_POST_PAGE_OPTIONS 1 /* See struct defn below */ - /* Overkill ... */ -#define MAX_OPTIONS (10 + MAX_PRE_PAGE_OPTIONS \ - + MAX_POST_PAGE_OPTIONS) - -/* A string unlikely to be used as a real command by a PDF viewer */ -#define FORK_EXEC_CMD "*FORK EXEC*" - - -/* Used in the pdf_viewer_t type... see comment below */ -typedef enum -{ - USE_SENDX, USE_FORK_EXEC -} reload_method_t; - - -/* - * This struct contains the information needed for both - * (a) initially starting up a PDF viewer, and - * (b) telling the viewer to reload the document. - * Of course, the viewer has to support that functionality. - * Two possible ways are supported. - * (a) Send the viewer's window (a) simulated keypress(ss) - * (b) fork()/exec() a second instance of the program which somehow signals - * the running instance. Note that this is problematical if the - * arguments for the "reload" case are different than the options - * for the "start up the viewer" case, because the command-line - * (and environment variable) syntax have to be extended. - * Arguably, if both the start-up and reload can be done with shell - * commands, the user should just write a shell script and be done with - * it. - * These could be extended with this as well: - * (c) send a Unix signal to the currently running viewer. - * This would require augmenting reload_method_t and pdf_viewer_t. - */ - -typedef struct -{ - const char * short_name; /* cmd line option name */ - const char * program_name; /* program to exec() */ - reload_method_t method; /* method to induce reload */ - const char * window_name; /* when no file is viewed */ - const char * window_name_fmt; /* fmt string for file viewed */ - const char * exec_pre_options[MAX_OPTIONS]; /* before filename in cmd */ - const char * exec_post_options[MAX_OPTIONS];/* after filename in cmd */ - const char * reload_cmds[MAX_RELOAD_CMDS]; /* cmds to reload a file */ - /* - * If the page number goes before the filename, use these options. - * The last one must be a printf format string with a %d and - * no other conversions specs. - * End list with a NULL. - */ - const char * initial_page_pre_options[MAX_PRE_PAGE_OPTIONS + 1]; /* */ - /* - * If the page number goes after the filename, use these options. - * The last one must be a printf format string with a %d and - * no other conversions specs. - * End list with a NULL. - */ - const char * initial_page_post_options[MAX_POST_PAGE_OPTIONS + 1]; /* */ -} pdf_viewer_t; - - -/* Reload commands (or prefixes thereof) */ -#define CTRL "Ctrl-" -#define ALT "Alt-" -#define CTRL_ALT "Ctrl-Alt-" -#define FN "Fn-" -#define FOCUS_IN "FOCUS-IN" -#define FOCUS_OUT "FOCUS-OUT" - - - -/* - * The first struct represents the default viewer with the default options. - */ -static -pdf_viewer_t pdf_viewers[] = -{ - {"ar9", "acroread", USE_SENDX, - AR9_WIN_NAME, AR9_WIN_NAME_FMT, - {"-openInNewInstance", NULL}, - {NULL}, - {"Ctrl-R", NULL}, - {"/a", "page=%d", NULL}, - {NULL} - }, - {"ar9-tab", "acroread", USE_SENDX, - AR9_WIN_NAME, AR9_WIN_NAME_FMT, - {NULL}, - {NULL}, - {"Ctrl-R", NULL}, - {NULL}, - {NULL} - }, - {"ar8", "acroread", USE_SENDX, - AR8_WIN_NAME, AR8_WIN_NAME_FMT, - {NULL}, - {NULL}, - {"Ctrl-W", FORK_EXEC_CMD, NULL}, - {NULL}, - {NULL} - }, - {"ar7", "acroread", USE_SENDX, - AR7_WIN_NAME, AR7_WIN_NAME_FMT, - {NULL}, - {NULL}, - {"Ctrl-W", "Alt-Left", NULL}, - {NULL}, - {NULL} - }, - {"ar5", "acroread", USE_SENDX, - AR5_WIN_NAME, AR5_WIN_NAME_FMT, - {NULL}, - {NULL}, - {"Ctrl-W", "Alt-Left", NULL}, - {NULL}, - {NULL} - }, - /* - * xpdf also allows 'xpdf -remote tex -reload', but if that xpdf server - * is not running, rather than a failure return, a blank window is - * opened. This is not much good to us. - * Using "tex-server" as the server name is an arbitrary choice. - */ - {"xpdf", "xpdf", USE_SENDX, - XPDF_WIN_NAME, XPDF_WIN_NAME_FMT, - {"-remote", "tex-server", NULL}, - {NULL}, - {"r", NULL}, - {NULL}, - {"%d", NULL} - }, - {"evince", "evince", USE_SENDX, - EVINCE_WIN_NAME, EVINCE_WIN_NAME_FMT, - {NULL}, - {NULL}, - {"Ctrl-R", NULL}, - {"-i", "%d", NULL}, - {NULL} - }, -#ifdef TRY_OCULAR - {"okular", "okular", USE_SENDX, - OKULAR_WIN_NAME, OKULAR_WIN_NAME_FMT, - {NULL}, - {NULL}, - {FOCUS_IN, "Fn-F5", FOCUS_OUT, NULL}, - {NULL}, - {NULL} - }, -#endif -}; - -#define DEFAULT_VIEWER (pdf_viewers[0].short_name) - - - -static void -usage(void) -{ - int i; - int viewers = sizeof(pdf_viewers) / sizeof(pdf_viewers[0]); - - fprintf(stderr, "This is version %s of %s.\n", VERSION, progname); - fprintf(stderr, "Usage:\n %s [-h|--help]\n", progname); - fprintf(stderr, " Show this help and exit.\n"); - - fprintf(stderr, " %s [-v|--version]\n", progname); - fprintf(stderr, " Show the version number and exit.\n"); - - fprintf(stderr, " %s [-r|--reset_focus] [-viewer <prog>] [-p <n>] " - "<file.pdf>\n", progname); - fprintf(stderr, " If the PDF viewer <prog> is displaying <file.pdf>, " - "reload that file.\n"); - fprintf(stderr, " Otherwise call <prog> to display <file.pdf>.\n"); - fprintf(stderr, " If '-r' or '--reset_focus' is used, attempt to"); - fprintf(stderr, " reset the input focus\n"); - fprintf(stderr, " after calling the viewer program.\n"); - fprintf(stderr, " If the viewer allows it and is not already\n"); - fprintf(stderr, " running, the argument of -p specifies the\n"); - fprintf(stderr, " first page to display.\n"); - fprintf(stderr, " The default viewer program is %s.\n", DEFAULT_VIEWER); - fprintf(stderr, " Implemented viewers:"); - for (i = 0; i < viewers - 1; i++) - fprintf(stderr, " '%s'", pdf_viewers[i].short_name); - fprintf(stderr, " and '%s'.\n", pdf_viewers[viewers - 1].short_name); - fprintf(stderr, " Note: ar9 uses acroread's -openInNewInstance argument," - " ar9-tab does not.\n"); -} - - - -/* - * Send one "command" to the given window. - * The command can be of these forms (for X an upper case letter or arrow - * key, such as "Left", and D one or more digits; see sendx.c): - * - Ctrl-X - * - Alt-X - * - Ctrl-Atl-X - * - Fn-FD - * - FOCUS-[IN|OUT] - * - <string> (not starting with any of the above prefixes) - * Allow other variations on the cases of "Ctrl" and "Alt". - * - * Return 0 on success, non-0 otherwise. - */ - -static int -send_command(const char * window_name, const char * reload_cmd) -{ - int alt_len, ctrl_len, ctrl_alt_len, fn_len, focus_len; - - if (!strcmp(reload_cmd, FORK_EXEC_CMD)) - return 999; - - ctrl_alt_len = strlen(CTRL_ALT); - if (!strncasecmp(CTRL_ALT, reload_cmd, ctrl_alt_len)) - return sendx_controlalt_token(reload_cmd + ctrl_alt_len, window_name); - - ctrl_len = strlen(CTRL); - if (!strncasecmp(CTRL, reload_cmd, ctrl_len)) - return sendx_control_token(reload_cmd + ctrl_len, window_name); - - alt_len = strlen(ALT); - if (!strncasecmp(ALT, reload_cmd, alt_len)) - return sendx_alt_token(reload_cmd + alt_len, window_name); - - fn_len = strlen(FN); - if (!strncasecmp(FN, reload_cmd, fn_len)) - return sendx_token(reload_cmd + fn_len, window_name); - - focus_len = strlen(FOCUS_IN); - if (!strncasecmp(FOCUS_IN, reload_cmd, focus_len)) - return set_focus(window_name); - - focus_len = strlen(FOCUS_OUT); - if (!strncasecmp(FOCUS_OUT, reload_cmd, focus_len)) - return reset_focus(); - - return sendx_string(reload_cmd, window_name); -} - - - -/* - * Try to reload the file. - * If not successful, try to start up a new instance of the viewer program. - * Return 0 on success, non-0 otherwise. - * - * If reset_focus is true, (attempt to) reset the input focus to the - * window which had focus when this program was called. This is - * currently only implemented for the USE_SENDX case. - */ - -static int -view_file(const char * filename, int viewer_index, int focus_reset, - int initial_page) -{ - char * window_name; - pid_t pid; - int success = 0; - pdf_viewer_t pdf_viewer = pdf_viewers[viewer_index]; - const char ** reload_cmds = pdf_viewer.reload_cmds; - - /* First try to reload the file */ - switch (pdf_viewers[viewer_index].method) - { - case USE_SENDX: - window_name = make_window_name(pdf_viewer.window_name_fmt, filename); - if (window_name == NULL) - return 99; - if (focus_reset) - (void)set_focus(window_name); - while (*reload_cmds) - { - /* - * Note: there is a race condition in the sendx.c code which - * can cause the program to crash and burn with a 'BadWindow' - * fault. This has been observed for AR8 (but not AR7, oddly) - * after the ^W causes AR8 to change the window name. It seems - * that Window_With_Name() tries to access a BadWindow within - * its recursive call. - * If this continues to be a problem, a usleep() may make the - * problem go away. - */ - success = ! send_command(window_name, *reload_cmds); - if (! success && reload_cmds != pdf_viewer.reload_cmds) - { - /* - * In some cases the window name might be changed because - * of the first command. - * For example, in AR7 the first command (^W) "closes" - * the document, and the window title changes to reflect - * the fact there is no document. So try that command with - * the "plain" window name. - */ - success = ! send_command(pdf_viewer.window_name, *reload_cmds); - } - if (! success) - break; - reload_cmds++; - } - if (focus_reset) - (void)reset_focus(); - break; - - case USE_FORK_EXEC: - return 2; /* TODO: someone who cares can put some code here */ - break; - - default: - fprintf(stderr, "%s: internal error: invalid reload_method. Sorry.\n", - progname); - return 99; - break; - } - - if (success) - return 0; - - /* - * No luck re-loading the file. - * (Try to) start a new instance of the viewer program. - */ - if ((pid = fork()) == 0) - { - const char * argv_list[2 * MAX_OPTIONS + 3]; - const char ** p; - int i = 0; - - argv_list[i++] = pdf_viewer.program_name; - for (p = pdf_viewer.exec_pre_options; *p;) - argv_list[i++] = *p++; - - if (pdf_viewer.initial_page_pre_options[0] != NULL) - { - int j = 0; - char * buf; - - while (pdf_viewer.initial_page_pre_options[j + 1] != NULL) - argv_list[i++] = pdf_viewer.initial_page_pre_options[j++]; - - /* 10 is more than enough for the page number */ - buf = malloc(strlen(pdf_viewer.initial_page_pre_options[j]) + 10); - if (buf != NULL) - { - /* 1e8 or more pages? I doubt it. */ - sprintf(buf, pdf_viewer.initial_page_pre_options[j], - initial_page > 99999999 ? 1 : initial_page); - argv_list[i++] = buf; - } - else - fprintf(stderr, "%s: unable to allocate memory for page " - "specification!!\n" - "Crossing fingers and continuing.", progname); - } - - argv_list[i++] = filename; - - if (pdf_viewer.initial_page_post_options[0] != NULL) - { - int j = 0; - char * buf; - - while (pdf_viewer.initial_page_post_options[j + 1] != NULL) - argv_list[i++] = pdf_viewer.initial_page_post_options[j++]; - - buf = malloc(strlen(pdf_viewer.initial_page_post_options[j]) + 10); - if (buf != NULL) - { - sprintf(buf, pdf_viewer.initial_page_post_options[j], - initial_page > 99999999 ? 1 : initial_page); - argv_list[i++] = buf; - } - else - fprintf(stderr, "%s: unable to allocate memory for page " - "specification!!\n" - "Crossing fingers and continuing.", progname); - } - - argv_list[i++] = NULL; -#ifdef DEBUG - { - int k = 0; - for (; k < i-1; k++) - fprintf(stderr, "%s\n", argv_list[k]); - } -#endif - if (execvp(pdf_viewer.program_name, (char **)argv_list)) - { - fprintf(stderr, "%s: %s startup failed\n", progname, - pdf_viewer.program_name); - return 5; - } - } - else if (pid < 0) - { - fprintf(stderr, "%s: fork() failed!?\n", progname); - return 10; - } - - return 0; -} - - - -int -main(int argc, char * argv[]) -{ - const char * viewer = pdf_viewers[0].short_name; - char * env_viewer; - int i; - int initial_page = 1; - int viewer_index = -1; - int focus_reset = 0; - - progname = argv[0]; - argc--; - argv++; - - env_viewer = getenv("PDF_VIEWER"); - if (env_viewer != NULL) - viewer = env_viewer; - - if (argc < 1 || !strcmp(argv[0], "-h") || !strcmp(argv[0], "--help")) - { - usage(); - return argc < 2 ? EXIT_FAILURE : EXIT_SUCCESS; - } - - if (!strcmp(argv[0], "-v") || !strcmp(argv[0], "--version")) - { - printf("This is pdfopen version %s\n", VERSION); - return EXIT_SUCCESS; - } - - while (argc > 0) - { - if (!strcmp(argv[0], "--reset_focus") || !strcmp(argv[0], "-r")) - { - argc--; - argv++; - focus_reset = 1; - continue; - } - - if (argc >= 2 && !strcmp(argv[0], "-viewer")) - { - viewer = argv[1]; - argc -= 2; - argv += 2; - continue; - } - - if (argc >= 2 && !strcmp(argv[0], "-p")) - { - initial_page = atoi(argv[1]); - argc -= 2; - argv += 2; - continue; - } - - break; - } - - /* Should only have 1 filename left now */ - if (argc != 1) - { - fprintf(stderr, "%s: invalid argument(s)\n", progname); - usage(); - return EXIT_FAILURE; - } - - for (i = 0; i < sizeof(pdf_viewers) / sizeof(pdf_viewers[0]); i++) - { - if (!strcmp(pdf_viewers[i].short_name, viewer)) - { - viewer_index = i; - break; - } - } - - if (viewer_index < 0) - { - fprintf(stderr, "%s: Unknown PDF viewer '%s'\n", progname, viewer); - usage(); - - return EXIT_FAILURE; - } - - if (view_file(argv[0], viewer_index, focus_reset, initial_page)) - return EXIT_FAILURE; - - return EXIT_SUCCESS; -} |