From b0bca8917e1d6d712120deaf686a1c09979aff31 Mon Sep 17 00:00:00 2001 From: malc Date: Mon, 19 Aug 2024 11:50:25 +0300 Subject: [PATCH 1/6] 19.08.2024 --- BUILDING | 8 ++----- build.bash | 15 ++++++++---- config.ml | 14 +++++++---- genconfstruct.sh | 13 +++++----- glutils.ml | 2 +- help.ml | 2 +- link.c | 62 ++++++++++++++++++++++++------------------------ main.ml | 2 +- misc/getmupdf.sh | 2 +- misc/llppac | 8 ++++--- todo.org | 12 ++++++++++ utils.ml | 6 ++--- 12 files changed, 84 insertions(+), 62 deletions(-) diff --git a/BUILDING b/BUILDING index 8ba4928e..3a8c2e92 100644 --- a/BUILDING +++ b/BUILDING @@ -3,7 +3,7 @@ Prerequisites for building from sources: mupdf [https://mupdf.com] opengl [https://en.wikipedia.org/wiki/OpenGL] git [https://git-scm.com] - ocaml 4.14.0 [https://ocaml.org] + ocaml 5.2.0 [https://ocaml.org] If not present will be downloaded from the network and built/used locally without system-wide installation. This requires either: @@ -19,9 +19,5 @@ To download mupdf+prerequisites that llpp is known to work with: To build llpp (binary will be in build/llpp): - bash build.bash build - # by default llpp looks for .config/llpp.conf file - # hence .config directory should be present otherwise - # llpp will fail to start - -To build man pages (will be in build/doc/[name].1) +To build man pages - bash build.bash build doc diff --git a/build.bash b/build.bash index 704394f6..41c2397a 100755 --- a/build.bash +++ b/build.bash @@ -39,7 +39,8 @@ test -d $mudir || die muPDF wasn\'t found in $outd/, consult $srcd/BUILDING mkdir -p $outd/{$wsid,lablGL} -isfresh() { test "$(<$1.past)" = "$2"; } 2>/dev/null +# thanks to Sebastian Rasmussen +isfresh() { test "$(cat $1.past)" = "$2"; } 2>/dev/null mbt=${mbt:-release} test -n "${gmk:-}" && gmk=false || gmk=true @@ -71,10 +72,15 @@ oincs() { } oflags() { + local f="" case "${1#$outd/}" in lablGL/*) f="-g";; - utf8syms.cmo|confstruct.cmo|config.cmo|ffi.cmo|wsi/cocoa/wsi.cmo) + utf8syms.cmo|confstruct.cmo) f="-g -strict-sequence -strict-formats -alert @all-missing-mli";; + wsi/x11/wsi.cm[io]) f="-g -I +unix";; + utils.cmi) f="-g -I +unix -I +str";; + config.cmo|ffi.cmo|main.cmo|utils.cmo|parser.cmo|uiutils.cmo|help.cmo) + f="-g -I +unix -I +str -strict-sequence -strict-formats -alert @all-missing-mli";; *) f="-g -strict-sequence -strict-formats -alert @all -warn-error @A";; esac echo $(oincs $outd $1) $f @@ -104,8 +110,8 @@ mflags() { } overs=$(ocamlc -vnum 2>/dev/null) || overs="" -if test "$overs" != "4.14.0~rc1"; then - url=https://caml.inria.fr/pub/distrib/ocaml-4.14/ocaml-4.14.0~rc1.tar.xz +if test "$overs" != "5.2.0"; then + url="https://caml.inria.fr/pub/distrib/ocaml-5.2/ocaml-5.2.0.tar.xz" txz=$outd/$(basename $url) keycmd="printf $url; digest $txz;" isfresh $txz "$(eval $keycmd)" || { @@ -321,6 +327,7 @@ else fi cmd="ocamlc -custom $libs -o $outd/llpp $cobjs $modules -cclib \"$clibs\"" +cmd="$cmd -I +unix -I +str" keycmd="digest $outd/llpp $cobjs $modules $mulibs" isfresh "$outd/llpp" "$cmd$(eval $keycmd)" || { echo linking $outd/llpp diff --git a/config.ml b/config.ml index 6c28f9a2..fbfd58f9 100644 --- a/config.ml +++ b/config.ml @@ -14,11 +14,14 @@ let multicolumns_of_string s = try (int_of_string s, 0, 0) with _ -> - Scanf.sscanf s "%u,%u,%u" (fun n a b -> - if a > 1 || b > 1 - then error "subtly broken"; - (n, a, b) - ) + try + Scanf.sscanf s "%u,%u,%u" (fun n a b -> + if a > 1 || b > 1 + then error "subtly broken"; + (n, a, b) + ) + with End_of_file -> + (1, 0, 0) include Confstruct @@ -365,6 +368,7 @@ module S = struct let tilelru : (tilemapkey * opaque * pixmapsize) Queue.t = Queue.create () let fontpath = ref E.s let redirstderr = ref false + let loading = ref true end let conf = { defconf with keyhashes = copykeyhashes defconf } diff --git a/genconfstruct.sh b/genconfstruct.sh index 683caeb2..73bbf259 100644 --- a/genconfstruct.sh +++ b/genconfstruct.sh @@ -2,6 +2,7 @@ set -eu cat<&2|}' -s passcmd Utils.E.s -s savecmd Utils.E.s +s passcmd zs +s savecmd zs b updatecurs true K keyhashes '(string * keyhash) list' \ '(let mk n = (n, Hashtbl.create 1) in @@ -119,15 +120,15 @@ s stcmd "{|echo SyncTex|}" b riani false g paxmark mark MarkWord b leftscroll false -s title Utils.E.s +s title zs f lastvisit 0.0 b annotinline true b coarseprespos false -g css css Utils.E.s +g css css zs b usedoccss true -s key Utils.E.s +s key zs P pax -g dcf dcf Utils.E.s +g dcf dcf zs s hcs "{|aoeuidhtns|}" i rlw 420 i rlh 595 diff --git a/glutils.ml b/glutils.ml index a49f879f..9558a7f0 100644 --- a/glutils.ml +++ b/glutils.ml @@ -27,7 +27,7 @@ let drawstring size x y s = Gl.disable `blend; Gl.disable `texture_2d -let drawstringf size x y = Printf.kprintf (drawstring size (x+1) (y+size+1)) +let drawstringf size x y = Printf.ksprintf (drawstring size (x+1) (y+size+1)) let redisplay = ref false let postRedisplay who = Utils.vlog "redisplay for [%S]" who; diff --git a/help.ml b/help.ml index b21ae275..038aba66 100644 --- a/help.ml +++ b/help.ml @@ -1,6 +1,6 @@ let keys = {|-----Quitting----- -escape/q - quit +q - quit Q - quit without saving the configuration or changes W - save changes diff --git a/link.c b/link.c index a4ef9dfb..7badd5cd 100644 --- a/link.c +++ b/link.c @@ -26,13 +26,14 @@ #pragma GCC diagnostic ignored "-Wdocumentation" #pragma GCC diagnostic ignored "-Wdouble-promotion" #pragma GCC diagnostic ignored "-Wimplicit-int-float-conversion" +#pragma GCC diagnostic ignored "-Wdeclaration-after-statement" +#pragma GCC diagnostic ignored "-Wunsafe-buffer-usage" #else #pragma GCC diagnostic error "-Wcast-qual" #endif #include GL_H -#define CAML_NAME_SPACE #include #include #include @@ -40,6 +41,7 @@ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wfloat-equal" +#pragma GCC diagnostic ignored "-Wundef" #include #include #pragma GCC diagnostic pop @@ -357,7 +359,7 @@ static int openxref (char *filename, char *mimetype, char *password, static void docinfo (void) { - struct { char *tag; char *name; } tab[] = { + const struct { const char *tag; const char *name; } tab[] = { { FZ_META_INFO_TITLE, "Title" }, { FZ_META_INFO_AUTHOR, "Author" }, { FZ_META_FORMAT, "Format" }, @@ -366,6 +368,8 @@ static void docinfo (void) { FZ_META_INFO_PRODUCER, "Producer" }, { FZ_META_INFO_CREATIONDATE, "Creation date" }, { FZ_META_INFO_MODIFICATIONDATE, "Modification date"}, + { FZ_META_INFO_SUBJECT, "Subject" }, + { FZ_META_INFO_KEYWORDS, "Keywords" }, }; int len = 0, need; char *buf = NULL; @@ -593,7 +597,12 @@ static void initpdims1 (void) pdf_obj *obj = pdf_dict_getp (ctx, pdf_trailer (ctx, pdf), "Root/Pages/MediaBox"); rootmediabox = pdf_to_rect (ctx, obj); - pdf_load_page_tree (ctx, pdf); + fz_try (ctx) { + pdf_load_page_tree (ctx, pdf); + } + fz_catch (ctx) { + printd ("emsg pdf_load_page_tree: %s", fz_caught_message (ctx)); + } } for (pageno = 0; pageno < cxcount; ++pageno) { @@ -605,19 +614,7 @@ static void initpdims1 (void) pdf_obj *pageobj = NULL; fz_var (pageobj); - if (pdf->rev_page_map) { - for (int i = 0; i < pdf->rev_page_count; ++i) { - if (pdf->rev_page_map[i].page == pageno) { - pageobj = pdf_get_xref_entry ( - ctx, pdf, pdf->rev_page_map[i].object - )->obj; - break; - } - } - } - if (!pageobj) { - pageobj = pdf_lookup_page_obj (ctx, pdf, pageno); - } + pageobj = pdf_lookup_page_obj (ctx, pdf, pageno); rotate = pdf_to_int (ctx, pdf_dict_gets (ctx, pageobj, "Rotate")); @@ -952,20 +949,17 @@ static struct pagedim *pdimofpageno (int pageno) static void recurse_outline (fz_outline *outline, int level) { + /* Significantly simplified by Sebastian Rasmussen */ while (outline) { - int pageno; - fz_point p; fz_location loc; + int pageno; + fz_point p = { .x = outline->x, .y = outline->y }; - loc = fz_resolve_link (state.ctx, state.doc, String_val (outline->uri), + loc = fz_resolve_link (state.ctx, state.doc, outline->uri, &p.x, &p.y); pageno = fz_page_number_from_location (state.ctx, state.doc, loc); if (pageno >= 0) { - struct pagedim *pdim = - pdimofpageno ( - fz_page_number_from_location (state.ctx, state.doc, - outline->page) - ); + struct pagedim *pdim = pdimofpageno (pageno); int h = fz_maxi (fz_absi (pdim->bounds.y1 - pdim->bounds.y0), 0); p = fz_transform_point (p, pdim->ctm); printd ("o %d %d %d %d %s", @@ -1497,10 +1491,8 @@ static void *mainloop (void UNUSED_ATTR *unused) break; } case Creqlayout: { - char *nameddest; int rotate, off, h; int fitmodel; - pdf_document *pdf; printd ("clear"); ret = sscanf (p, "%d %d %d %n", &rotate, &fitmodel, &h, &off); @@ -1508,7 +1500,6 @@ static void *mainloop (void UNUSED_ATTR *unused) errx (1, "bad reqlayout line `%.*s' ret=%d", len, p, ret); } lock ("reqlayout"); - pdf = pdf_specifics (state.ctx, state.doc); if (state.rotate != rotate || state.fitmodel != fitmodel) { state.gen += 1; } @@ -1518,8 +1509,12 @@ static void *mainloop (void UNUSED_ATTR *unused) layout (); process_outline (); - nameddest = p + off; - if (pdf && nameddest && *nameddest) { +#ifdef TODO_LINK_URI + char *nameddest = p + off; + if (nameddest && *nameddest) { + fz_link_dest ld; + const char *uri = "#%s" % nameddest; + sd = fz_resolve_link_dest (state.ctx, doc, uri); fz_point xy; struct pagedim *pdim; int pageno = pdf_lookup_anchor (state.ctx, pdf, nameddest, @@ -1528,6 +1523,7 @@ static void *mainloop (void UNUSED_ATTR *unused) xy = fz_transform_point (xy, pdim->ctm); printd ("a %d %d %d", pageno, (int) xy.x, (int) xy.y); } +#endif state.gen++; unlock ("reqlayout"); @@ -2558,7 +2554,9 @@ ML (getfileannot (value ptr_v, value n_v)) pdf_obj *fs = pdf_dict_get (state.ctx, pdf_annot_obj (state.ctx, slink->u.annot), PDF_NAME (FS)); - ret_v = caml_copy_string (pdf_embedded_file_name (state.ctx, fs)); + pdf_embedded_file_params params; + pdf_get_embedded_file_params (state.ctx, fs, ¶ms); + ret_v = caml_copy_string (params.filename); unlock (__func__); CAMLreturn (ret_v); @@ -2572,11 +2570,12 @@ ML0 (savefileannot (value ptr_v, value n_v, value path_v)) lock (__func__); struct slink *slink = &page->slinks[Int_val (n_v)]; + fz_try (state.ctx) { pdf_obj *fs = pdf_dict_get (state.ctx, pdf_annot_obj (state.ctx, slink->u.annot), PDF_NAME (FS)); - fz_buffer *buf = pdf_load_embedded_file (state.ctx, fs); + fz_buffer *buf = pdf_load_embedded_file_contents (state.ctx, fs); fz_save_buffer (state.ctx, buf, path); fz_drop_buffer (state.ctx, buf); printd ("progress 1 saved '%s'", path); @@ -2585,6 +2584,7 @@ ML0 (savefileannot (value ptr_v, value n_v, value path_v)) printd ("emsg saving '%s': %s", path, fz_caught_message (state.ctx)); } unlock (__func__); + CAMLreturn0; } ML (getlinkrect (value ptr_v, value n_v)) diff --git a/main.ml b/main.ml index a2f439c1..263ac06c 100644 --- a/main.ml +++ b/main.ml @@ -53,7 +53,7 @@ let adderrmsg src msg = S.newerrmsgs := true; Glutils.postRedisplay src -let settextfmt fmt = Printf.kprintf (fun s -> S.text := s) fmt +let settextfmt fmt = Printf.ksprintf (fun s -> S.text := s) fmt let impmsg fmt = Printf.ksprintf (fun s -> showtext '!' s) fmt let adderrfmt src fmt = Printf.ksprintf (fun s -> adderrmsg src s) fmt diff --git a/misc/getmupdf.sh b/misc/getmupdf.sh index 29cb0ee9..4a34d612 100644 --- a/misc/getmupdf.sh +++ b/misc/getmupdf.sh @@ -5,7 +5,7 @@ MUPDF_OUTPUT_DIR="$1" u="git://git.ghostscript.com/mupdf" #u="https://github.com/ArtifexSoftware/mupdf" MUPDF_URL="${2-$u}" -MUPDF_DESIRED_VERSION="f6ddaf30da1defe3be961f1172b83554bc6f6b48" +MUPDF_DESIRED_VERSION="fac9da1c7cd03776df1011e1e4cb168c33e7a194" if [ ! -d ${MUPDF_OUTPUT_DIR} ]; then echo "mupdf does not exist, fetching it from ${MUPDF_URL}" diff --git a/misc/llppac b/misc/llppac index 46dd7277..66d039e1 100755 --- a/misc/llppac +++ b/misc/llppac @@ -145,8 +145,10 @@ case $type in fi ;; image) - missing convert "convert(http://www.imagemagick.org/script/convert.php)" - conv='convert - pdf:"$casp"' + missing ffmpeg "ffmpeg(https://www.ffmpeg.org" + unset dc + caspsuf=".jpg" + conv='ffmpeg -loglevel fatal -i - "$casp"' ;; dvi) test -n "$dc" && die "cannot convert compressed '$mime'" @@ -168,4 +170,4 @@ casp=$cachedir/${hash%% *}$caspsuf { test -n "${force-}" || test ! -e "$casp"; } && eval "$filt" "$conv" shift -exec llpp -origin $origin "$@" "$casp" +exec llpp -origin "$origin" "$@" "$casp" diff --git a/todo.org b/todo.org index 9968a8ef..0fda0204 100644 --- a/todo.org +++ b/todo.org @@ -45,3 +45,15 @@ * TODO llpp -last and llpp select first entry in history behave differently 586cb865549a22765a91ee0983e02a56429b1577 * TODO llpp recode and comment "tile" handling +* TODO changing interpagespace in setup breaks navigation +- State "TODO" from [2023-02-17 Fri 05:39] +* TODO scaled page indicator lines are drawn on top of scrollbar +* TODO don't forget to credit sebras for outline location simplification +- State "TODO" from [2023-02-22 Wed 02:54] +* TODO fix interpagespace setting (was setting it to negated value) +- State "TODO" from [2023-02-22 Wed 03:55] +* TODO zoom in on something quit llpp, reopen... whoops +- State "TODO" from [2023-02-22 Wed 03:59] +* TODO zoom in in ecma376.pdf it will enter endless eviction loop +- State "TODO" from [2023-02-22 Wed 04:00] +* TODO x location is not restored when entering from history (-last works!) diff --git a/utils.ml b/utils.ml index 80eccde2..60bce663 100644 --- a/utils.ml +++ b/utils.ml @@ -26,7 +26,7 @@ let exntos = function let onoffs = function | true -> "on" | false -> "off" -let error fmt = Printf.kprintf failwith fmt +let error fmt = Printf.ksprintf failwith fmt module IntSet = Set.Make (struct type t = int let compare = (-) end) @@ -182,7 +182,7 @@ let filecontents path = s let getcmdoutput errfun cmd = - let reperror fmt = Printf.kprintf errfun fmt in + let reperror fmt = Printf.ksprintf errfun fmt in let clofail s e = error "failed to close %s: %s" s e in match Unix.pipe () with | exception exn -> @@ -249,7 +249,7 @@ let r32 s pos = ((r16 s (pos+2)) lsl 16) lor (r16 s pos) let r32s s pos = Bytes.get_int32_le s pos |> Int32.to_int let vlogf = ref ignore -let vlog fmt = Printf.kprintf !vlogf fmt +let vlog fmt = Printf.ksprintf !vlogf fmt let pipef ?(closew=true) cap f cmd = match Unix.pipe () with From ff35fd605de748bc45cc2cc5fc19aad3eefead20 Mon Sep 17 00:00:00 2001 From: malc Date: Fri, 30 Aug 2024 20:29:21 +0300 Subject: [PATCH 2/6] Pacify -Werror=calloc-transposed-args --- link.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/link.c b/link.c index 7badd5cd..71a3e0c7 100644 --- a/link.c +++ b/link.c @@ -476,7 +476,7 @@ static void *loadpage (int pageno, int pindex) fz_device *dev; struct page *page; - page = calloc (sizeof (struct page), 1); + page = calloc (1, sizeof (struct page)); if (!page) { err (1, errno, "calloc page %d", pageno); } From 1d9dcee7462b9d1e3795650e62535e9c6fa20e40 Mon Sep 17 00:00:00 2001 From: malc Date: Fri, 30 Aug 2024 20:54:02 +0300 Subject: [PATCH 3/6] Suppress Wswitch-default Hard to weasel out and just add "default" labels here and there given that search's the_searchresult has type a_searchresult and clang is inconsolable no matter how you spin that switch. --- link.c | 1 + 1 file changed, 1 insertion(+) diff --git a/link.c b/link.c index 71a3e0c7..aa588b3d 100644 --- a/link.c +++ b/link.c @@ -28,6 +28,7 @@ #pragma GCC diagnostic ignored "-Wimplicit-int-float-conversion" #pragma GCC diagnostic ignored "-Wdeclaration-after-statement" #pragma GCC diagnostic ignored "-Wunsafe-buffer-usage" +#pragma GCC diagnostic ignored "-Wswitch-default" #else #pragma GCC diagnostic error "-Wcast-qual" #endif From e3efbd5a7cbe0bf439799c4c22b6f139ff4c61df Mon Sep 17 00:00:00 2001 From: malc Date: Fri, 30 Aug 2024 21:00:55 +0300 Subject: [PATCH 4/6] Cower all bases NB consider abort replacement options --- link.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/link.c b/link.c index aa588b3d..851db9e6 100644 --- a/link.c +++ b/link.c @@ -28,7 +28,6 @@ #pragma GCC diagnostic ignored "-Wimplicit-int-float-conversion" #pragma GCC diagnostic ignored "-Wdeclaration-after-statement" #pragma GCC diagnostic ignored "-Wunsafe-buffer-usage" -#pragma GCC diagnostic ignored "-Wswitch-default" #else #pragma GCC diagnostic error "-Wcast-qual" #endif @@ -909,6 +908,7 @@ static void layout (void) p->left = 0; zoom = state.w / w; break; + default: abort (); } p->zoomctm = fz_scale (zoom, zoom); @@ -1111,7 +1111,7 @@ static void search (regex_t *re, int pageno, int y, int forward) fz_stext_block *block; fz_stext_page *text = NULL; int niters = 0, num_matches = 0; - enum a_searchresult the_searchresult = NotFound; + int searchresult = NotFound; start = now (); while (pageno >= 0 && pageno < state.pagecount && num_matches == 0) { @@ -1120,7 +1120,7 @@ static void search (regex_t *re, int pageno, int y, int forward) if (hasdata (state.csock)) { fz_drop_stext_page (state.ctx, text); fz_drop_page (state.ctx, page); - the_searchresult = Interrupted; + searchresult = Interrupted; break; } else { @@ -1151,9 +1151,8 @@ static void search (regex_t *re, int pageno, int y, int forward) continue; } - the_searchresult = - matchline (re, line, num_matches, pageno); - num_matches += the_searchresult == Found; + searchresult = matchline (re, line, num_matches, pageno); + num_matches += searchresult == Found; } } } @@ -1170,9 +1169,8 @@ static void search (regex_t *re, int pageno, int y, int forward) continue; } - the_searchresult = - matchline (re, line, num_matches, pageno); - num_matches += the_searchresult == Found; + searchresult = matchline (re, line, num_matches, pageno); + num_matches += searchresult == Found; } } } @@ -1191,10 +1189,11 @@ static void search (regex_t *re, int pageno, int y, int forward) page = NULL; } dur = now () - start; - switch (the_searchresult) { + switch (searchresult) { case Found: case NotFound: cap = ""; break; case Error: cap = "error "; break; case Interrupted: cap = "interrupt "; break; + default: abort (); } if (num_matches) { printd ("progress 1 %sfound %d in %f sec", cap, num_matches, dur); @@ -2430,6 +2429,8 @@ ML (findlink (value ptr_v, value dir_v)) } } break; + + default: abort (); } } else { @@ -2444,6 +2445,9 @@ ML (findlink (value ptr_v, value dir_v)) found = page->slinks + (page->slinkcount - 1); } break; + + default: + abort (); } } if (found) { From 2a174514619db7bd0814cc9409882f4264f15a54 Mon Sep 17 00:00:00 2001 From: malc Date: Tue, 7 Jan 2025 11:12:39 +0300 Subject: [PATCH 5/6] Respect inversion when drawing page separators --- main.ml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/main.ml b/main.ml index 263ac06c..8285c424 100644 --- a/main.ml +++ b/main.ml @@ -3938,7 +3938,8 @@ let display () = Glutils.filledrect x0 y0 x1 y1; in Gl.enable `blend; - GlDraw.color (0.1, 0.1, 0.1) ~alpha:0.5; + let i, alpha = if conf.invert then (0.9, 0.2) else (0.1, 0.2) in + GlDraw.color (i, i, i) ~alpha; GlFunc.blend_func ~src:`src_alpha ~dst:`one_minus_src_alpha; (match !S.layout with | _ :: [] -> drawsep (conf.pgscale *. float !S.winh) From 3795c48b607f4fe98062e5a4a19310899398be42 Mon Sep 17 00:00:00 2001 From: Florian Stecker Date: Thu, 12 Jun 2025 23:47:31 -0400 Subject: [PATCH 6/6] Compatibility with libmupdf 1.26 --- link.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/link.c b/link.c index ff635b2a..9134726c 100644 --- a/link.c +++ b/link.c @@ -2560,8 +2560,8 @@ ML (getfileannot (value ptr_v, value n_v)) pdf_obj *fs = pdf_dict_get (state.ctx, pdf_annot_obj (state.ctx, slink->u.annot), PDF_NAME (FS)); - pdf_embedded_file_params params; - pdf_get_embedded_file_params (state.ctx, fs, ¶ms); + pdf_filespec_params params; + pdf_get_filespec_params (state.ctx, fs, ¶ms); ret_v = caml_copy_string (params.filename); unlock (__func__);