comparison src/redisplay.c @ 4967:0d4c9d0f6a8d

rewrite dynarr code -------------------- ChangeLog entries follow: -------------------- src/ChangeLog addition: 2010-02-03 Ben Wing <ben@xemacs.org> * device-x.c (x_get_resource_prefix): * device-x.c (Fx_get_resource): * device-x.c (Fx_get_resource_prefix): * device-x.c (Fx_put_resource): * dialog-msw.c: * dialog-msw.c (handle_question_dialog_box): * dired-msw.c (mswindows_sort_files): * dired-msw.c (mswindows_get_files): * extents.c (extent_fragment_sort_by_priority): * extents.c (Fset_extent_parent): * file-coding.c (coding_reader): * file-coding.c (coding_writer): * file-coding.c (gzip_convert): * frame.c (generate_title_string): * gutter.c (calculate_gutter_size_from_display_lines): * indent.c (vmotion_1): * lread.c (read_bit_vector): * mule-coding.c (iso2022_decode): * rangetab.c: * rangetab.c (Fcopy_range_table): * rangetab.c (Fget_range_table): * rangetab.c (unified_range_table_copy_data): * redisplay-msw.c (mswindows_output_string): * redisplay-output.c (output_display_line): * redisplay-output.c (redisplay_move_cursor): * redisplay-output.c (redisplay_clear_bottom_of_window): * redisplay-tty.c (tty_output_ichar_dynarr): * redisplay-tty.c (set_foreground_to): * redisplay-tty.c (set_background_to): * redisplay-xlike-inc.c (XLIKE_output_string): * redisplay.c (redisplay_window_text_width_string): * redisplay.c (redisplay_text_width_string): * redisplay.c (create_text_block): * redisplay.c (SET_CURRENT_MODE_CHARS_PIXSIZE): * redisplay.c (generate_fstring_runes): * redisplay.c (regenerate_modeline): * redisplay.c (ensure_modeline_generated): * redisplay.c (real_current_modeline_height): * redisplay.c (create_string_text_block): * redisplay.c (regenerate_window): * redisplay.c (REGEN_INC_FIND_START_END): * redisplay.c (point_visible): * redisplay.c (redisplay_window): * redisplay.c (mark_glyph_block_dynarr): * redisplay.c (line_start_cache_start): * redisplay.c (start_with_line_at_pixpos): * redisplay.c (update_line_start_cache): * redisplay.c (glyph_to_pixel_translation): * redisplay.c (pixel_to_glyph_translation): * sysdep.c (qxe_readdir): * text.c (dfc_convert_to_external_format): * text.c (dfc_convert_to_internal_format): * toolbar-common.c (common_output_toolbar_button): * window.c (window_modeline_height): * window.c (Fwindow_last_line_visible_height): * window.c (window_displayed_height): * window.c (window_scroll): * window.c (get_current_pixel_pos): Use Dynarr_begin() in place of Dynarr_atp (foo, 0). * dynarr.c (Dynarr_realloc): * dynarr.c (Dynarr_lisp_realloc): * dynarr.c (Dynarr_resize): * dynarr.c (Dynarr_insert_many): * dynarr.c (Dynarr_delete_many): * dynarr.c (Dynarr_memory_usage): * dynarr.c (stack_like_malloc): * dynarr.c (stack_like_free): * lisp.h: * lisp.h (DECLARE_DYNARR_LISP_IMP): * lisp.h (XD_DYNARR_DESC): * lisp.h (Dynarr_pop): * gutter.c (output_gutter): * redisplay-output.c (sync_rune_structs): * redisplay-output.c (redisplay_output_window): Redo the dynarr code, add greater checks. Rename the `len', `largest' and `max' members to `len_', `largest_' and `max_' to try and catch existing places that might directly modify these values. Make new accessors Dynarr_largest() and Dynarr_max() and make them and existing Dynarr_length() be non-lvalues by adding '+ 0' to them; fix a couple of places in the redisplay code that tried to modify the length directly by setting Dynarr_length(). Use the accessors whenever possible even in the dynarr code itself. The accessors also verify that 0 <= len <= largest <= max. Rename settor function Dynarr_set_size() to Dynarr_set_length() and use it more consistently; also create lower-level Dynarr_set_length_1(). This latter function should be the only function that directly modifies the `len_' member of a Dynarr, and in the process makes sure that the `largest' value is kept correct. Consistently use ERROR_CHECK_STRUCTURES instead of ERROR_CHECK_TYPES for error-checking code. Reintroduce the temporarily disabled verification code on the positions of Dynarr_at(), Dynarr_atp() and Dynarr_atp_past_end(). Also create Dynarr_resize_if() in place of a repeated code fragment. Clean up all the functions that modify Dynarrs to use the new macros and functions and verify the correctness of the Dynarr both before and after the change. Note that there are two kinds of verification -- one for accessing and one for modifying. The difference is that the modify verification additionally checks to make sure that the Dynarr isn't locked. (This is used in redisplay to check for problems with reentrancy.) * lrecord.h: Move XD_DYNARR_DESC to lisp.h, grouping with the dynarr code.
author Ben Wing <ben@xemacs.org>
date Wed, 03 Feb 2010 20:51:18 -0600
parents 19a72041c5ed
children 4d35e52790f8
comparison
equal deleted inserted replaced
4966:48b63cd88a21 4967:0d4c9d0f6a8d
659 fixup_internal_substring (nonreloc, reloc, offset, &len); 659 fixup_internal_substring (nonreloc, reloc, offset, &len);
660 if (STRINGP (reloc)) 660 if (STRINGP (reloc))
661 nonreloc = XSTRING_DATA (reloc); 661 nonreloc = XSTRING_DATA (reloc);
662 convert_ibyte_string_into_ichar_dynarr (nonreloc, len, rtw_ichar_dynarr); 662 convert_ibyte_string_into_ichar_dynarr (nonreloc, len, rtw_ichar_dynarr);
663 return redisplay_window_text_width_ichar_string 663 return redisplay_window_text_width_ichar_string
664 (w, findex, Dynarr_atp (rtw_ichar_dynarr, 0), 664 (w, findex, Dynarr_begin (rtw_ichar_dynarr),
665 Dynarr_length (rtw_ichar_dynarr)); 665 Dynarr_length (rtw_ichar_dynarr));
666 } 666 }
667 667
668 int 668 int
669 redisplay_text_width_string (Lisp_Object domain, Lisp_Object face, 669 redisplay_text_width_string (Lisp_Object domain, Lisp_Object face,
695 and then we need to either fix the callers to pass in 695 and then we need to either fix the callers to pass in
696 a window, or change *text_width() to take a domain 696 a window, or change *text_width() to take a domain
697 argument. */ 697 argument. */
698 text_width, (XWINDOW (window), 698 text_width, (XWINDOW (window),
699 &cachel, 699 &cachel,
700 Dynarr_atp (rtw_ichar_dynarr, 0), 700 Dynarr_begin (rtw_ichar_dynarr),
701 Dynarr_length (rtw_ichar_dynarr))); 701 Dynarr_length (rtw_ichar_dynarr)));
702 } 702 }
703 703
704 /* Return the display block from DL of the given TYPE. A display line 704 /* Return the display block from DL of the given TYPE. A display line
705 can have only one display block of each possible type. If DL does 705 can have only one display block of each possible type. If DL does
2310 propagation data then we are clipping the glyph and there 2310 propagation data then we are clipping the glyph and there
2311 can be no propagation data before that point. The theory 2311 can be no propagation data before that point. The theory
2312 works because we always recalculate the extent-fragments 2312 works because we always recalculate the extent-fragments
2313 for propagated data, we never actually propagate the 2313 for propagated data, we never actually propagate the
2314 fragments that still need to be displayed. */ 2314 fragments that still need to be displayed. */
2315 if (*prop && Dynarr_atp (*prop, 0)->type == PROP_GLYPH) 2315 if (*prop && Dynarr_begin (*prop)->type == PROP_GLYPH)
2316 { 2316 {
2317 last_glyph = Dynarr_atp (*prop, 0)->data.p_glyph.glyph; 2317 last_glyph = Dynarr_begin (*prop)->data.p_glyph.glyph;
2318 Dynarr_free (*prop); 2318 Dynarr_free (*prop);
2319 *prop = 0; 2319 *prop = 0;
2320 } 2320 }
2321 /* Now compute the face and begin/end-glyph information. */ 2321 /* Now compute the face and begin/end-glyph information. */
2322 data.findex = 2322 data.findex =
4080 4080
4081 /* If max_pos is == -1, it is considered to be infinite. The same is 4081 /* If max_pos is == -1, it is considered to be infinite. The same is
4082 true of max_pixsize. */ 4082 true of max_pixsize. */
4083 #define SET_CURRENT_MODE_CHARS_PIXSIZE \ 4083 #define SET_CURRENT_MODE_CHARS_PIXSIZE \
4084 if (Dynarr_length (data->db->runes)) \ 4084 if (Dynarr_length (data->db->runes)) \
4085 cur_pixsize = data->pixpos - Dynarr_atp (data->db->runes, 0)->xpos; \ 4085 cur_pixsize = data->pixpos - Dynarr_begin (data->db->runes)->xpos; \
4086 else \ 4086 else \
4087 cur_pixsize = 0; 4087 cur_pixsize = 0;
4088 4088
4089 /* Note that this function does "positions" in terms of characters and 4089 /* Note that this function does "positions" in terms of characters and
4090 not in terms of columns. This is necessary to make the formatting 4090 not in terms of columns. This is necessary to make the formatting
4206 Ibyte *str; 4206 Ibyte *str;
4207 Charcount size; 4207 Charcount size;
4208 4208
4209 decode_mode_spec (w, ch, type); 4209 decode_mode_spec (w, ch, type);
4210 4210
4211 str = Dynarr_atp (mode_spec_ibyte_string, 0); 4211 str = Dynarr_begin (mode_spec_ibyte_string);
4212 size = bytecount_to_charcount 4212 size = bytecount_to_charcount
4213 /* Skip the null character added by `decode_mode_spec' */ 4213 /* Skip the null character added by `decode_mode_spec' */
4214 (str, Dynarr_length (mode_spec_ibyte_string)) - 1; 4214 (str, Dynarr_length (mode_spec_ibyte_string)) - 1;
4215 4215
4216 if (size <= *offset) 4216 if (size <= *offset)
4487 static void 4487 static void
4488 regenerate_modeline (struct window *w) 4488 regenerate_modeline (struct window *w)
4489 { 4489 {
4490 display_line_dynarr *dla = window_display_lines (w, DESIRED_DISP); 4490 display_line_dynarr *dla = window_display_lines (w, DESIRED_DISP);
4491 4491
4492 if (!Dynarr_length (dla) || !Dynarr_atp (dla, 0)->modeline) 4492 if (!Dynarr_length (dla) || !Dynarr_begin (dla)->modeline)
4493 return; 4493 return;
4494 else 4494 else
4495 { 4495 {
4496 generate_modeline (w, Dynarr_atp (dla, 0), DESIRED_DISP); 4496 generate_modeline (w, Dynarr_begin (dla), DESIRED_DISP);
4497 redisplay_update_line (w, 0, 0, 0); 4497 redisplay_update_line (w, 0, 0, 0);
4498 } 4498 }
4499 } 4499 }
4500 4500
4501 /* Make sure that modeline display line is present in the given 4501 /* Make sure that modeline display line is present in the given
4543 } 4543 }
4544 4544
4545 /* If we're adding a new place marker go ahead and generate the 4545 /* If we're adding a new place marker go ahead and generate the
4546 modeline so that it is available for use by 4546 modeline so that it is available for use by
4547 window_modeline_height. */ 4547 window_modeline_height. */
4548 generate_modeline (w, Dynarr_atp (dla, 0), type); 4548 generate_modeline (w, Dynarr_begin (dla), type);
4549 } 4549 }
4550 4550
4551 return need_modeline; 4551 return need_modeline;
4552 } 4552 }
4553 4553
4562 { 4562 {
4563 display_line_dynarr *dla = window_display_lines (w, CMOTION_DISP); 4563 display_line_dynarr *dla = window_display_lines (w, CMOTION_DISP);
4564 4564
4565 if (Dynarr_length (dla)) 4565 if (Dynarr_length (dla))
4566 { 4566 {
4567 if (Dynarr_atp (dla, 0)->modeline) 4567 if (Dynarr_begin (dla)->modeline)
4568 return (Dynarr_atp (dla, 0)->ascent + 4568 return (Dynarr_begin (dla)->ascent +
4569 Dynarr_atp (dla, 0)->descent); 4569 Dynarr_begin (dla)->descent);
4570 } 4570 }
4571 } 4571 }
4572 return 0; 4572 return 0;
4573 } 4573 }
4574 4574
4779 /* Check for face changes. */ 4779 /* Check for face changes. */
4780 if (initial || (!no_more_frags && data.byte_charpos == data.ef->end)) 4780 if (initial || (!no_more_frags && data.byte_charpos == data.ef->end))
4781 { 4781 {
4782 Lisp_Object last_glyph = Qnil; 4782 Lisp_Object last_glyph = Qnil;
4783 /* Deal with clipped glyphs that we have already displayed. */ 4783 /* Deal with clipped glyphs that we have already displayed. */
4784 if (*prop && Dynarr_atp (*prop, 0)->type == PROP_GLYPH) 4784 if (*prop && Dynarr_begin (*prop)->type == PROP_GLYPH)
4785 { 4785 {
4786 last_glyph = Dynarr_atp (*prop, 0)->data.p_glyph.glyph; 4786 last_glyph = Dynarr_begin (*prop)->data.p_glyph.glyph;
4787 Dynarr_free (*prop); 4787 Dynarr_free (*prop);
4788 *prop = 0; 4788 *prop = 0;
4789 } 4789 }
4790 /* Now compute the face and begin/end-glyph information. */ 4790 /* Now compute the face and begin/end-glyph information. */
4791 data.findex = 4791 data.findex =
5647 5647
5648 if (need_modeline) 5648 if (need_modeline)
5649 { 5649 {
5650 /* We know that this is the right thing to use because we put it 5650 /* We know that this is the right thing to use because we put it
5651 there when we first started working in this function. */ 5651 there when we first started working in this function. */
5652 generate_modeline (w, Dynarr_atp (dla, 0), type); 5652 generate_modeline (w, Dynarr_begin (dla), type);
5653 } 5653 }
5654 5654
5655 if (depth >= 0) 5655 if (depth >= 0)
5656 exit_redisplay_critical_section (depth); 5656 exit_redisplay_critical_section (depth);
5657 } 5657 }
5661 /* Determine start and end of lines. */ \ 5661 /* Determine start and end of lines. */ \
5662 if (!Dynarr_length (cdla)) \ 5662 if (!Dynarr_length (cdla)) \
5663 return 0; \ 5663 return 0; \
5664 else \ 5664 else \
5665 { \ 5665 { \
5666 if (Dynarr_atp (cdla, 0)->modeline && Dynarr_atp (ddla, 0)->modeline) \ 5666 if (Dynarr_begin (cdla)->modeline && Dynarr_begin (ddla)->modeline) \
5667 { \ 5667 { \
5668 dla_start = 1; \ 5668 dla_start = 1; \
5669 } \ 5669 } \
5670 else if (!Dynarr_atp (cdla, 0)->modeline \ 5670 else if (!Dynarr_begin (cdla)->modeline \
5671 && !Dynarr_atp (ddla, 0)->modeline) \ 5671 && !Dynarr_begin (ddla)->modeline) \
5672 { \ 5672 { \
5673 dla_start = 0; \ 5673 dla_start = 0; \
5674 } \ 5674 } \
5675 else \ 5675 else \
5676 ABORT (); /* structs differ */ \ 5676 ABORT (); /* structs differ */ \
6100 { 6100 {
6101 struct buffer *b = XBUFFER (w->buffer); 6101 struct buffer *b = XBUFFER (w->buffer);
6102 display_line_dynarr *dla = window_display_lines (w, type); 6102 display_line_dynarr *dla = window_display_lines (w, type);
6103 int first_line; 6103 int first_line;
6104 6104
6105 if (Dynarr_length (dla) && Dynarr_atp (dla, 0)->modeline) 6105 if (Dynarr_length (dla) && Dynarr_begin (dla)->modeline)
6106 first_line = 1; 6106 first_line = 1;
6107 else 6107 else
6108 first_line = 0; 6108 first_line = 0;
6109 6109
6110 if (Dynarr_length (dla) > first_line) 6110 if (Dynarr_length (dla) > first_line)
7595 static void 7595 static void
7596 mark_glyph_block_dynarr (glyph_block_dynarr *gba) 7596 mark_glyph_block_dynarr (glyph_block_dynarr *gba)
7597 { 7597 {
7598 if (gba) 7598 if (gba)
7599 { 7599 {
7600 glyph_block *gb = Dynarr_atp (gba, 0); 7600 glyph_block *gb = Dynarr_begin (gba);
7601 glyph_block *gb_last = Dynarr_past_lastp (gba); 7601 glyph_block *gb_last = Dynarr_past_lastp (gba);
7602 7602
7603 for (; gb < gb_last; gb++) 7603 for (; gb < gb_last; gb++)
7604 { 7604 {
7605 if (!NILP (gb->glyph)) 7605 if (!NILP (gb->glyph))
7730 line_start_cache_dynarr *cache = w->line_start_cache; 7730 line_start_cache_dynarr *cache = w->line_start_cache;
7731 7731
7732 if (!Dynarr_length (cache)) 7732 if (!Dynarr_length (cache))
7733 return -1; 7733 return -1;
7734 else 7734 else
7735 return Dynarr_atp (cache, 0)->start; 7735 return Dynarr_begin (cache)->start;
7736 } 7736 }
7737 7737
7738 /* Return the very last buffer position contained in the given 7738 /* Return the very last buffer position contained in the given
7739 window's cache, or -1 if the cache is empty. Assumes that the 7739 window's cache, or -1 if the cache is empty. Assumes that the
7740 cache is valid. */ 7740 cache is valid. */
8225 explicit window-start not at a newline character etc. 8225 explicit window-start not at a newline character etc.
8226 The existence of those are indeed known to create crashes 8226 The existence of those are indeed known to create crashes
8227 on that assert. So we have no option but to continue the 8227 on that assert. So we have no option but to continue the
8228 search if we found point at the top of the line_start_cache 8228 search if we found point at the top of the line_start_cache
8229 again. */ 8229 again. */
8230 cur_pos = Dynarr_atp (w->line_start_cache,0)->start; 8230 cur_pos = Dynarr_begin (w->line_start_cache)->start;
8231 } 8231 }
8232 prev_pos = cur_pos; 8232 prev_pos = cur_pos;
8233 } 8233 }
8234 } 8234 }
8235 8235
8402 Dynarr_reset (cache); 8402 Dynarr_reset (cache);
8403 } 8403 }
8404 8404
8405 if (!Dynarr_length (cache)) 8405 if (!Dynarr_length (cache))
8406 { 8406 {
8407 Dynarr_add_many (cache, Dynarr_atp (internal_cache, 0), 8407 Dynarr_add_many (cache, Dynarr_begin (internal_cache),
8408 Dynarr_length (internal_cache)); 8408 Dynarr_length (internal_cache));
8409 w->line_cache_validation_override--; 8409 w->line_cache_validation_override--;
8410 return; 8410 return;
8411 } 8411 }
8412 8412
8432 } 8432 }
8433 8433
8434 if (!(ic_elt >= 0)) 8434 if (!(ic_elt >= 0))
8435 { 8435 {
8436 Dynarr_reset (cache); 8436 Dynarr_reset (cache);
8437 Dynarr_add_many (cache, Dynarr_atp (internal_cache, 0), 8437 Dynarr_add_many (cache, Dynarr_begin (internal_cache),
8438 Dynarr_length (internal_cache)); 8438 Dynarr_length (internal_cache));
8439 w->line_cache_validation_override--; 8439 w->line_cache_validation_override--;
8440 return; 8440 return;
8441 } 8441 }
8442 8442
8443 Dynarr_insert_many_at_start (cache, Dynarr_atp (internal_cache, 0), 8443 Dynarr_insert_many_at_start (cache, Dynarr_begin (internal_cache),
8444 ic_elt + 1); 8444 ic_elt + 1);
8445 } 8445 }
8446 8446
8447 if (end > high_bound) 8447 if (end > high_bound)
8448 { 8448 {
8457 } 8457 }
8458 8458
8459 if (!(ic_elt < Dynarr_length (internal_cache))) 8459 if (!(ic_elt < Dynarr_length (internal_cache)))
8460 { 8460 {
8461 Dynarr_reset (cache); 8461 Dynarr_reset (cache);
8462 Dynarr_add_many (cache, Dynarr_atp (internal_cache, 0), 8462 Dynarr_add_many (cache, Dynarr_begin (internal_cache),
8463 Dynarr_length (internal_cache)); 8463 Dynarr_length (internal_cache));
8464 w->line_cache_validation_override--; 8464 w->line_cache_validation_override--;
8465 return; 8465 return;
8466 } 8466 }
8467 8467
8489 8489
8490 /* If this assert is triggered then regenerate_window failed 8490 /* If this assert is triggered then regenerate_window failed
8491 to layout a single line. This is not possible since we 8491 to layout a single line. This is not possible since we
8492 force at least a single line to be layout for CMOTION_DISP */ 8492 force at least a single line to be layout for CMOTION_DISP */
8493 assert (Dynarr_length (internal_cache)); 8493 assert (Dynarr_length (internal_cache));
8494 assert (startp == Dynarr_atp (internal_cache, 0)->start); 8494 assert (startp == Dynarr_begin (internal_cache)->start);
8495 8495
8496 ic_elt = Dynarr_length (internal_cache) - 1; 8496 ic_elt = Dynarr_length (internal_cache) - 1;
8497 if (low_bound != -1) 8497 if (low_bound != -1)
8498 { 8498 {
8499 while (ic_elt >= 0) 8499 while (ic_elt >= 0)
8524 ic_elt--; 8524 ic_elt--;
8525 } 8525 }
8526 8526
8527 if (ic_elt >= 0) /* we still have lines to add.. */ 8527 if (ic_elt >= 0) /* we still have lines to add.. */
8528 { 8528 {
8529 Dynarr_insert_many (cache, Dynarr_atp (internal_cache, 0), 8529 Dynarr_insert_many (cache, Dynarr_begin (internal_cache),
8530 ic_elt + 1, marker); 8530 ic_elt + 1, marker);
8531 marker += (ic_elt + 1); 8531 marker += (ic_elt + 1);
8532 } 8532 }
8533 8533
8534 if (startp < low_bound || low_bound == -1) 8534 if (startp < low_bound || low_bound == -1)
8559 update_internal_cache_list (w, CMOTION_DISP); 8559 update_internal_cache_list (w, CMOTION_DISP);
8560 8560
8561 /* See comment above about regenerate_window failing. */ 8561 /* See comment above about regenerate_window failing. */
8562 assert (Dynarr_length (internal_cache)); 8562 assert (Dynarr_length (internal_cache));
8563 8563
8564 Dynarr_add_many (cache, Dynarr_atp (internal_cache, 0), 8564 Dynarr_add_many (cache, Dynarr_begin (internal_cache),
8565 Dynarr_length (internal_cache)); 8565 Dynarr_length (internal_cache));
8566 high_bound = Dynarr_lastp (cache)->end; 8566 high_bound = Dynarr_lastp (cache)->end;
8567 startp = high_bound + 1; 8567 startp = high_bound + 1;
8568 } 8568 }
8569 while (to > high_bound); 8569 while (to > high_bound);
8604 8604
8605 num_disp_lines = Dynarr_length (dla); 8605 num_disp_lines = Dynarr_length (dla);
8606 modeline = 0; 8606 modeline = 0;
8607 if (num_disp_lines) 8607 if (num_disp_lines)
8608 { 8608 {
8609 if (Dynarr_atp (dla, 0)->modeline) 8609 if (Dynarr_begin (dla)->modeline)
8610 { 8610 {
8611 num_disp_lines--; 8611 num_disp_lines--;
8612 modeline = 1; 8612 modeline = 1;
8613 } 8613 }
8614 } 8614 }
9061 if (Dynarr_length (db->runes)) 9061 if (Dynarr_length (db->runes))
9062 { 9062 {
9063 if (x_check <= left_bound) 9063 if (x_check <= left_bound)
9064 { 9064 {
9065 if (dl->modeline) 9065 if (dl->modeline)
9066 *modeline_closest = Dynarr_atp (db->runes, 0)->charpos; 9066 *modeline_closest = Dynarr_begin (db->runes)->charpos;
9067 else 9067 else
9068 *closest = Dynarr_atp (db->runes, 0)->charpos; 9068 *closest = Dynarr_begin (db->runes)->charpos;
9069 } 9069 }
9070 else 9070 else
9071 { 9071 {
9072 if (dl->modeline) 9072 if (dl->modeline)
9073 *modeline_closest = Dynarr_lastp (db->runes)->charpos; 9073 *modeline_closest = Dynarr_lastp (db->runes)->charpos;