/* See license.txt in the root of this project. */ # include "luametatex.h" /*tex This module contains experimental code, used in \CONTEXT\ (exclusively) and it is not part of the game. The functionality might change and even disappear. So we don't document it apart from usage in \CONTEXT. In spite of what one might expect, the gain in using \CCODE\ instead of \LUA\ is not always what one expects, also because many features of \CONTEXT\ seldom kick in. Many \LUAMETATEX\ features only make sense in \CONTEXT, and the following definitely fit into that category. */ /*tex Maybe we should just assume a flattened list so that we don't need a nested call. */ typedef struct profiling_specification { /* specification */ scaled maximum; scaled step; scaled margin; int method; /* state */ scaledwhd whd; scaled position; scaled width; halfword parent; } profiling_specification; static void helperlib_aux_resetprofile(profiling_specification *profile) { memset(profile, 0, sizeof(profiling_specification)); } static void helperlib_aux_getprofile(lua_State *L, profiling_specification *profile, halfword current) { while (current) { switch (node_type(current)) { case glyph_node: profile->whd.wd = tex_glyph_width(current); profile->whd.ht = tex_glyph_height(current); profile->whd.dp = tex_glyph_depth(current); break; case kern_node: profile->whd.wd = kern_amount(current); profile->whd.ht = 0; profile->whd.dp = 0; break; case disc_node: if (disc_no_break_head(current)) { helperlib_aux_getprofile(L, profile, disc_no_break_head(current)); } else { profile->whd.wd = 0; // not needed profile->whd.ht = 0; // not needed profile->whd.dp = 0; // not needed } goto DONE; case glue_node: profile->whd.wd = tex_effective_glue(profile->parent, current); if (is_leader(current)) { halfword leader = glue_leader_ptr(current); if (leader) { /* can be a helper */ switch (node_type(leader)) { case hlist_node: case vlist_node: profile->whd.ht = box_height(leader); profile->whd.dp = box_depth(leader); break; case rule_node: if (node_subtype(leader) == strut_rule_code) { profile->whd.ht = 0; profile->whd.dp = 0; } else { profile->whd.ht = rule_height(leader); profile->whd.dp = rule_depth(leader); } break; case glyph_node: profile->whd.ht = tex_glyph_height(leader); profile->whd.dp = tex_glyph_depth(leader); break; default: profile->whd.ht = 0; profile->whd.dp = 0; break; } } else { profile->whd.ht = 0; profile->whd.dp = 0; } } else { profile->whd.ht = 0; profile->whd.dp = 0; } break; case hlist_node: profile->whd.wd = box_width(current); if (box_options(current) & box_option_no_profiling) { profile->whd.ht = 0; profile->whd.dp = 0; } else { profile->whd.ht = box_height(current) - box_shift_amount(current); profile->whd.dp = box_depth(current) + box_shift_amount(current); } break; case vlist_node: profile->whd.wd = box_width(current); profile->whd.ht = box_height(current) - box_shift_amount(current); profile->whd.dp = box_depth(current) + box_shift_amount(current); break; case rule_node: profile->whd.wd = rule_width(current); if (node_subtype(current) == strut_rule_code) { profile->whd.ht = 0; profile->whd.dp = 0; } else { profile->whd.ht = rule_height(current); profile->whd.dp = rule_depth(current); } break; case math_node: if (tex_math_glue_is_zero(current) || tex_ignore_math_skip(current)) { profile->whd.wd = math_surround(current); } else { profile->whd.wd = tex_effective_glue(profile->parent, current); } profile->whd.ht = 0; profile->whd.dp = 0; break; default: profile->whd.ht = 0; // not needed profile->whd.wd = 0; // not needed profile->whd.dp = 0; // not needed goto DONE; } profile->position = profile->width; profile->width = profile->position + profile->whd.wd; { // scaled p = lround((double) (profile->position - profile->margin) / profile->step); // scaled w = lround((double) (profile->width + profile->margin) / profile->step); scaled p = floor((double) (profile->position - profile->margin)/profile->step + 0.5); scaled w = floor((double) (profile->width + profile->margin)/profile->step - 0.5); if (p < 0) { p = 0; } if (w < 0) { w = 0; } if (p > w) { scaled t = w; w = p; p = t; } if (w > profile->maximum) { for (int i = profile->maximum + 1; i <= w + 1; i++) { lua_pushinteger(L, 0); lua_rawseti(L, -2, i); } profile->maximum = w; } for (int i = p; i <= w; i++) { /*tex some inefficient horror: it would be nice to have a direct integer fetch. */ scaled what = 0; lua_rawgeti(L, -1, i); what = lmt_toscaled(L, -1); lua_pop(L, 1); if (profile->method == 1) { if (profile->whd.dp > what) { lua_pushinteger(L, profile->whd.dp); lua_rawseti(L, -2, i); } } else { if (profile->whd.ht > what) { lua_pushinteger(L, profile->whd.ht); lua_rawseti(L, -2, i); } } } } DONE: current = node_next(current); } profile->whd.wd = 0; // not needed profile->whd.ht = 0; // not needed profile->whd.dp = 0; // not needed } static int helperlib_getprofile(lua_State *L) { halfword line = lmt_check_isdirect(L, 1); halfword list = lmt_check_isdirect(L, 2); if (line && list && lua_gettop(L) == 3 && lua_type(L, 3) == LUA_TTABLE) { profiling_specification profile; helperlib_aux_resetprofile(&profile); set_numeric_field_by_index(profile.step, step, 0); set_numeric_field_by_index(profile.margin, margin, 0); set_numeric_field_by_index(profile.maximum, maximum, 0); set_numeric_field_by_index(profile.method, method, 0); if (profile.step > 0 && profile.margin > 0 && profile.maximum > 0) { profile.parent = line; lua_createtable(L, profile.maximum + 2, 1); for (int i = 0; i <= profile.maximum + 2; i++) { lua_pushinteger(L, 0); lua_rawseti(L, -2, i); } helperlib_aux_getprofile(L, &profile, list); lua_pushinteger(L, profile.maximum); return 2; } } lua_pushnil(L); lua_pushnil(L); return 2; } /* */ typedef int (*snapping_action) (halfword, halfword, snapping_specification*); static int helperlib_aux_snap(lua_State *L, snapping_action action) { halfword first = lmt_check_isdirect(L, 1); halfword last = lmt_check_isdirect(L, 2); if (first && lua_gettop(L) == 3 && lua_type(L, 3) == LUA_TTABLE) { snapping_specification snap; tex_snapping_reset(&snap); set_numeric_field_by_index(snap.method, method, 0); if (tex_snapping_needed(&snap)) { set_numeric_field_by_index(snap.height, height, 0); set_numeric_field_by_index(snap.depth, depth, 0); set_numeric_field_by_index(snap.top, top, 0); set_numeric_field_by_index(snap.bottom, bottom, 0); return action(first, last, &snap); } } return 0; } static int helperlib_snaplist(lua_State *L) { lua_pushboolean(L, helperlib_aux_snap(L, &tex_snapping_content)); return 1; } static int helperlib_snapindeed(lua_State *L) { lua_pushboolean(L, helperlib_aux_snap(L, &tex_snapping_indeed)); return 1; } /* */ /* The table is at index 2! */ static halfword helperlib_aux_mathprocessed(lua_State *L, halfword id, halfword start, halfword n, halfword parent, int *done, halfword *newstart, halfword *newinitial ) { lua_rawgeti(L, 2, id); if (lua_type(L, -1) == LUA_TFUNCTION) { int top = lua_gettop(L); lua_pushinteger(L, start); lua_pushvalue(L, -1); lua_pushinteger(L, n); lua_pushinteger(L, parent); lua_call(L, 4, 3); *done = lua_toboolean(L, -1); *newstart = lmt_opthalfword(L, -2, 0); *newinitial = lmt_opthalfword(L, -2, 0); lua_settop(L, top - 1); return 1; } else { lua_pop(L, 1); return 0; } } static halfword helperlib_aux_mathprocess(lua_State *L, halfword start, halfword n, halfword parent) { halfword initial = start; n = n < 0 ? 0 : n + 1; while (start) { halfword noad = null; halfword id = node_type(start); int done; halfword newstart, newinitial; /* todo: add tracing option trace(start,id,n) */ // if trace_processing then // if id == noad_code then // report_processing("%w%S, class %a",n*2,nutstring(start),classes[getsubtype(start)]) // elseif id == mathchar_code then // local char, font, fam = getcharspec(start) // report_processing("%w%S, family %a, font %a, char %a, shape %c",n*2,nutstring(start),fam,font,char,char) // else // report_processing("%w%S",n*2,nutstring(start)) // end // end if (helperlib_aux_mathprocessed(L, id, start, n, parent, &done, &newstart, &newinitial)) { if (newinitial) { initial = newinitial; // temp hack .. we will make all return head if (newstart) { start = newstart; } else { goto DONE; } } else { if (newstart) { start = newstart; } } } else { switch (id) { case simple_noad: case radical_noad: case accent_noad: noad = noad_nucleus(start); if (noad) { helperlib_aux_mathprocess(L, noad, n, start); } noad = noad_supscr(start); if (noad) { helperlib_aux_mathprocess(L, noad, n, start); } noad = noad_subscr(start); if (noad) { helperlib_aux_mathprocess(L, noad, n, start); } noad = noad_supprescr(start); if (noad) { helperlib_aux_mathprocess(L, noad, n, start); } noad = noad_subprescr(start); if (noad) { helperlib_aux_mathprocess(L, noad, n, start); } noad = noad_prime(start); if (noad) { helperlib_aux_mathprocess(L, noad, n, start); } switch (id) { case simple_noad: break; case radical_noad: noad = radical_left_delimiter(start); if (noad) { helperlib_aux_mathprocess(L, noad, n, start); } noad = radical_right_delimiter(start); if (noad) { helperlib_aux_mathprocess(L, noad, n, start); } noad = radical_top_delimiter(start); if (noad) { helperlib_aux_mathprocess(L, noad, n, start); } noad = radical_bottom_delimiter(start); if (noad) { helperlib_aux_mathprocess(L, noad, n, start); } noad = radical_degree(start); if (noad) { helperlib_aux_mathprocess(L, noad, n, start); } break; case accent_noad: noad = accent_top_character(start); if (noad) { helperlib_aux_mathprocess(L, noad, n, start); } noad = accent_middle_character(start); if (noad) { helperlib_aux_mathprocess(L, noad, n, start); } noad = accent_bottom_character(start); if (noad) { helperlib_aux_mathprocess(L, noad, n, start); } break; } break; case math_char_node: case math_text_char_node: case delimiter_node: goto DONE; case sub_box_node: case sub_mlist_node: noad = math_kernel_list(start); if (noad) { helperlib_aux_mathprocess(L, noad, n, start); } break; case fraction_noad: noad = fraction_numerator(start); if (noad) { helperlib_aux_mathprocess(L, noad, n, start); } noad = fraction_denominator(start); if (noad) { helperlib_aux_mathprocess(L, noad, n, start); } noad = fraction_left_delimiter(start); if (noad) { helperlib_aux_mathprocess(L, noad, n, start); } noad = fraction_middle_delimiter(start); if (noad) { helperlib_aux_mathprocess(L, noad, n, start); } noad = fraction_right_delimiter(start); if (noad) { helperlib_aux_mathprocess(L, noad, n, start); } break; case fence_noad: noad = fence_delimiter(start); if (noad) { helperlib_aux_mathprocess(L, noad, n, start); } noad = fence_delimiter_top(start); if (noad) { helperlib_aux_mathprocess(L, noad, n, start); } noad = fence_delimiter_bottom(start); if (noad) { helperlib_aux_mathprocess(L, noad, n, start); } break; case choice_node: noad = choice_display_mlist(start); if (noad) { helperlib_aux_mathprocess(L, noad, n, start); } noad = choice_text_mlist(start); if (noad) { helperlib_aux_mathprocess(L, noad, n, start); } noad = choice_script_mlist(start); if (noad) { helperlib_aux_mathprocess(L, noad, n, start); } noad = choice_script_script_mlist(start); if (noad) { helperlib_aux_mathprocess(L, noad, n, start); } break; } } start = node_next(start); } DONE: return parent ? 0 : initial; // only first level -- for now } static int helperlib_mathprocess(lua_State *L) { halfword start = lmt_check_isdirect(L, 1); if (start && lua_type(L, 2) == LUA_TTABLE) { halfword initial = helperlib_aux_mathprocess(L, start, -1, null); if (initial) { lua_pushinteger(L, initial); return 1; } } lua_pushnil(L); return 1; } static int helperlib_mathnested(lua_State *L) { halfword current = lmt_check_isdirect(L, 1); if (current && lua_type(L, 2) == LUA_TTABLE) { halfword n = lmt_optinteger(L, 3, -1); halfword id = node_type(current); halfword noad; switch (id) { case simple_noad: case radical_noad: case accent_noad: noad = noad_nucleus(current); if (noad) { helperlib_aux_mathprocess(L, noad, n, current); } noad = noad_supscr(current); if (noad) { helperlib_aux_mathprocess(L, noad, n, current); } noad = noad_subscr(current); if (noad) { helperlib_aux_mathprocess(L, noad, n, current); } noad = noad_supprescr(current); if (noad) { helperlib_aux_mathprocess(L, noad, n, current); } noad = noad_subprescr(current); if (noad) { helperlib_aux_mathprocess(L, noad, n, current); } noad = noad_prime(current); if (noad) { helperlib_aux_mathprocess(L, noad, n, current); } switch (id) { case simple_noad: break; case radical_noad: noad = radical_left_delimiter(current); if (noad) { helperlib_aux_mathprocess(L, noad, n, current); } noad = radical_right_delimiter(current); if (noad) { helperlib_aux_mathprocess(L, noad, n, current); } noad = radical_top_delimiter(current); if (noad) { helperlib_aux_mathprocess(L, noad, n, current); } noad = radical_bottom_delimiter(current); if (noad) { helperlib_aux_mathprocess(L, noad, n, current); } noad = radical_degree(current); if (noad) { helperlib_aux_mathprocess(L, noad, n, current); } break; case accent_noad: noad = accent_top_character(current); if (noad) { helperlib_aux_mathprocess(L, noad, n, current); } noad = accent_middle_character(current); if (noad) { helperlib_aux_mathprocess(L, noad, n, current); } noad = accent_bottom_character(current); if (noad) { helperlib_aux_mathprocess(L, noad, n, current); } break; } break; case math_char_node: case math_text_char_node: case delimiter_node: break; case sub_box_node: case sub_mlist_node: noad = math_kernel_list(current); if (noad) { helperlib_aux_mathprocess(L, noad, n, current); } break; case fraction_noad: noad = fraction_numerator(current); if (noad) { helperlib_aux_mathprocess(L, noad, n, current); } noad = fraction_denominator(current); if (noad) { helperlib_aux_mathprocess(L, noad, n, current); } noad = fraction_left_delimiter(current); if (noad) { helperlib_aux_mathprocess(L, noad, n, current); } noad = fraction_middle_delimiter(current); if (noad) { helperlib_aux_mathprocess(L, noad, n, current); } noad = fraction_right_delimiter(current); if (noad) { helperlib_aux_mathprocess(L, noad, n, current); } break; case fence_noad: noad = fence_delimiter(current); if (noad) { helperlib_aux_mathprocess(L, noad, n, current); } noad = fence_delimiter_top(current); if (noad) { helperlib_aux_mathprocess(L, noad, n, current); } noad = fence_delimiter_bottom(current); if (noad) { helperlib_aux_mathprocess(L, noad, n, current); } break; case choice_node: noad = choice_display_mlist(current); if (noad) { helperlib_aux_mathprocess(L, noad, n, current); } noad = choice_text_mlist(current); if (noad) { helperlib_aux_mathprocess(L, noad, n, current); } noad = choice_script_mlist(current); if (noad) { helperlib_aux_mathprocess(L, noad, n, current); } noad = choice_script_script_mlist(current); if (noad) { helperlib_aux_mathprocess(L, noad, n, current); } break; } } return 0; } static void helperlib_aux_mathstep(lua_State *L, halfword start, halfword n, halfword parent) { int top = lua_gettop(L); lua_pushinteger(L, start); lua_pushinteger(L, n); lua_pushinteger(L, parent); lua_call(L, 3, 0); lua_settop(L, top - 1); } static int helperlib_mathstep(lua_State *L) { halfword current = lmt_check_isdirect(L, 1); if (current && lua_type(L, 2) == LUA_TFUNCTION) { halfword n = lmt_optinteger(L, 3, -1); halfword id = lmt_optinteger(L, 4, node_type(current)); halfword noad; switch (id) { case simple_noad: case radical_noad: case accent_noad: noad = noad_nucleus(current); if (noad) { helperlib_aux_mathstep(L, noad, n, current); } noad = noad_supscr(current); if (noad) { helperlib_aux_mathstep(L, noad, n, current); } noad = noad_subscr(current); if (noad) { helperlib_aux_mathstep(L, noad, n, current); } noad = noad_supprescr(current); if (noad) { helperlib_aux_mathstep(L, noad, n, current); } noad = noad_subprescr(current); if (noad) { helperlib_aux_mathstep(L, noad, n, current); } noad = noad_prime(current); if (noad) { helperlib_aux_mathstep(L, noad, n, current); } switch (id) { case simple_noad: break; case radical_noad: noad = radical_left_delimiter(current); if (noad) { helperlib_aux_mathstep(L, noad, n, current); } noad = radical_right_delimiter(current); if (noad) { helperlib_aux_mathstep(L, noad, n, current); } noad = radical_top_delimiter(current); if (noad) { helperlib_aux_mathstep(L, noad, n, current); } noad = radical_bottom_delimiter(current); if (noad) { helperlib_aux_mathstep(L, noad, n, current); } noad = radical_degree(current); if (noad) { helperlib_aux_mathstep(L, noad, n, current); } break; case accent_noad: noad = accent_top_character(current); if (noad) { helperlib_aux_mathstep(L, noad, n, current); } noad = accent_middle_character(current); if (noad) { helperlib_aux_mathstep(L, noad, n, current); } noad = accent_bottom_character(current); if (noad) { helperlib_aux_mathstep(L, noad, n, current); } break; } break; case math_char_node: case math_text_char_node: case delimiter_node: break; case sub_box_node: case sub_mlist_node: noad = math_kernel_list(current); if (noad) { helperlib_aux_mathstep(L, noad, n, current); } break; case fraction_noad: noad = fraction_numerator(current); if (noad) { helperlib_aux_mathstep(L, noad, n, current); } noad = fraction_denominator(current); if (noad) { helperlib_aux_mathstep(L, noad, n, current); } noad = fraction_left_delimiter(current); if (noad) { helperlib_aux_mathstep(L, noad, n, current); } noad = fraction_middle_delimiter(current); if (noad) { helperlib_aux_mathstep(L, noad, n, current); } noad = fraction_right_delimiter(current); if (noad) { helperlib_aux_mathstep(L, noad, n, current); } break; case fence_noad: noad = fence_delimiter(current); if (noad) { helperlib_aux_mathstep(L, noad, n, current); } noad = fence_delimiter_top(current); if (noad) { helperlib_aux_mathstep(L, noad, n, current); } noad = fence_delimiter_bottom(current); if (noad) { helperlib_aux_mathstep(L, noad, n, current); } break; case choice_node: noad = choice_display_mlist(current); if (noad) { helperlib_aux_mathstep(L, noad, n, current); } noad = choice_text_mlist(current); if (noad) { helperlib_aux_mathstep(L, noad, n, current); } noad = choice_script_mlist(current); if (noad) { helperlib_aux_mathstep(L, noad, n, current); } noad = choice_script_script_mlist(current); if (noad) { helperlib_aux_mathstep(L, noad, n, current); } break; } } return 0; } /* */ static int helperlib_aux_nil(lua_State *L) { lua_pushnil(L); return 1; } static int helperlib_aux_next_horizontal(lua_State *L) { halfword t; halfword l = null; if (lua_isnil(L, 2)) { t = lmt_tohalfword(L, 1) ; lua_settop(L, 1); } else { t = lmt_tohalfword(L, 2) ; t = node_next(t); lua_settop(L, 2); } while (t) { switch (node_type(t)) { case glyph_node: goto FOUND; case disc_node: if (disc_no_break_head(t)) { goto FOUND; } else { break; } case rule_node: if (rule_width(t) > 0) { goto FOUND; } else { break; } case glue_node: l = glue_leader_ptr(t); if (l) { goto FOUND; } else if (glue_amount(t) || glue_stretch(t) || glue_shrink(t)) { goto FOUND; } else { break; } case kern_node: if (kern_amount(t)) { goto FOUND; } else { break; } case math_node: if (tex_math_glue_is_zero(t) || tex_ignore_math_skip(t)) { if (math_surround(t)) { goto FOUND; } } else if (math_amount(t) || math_stretch(t) || math_shrink(t)) { goto FOUND; } break; case dir_node: goto FOUND; case whatsit_node: goto FOUND; case hlist_node: case vlist_node: l = box_list(t); if (l) { goto FOUND; } else if (box_width(t)) { goto FOUND; } else { break; } default: /* nothing relevant */ break; } t = node_next(t); } lua_pushnil(L); return 1; FOUND: lua_pushinteger(L, t); lua_pushinteger(L, node_type(t)); lua_pushinteger(L, node_subtype(t)); if (l) { lua_pushinteger(L, l); return 4; } else { return 3; } } static int helperlib_traversehorizontal(lua_State *L) { if (lua_isnil(L, 1)) { lua_pushcclosure(L, helperlib_aux_nil, 0); return 1; } else { // halfword n = nodelib_valid_direct_from_index(L, 1); halfword n = lmt_check_isdirect(L, 1); if (n) { lua_pushcclosure(L, helperlib_aux_next_horizontal, 0); lua_pushinteger(L, n); lua_pushnil(L); return 3; } else { lua_pushcclosure(L, helperlib_aux_nil, 0); return 1; } } } static int helperlib_aux_next_vertical(lua_State *L) { halfword t; halfword l = null; if (lua_isnil(L, 2)) { t = lmt_tohalfword(L, 1) ; lua_settop(L, 1); } else { t = lmt_tohalfword(L, 2) ; t = node_next(t); lua_settop(L, 2); } while (t) { switch (node_type(t)) { case rule_node: if ((rule_height(t) + rule_depth(t)) > 0) { goto FOUND; } else { break; } case kern_node: if (kern_amount(t)) { goto FOUND; } else { break; } case glue_node: l = glue_leader_ptr(t); if (l) { goto FOUND; } else if (glue_amount(t) || glue_stretch(t) || glue_shrink(t)) { goto FOUND; } else { break; } case whatsit_node: goto FOUND; case hlist_node: case vlist_node: l = box_list(t); if (l) { goto FOUND; } else if (box_height(t) + box_depth(t)) { goto FOUND; } else { break; } default: /* nothing relevant */ break; } t = node_next(t); } lua_pushnil(L); return 1; FOUND: lua_pushinteger(L, t); lua_pushinteger(L, node_type(t)); lua_pushinteger(L, node_subtype(t)); if (l) { lua_pushinteger(L, l); return 4; } else { return 3; } } static int helperlib_traversevertical(lua_State *L) { if (lua_isnil(L, 1)) { lua_pushcclosure(L, helperlib_aux_nil, 0); return 1; } else { // halfword n = nodelib_valid_direct_from_index(L, 1); halfword n = lmt_check_isdirect(L, 1); if (n) { lua_pushcclosure(L, helperlib_aux_next_vertical, 0); lua_pushinteger(L, n); lua_pushnil(L); return 3; } else { lua_pushcclosure(L, helperlib_aux_nil, 0); return 1; } } } /* */ static int helperlib_aux_next_char_method(lua_State *L) { halfword t; if (lua_isnil(L, 2)) { t = lmt_tohalfword(L, 1) ; lua_settop(L, 1); } else { t = lmt_tohalfword(L, 2) ; t = node_next(t); lua_settop(L, 2); } while (t) { if (node_type(t) == glyph_node && ! glyph_protected(t)) { lua_rawgeti(L, lua_upvalueindex(1), glyph_character(t)); if (lua_type(L, -1) != LUA_TNIL) { lua_pop(L, 1); break; } lua_pop(L, 1); } t = node_next(t); } if (t) { /* 3 has method, 4 gets node, so we need to swap: node, method, char, font */ /* how ? */ lua_pushinteger(L, t); lua_rawgeti(L, lua_upvalueindex(1), glyph_character(t)); // lua_rotate(L, 3, 2); lua_pushinteger(L, glyph_character(t)); lua_pushinteger(L, glyph_font(t)); return 4; } else { lua_pushnil(L); return 1; } } static int helperlib_traversecharmethod(lua_State *L) { if (lua_isnil(L, 1) || lua_type(L, 2) != LUA_TTABLE) { lua_pushcclosure(L, helperlib_aux_nil, 0); return 1; } else { halfword n = lmt_check_isdirect(L, 1); if (n) { lua_pushvalue(L, 2); lua_pushcclosure(L, helperlib_aux_next_char_method, 1); lua_pushinteger(L, n); lua_pushnil(L); return 3; } else { lua_pushcclosure(L, helperlib_aux_nil, 0); return 1; } } } static int helperlib_aux_next_glyph_method(lua_State *L) { halfword t; if (lua_isnil(L, 2)) { t = lmt_tohalfword(L, 1) ; lua_settop(L, 1); } else { t = lmt_tohalfword(L, 2) ; t = node_next(t); lua_settop(L, 2); } while (t) { if (node_type(t) == glyph_node) { lua_rawgeti(L, lua_upvalueindex(1), glyph_character(t)); if (lua_type(L, -1) != LUA_TNIL) { lua_pop(L, 1); break; } lua_pop(L, 1); } t = node_next(t); } if (t) { /* 3 has method, 4 gets node, so we need to swap: node, method, char, font */ /* how ? */ lua_pushinteger(L, t); lua_rawgeti(L, lua_upvalueindex(1), glyph_character(t)); // lua_rotate(L, 3, 2); lua_pushinteger(L, glyph_character(t)); lua_pushinteger(L, glyph_font(t)); return 4; } else { lua_pushnil(L); return 1; } } static int helperlib_traverseglyphmethod(lua_State *L) { if (lua_isnil(L, 1) || lua_type(L, 2) != LUA_TTABLE) { lua_pushcclosure(L, helperlib_aux_nil, 0); return 1; } else { halfword n = lmt_check_isdirect(L, 1); if (n) { lua_pushvalue(L, 2); lua_pushcclosure(L, helperlib_aux_next_glyph_method, 1); lua_pushinteger(L, n); lua_pushnil(L); return 3; } else { lua_pushcclosure(L, helperlib_aux_nil, 0); return 1; } } } // traverseattr // traverseattrmethod /* */ // static size_t helperlib_aux_f_3_3(double n, char *s) // { // if (fmod(n, 1) == 0) { // /* this is really needed in order to get integers */ // return snprintf(s, 8, "%i", (int) n); // } else { // int i = snprintf(s, 8, "%0.3f", n) ; // int l = i - 1; // while (l > 1) { // if (s[l - 1] == '.') { // break; // } else if (s[l] == '0') { // --i; // } else { // break; // } // l--; // } // return i; // } // } // // // static size_t helperlib_aux_f_3_3(double n, char *s) // // { // // int i = snprintf(s, 8, "%0.3f", n) ; // // int l = i - 1; // // while (l >= 0) { // // if (s[l] == '.') { // // --i; // // break; // // } else if (s[l] == '0') { // // --i; // // } else { // // break; // // } // // l--; // // } // // if (i <= 0) { // // s[0] = '0'; // // s[1] = '\0'; // // return 1; // // } else { // // return i; // // } // // } // // static size_t helperlib_aux_f_3(lua_State *L, int slot, char *s) // { // double n = lua_tonumber(L, slot); // if (n <= 0.0) { // s[0] = '0'; // s[1] = '\0'; // return 1; // } else if (n >= 1.0) { // s[0] = '1'; // s[1] = '\0'; // return 1; // } else { // return helperlib_aux_f_3_3(n, s); // } // } // // static int helperlib_pdf_gray(lua_State *L) // { // double s = lua_tonumber(L, 1); // if (s <= 0.0) { // lua_pushlstring(L, "0 g 0 G", 7); // } else if (s >= 1.0) { // lua_pushlstring(L, "1 g 1 G", 7); // } else { // luaL_Buffer buffer; // char ss[10]; // size_t sl = helperlib_aux_f_3_3(s, ss); // luaL_buffinitsize(L, &buffer, 20); // luaL_addlstring(&buffer, (const char *) &ss, sl); // luaL_addlstring(&buffer," g ", 4); // luaL_addlstring(&buffer, (const char *) &ss, sl); // luaL_addlstring(&buffer," G", 3); // luaL_pushresult(&buffer); // } // return 1; // } // // static int helperlib_pdf_rgb(lua_State *L) // { // luaL_Buffer buffer; // char rs[10]; // char gs[10]; // char bs[10]; // size_t rl = helperlib_aux_f_3(L, 1, rs); // size_t gl = helperlib_aux_f_3(L, 2, gs); // size_t bl = helperlib_aux_f_3(L, 3, bs); // luaL_buffinitsize(L, &buffer, 60); // luaL_addlstring(&buffer, (const char *) &rs, rl); // luaL_addlstring(&buffer," ", 1); // luaL_addlstring(&buffer, (const char *) &gs, gl); // luaL_addlstring(&buffer," ", 1); // luaL_addlstring(&buffer, (const char *) &bs, bl); // luaL_addlstring(&buffer," rg ", 4); // luaL_addlstring(&buffer, (const char *) &rs, rl); // luaL_addlstring(&buffer," ", 1); // luaL_addlstring(&buffer, (const char *) &gs, gl); // luaL_addlstring(&buffer," ", 1); // luaL_addlstring(&buffer, (const char *) &bs, bl); // luaL_addlstring(&buffer," RG", 3); // luaL_pushresult(&buffer); // return 1; // } // // static int helperlib_pdf_cmyk(lua_State *L) // { // luaL_Buffer buffer; // char cs[10]; // char ms[10]; // char ys[10]; // char ks[10]; // size_t cl = helperlib_aux_f_3(L, 1, cs); // size_t ml = helperlib_aux_f_3(L, 2, ms); // size_t yl = helperlib_aux_f_3(L, 3, ys); // size_t kl = helperlib_aux_f_3(L, 4, ks); // luaL_buffinitsize(L, &buffer, 80); // luaL_addlstring(&buffer, (const char *) &cs, cl); // luaL_addlstring(&buffer," ", 1); // luaL_addlstring(&buffer, (const char *) &ms, ml); // luaL_addlstring(&buffer," ", 1); // luaL_addlstring(&buffer, (const char *) &ys, yl); // luaL_addlstring(&buffer," ", 1); // luaL_addlstring(&buffer, (const char *) &ks, kl); // luaL_addlstring(&buffer," k ", 4); // luaL_addlstring(&buffer, (const char *) &cs, cl); // luaL_addlstring(&buffer," ", 1); // luaL_addlstring(&buffer, (const char *) &ms, ml); // luaL_addlstring(&buffer," ", 1); // luaL_addlstring(&buffer, (const char *) &ys, yl); // luaL_addlstring(&buffer," ", 1); // luaL_addlstring(&buffer, (const char *) &ks, kl); // luaL_addlstring(&buffer," K", 3); // luaL_pushresult(&buffer); // return 1; // } /* */ static struct luaL_Reg helperlib_function_list[] = { /* */ { "getprofile", helperlib_getprofile }, /* */ { "snaplist", helperlib_snaplist }, { "snapindeed", helperlib_snapindeed }, /* */ { "mathprocess", helperlib_mathprocess }, { "mathnested", helperlib_mathnested }, { "mathstep", helperlib_mathstep }, /* */ { "traversehorizontal", helperlib_traversehorizontal }, { "traversevertical", helperlib_traversevertical }, /* */ { "traversecharmethod", helperlib_traversecharmethod }, { "traverseglyphmethod", helperlib_traverseglyphmethod }, /* */ // { "pdfgray", helperlib_pdf_gray }, // { "pdfrgb", helperlib_pdf_rgb }, // { "pdfcmyk", helperlib_pdf_cmyk }, /* */ { NULL, NULL }, }; int luaopen_helper(lua_State *L) { lua_newtable(L); luaL_setfuncs(L, helperlib_function_list, 0); return 1; }