diff --git a/manual/luatex-languages.tex b/manual/luatex-languages.tex index 990a8dcc038d568ccf74fe8cc6686ab5bd8cfc38..54a7b390d5ffac254c3eba712a693703ba6be912 100644 --- a/manual/luatex-languages.tex +++ b/manual/luatex-languages.tex @@ -263,7 +263,82 @@ The word end is determined as follows: \NC adjust \NC when hyphenationbounds 2 or 3 \NC \NR \stoptabulate -(Future versions of \LUATEX\ might provide more granularity.) +% (Future versions of \LUATEX\ might provide more granularity.) + +In traditional \TEX\ ligature building and hyphenation are interwoven with the +line break mechanism. In \LUATEX\ these phases are isolated. As a consequence we +deal differently with (a sequence of) explicit hyphens. We already have added +some control over aspects of the hyphenation and yet another one concerns +automatic hyphens (e.g.\ \type {-} characters in the input). + +When \type {\automatichyphenmode} has a value of 0, a hyphen will be turned into +an automatic discretionary. The snippets before and after it will not be +hyphenated. A side effect is that a leading hyphen can lead to a split but one +will seldom run into that situation. Setting a pre and post character makes this +more prominent. A value of 1 will prevent this side effect and a value of 2 will +not turn the hyphen into a discretionary. Experiments with other options, like +permitting hyphenation, of the words on both sides were discarded. + +\startbuffer[a] +before-after \par +before--after \par +before---after \par +\stopbuffer + +\startbuffer[b] +-before \par +after- \par +--before \par +after-- \par +---before \par +after--- \par +\stopbuffer + +\startbuffer[c] +before-after \par +before--after \par +before---after \par +\stopbuffer + +We show three samples: + +Input A: \typebuffer[a] +Input B: \typebuffer[b] +Input C: \typebuffer[c] + +\startbuffer[demo] +\startcombination[nx=4,ny=3,location=top] + {\framed[align=normal,strut=no,top=\vskip.5ex,bottom=\vskip.5ex]{\automatichyphenmode\zerocount \hsize6em \getbuffer[a]}} {A~0~6em} + {\framed[align=normal,strut=no,top=\vskip.5ex,bottom=\vskip.5ex]{\automatichyphenmode\zerocount \hsize2pt \getbuffer[a]}} {A~0~2pt} + {\framed[align=normal,strut=no,top=\vskip.5ex,bottom=\vskip.5ex]{\automatichyphenmode\plusone \hsize2pt \getbuffer[a]}} {A~1~2pt} + {\framed[align=normal,strut=no,top=\vskip.5ex,bottom=\vskip.5ex]{\automatichyphenmode\plustwo \hsize2pt \getbuffer[a]}} {A~2~2pt} + {\framed[align=normal,strut=no,top=\vskip.5ex,bottom=\vskip.5ex]{\automatichyphenmode\zerocount \hsize6em \getbuffer[b]}} {B~0~6em} + {\framed[align=normal,strut=no,top=\vskip.5ex,bottom=\vskip.5ex]{\automatichyphenmode\zerocount \hsize2pt \getbuffer[b]}} {B~0~2pt} + {\framed[align=normal,strut=no,top=\vskip.5ex,bottom=\vskip.5ex]{\automatichyphenmode\plusone \hsize2pt \getbuffer[b]}} {B~1~2pt} + {\framed[align=normal,strut=no,top=\vskip.5ex,bottom=\vskip.5ex]{\automatichyphenmode\plustwo \hsize2pt \getbuffer[b]}} {B~2~2pt} + {\framed[align=normal,strut=no,top=\vskip.5ex,bottom=\vskip.5ex]{\automatichyphenmode\zerocount \hsize6em \getbuffer[c]}} {C~0~6em} + {\framed[align=normal,strut=no,top=\vskip.5ex,bottom=\vskip.5ex]{\automatichyphenmode\zerocount \hsize2pt \getbuffer[c]}} {C~0~2pt} + {\framed[align=normal,strut=no,top=\vskip.5ex,bottom=\vskip.5ex]{\automatichyphenmode\plusone \hsize2pt \getbuffer[c]}} {C~1~2pt} + {\framed[align=normal,strut=no,top=\vskip.5ex,bottom=\vskip.5ex]{\automatichyphenmode\plustwo \hsize2pt \getbuffer[c]}} {C~2~2pt} +\stopcombination +\stopbuffer + +\startplacefigure[reference=automatic:1,title={The automatic modes \type {0} (default), \type {1} and \type {2}, with a \type {\hsize} +of 6em and 2pt (which triggers a linebreak).}] + \dontcomplain \tt \getbuffer[demo] +\stopplacefigure + +\startplacefigure[reference=automatic:2,title={The automatic modes \type {0} (default), \type {1} and \type {2}, with \type +{\preexhyphenchar} and \type {\postexhyphenchar} set to characters \type {A} and \type {B}.}] + \postexhyphenchar`A\relax + \preexhyphenchar `B\relax + \dontcomplain \tt \getbuffer[demo] +\stopplacefigure + +As with primitive companions of other single character commands, the \type {\-} +command has a more verbose primitive version in \type {\explicitdiscretionary} +and the normally intercepted in the hyphenator character \type {-} (or whatever +is configured) is available as \type {\automaticdiscretionary}. \section{The main control loop} diff --git a/manual/luatex-nodes.tex b/manual/luatex-nodes.tex index 21f1789e5a99b08462d7b78c7b516a2876fec246..d3c2c06dae1a3bb51a4354cb144ebeb10517f3ed 100644 --- a/manual/luatex-nodes.tex +++ b/manual/luatex-nodes.tex @@ -301,11 +301,15 @@ a \type {userskip} with subtype zero). \starttabulate[|lT|l|p|] \NC \rmbf field \NC \bf type \NC \bf explanation \NC \NR -\NC subtype \NC number \NC not used \NC \NR +\NC subtype \NC number \NC \showsubtypes{penalty} \NC \NR \NC attr \NC node \NC list of attributes \NC \NR \NC penalty \NC number \NC the penalty value \NC \NR \stoptabulate +The subtypes are just informative and \TEX\ itself doesn't use them. When you +run into an \type {linebreakpenalty} you need to keep in mind that it's a +accumulation of \type {club}, \type{widow} and other relevant penalties. + \subsubsection[glyphnodes]{glyph nodes} \starttabulate[|lT|l|p|] @@ -1705,6 +1709,13 @@ tail node. node.slide(<node> n) \stopfunctioncall +After some callbacks automatic sliding takes place. This feature can be turned +off with \type {node.fix_node_lists(false)} but you better make sure then that +you don't mess up lists. In most cases \TEX\ itself only uses \type {next} +pointers but your other callbacks might expect proper \type {prev} pointers too. +Future versions of \LUATEX\ can add more checking but this will not influence +usage. + \subsubsection{\type {node.check_discretionary} and \type {node.check_discretionaries}} When you fool around with disc nodes you need to be aware of the fact that they diff --git a/manual/luatex-tex.tex b/manual/luatex-tex.tex index 650f3ca056db95185732b5c2b9c25e2c7c6f9a47..fac1af39353a0809729542d727ce3cb525605f63 100644 --- a/manual/luatex-tex.tex +++ b/manual/luatex-tex.tex @@ -161,7 +161,7 @@ The current list is: \NC pool_ptr \NC string pool index \NC \NR \NC pool_size \NC current size allocated for string characters \NC \NR \NC save_size \NC save stack size \NC \NR -\NC shell_escape \NC \type {0} means disabled, \type {1} means anything is permitted and \type {2} is restricted \NC \NR +\NC shell_escape \NC \type {0} means disabled, \type {1} means anything is permitted and \type {2} is restricted \NC \NR \NC safer_option \NC \type {1} means safer is enforced \NC \NR \NC kpse_used \NC \type {1} means that kpse is used \NC \NR \NC stack_size \NC input stack size \NC \NR diff --git a/manual/luatex.pdf b/manual/luatex.pdf index 006bfc7856ebcbc182574062de7e8c5b984448ac..277bf24122390d3909133f74766222663d38f1de 100644 Binary files a/manual/luatex.pdf and b/manual/luatex.pdf differ diff --git a/manual/luatex.tex b/manual/luatex.tex index 1ccc9b7a59a39552d9eaac9a2a7bafcd5174e6a6..1613b920b206b2b2c5a64f9b3369792a370c5db0 100644 --- a/manual/luatex.tex +++ b/manual/luatex.tex @@ -29,8 +29,8 @@ \dontcomplain \startdocument - [status=intermediate release, - version=1.0.4] + [status=release, + version=1.0.5] \component luatex-titlepage diff --git a/source/texk/web2c/luatexdir/font/luafont.w b/source/texk/web2c/luatexdir/font/luafont.w index 4e874d9becb896585da678362505845b75366417..d7a5c5f904d3c4f6ff5970724e36c767fc417df4 100644 --- a/source/texk/web2c/luatexdir/font/luafont.w +++ b/source/texk/web2c/luatexdir/font/luafont.w @@ -1995,8 +1995,9 @@ halfword handle_ligaturing(halfword head, halfword tail) vlink(tail) = null; } - /* |if (fix_node_lists)| */ - fix_node_list(head); + if (fix_node_lists) { + fix_node_list(head); + } prev = head; cur = vlink(prev); @@ -2184,7 +2185,9 @@ static halfword run_lua_ligkern_callback(halfword head, halfword tail, int callb luatex_error(Luas, (i == LUA_ERRRUN ? 0 : 1)); return tail; } - fix_node_list(head); + if (fix_node_lists) { + fix_node_list(head); + } lua_settop(Luas, top); return tail; } diff --git a/source/texk/web2c/luatexdir/lang/hyphen.w b/source/texk/web2c/luatexdir/lang/hyphen.w index 8e13896090d769a68b025dba26403c1a7bf58d84..35befb743debbf7e34b4429727f7a3edc25b6d8d 100644 --- a/source/texk/web2c/luatexdir/lang/hyphen.w +++ b/source/texk/web2c/luatexdir/lang/hyphen.w @@ -776,6 +776,8 @@ void hnj_hyphen_load(HyphenDict * dict, const unsigned char *f) } @ @c +extern halfword insert_syllable_discretionary(halfword t, lang_variables * lan); + void hnj_hyphen_hyphenate(HyphenDict * dict, halfword first1, halfword last1, @@ -791,9 +793,9 @@ void hnj_hyphen_hyphenate(HyphenDict * dict, char *hyphens = hnj_malloc(hyphen_len + 1); /* Add a '.' to beginning and end to facilitate matching */ - set_vlink(begin_point, first1); - set_vlink(end_point, get_vlink(last1)); - set_vlink(last1, end_point); + vlink(begin_point) = first1; + vlink(end_point) = vlink(last1); + vlink(last1) = end_point; for (char_num = 0; char_num < hyphen_len; char_num++) { hyphens[char_num] = '0'; @@ -801,16 +803,16 @@ void hnj_hyphen_hyphenate(HyphenDict * dict, hyphens[hyphen_len] = 0; /* now, run the finite state machine */ - for (char_num = 0, here = begin_point; here != get_vlink(end_point); - here = get_vlink(here)) { + for (char_num = 0, here = begin_point; here != vlink(end_point); + here = vlink(here)) { int ch; if (here == begin_point || here == end_point) { ch = '.'; } else { - ch = get_hj_code(char_lang(here),get_character(here)); + ch = get_hj_code(char_lang(here),character(here)); if (ch <= 32) { - ch = get_character(here); + ch = character(here); } } while (state != -1) { @@ -857,14 +859,14 @@ void hnj_hyphen_hyphenate(HyphenDict * dict, } /* restore the correct pointers */ - set_vlink(last1, get_vlink(end_point)); + vlink(last1) = vlink(end_point); /* pattern is \.{\^.\^w\^o\^r\^d\^.\^} |word_len|=4, |ext_word_len|=6, |hyphens|=7 * check \.{ \^ \^ \^ } so drop first two and stop after |word_len-1| */ - for (here = first1, char_num = 2; here != left; here = get_vlink(here)) + for (here = first1, char_num = 2; here != left; here = vlink(here)) char_num++; - for (; here != right; here = get_vlink(here)) { + for (; here != right; here = vlink(here)) { if (hyphens[char_num] & 1) here = insert_syllable_discretionary(here, lan); char_num++; diff --git a/source/texk/web2c/luatexdir/lang/texlang.h b/source/texk/web2c/luatexdir/lang/texlang.h index 5e7a046195f2c092253b36bcd0d43a6a1de1c31e..0fa11d4c82f79f7b2905298c92965d904c12452a 100644 --- a/source/texk/web2c/luatexdir/lang/texlang.h +++ b/source/texk/web2c/luatexdir/lang/texlang.h @@ -67,7 +67,7 @@ extern int get_post_exhyphen_char(int lan); extern void set_hyphenation_min(int lan, int val); extern int get_hyphenation_min(int lan); -extern halfword compound_word_break(halfword t, int clang); +/* extern halfword compound_word_break(halfword t, int clang); */ extern void dump_language_data(void); extern void undump_language_data(void); @@ -82,5 +82,7 @@ extern void new_post_exhyphen_char(void); extern void new_hyphenation_min(void); extern void new_hj_code(void); +extern void set_disc_field(halfword f, halfword t); +extern halfword insert_syllable_discretionary(halfword t, lang_variables * lan); #endif diff --git a/source/texk/web2c/luatexdir/lang/texlang.w b/source/texk/web2c/luatexdir/lang/texlang.w index bd519af632ab8192a136c0ce982805ebcc717be8..337d2eca51dfebcfc08bc7806e177c8380d309ad 100644 --- a/source/texk/web2c/luatexdir/lang/texlang.w +++ b/source/texk/web2c/luatexdir/lang/texlang.w @@ -60,7 +60,8 @@ struct tex_language *new_language(int n) lang->post_exhyphen_char = 0; lang->hyphenation_min = -1; if (saving_hyph_codes_par) { - hj_codes_from_lc_codes(l); /* for now, we might just use specific value for whatever task */ + /* for now, we might just use specific value for whatever task */ + hj_codes_from_lc_codes(l); } return lang; } else { @@ -198,10 +199,10 @@ void load_tex_patterns(int curlang, halfword head) const char *clean_hyphenation(int id, const char *buff, char **cleaned) { int items = 0; - unsigned char word[MAX_WORD_LEN + 1]; /* work buffer for bytes */ - unsigned uword[MAX_WORD_LEN + 1] = { 0 }; /* work buffer for unicode */ - int u = 0; /* unicode buffer value */ - int i = 0; /* index into buffer */ + unsigned char word[MAX_WORD_LEN + 1]; /* work buffer for bytes */ + unsigned uword[MAX_WORD_LEN + 1] = { 0 }; /* work buffer for unicode */ + int u = 0; /* unicode buffer value */ + int i = 0; /* index into buffer */ char *uindex = (char *)word; const char *s = buff; @@ -218,12 +219,12 @@ const char *clean_hyphenation(int id, const char *buff, char **cleaned) /* now convert the input to unicode */ word[i] = '\0'; utf2uni_strcpy(uword, (const char *)word); - /* build the new word string */ i = 0; while (uword[i]>0) { u = uword[i++]; - if (u == '-') { /* skip */ + if (u == '-') { + /* skip */ } else if (u == '=') { STORE_CHAR(id,'-'); } else if (u == '{') { @@ -253,7 +254,7 @@ const char *clean_hyphenation(int id, const char *buff, char **cleaned) if (u == '}') { items++; } - if (items != 3) { /* syntax error */ + if (items != 3) { *cleaned = NULL; tex_error("exception syntax error", NULL); return s; @@ -322,51 +323,61 @@ void load_tex_hyphenation(int curlang, halfword head) } @ @c -halfword insert_discretionary(halfword t, halfword pre, halfword post, halfword replace, int penalty) +static halfword insert_discretionary(halfword t, halfword pre, halfword post, halfword replace, int penalty) { - halfword g, n; + halfword g; int f; - n = new_node(disc_node, syllable_disc); - disc_penalty(n) = penalty; - try_couple_nodes(n, vlink(t)); - couple_nodes(t, n); - if (replace != null) + halfword d = new_node(disc_node, syllable_disc); + int attr = node_attr(t) ; + disc_penalty(d) = penalty; + if (t == replace) { + /* prev disc next-next */ + try_couple_nodes(d, vlink(t)); + try_couple_nodes(alink(t), d); + alink(t) = null; + vlink(t) = null; + replace = t ; + } else { + /* prev disc next */ + try_couple_nodes(d, vlink(t)); + couple_nodes(t, d); + } + if (replace != null) { f = font(replace); - else - f = get_cur_font(); /* for compound words following explicit hyphens */ + } else { + /* For compound words following explicit hyphens. */ + f = get_cur_font(); + } for (g = pre; g != null; g = vlink(g)) { font(g) = f; - if (node_attr(t) != null) { + if (attr != null) { delete_attribute_ref(node_attr(g)); - node_attr(g) = node_attr(t); - attr_list_ref(node_attr(t)) += 1; + node_attr(g) = attr; + attr_list_ref(attr) += 1; } } for (g = post; g != null; g = vlink(g)) { font(g) = f; - if (node_attr(t) != null) { + if (attr != null) { delete_attribute_ref(node_attr(g)); - node_attr(g) = node_attr(t); - attr_list_ref(node_attr(t)) += 1; + node_attr(g) = attr; + attr_list_ref(attr) += 1; } } - for (g = replace; g != null; g = vlink(g)) { - if (node_attr(t) != null) { + if (attr != null) { + for (g = replace; g != null; g = vlink(g)) { delete_attribute_ref(node_attr(g)); - node_attr(g) = node_attr(t); - attr_list_ref(node_attr(t)) += 1; + node_attr(g) = attr; + attr_list_ref(attr) += 1; } + delete_attribute_ref(node_attr(d)); + node_attr(d) = attr; + attr_list_ref(attr) += 1; } - if (node_attr(t) != null) { - delete_attribute_ref(node_attr(vlink(t))); - node_attr(vlink(t)) = node_attr(t); - attr_list_ref(node_attr(t)) += 1; - } - t = vlink(t); - set_disc_field(pre_break(t), pre); - set_disc_field(post_break(t), post); - set_disc_field(no_break(t), replace); - return t; + set_disc_field(pre_break(d), pre); + set_disc_field(post_break(d), post); + set_disc_field(no_break(d), replace); + return d; } halfword insert_syllable_discretionary(halfword t, lang_variables * lan) @@ -413,43 +424,38 @@ halfword insert_syllable_discretionary(halfword t, lang_variables * lan) } @ @c -halfword compound_word_break(halfword t, int clang) +static halfword insert_character(halfword t, int c) +{ + halfword p; + p = new_node(glyph_node, 0); + set_to_character(p); + character(p) = c; + if (t != null) { + couple_nodes(t, p); + } + return p; +} + +static halfword compound_word_break(halfword t, int clang) { halfword disc = null; halfword pre = null; halfword pos = null; halfword pre_exhyphen_char = get_pre_exhyphen_char(clang); halfword post_exhyphen_char = get_post_exhyphen_char(clang); - if (pre_exhyphen_char > 0) + if (pre_exhyphen_char > 0) { pre = insert_character(null,pre_exhyphen_char); + } else { + pre = insert_character(null,ex_hyphen_char_par); + } if (post_exhyphen_char > 0) pos = insert_character(null,post_exhyphen_char); - disc = insert_discretionary(t,pre,pos,null,ex_hyphen_penalty_par); + disc = insert_discretionary(t,pre,pos,t,ex_hyphen_penalty_par); subtype(disc) = automatic_disc; set_automatic_disc_penalty(disc); return disc; } -halfword insert_complex_discretionary(halfword t, lang_variables * lan, - halfword pre, halfword pos, - halfword replace) -{ - (void) lan; - return insert_discretionary(t,pre,pos,replace,hyphen_penalty_par); -} - -halfword insert_character(halfword t, int c) -{ - halfword p; - p = new_node(glyph_node, 0); - set_to_character(p); - character(p) = c; - if (t != null) { - couple_nodes(t, p); - } - return p; -} - @ @c void set_disc_field(halfword f, halfword t) { @@ -713,6 +719,20 @@ there was not the best idea ever. */ +/* + We only accept an explicit hyphen when there is a preceding glyph and we skip a sequence of + explicit hyphens as that normally indicates a -- or --- ligature in which case we can in a + worse case usage get bad node lists later on due to messed up ligature building as these + dashes are ligatures in base fonts. This is a side effect of the separating the hyphenation, + ligaturing and kerning steps. A test is cmr with ------. + + A font handler can collapse successive hyphens but it's not nice to put the burden there. A + somewhat messy border case is ---- but in LuaTeX we don't treat -- and --- special. Also, + traditional TeX will break a line at -foo but this can be disabled by setting the automatic + mode to 1. + +*/ + static halfword find_next_wordstart(halfword r, halfword first_language, halfword strict_bound) { register int l; @@ -757,27 +777,31 @@ static halfword find_next_wordstart(halfword r, halfword first_language, halfwor if (is_simple_character(r)) { chr = character(r) ; if (chr == ex_hyphen_char_par) { - /* - We only accept an explicit hyphen when there is a preceding glyph and - we skip a sequence of explicit hyphens as that normally indicates a - -- or --- ligature in which case we can in a worse case usage get bad - node lists later on due to messed up ligature building as these dashes - are ligatures in base fonts. This is a side effect of the separating the - hyphenation, ligaturing and kerning steps. A test is cmr with ------. - */ t = vlink(r) ; - if ((start_ok == 0) && (t!=null) && (type(t) == glyph_node) && (character(t) != ex_hyphen_char_par)) { - compound_word_break(r, char_lang(r)); - start_ok = 1 ; + if ((automatic_hyphen_mode_par == 0) && (t != null) && (type(t) == glyph_node) && (character(t) != ex_hyphen_char_par)) { + /* we have no word yet and the next character is a non hyphen */ + r = compound_word_break(r, char_lang(r)); } else { - start_ok = 0; + /* we jump over the sequence of hyphens */ + while ((t != null) && (type(t) == glyph_node) && (character(t) == ex_hyphen_char_par)) { + r = t ; + t = vlink(r) ; + } + if (t == null) { + /* we reached the end of the list so we have no word start */ + return null; + } } + /* we need a restart */ + start_ok = 0; } else if (start_ok && (char_lang(r)>=first_language) && ((l = get_hj_code(char_lang(r),chr)) > 0)) { if (char_uchyph(r) || l == chr || l <= 32) { return r; } else { start_ok = 0; } + } else { + /* go on */ } } break; @@ -839,18 +863,23 @@ void hnj_hyphenation(halfword head, halfword tail) halfword strict_bound = hyphenation_bounds_par; halfword s, r = head, wordstart = null, save_tail1 = null, left = null, right = null; - /* this first movement assures two things: - \item{a)} that we won't waste lots of time on something that has been - handled already (in that case, none of the glyphs match |simple_character|). - \item{b)} that the first word can be hyphenated. if the movement was - not explicit, then the indentation at the start of a paragraph - list would make |find_next_wordstart()| look too far ahead. - */ + /* + This first movement assures two things: + + \item{a)} that we won't waste lots of time on something that has been handled already + (in that case, none of the glyphs match |simple_character|). + + \item{b)} that the first word can be hyphenated. if the movement was not explicit, + then the indentation at the start of a paragraph list would make |find_next_wordstart()| + look too far ahead. + */ while (r != null && (type(r) != glyph_node || !is_simple_character(r))) { r = vlink(r); } - /* this will make |r| a glyph node with subtype character */ + /* + This will make |r| a glyph node with subtype character. + */ r = find_next_wordstart(r,first_language,strict_bound); if (r == null) return; @@ -860,15 +889,17 @@ void hnj_hyphenation(halfword head, halfword tail) s = new_penalty(0,word_penalty); couple_nodes(tail, s); - while (r != null) { /* could be while(1), but let's be paranoid */ + while (r != null) { /* could be while(1), but let's be paranoid */ int clang, lhmin, rhmin, hmin; halfword hyf_font; halfword end_word = r; wordstart = r; assert(is_simple_character(wordstart)); hyf_font = font(wordstart); - if (hyphen_char(hyf_font) < 0) /* for backward compat */ + if (hyphen_char(hyf_font) < 0) { + /* For backward compatibility: */ hyf_font = 0; + } clang = char_lang(wordstart); lhmin = char_lhmin(wordstart); rhmin = char_rhmin(wordstart); @@ -889,6 +920,7 @@ void hnj_hyphenation(halfword head, halfword tail) ) { if (character(r) == ex_hyphen_char_par) { explicit_hyphen = true; + break; } wordlen++; if (lchar <= 32) { @@ -911,12 +943,27 @@ void hnj_hyphenation(halfword head, halfword tail) lchar = character(r) ; } hy = uni2string(hy, (unsigned) lchar); - /* this should not be needed any more */ - /*if (vlink(r)!=null) alink(vlink(r))=r; */ end_word = r; r = vlink(r); } - if ( valid_wordend(r,strict_bound) + if (explicit_hyphen == true) { + /* we are not at the start, so we only need to look ahead */ + halfword t = vlink(r) ; + if ((automatic_hyphen_mode_par == 0 || automatic_hyphen_mode_par == 1) && (t != null) && ((type(t) == glyph_node) && (character(t) != ex_hyphen_char_par))) { + /* we have a word already but the next character may not be a hyphen too */ + r = compound_word_break(r, char_lang(r)); + } else { + /* we jump over the sequence of hyphens */ + while ((t != null) && (type(t) == glyph_node) && (character(t) == ex_hyphen_char_par)) { + r = t ; + t = vlink(r) ; + } + if (t == null) { + /* we reached the end of the list and will quit the loop later */ + r = null; + } + } + } else if ( valid_wordend(r,strict_bound) && clang >= first_language && wordlen >= lhmin + rhmin && (hmin <= 0 || wordlen >= hmin) @@ -924,35 +971,10 @@ void hnj_hyphenation(halfword head, halfword tail) && (lang = tex_languages[clang]) != NULL ) { *hy = 0; - if ( lang->exceptions != 0 - && (replacement = hyphenation_exception(lang->exceptions, utf8word)) != NULL - ) { -#ifdef VERBOSE - formatted_warning("hyphenation","replacing %s (c=%d) by %s", utf8word, clang, replacement); -#endif + if (lang->exceptions != 0 && (replacement = hyphenation_exception(lang->exceptions, utf8word)) != NULL) { + /* handle the exception and go on to the next word */ do_exception(wordstart, r, replacement); free(replacement); - } else if (explicit_hyphen == true) { - /* - insert an explicit discretionary after each of the last in a - set of explicit hyphens - */ - halfword rr = r; -#ifdef VERBOSE - formatted_warning("hyphenation","explicit hyphen(s) found in %s (c=%d)", utf8word, clang); -#endif - while (rr != wordstart) { - if (is_simple_character(rr)) { - if (character(rr) == ex_hyphen_char_par) { - compound_word_break(rr, clang); - while (character(alink(rr)) == ex_hyphen_char_par) - rr = alink(rr); - if (rr == wordstart) - break; - } - } - rr = alink(rr); - } } else if (lang->patterns != NULL) { left = wordstart; for (i = lhmin; i > 1; i--) { @@ -960,10 +982,7 @@ void hnj_hyphenation(halfword head, halfword tail) while (!is_simple_character(left)) { left = vlink(left); } - /* - if (!left) - break ; - */ + /* if (!left) break; */ /* what is left overruns right .. a bit messy */ } right = r; @@ -972,20 +991,10 @@ void hnj_hyphenation(halfword head, halfword tail) while (!is_simple_character(right)) { right = alink(right); } - /* - if (!right) - break ; - */ + /* if (!right) break; */ /* what is right overruns left .. a bit messy */ } - /* maybe an extra check ... */ - /* |if (left && right) {| */ -#ifdef VERBOSE - formatted_warning("hyphenation","hyphenate %s (c=%d,l=%d,r=%d) from %c to %c", - utf8word, clang, lhmin, rhmin, character(left), character(right)); -#endif - (void) hnj_hyphen_hyphenate(lang->patterns, wordstart, end_word, wordlen, left, right, &langdata); - /* |}| */ + (void) hnj_hyphen_hyphenate(lang->patterns, wordstart, end_word, wordlen, left, right, &langdata); } } explicit_hyphen = false; @@ -1026,7 +1035,7 @@ void new_hyphenation(halfword head, halfword tail) } } -@ dumping and undumping languages +@ Dumping and undumping languages. @c #define dump_string(a) \ @@ -1139,20 +1148,19 @@ void new_hyph_exceptions(void) flush_list(def_ref); } -@ Similarly, when \TeX\ has scanned `\.{\\patterns}', it calls on a -procedure named |new_patterns|. +@ Similarly, when \TeX\ has scanned `\.{\\patterns}', it calls on a procedure named +|new_patterns|. @c void new_patterns(void) -{ /* initializes the hyphenation pattern data */ +{ (void) scan_toks(false, true); load_tex_patterns(language_par, def_ref); flush_list(def_ref); } -@ `\.{\\prehyphenchar}', sets the |pre_break| character, and -`\.{\\posthyphenchar}' the |post_break| character. Their respective defaults are -ascii hyphen ("-") and zero (nul). +@ `\.{\\prehyphenchar}', sets the |pre_break| character, and `\.{\\posthyphenchar}' the +|post_break| character. Their respective defaults are ascii hyphen ("-") and zero (nul). @c void new_pre_hyphen_char(void) @@ -1169,9 +1177,8 @@ void new_post_hyphen_char(void) set_post_hyphen_char(language_par, cur_val); } -@ `\.{\\preexhyphenchar}', sets the |pre_break| character, and -`\.{\\postexhyphenchar}' the |post_break| character. Their defaults are both zero -(nul). +@ `\.{\\preexhyphenchar}', sets the |pre_break| character, and `\.{\\postexhyphenchar}' the +|post_break| character. Their defaults are both zero (nul). @c void new_pre_exhyphen_char(void) diff --git a/source/texk/web2c/luatexdir/lua/liolibext.c b/source/texk/web2c/luatexdir/lua/liolibext.c index e910139c2ce5c0cf74b10fbde3df963eb3e07c62..2e09c4541d40ad5c2313f4f2e039706d9e6cfa9c 100644 --- a/source/texk/web2c/luatexdir/lua/liolibext.c +++ b/source/texk/web2c/luatexdir/lua/liolibext.c @@ -29,11 +29,9 @@ #endif #include "lualib.h" - - #ifdef LuajitTeX /* luajit has its own way for io, which is a mix of */ -/* lua 5.1 and lua 5.2 . We use the stock luajit. */ +/* lua 5.1 and lua 5.2 . We use the stock luajit. */ #else /* ** {====================================================== @@ -61,7 +59,6 @@ /* }====================================================== */ - #if defined(LUA_USE_POSIX) #define l_fseek(f,o,w) fseeko(f,o,w) @@ -92,9 +89,6 @@ #endif/* #ifdef LuajitTeX */ - - - static FILE *tofile (lua_State *L) { #ifdef LuajitTeX FILE **f = luaL_checkudata(L,1,LUA_FILEHANDLE); @@ -110,6 +104,8 @@ static FILE *tofile (lua_State *L) { #endif } +#define uchar(c) ((unsigned char)(c)) + /* HH: A few helpers to avoid reading numbers as strings. For now we put them in their own namespace. We also have a few helpers that can make io functions tex friendly. @@ -125,6 +121,19 @@ static int readcardinal1(lua_State *L) { return 1; } +static int readcardinal1_s(lua_State *L) { + size_t l; + const char *s = luaL_checklstring(L, 1, &l); + size_t p = luaL_checkinteger(L, 2) - 1; + if (p < 0 || p >= l) { + lua_pushnil(L); + } else { + int a = uchar(s[p]); + lua_pushinteger(L, a); + } + return 1; +} + static int readcardinal2(lua_State *L) { FILE *f = tofile(L); int a = getc(f); @@ -137,6 +146,20 @@ static int readcardinal2(lua_State *L) { return 1; } +static int readcardinal2_s(lua_State *L) { + size_t l; + const char *s = luaL_checklstring(L, 1, &l); + size_t p = luaL_checkinteger(L, 2) - 1; + if (p < 0 || p+1 >= l) { + lua_pushnil(L); + } else { + int a = uchar(s[p++]); + int b = uchar(s[p]); + lua_pushinteger(L, 0x100 * a + b); + } + return 1; +} + static int readcardinal3(lua_State *L) { FILE *f = tofile(L); int a = getc(f); @@ -150,6 +173,21 @@ static int readcardinal3(lua_State *L) { return 1; } +static int readcardinal3_s(lua_State *L) { + size_t l; + const char *s = luaL_checklstring(L, 1, &l); + size_t p = luaL_checkinteger(L, 2) - 1; + if (p < 0 || p+2 >= l) { + lua_pushnil(L); + } else { + int a = uchar(s[p++]); + int b = uchar(s[p++]); + int c = uchar(s[p]); + lua_pushinteger(L, 0x10000 * a + 0x100 * b + c); + } + return 1; +} + static int readcardinal4(lua_State *L) { FILE *f = tofile(L); int a = getc(f); @@ -164,6 +202,22 @@ static int readcardinal4(lua_State *L) { return 1; } +static int readcardinal4_s(lua_State *L) { + size_t l; + const char *s = luaL_checklstring(L, 1, &l); + size_t p = luaL_checkinteger(L, 2) - 1; + if (p < 0 || p+3 >= l) { + lua_pushnil(L); + } else { + int a = uchar(s[p++]); + int b = uchar(s[p++]); + int c = uchar(s[p++]); + int d = uchar(s[p]); + lua_pushinteger(L,0x1000000 * a + 0x10000 * b + 0x100 * c + d); + } + return 1; +} + static int readinteger1(lua_State *L) { FILE *f = tofile(L); int a = getc(f); @@ -176,6 +230,22 @@ static int readinteger1(lua_State *L) { return 1; } +static int readinteger1_s(lua_State *L) { + size_t l; + const char *s = luaL_checklstring(L, 1, &l); + size_t p = luaL_checkinteger(L, 2) - 1; + if (p < 0 || p >= l) { + lua_pushnil(L); + } else { + int a = uchar(s[p]); + if (a >= 0x80) + lua_pushinteger(L, a - 0x100); + else + lua_pushinteger(L, a); + } + return 1; +} + static int readinteger2(lua_State *L) { FILE *f = tofile(L); int a = getc(f); @@ -189,6 +259,23 @@ static int readinteger2(lua_State *L) { return 1; } +static int readinteger2_s(lua_State *L) { + size_t l; + const char *s = luaL_checklstring(L, 1, &l); + size_t p = luaL_checkinteger(L, 2) - 1; + if (p < 0 || p+1 >= l) { + lua_pushnil(L); + } else { + int a = uchar(s[p++]); + int b = uchar(s[p]); + if (a >= 0x80) + lua_pushinteger(L, 0x100 * a + b - 0x10000); + else + lua_pushinteger(L, 0x100 * a + b); + } + return 1; +} + static int readinteger3(lua_State *L) { FILE *f = tofile(L); int a = getc(f); @@ -203,6 +290,24 @@ static int readinteger3(lua_State *L) { return 1; } +static int readinteger3_s(lua_State *L) { + size_t l; + const char *s = luaL_checklstring(L, 1, &l); + size_t p = luaL_checkinteger(L, 2) - 1; + if (p < 0 || p+2 >= l) { + lua_pushnil(L); + } else { + int a = uchar(s[p++]); + int b = uchar(s[p++]); + int c = uchar(s[p]); + if (a >= 0x80) + lua_pushinteger(L, 0x10000 * a + 0x100 * b + c - 0x1000000); + else + lua_pushinteger(L, 0x10000 * a + 0x100 * b + c); + } + return 1; +} + static int readinteger4(lua_State *L) { FILE *f = tofile(L); int a = getc(f); @@ -218,6 +323,25 @@ static int readinteger4(lua_State *L) { return 1; } +static int readinteger4_s(lua_State *L) { + size_t l; + const char *s = luaL_checklstring(L, 1, &l); + size_t p = luaL_checkinteger(L, 2) - 1; + if (p < 0 || p+3 >= l) { + lua_pushnil(L); + } else { + int a = uchar(s[p++]); + int b = uchar(s[p++]); + int c = uchar(s[p++]); + int d = uchar(s[p]); + if (a >= 0x80) + lua_pushinteger(L, 0x1000000 * a + 0x10000 * b + 0x100 * c + d - 0x100000000); + else + lua_pushinteger(L, 0x1000000 * a + 0x10000 * b + 0x100 * c + d); + } + return 1; +} + static int readfixed2(lua_State *L) { FILE *f = tofile(L); int a = getc(f); @@ -225,9 +349,26 @@ static int readfixed2(lua_State *L) { if (b == EOF) lua_pushnil(L); else if (a >= 0x80) - lua_pushinteger(L, a + b/0xFFFF - 0x100); + lua_pushinteger(L, (a - 0x100) + b/0x100); else - lua_pushinteger(L, a + b/0xFFFF); + lua_pushinteger(L, (a ) + b/0x100); + return 1; +} + +static int readfixed2_s(lua_State *L) { + size_t l; + const char *s = luaL_checklstring(L, 1, &l); + size_t p = luaL_checkinteger(L, 2) - 1; + if (p < 0 || p+3 >= l) { + lua_pushnil(L); + } else { + int a = uchar(s[p++]); + int b = uchar(s[p]); + if (a >= 0x80) + lua_pushinteger(L, (a - 0x100) + b/0x100); + else + lua_pushinteger(L, (a ) + b/0x100); + } return 1; } @@ -240,15 +381,34 @@ static int readfixed4(lua_State *L) { if (d == EOF) lua_pushnil(L); else if (a >= 0x80) - lua_pushnumber(L, (0x1000000 * a + 0x10000 * b + 0x100 * c + d - 0x100000000)/65536.0); + lua_pushnumber(L, (0x100 * a + b - 0x10000) + (0x100 * c + d)/0x10000); else - lua_pushnumber(L, (0x1000000 * a + 0x10000 * b + 0x100 * c + d)/65536.0); + lua_pushnumber(L, (0x100 * a + b ) + (0x100 * c + d)/0x10000); /* from ff */ /* int n = 0x1000000 * a + 0x10000 * b + 0x100 * c + d; */ /* lua_pushnumber(L,(real) (n>>16) + ((n&0xffff)/65536.0)); */ return 1; } +static int readfixed4_s(lua_State *L) { + size_t l; + const char *s = luaL_checklstring(L, 1, &l); + size_t p = luaL_checkinteger(L, 2) - 1; + if (p < 0 || p+3 >= l) { + lua_pushnil(L); + } else { + int a = uchar(s[p++]); + int b = uchar(s[p++]); + int c = uchar(s[p++]); + int d = uchar(s[p]); + if (a >= 0x80) + lua_pushnumber(L, (0x100 * a + b - 0x10000) + (0x100 * c + d)/0x10000); + else + lua_pushnumber(L, (0x100 * a + b ) + (0x100 * c + d)/0x10000); + } + return 1; +} + static int read2dot14(lua_State *L) { FILE *f = tofile(L); int a = getc(f); @@ -263,6 +423,21 @@ static int read2dot14(lua_State *L) { return 1; } +static int read2dot14_s(lua_State *L) { + size_t l; + const char *s = luaL_checklstring(L, 1, &l); + size_t p = luaL_checkinteger(L, 2) - 1; + if (p < 0 || p+1 >= l) { + lua_pushnil(L); + } else { + int a = uchar(s[p++]); + int b = uchar(s[p]); + int n = 0x100 * a + b; + lua_pushnumber(L,(real) ((n<<16)>>(16+14)) + ((n&0x3fff)/16384.0)); + } + return 1; +} + static int getposition(lua_State *L) { FILE *f = tofile(L); long p = ftell(f); @@ -317,6 +492,28 @@ static int readbytetable(lua_State *L) { return 1; } +static int readbytetable_s(lua_State *L) { + size_t l; + const char *s = luaL_checklstring(L, 1, &l); + size_t p = luaL_checkinteger(L, 2) - 1; + int n = lua_tointeger(L,3); + if (p < 0 || p >= l) { + lua_pushnil(L); + } else { + int i ; + if (p + n >= l) { + n = l - p ; + } + lua_createtable(L, n, 0); + for (i=1;i<=n;i++) { + int a = uchar(s[p++]); + lua_pushinteger(L, a); + lua_rawseti(L,-2,i); + } + } + return 1; +} + static int readbytes(lua_State *L) { FILE *f = tofile(L); int n = lua_tointeger(L,2); @@ -332,6 +529,27 @@ static int readbytes(lua_State *L) { return n; } +static int readbytes_s(lua_State *L) { + size_t l; + const char *s = luaL_checklstring(L, 1, &l); + size_t p = luaL_checkinteger(L, 2) - 1; + int n = lua_tointeger(L,3); + if (p < 0 || p >= l) { + return 0; + } else { + int i ; + if (p + n >= l) { + n = l - p ; + } + lua_createtable(L, n, 0); + for (i=1;i<=n;i++) { + int a = uchar(s[p++]); + lua_pushinteger(L, a); + } + return n; + } +} + static int recordfilename(lua_State *L) { const char *fname = luaL_checkstring(L, 1); @@ -448,7 +666,35 @@ static const luaL_Reg fiolib[] = { {NULL, NULL} }; +static const luaL_Reg siolib[] = { + { "readcardinal1", readcardinal1_s }, + { "readcardinal2", readcardinal2_s }, + { "readcardinal3", readcardinal3_s }, + { "readcardinal4", readcardinal4_s }, + { "readinteger1", readinteger1_s }, + { "readinteger2", readinteger2_s }, + { "readinteger3", readinteger3_s }, + { "readinteger4", readinteger4_s }, + { "readfixed2", readfixed2_s }, + { "readfixed4", readfixed4_s }, + { "read2dot14", read2dot14_s }, + { "readbytes", readbytes_s }, + { "readbytetable", readbytetable_s }, + /* done */ + {NULL, NULL} +}; + +/* + The sio helpers are experimental and might be handy at some point. Speed-wise + there is no gain over file access because with ssd and caching we basically + operate in memory too. We keep them as complement to the file ones. I did + consider using an userdata object for the position etc but some simple tests + demonstrated that there is no real gain and the current ones permits to wrap + up whatever interface one likes. +*/ + int luaopen_fio(lua_State *L) { luaL_register(L, "fio", fiolib); + luaL_register(L, "sio", siolib); return 1; } diff --git a/source/texk/web2c/luatexdir/lua/lnodelib.c b/source/texk/web2c/luatexdir/lua/lnodelib.c index 49929fa27926e5c1db04dfd2f75f6ddc7c328f20..eeb93b3a09b7b38b67300c8e5211ac6eb3e1f4d4 100644 --- a/source/texk/web2c/luatexdir/lua/lnodelib.c +++ b/source/texk/web2c/luatexdir/lua/lnodelib.c @@ -268,6 +268,19 @@ static int get_valid_node_subtype_id(lua_State * L, int n) return i; } +/* enable fixer ... more fixers can be added in the future */ + +static int lua_nodelib_fix_node_lists(lua_State * L) +{ + if (lua_type(L, -1) == LUA_TBOOLEAN) { + fix_node_lists = lua_toboolean(L,-1); + } else if (lua_type(L, -1) == LUA_TNUMBER) { + fix_node_lists = lua_tointeger(L,-1); + } + return 0; +} + + /* two simple helpers to speed up and simplify lua code (replaced by getnext and getprev) */ static int lua_nodelib_next(lua_State * L) @@ -3198,7 +3211,7 @@ static int lua_nodelib_set_glue(lua_State * L) stretch_order(n) = ((top > 4 && lua_type(L, 5) == LUA_TNUMBER)) ? lua_tointeger(L,5) : 0; shrink_order(n) = ((top > 5 && lua_type(L, 6) == LUA_TNUMBER)) ? lua_tointeger(L,6) : 0; } - return 0; + return 0; } return luaL_error(L, "glue (spec) expected"); } @@ -7588,6 +7601,99 @@ static int lua_nodelib_check_discretionary(lua_State * L) { return 0; } +/* synctex but not */ + +static int lua_nodelib_set_synctex_mode(lua_State * L) +{ + halfword mode = lua_tointeger(L, 1); + synctex_set_mode(mode); + return 0; +} + +static int lua_nodelib_set_synctex_tag(lua_State * L) +{ + halfword tag = lua_tointeger(L, 1); + synctex_set_tag(tag); + return 0; +} + +static int lua_nodelib_set_synctex_line(lua_State * L) +{ + halfword line = lua_tointeger(L, 1); + synctex_set_line(line); + return 0; +} + +static int lua_nodelib_direct_set_synctex_fields(lua_State * L) +{ + halfword n = lua_tointeger(L, 1); + halfword tag = lua_tointeger(L, 2); + halfword line = lua_tointeger(L, 3); + if (n != null) { + switch (type(n)) { + case math_node: + if (tag) synctex_tag_math(n) = tag; + if (line) synctex_line_math(n) = line; + break; + case glue_node: + if (tag) synctex_tag_glue(n) = tag; + if (line) synctex_line_glue(n) = line; + break; + case kern_node: + if (tag) synctex_tag_kern(n) = tag; + if (line) synctex_line_kern(n) = line; + break; + case hlist_node: + case vlist_node: + case unset_node: + if (tag) synctex_tag_box(n) = tag; + if (line) synctex_line_box(n) = line; + break; + case rule_node: + if (tag) synctex_tag_rule(n) = tag; + if (line) synctex_line_rule(n) = line; + break; + } + } + return 0; +} + +static int lua_nodelib_direct_get_synctex_fields(lua_State * L) +{ + halfword n = lua_tointeger(L, 1); + if (n != null) { + switch (type(n)) { + case math_node: + lua_pushinteger(L,synctex_tag_math(n)); + lua_pushinteger(L,synctex_line_math(n)); + break; + case glue_node: + lua_pushinteger(L,synctex_tag_glue(n)); + lua_pushinteger(L,synctex_line_glue(n)); + break; + case kern_node: + lua_pushinteger(L,synctex_tag_kern(n)); + lua_pushinteger(L,synctex_line_kern(n)); + break; + case hlist_node: + case vlist_node: + case unset_node: + lua_pushinteger(L,synctex_tag_box(n)); + lua_pushinteger(L,synctex_line_box(n)); + break; + case rule_node: + lua_pushinteger(L,synctex_tag_rule(n)); + lua_pushinteger(L,synctex_line_rule(n)); + break; + } + return 2; + } else { + return 0; + } +} + +/* done */ + static const struct luaL_Reg nodelib_p[] = { {"__index", lua_nodelib_get_property_t}, {"__newindex", lua_nodelib_set_property_t}, @@ -7733,6 +7839,9 @@ static const struct luaL_Reg direct_nodelib_f[] = { {"check_discretionary", lua_nodelib_direct_check_discretionary}, {"check_discretionaries", lua_nodelib_direct_check_discretionaries}, /* done */ + {"set_synctex_fields", lua_nodelib_direct_set_synctex_fields}, + {"get_synctex_fields", lua_nodelib_direct_get_synctex_fields}, + /* done */ {NULL, NULL} /* sentinel */ }; @@ -7824,6 +7933,13 @@ static const struct luaL_Reg nodelib_f[] = { {"check_discretionary", lua_nodelib_check_discretionary}, {"check_discretionaries", lua_nodelib_check_discretionaries}, /* done */ + {"set_synctex_mode", lua_nodelib_set_synctex_mode}, + {"set_synctex_tag", lua_nodelib_set_synctex_tag}, + {"set_synctex_line", lua_nodelib_set_synctex_line}, + /* {"set_synctex_fields", lua_nodelib_set_synctex_fields}, */ + /* {"get_synctex_fields", lua_nodelib_get_synctex_fields}, */ + /* done */ + {"fix_node_lists", lua_nodelib_fix_node_lists}, {NULL, NULL} /* sentinel */ }; diff --git a/source/texk/web2c/luatexdir/lua/luanode.w b/source/texk/web2c/luatexdir/lua/luanode.w index af15748bacd6392a217ea520da44347505c32870..c09cac1ff01b4ecef0c8bd89805110ea02070384 100644 --- a/source/texk/web2c/luatexdir/lua/luanode.w +++ b/source/texk/web2c/luatexdir/lua/luanode.w @@ -96,21 +96,18 @@ void lua_node_filter(int filterid, int extrainfo, halfword head_node, halfword * start_node = vlink(head_node); if (start_node != null) { /* maybe just always slide (harmless and fast) */ - last_node = vlink(start_node); if (fix_node_lists) { - while (last_node != null) { - alink(last_node) = start_node; - start_node = last_node; - last_node = vlink(start_node); - } + /* slides and returns last node */ + *tail_node = fix_node_list(start_node); } else { + last_node = vlink(start_node); while (last_node != null) { start_node = last_node; last_node = vlink(start_node); } + /* we're at the end now */ + *tail_node = start_node; } - /* we're at the end now */ - *tail_node = start_node; } else { /* we're already at the end */ *tail_node = head_node; diff --git a/source/texk/web2c/luatexdir/luatex.c b/source/texk/web2c/luatexdir/luatex.c index 3eba56679b8d1e9e2d088b321f031c55cd0f9509..fac1851d9eafcbc15efd5c71500200b97511a1c7 100644 --- a/source/texk/web2c/luatexdir/luatex.c +++ b/source/texk/web2c/luatexdir/luatex.c @@ -29,9 +29,9 @@ #define TeX int luatex_version = 100; /* \.{\\luatexversion} */ -int luatex_revision = '4'; /* \.{\\luatexrevision} */ -int luatex_date_info = 2017033109; /* the compile date is now hardwired :YEAR MONTH DAY HOUR*/ -const char *luatex_version_string = "1.0.4"; +int luatex_revision = '5'; /* \.{\\luatexrevision} */ +int luatex_date_info = 2017033110; /* the compile date is now hardwired :YEAR MONTH DAY HOUR*/ +const char *luatex_version_string = "1.0.5"; const char *engine_name = my_name; /* the name of this engine */ #include <kpathsea/c-ctype.h> diff --git a/source/texk/web2c/luatexdir/tex/commands.w b/source/texk/web2c/luatexdir/tex/commands.w index 84235914c64a269e989dcd12f6e2611feeea99c1..27c5ac9cea644792abdfb32958209e5bbfc65a25 100644 --- a/source/texk/web2c/luatexdir/tex/commands.w +++ b/source/texk/web2c/luatexdir/tex/commands.w @@ -160,6 +160,7 @@ void initialize_commands(void) primitive_luatex("hyphenpenaltymode", assign_int_cmd, int_base + hyphen_penalty_mode_code, int_base); primitive_luatex("automatichyphenpenalty", assign_int_cmd, int_base + automatic_hyphen_penalty_code, int_base); primitive_luatex("explicithyphenpenalty", assign_int_cmd, int_base + explicit_hyphen_penalty_code, int_base); + primitive_luatex("automatichyphenmode", assign_int_cmd, int_base + automatic_hyphen_mode_code, int_base); /* Many of \TeX's primitives need no |equiv|, since they are identifiable by their |eq_type| alone. These primitives are loaded into the hash table @@ -445,8 +446,10 @@ void initialize_commands(void) primitive_tex("unhcopy", un_hbox_cmd, copy_code, 0); primitive_tex("unvbox", un_vbox_cmd, box_code, 0); primitive_tex("unvcopy", un_vbox_cmd, copy_code, 0); - primitive_tex("-", discretionary_cmd, explicit_disc, 0); + primitive_tex("-", discretionary_cmd, explicit_disc, 0); /* good old tex */ primitive_tex("discretionary", discretionary_cmd, discretionary_disc, 0); + primitive_luatex("explicitdiscretionary", discretionary_cmd, explicit_disc, 0); + primitive_luatex("automaticdiscretionary", discretionary_cmd, automatic_disc, 0); primitive_luatex("localleftbox", assign_local_box_cmd, 0, 0); primitive_luatex("localrightbox", assign_local_box_cmd, 1, 0); diff --git a/source/texk/web2c/luatexdir/tex/dumpdata.w b/source/texk/web2c/luatexdir/tex/dumpdata.w index aa0d1655d6dce960eee38bf71180f03efd350167..4f8b1fc896a08e9af5bd3ee09a686d474c983861 100644 --- a/source/texk/web2c/luatexdir/tex/dumpdata.w +++ b/source/texk/web2c/luatexdir/tex/dumpdata.w @@ -23,7 +23,7 @@ /* we start with 907: the sum of the values of the bytes of "don knuth" */ -#define FORMAT_ID (907+28) +#define FORMAT_ID (907+29) #if ((FORMAT_ID>=0) && (FORMAT_ID<=256)) #error Wrong value for FORMAT_ID. #endif diff --git a/source/texk/web2c/luatexdir/tex/equivalents.h b/source/texk/web2c/luatexdir/tex/equivalents.h index d7ca036e25afa8caa832a79e3d0526b7c7396441..a853f55872c37c5a28ea786947e747758430a6c0 100644 --- a/source/texk/web2c/luatexdir/tex/equivalents.h +++ b/source/texk/web2c/luatexdir/tex/equivalents.h @@ -291,6 +291,7 @@ the |number_regs| \.{\\dimen} registers. # define hyphen_penalty_mode_code 100 # define automatic_hyphen_penalty_code 101 # define explicit_hyphen_penalty_code 102 +# define automatic_hyphen_mode_code 103 # define math_option_code (explicit_hyphen_penalty_code+1) @@ -773,6 +774,7 @@ extern halfword last_cs_name; #define hyphen_penalty_mode_par int_par(hyphen_penalty_mode_code) #define automatic_hyphen_penalty_par int_par(automatic_hyphen_penalty_code) #define explicit_hyphen_penalty_par int_par(explicit_hyphen_penalty_code) +#define automatic_hyphen_mode_par int_par(automatic_hyphen_mode_code) #define cur_lang_par int_par(cur_lang_code) #define cur_font_par equiv(cur_font_loc) diff --git a/source/texk/web2c/luatexdir/tex/maincontrol.w b/source/texk/web2c/luatexdir/tex/maincontrol.w index 0baba872e8e90622fa2d8a8f6bb165d832259936..1d8b020cf0a2f1d19c4de3d6112f872a42d03bab 100644 --- a/source/texk/web2c/luatexdir/tex/maincontrol.w +++ b/source/texk/web2c/luatexdir/tex/maincontrol.w @@ -1759,18 +1759,42 @@ void append_discretionary(void) if (cur_chr == explicit_disc) { /* \- */ c = get_pre_hyphen_char(cur_lang_par); - if (c != 0) { + if (c > 0) { vlink(pre_break(tail)) = new_char(equiv(cur_font_loc), c); alink(vlink(pre_break(tail))) = pre_break(tail); tlink(pre_break(tail)) = vlink(pre_break(tail)); } c = get_post_hyphen_char(cur_lang_par); - if (c != 0) { + if (c > 0) { vlink(post_break(tail)) = new_char(equiv(cur_font_loc), c); alink(vlink(post_break(tail))) = post_break(tail); tlink(post_break(tail)) = vlink(post_break(tail)); } set_explicit_disc_penalty(tail); + } else if (cur_chr == automatic_disc) { + /* - as done in hyphenator */ + c = get_pre_exhyphen_char(cur_lang_par); + if (c <= 0) { + c = ex_hyphen_char_par; + } + if (c > 0) { + vlink(pre_break(tail)) = new_char(equiv(cur_font_loc), c); + alink(vlink(pre_break(tail))) = pre_break(tail); + tlink(pre_break(tail)) = vlink(pre_break(tail)); + } + c = get_post_exhyphen_char(cur_lang_par); + if (c > 0) { + vlink(post_break(tail)) = new_char(equiv(cur_font_loc), c); + alink(vlink(post_break(tail))) = post_break(tail); + tlink(post_break(tail)) = vlink(post_break(tail)); + } + c = ex_hyphen_char_par; + if (c > 0) { + vlink(no_break(tail)) = new_char(equiv(cur_font_loc), c); + alink(vlink(no_break(tail))) = no_break(tail); + tlink(no_break(tail)) = vlink(no_break(tail)); + } + set_automatic_disc_penalty(tail); } else { /* \discretionary */ if (scan_keyword("penalty")) { diff --git a/source/texk/web2c/luatexdir/tex/texfileio.w b/source/texk/web2c/luatexdir/tex/texfileio.w index 2281de12c4c858652b47a963712898c5e9ba46ec..c1610d10d904353743b98053ca593235b7e21e37 100644 --- a/source/texk/web2c/luatexdir/tex/texfileio.w +++ b/source/texk/web2c/luatexdir/tex/texfileio.w @@ -967,8 +967,9 @@ void start_input(void) update_terminal(); istate = new_line; /* Prepare new file {\sl Sync\TeX} information */ - synctexstartinput(); /* Give control to the {\sl Sync\TeX} controller */ - + if (synctex_par) { + synctexstartinput(); /* Give control to the {\sl Sync\TeX} controller */ + } /* Read the first line of the new file */ /* Here we have to remember to tell the |lua_input_ln| routine not to start with a |get|. If the file is empty, it is considered to diff --git a/source/texk/web2c/luatexdir/tex/texnodes.h b/source/texk/web2c/luatexdir/tex/texnodes.h index b838dd0a2f95570e01d5fd5575de8d8d3ae2b8be..bc21d52603313c653b272251fa13940c998e6606 100644 --- a/source/texk/web2c/luatexdir/tex/texnodes.h +++ b/source/texk/web2c/luatexdir/tex/texnodes.h @@ -23,19 +23,6 @@ #ifndef __NODES_H__ # define __NODES_H__ -/* these are in texlang.c */ - -# define set_vlink(a,b) vlink(a)=b -# define get_vlink(a) vlink(a) -# define get_character(a) character(a) - -extern halfword insert_discretionary(halfword t, halfword pre, halfword post, halfword replace, int penalty); -extern halfword insert_syllable_discretionary(halfword t, lang_variables * lan); -extern halfword insert_word_discretionary(halfword t, lang_variables * lan); -extern halfword insert_complex_discretionary(halfword t, lang_variables * lan, halfword pre, halfword post, halfword replace); -extern halfword insert_character(halfword t, int n); -extern void set_disc_field(halfword f, halfword t); - # define varmemcast(a) (memory_word *)(a) extern memory_word *volatile varmem; @@ -928,7 +915,7 @@ extern halfword do_copy_node_list(halfword, halfword); extern halfword copy_node_list(halfword); extern halfword copy_node(const halfword); extern void check_node(halfword); -extern void fix_node_list(halfword); +extern halfword fix_node_list(halfword); extern int fix_node_lists; extern char *sprint_node_mem_usage(void); extern halfword raw_glyph_node(void); @@ -1013,5 +1000,9 @@ extern int lua_properties_use_metatable ; extern halfword make_local_par_node(int mode); +extern void synctex_set_mode(int mode); +extern void synctex_set_tag(int tag); +extern void synctex_set_line(int line); + #endif diff --git a/source/texk/web2c/luatexdir/tex/texnodes.w b/source/texk/web2c/luatexdir/tex/texnodes.w index 7967006ec35986ec79b4a9754d2318f6c5675385..6a467e11545c42384ea61fe446e506fbc26727a1 100644 --- a/source/texk/web2c/luatexdir/tex/texnodes.w +++ b/source/texk/web2c/luatexdir/tex/texnodes.w @@ -827,6 +827,25 @@ static int copy_error(halfword p) return 0; } +@ @c +static halfword synctex_anyway_mode = 0; +static halfword synctex_line_field = 0; + +void synctex_set_mode(int m) +{ + synctex_anyway_mode = m; +}; + +void synctex_set_tag(int t) +{ + cur_input.synctex_tag_field = t; +}; + +void synctex_set_line(int l) +{ + synctex_line_field = l; +}; + @ @c halfword new_node(int i, int j) { @@ -892,7 +911,32 @@ halfword new_node(int i, int j) default: break; } - if (synctex_par) { + if (synctex_anyway_mode) { + switch (i) { + case math_node: + synctex_tag_math(n) = cur_input.synctex_tag_field; + synctex_line_math(n) = (synctex_line_field) ? synctex_line_field : line; + break; + case glue_node: + synctex_tag_glue(n) = cur_input.synctex_tag_field; + synctex_line_glue(n) = (synctex_line_field) ? synctex_line_field : line; + break; + case kern_node: + synctex_tag_kern(n) = cur_input.synctex_tag_field; + synctex_line_kern(n) = (synctex_line_field) ? synctex_line_field : line; + break; + case hlist_node: + case vlist_node: + case unset_node: + synctex_tag_box(n) = cur_input.synctex_tag_field; + synctex_line_box(n) = (synctex_line_field) ? synctex_line_field : line; + break; + case rule_node: + synctex_tag_rule(n) = cur_input.synctex_tag_field; + synctex_line_rule(n) = (synctex_line_field) ? synctex_line_field : line; + break; + } + } else if (synctex_par) { /* handle synctex extension */ switch (i) { case math_node: @@ -1718,18 +1762,19 @@ void check_node(halfword p) } @ @c -void fix_node_list(halfword head) +halfword fix_node_list(halfword head) { - halfword p, q; + halfword next, tail; if (head == null) - return; - p = head; - q = vlink(p); - while (q != null) { - alink(q) = p; - p = q; - q = vlink(p); + return null; + tail = head; + next = vlink(head); + while (next != null) { + alink(next) = tail; + tail = next; + next = vlink(tail); } + return tail; } @ @c