mirror of
https://github.com/ctm/executor.git
synced 2025-02-20 11:28:56 +00:00
645 lines
16 KiB
C
645 lines
16 KiB
C
/* Copyright 1986-1996 by Abacus Research and
|
|
* Development, Inc. All rights reserved.
|
|
*/
|
|
|
|
#if !defined (OMIT_RCSID_STRINGS)
|
|
char ROMlib_rcsid_teMisc[] =
|
|
"$Id: teMisc.c 63 2004-12-24 18:19:43Z ctm $";
|
|
#endif
|
|
|
|
/* Forward declarations in TextEdit.h (DO NOT DELETE THIS LINE) */
|
|
|
|
/*
|
|
* TODO: for better compatability we should ignore trailing spaces when doing
|
|
* calculations.
|
|
*/
|
|
|
|
#include "rsys/common.h"
|
|
#include "WindowMgr.h"
|
|
#include "ControlMgr.h"
|
|
#include "EventMgr.h"
|
|
#include "TextEdit.h"
|
|
#include "MemoryMgr.h"
|
|
|
|
#include "rsys/cquick.h"
|
|
#include "rsys/tesave.h"
|
|
#include "rsys/hook.h"
|
|
#include "rsys/text.h"
|
|
|
|
int16 nextbreak (TEHandle teh, int16 off, int16 len,
|
|
int16 max_width);
|
|
|
|
#if ERROR_SUPPORTED_P (ERROR_TEXT_EDIT_SLAM)
|
|
void
|
|
ROMlib_sledgehammer_te (TEHandle te)
|
|
{
|
|
int16 n_lines;
|
|
int16 width;
|
|
int16 length;
|
|
Rect *dest_rect;
|
|
Handle hText;
|
|
char *Text;
|
|
int16 current_lineno;
|
|
int16 *line_starts;
|
|
LHHandle lh_table;
|
|
int te_size;
|
|
int i;
|
|
|
|
line_starts = TE_LINE_STARTS (te);
|
|
hText = TE_HTEXT (te);
|
|
Text = (char *) STARH (hText);
|
|
length = TE_LENGTH (te);
|
|
n_lines = TE_N_LINES (te);
|
|
dest_rect = &TE_DEST_RECT (te);
|
|
width = RECT_WIDTH (dest_rect);
|
|
|
|
if (TE_STYLIZED_P (te))
|
|
{
|
|
TEStyleHandle te_style;
|
|
int lh_table_size, te_style_size;
|
|
int16 n_runs, n_styles;
|
|
int16 *style_count_vec;
|
|
STHandle style_table;
|
|
|
|
te_style = TE_GET_STYLE (te);
|
|
style_table = TE_STYLE_STYLE_TABLE (te_style);
|
|
|
|
lh_table = TE_STYLE_LH_TABLE (te_style);
|
|
lh_table_size = GetHandleSize ((Handle) lh_table);
|
|
gui_assert (lh_table_size == (n_lines + 1) * (int) sizeof (LHElement));
|
|
|
|
te_style_size = GetHandleSize ((Handle) te_style);
|
|
n_runs = TE_STYLE_N_RUNS (te_style);
|
|
gui_assert (te_style_size
|
|
== ((int) sizeof (TEStyleRec)
|
|
- (int) sizeof TE_STYLE_RUNS ((TEStyleHandle) NULL)
|
|
+ ((n_runs + 1)
|
|
* (int)
|
|
sizeof *TE_STYLE_RUNS ((TEStyleHandle) NULL))));
|
|
n_styles = TE_STYLE_N_STYLES (te_style);
|
|
style_count_vec = alloca (n_styles * sizeof *style_count_vec);
|
|
memset (style_count_vec, 0, n_styles * sizeof *style_count_vec);
|
|
for (i = 0; i < n_runs; i ++)
|
|
{
|
|
int16 style_index;
|
|
StyleRun *run;
|
|
|
|
run = TE_STYLE_RUN (te_style, i);
|
|
style_index = STYLE_RUN_STYLE_INDEX (run);
|
|
|
|
if (!i)
|
|
gui_assert (!STYLE_RUN_START_CHAR (run));
|
|
else if (i > 0)
|
|
{
|
|
StyleRun *prev_run;
|
|
int16 prev_style_index;
|
|
|
|
prev_run = TE_STYLE_RUN (te_style, i - 1);
|
|
prev_style_index = STYLE_RUN_STYLE_INDEX (prev_run);
|
|
|
|
gui_assert (prev_style_index != style_index);
|
|
/* guarantee that runs are strictly increasing */
|
|
gui_assert (STYLE_RUN_START_CHAR (prev_run)
|
|
< STYLE_RUN_START_CHAR (run));
|
|
}
|
|
|
|
gui_assert (style_index >= 0 && style_index < n_styles);
|
|
|
|
style_count_vec[style_index] ++;
|
|
}
|
|
|
|
{
|
|
StyleRun *last_run = TE_STYLE_RUN (te_style, n_runs);
|
|
|
|
gui_assert (STYLE_RUN_START_CHAR (last_run) == length + 1
|
|
&& (STYLE_RUN_STYLE_INDEX (last_run) == -1));
|
|
}
|
|
|
|
/* ### check that styles are not duplicated */
|
|
for (i = 0; i < n_styles; i ++)
|
|
{
|
|
STElement *style;
|
|
|
|
style = ST_ELT (style_table, i);
|
|
|
|
gui_assert (style_count_vec[i] > 0
|
|
&& style_count_vec[i] == ST_ELT_COUNT (style));
|
|
}
|
|
}
|
|
te_size = GetHandleSize ((Handle) te);
|
|
gui_assert ((((int) sizeof (TERec)
|
|
- (int) sizeof TE_LINE_STARTS (te))
|
|
+ (n_lines + 4) * (int) sizeof TE_LINE_STARTS (te)[1])
|
|
<= te_size);
|
|
|
|
for (current_lineno = 0;
|
|
current_lineno < n_lines;
|
|
current_lineno ++)
|
|
{
|
|
int16 current_line_start, next_break;
|
|
|
|
current_line_start = LINE_START (line_starts,
|
|
current_lineno);
|
|
next_break = nextbreak (te, current_line_start,
|
|
length, width);
|
|
gui_assert (next_break == LINE_START (line_starts,
|
|
current_lineno + 1));
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
A2 (PUBLIC, void, SetWordBreak, ProcPtr, wb, TEHandle, teh)
|
|
{
|
|
TE_SLAM (teh);
|
|
HxX (teh, wordBreak) = RM(wb);
|
|
TE_SLAM (teh);
|
|
}
|
|
|
|
/*
|
|
* TODO: make callback routines conform to IMI-395
|
|
*/
|
|
|
|
/*
|
|
* NOTE: on the 68k, SetClikLoop is provided by glue, and the glue doesn't
|
|
* correspond to the implementation of SetClikLoop below, because it
|
|
* has to address the goofy calling conventions that are used there.
|
|
* So this routine is only useful on the PPC.
|
|
*/
|
|
|
|
A2(PUBLIC, void, SetClikLoop, ProcPtr, cp, TEHandle, teh)
|
|
{
|
|
TE_SLAM (teh);
|
|
HxX(teh, clikLoop) = RM(cp);
|
|
TE_SLAM (teh);
|
|
}
|
|
|
|
A1(PUBLIC, INTEGER, ROMlib_wordb, char *, p) /* INTERNAL */
|
|
{
|
|
return (U(*p) <= 0x20);
|
|
}
|
|
|
|
#define MYWORDB(p) (U(p) <= 0x20)
|
|
|
|
int16
|
|
nextbreak (TEHandle teh, int16 off, int16 len,
|
|
int16 max_width)
|
|
{
|
|
char *sp, *ep;
|
|
char *minsp, *maxsp;
|
|
int16 width = 0;
|
|
Handle hText;
|
|
char *Text;
|
|
INTEGER curpos;
|
|
SignedByte hText_flags;
|
|
int16 retval;
|
|
|
|
/* ### warn if the width is less than that of any char? */
|
|
hText = TE_HTEXT (teh);
|
|
hText_flags = HGetState (hText);
|
|
HLock (hText);
|
|
Text = (char *) STARH (hText);
|
|
sp = Text + off;
|
|
ep = Text + len;
|
|
if (off > len)
|
|
warning_unexpected ("off > len");
|
|
minsp = sp;
|
|
if (Hx(teh, crOnly) < 0)
|
|
{
|
|
while (sp != ep && *sp++ != '\r')
|
|
;
|
|
retval = sp - Text; /* includes newline */
|
|
}
|
|
else
|
|
{
|
|
if (TE_STYLIZED_P (teh))
|
|
{
|
|
curpos = off;
|
|
while (width <= max_width && curpos != len
|
|
&& Text[curpos] != '\r')
|
|
width += ROMlib_StyleTextWidth (STARH (teh), curpos++, 1);
|
|
sp = Text + curpos;
|
|
}
|
|
else
|
|
{
|
|
/* Only the size face and font need to be saved so this is
|
|
overkill. */
|
|
TESAVE (teh);
|
|
PORT_TX_SIZE_X (thePort) = TE_TX_SIZE_X (teh);
|
|
PORT_TX_FACE (thePort) = TE_TX_FACE (teh);
|
|
PORT_TX_FONT_X (thePort) = TE_TX_FONT_X (teh);
|
|
while (width <= max_width && sp != ep && *sp != '\r')
|
|
width += CharWidth(*sp++);
|
|
TERESTORE ();
|
|
}
|
|
if (width > max_width)
|
|
{
|
|
maxsp = --sp;
|
|
if (*sp == ' ')
|
|
{
|
|
while (sp != ep && *sp == ' ')
|
|
sp++;
|
|
retval = sp - Text;
|
|
}
|
|
else
|
|
{
|
|
while (sp > minsp && !MYWORDB (*--sp))
|
|
;
|
|
if (sp == minsp)
|
|
retval = maxsp - Text; /* i.e. no wordbreaks */
|
|
else
|
|
retval = ++sp - Text; /* include the break on the line */
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (sp == ep)
|
|
retval = len; /* can't go no further */
|
|
else
|
|
retval = ++sp - Text; /* skip over the newline */
|
|
}
|
|
}
|
|
HSetState (hText, hText_flags);
|
|
if (retval == off && off < len) /* always advance at least one character */
|
|
++retval;
|
|
return retval;
|
|
}
|
|
|
|
/* return the `run' index that contains the current character */
|
|
int16 te_char_to_run_index (TEStyleHandle te_style, int16 sel)
|
|
{
|
|
StyleRun *current_run;
|
|
int16 n_runs;
|
|
int16 high, low, current;
|
|
int16 retval;
|
|
int16 current_elt;
|
|
|
|
n_runs = TE_STYLE_N_RUNS (te_style);
|
|
if (n_runs <= 1)
|
|
return 0;
|
|
|
|
low = 0;
|
|
high = n_runs;
|
|
current = (low + high) / 2;
|
|
|
|
while (low < high
|
|
&& (current_run = TE_STYLE_RUN (te_style, current),
|
|
current_elt = STYLE_RUN_START_CHAR (current_run)) != sel)
|
|
{
|
|
if (current_elt < sel)
|
|
low = current + 1;
|
|
else
|
|
high = current - 1;
|
|
current = (high + low) / 2;
|
|
}
|
|
if (STYLE_RUN_START_CHAR (TE_STYLE_RUN (te_style, current)) > sel)
|
|
retval = current - 1;
|
|
else
|
|
retval = current;
|
|
|
|
return retval;
|
|
}
|
|
|
|
/* return the line number that contains character index `sel' */
|
|
int16 te_char_to_lineno (TEPtr te, int16 sel)
|
|
{
|
|
int16 n_lines;
|
|
int16 *line_starts;
|
|
int16 high, low, current;
|
|
int16 retval;
|
|
int16 current_elt;
|
|
|
|
n_lines = TEP_N_LINES (te);
|
|
if (n_lines <= 1)
|
|
return 0;
|
|
line_starts = TEP_LINE_STARTS (te);
|
|
|
|
high = n_lines;
|
|
low = 0;
|
|
current = (high + low) / 2;
|
|
|
|
while (low < high
|
|
&& (current_elt = CW (line_starts[current])) != sel)
|
|
{
|
|
if (current_elt < sel)
|
|
low = current + 1;
|
|
else
|
|
high = current - 1;
|
|
current = (high + low) / 2;
|
|
}
|
|
if (CW (line_starts[current]) > sel
|
|
|| current == n_lines)
|
|
retval = current - 1;
|
|
else
|
|
retval = current;
|
|
|
|
return retval;
|
|
}
|
|
|
|
int16
|
|
calclhtab (TEHandle teh)
|
|
{
|
|
int16 n_lines;
|
|
StyleRun *current_run;
|
|
int16 *linestarts;
|
|
int16 first_changed;
|
|
int16 orig_height = -1, orig_ascent = -1;
|
|
LHHandle lh_table;
|
|
LHPtr lh;
|
|
TEStyleHandle sth;
|
|
int clear_lh_p;
|
|
|
|
n_lines = TE_N_LINES (teh);
|
|
|
|
sth = TE_GET_STYLE (teh);
|
|
lh_table = TE_STYLE_LH_TABLE (sth);
|
|
SetHandleSize ((Handle) lh_table,
|
|
sizeof (LHElement) * (n_lines + 1));
|
|
lh = STARH (lh_table);
|
|
first_changed = -1;
|
|
clear_lh_p = TRUE;
|
|
for (current_run = TE_STYLE_RUNS (sth), linestarts = TE_LINE_STARTS (teh);
|
|
linestarts <= (TE_LINE_STARTS (teh) + n_lines);)
|
|
{
|
|
STPtr current_style;
|
|
|
|
current_style = ST_ELT (TE_STYLE_STYLE_TABLE (sth),
|
|
STYLE_RUN_STYLE_INDEX (current_run));
|
|
if (clear_lh_p)
|
|
{
|
|
clear_lh_p = FALSE;
|
|
if (first_changed == -1)
|
|
{
|
|
orig_height = LH_HEIGHT (lh);
|
|
orig_ascent = LH_ASCENT (lh);
|
|
}
|
|
LH_HEIGHT_X (lh) = CWC (0);
|
|
LH_ASCENT_X (lh) = CWC (0);
|
|
}
|
|
|
|
if (ST_ELT_HEIGHT (current_style) > LH_HEIGHT (lh))
|
|
LH_HEIGHT_X (lh) = ST_ELT_HEIGHT_X (current_style);
|
|
if (ST_ELT_ASCENT (current_style) > LH_ASCENT (lh))
|
|
LH_ASCENT_X (lh) = ST_ELT_ASCENT_X (current_style);
|
|
|
|
if (CW (*linestarts) == TE_LENGTH (teh))
|
|
break;
|
|
|
|
if (STYLE_RUN_START_CHAR (current_run + 1) > CW (linestarts[1]))
|
|
{
|
|
if (first_changed == -1
|
|
&& ( LH_HEIGHT (lh) != orig_height
|
|
|| LH_ASCENT (lh) != orig_ascent))
|
|
first_changed = lh - STARH (lh_table);
|
|
linestarts ++;
|
|
lh ++;
|
|
clear_lh_p = TRUE;
|
|
}
|
|
else if (STYLE_RUN_START_CHAR (current_run + 1) < CW (linestarts[1]))
|
|
current_run ++;
|
|
else
|
|
{
|
|
if (first_changed == -1
|
|
&& ( LH_HEIGHT (lh) != orig_height
|
|
|| LH_ASCENT (lh) != orig_ascent))
|
|
first_changed = lh - STARH (lh_table);
|
|
linestarts ++;
|
|
lh ++;
|
|
clear_lh_p = TRUE;
|
|
current_run ++;
|
|
}
|
|
}
|
|
|
|
return first_changed;
|
|
}
|
|
|
|
/* guarantee that handle `te' has allocated enough space for at least
|
|
`n_lines' worth of `line_starts' */
|
|
void
|
|
te_guarantee_line_starts_allocation (TEHandle te, int n_lines)
|
|
{
|
|
int te_size;
|
|
int min_te_size;
|
|
|
|
te_size = GetHandleSize ((Handle) te);
|
|
|
|
min_te_size = ((sizeof (TERec)
|
|
- sizeof TE_LINE_STARTS (te))
|
|
+ (n_lines + 4) * sizeof *TE_LINE_STARTS (te));
|
|
if (te_size < min_te_size)
|
|
SetHandleSize ((Handle) te, min_te_size);
|
|
}
|
|
|
|
void
|
|
te_set_line_starts_allocation (TEHandle te, int n_lines)
|
|
{
|
|
SetHandleSize ((Handle) te,
|
|
((sizeof (TERec)
|
|
- sizeof TE_LINE_STARTS (te))
|
|
+ (n_lines + 4) * sizeof *TE_LINE_STARTS (te)));
|
|
}
|
|
|
|
/* recalculate the various text edit tables associated with `te' after
|
|
`nadded' characters are to be added (or deleted) at `sel' */
|
|
void
|
|
ROMlib_caltext (TEHandle te,
|
|
int16 sel, int16 n_added,
|
|
int16 *first_changed_out, int16 *last_changed_out)
|
|
{
|
|
int16 n_lines;
|
|
int16 *line_starts;
|
|
int16 first_lineno;
|
|
int16 t;
|
|
int16 width;
|
|
int16 length;
|
|
int16 first_changed = -1, last_changed = -1;
|
|
|
|
width = RECT_WIDTH (&TE_DEST_RECT (te));
|
|
|
|
if (width <= 0)
|
|
{
|
|
warning_unexpected ("width <= 0");
|
|
return;
|
|
}
|
|
|
|
n_lines = TE_N_LINES (te);
|
|
line_starts = TE_LINE_STARTS (te);
|
|
length = TE_LENGTH (te);
|
|
|
|
first_lineno = TE_CHAR_TO_LINENO (te, sel);
|
|
|
|
/* advance each line after the current line forward by `n_added' in
|
|
the optimistic case, where the insertion/deletion changes no
|
|
lines breaks, this is all we will do */
|
|
for (t = first_lineno + 1; t <= n_lines; t ++)
|
|
{
|
|
int line_start = LINE_START (line_starts, t);
|
|
int new_line_start = line_start + n_added;
|
|
|
|
LINE_START_X (line_starts, t) = CW (new_line_start);
|
|
}
|
|
|
|
/* starting from the first line, recompute all the end lines. we
|
|
can stop when we have pasted `sel + n_added', and the end of
|
|
lines are unchanging
|
|
|
|
note, as we loop, we may create more lines than there were
|
|
previuosly. make sure we keep `te' allocated to an appropriate
|
|
length */
|
|
{
|
|
/* break point for the current line, also the start point for
|
|
the next line */
|
|
int16 current_line_break;
|
|
int16 current_lineno;
|
|
|
|
/* start with the previous line, since deltion on the current line
|
|
can cause the previous line's break to change */
|
|
for (current_lineno = MAX (first_lineno - 1, 0);; current_lineno ++)
|
|
{
|
|
int16 current_line_start;
|
|
int16 orig_current_line_break;
|
|
|
|
/* compute the new break for the current line */
|
|
current_line_start = LINE_START (line_starts, current_lineno);
|
|
current_line_break = nextbreak (te, current_line_start,
|
|
length, width);
|
|
|
|
te_guarantee_line_starts_allocation (te, current_lineno + 1);
|
|
/* pull `line_starts' back out, since the `te' handle may have
|
|
been relocated */
|
|
line_starts = TE_LINE_STARTS (te);
|
|
orig_current_line_break = LINE_START (line_starts, current_lineno + 1);
|
|
LINE_START_X (line_starts, current_lineno + 1) = CW (current_line_break);
|
|
|
|
if (first_changed == -1
|
|
&& orig_current_line_break != current_line_break)
|
|
first_changed = LINE_START (line_starts, current_lineno);
|
|
|
|
if (current_line_break == length)
|
|
{
|
|
if (length == 0)
|
|
n_lines = 0;
|
|
else
|
|
n_lines = current_lineno + 1;
|
|
|
|
TE_N_LINES_X (te) = CW (n_lines);
|
|
te_set_line_starts_allocation (te, n_lines);
|
|
line_starts = TE_LINE_STARTS (te);
|
|
LINE_START_X (line_starts, n_lines + 1) = CWC (0);
|
|
|
|
last_changed = length;
|
|
break;
|
|
}
|
|
else if (current_line_break == orig_current_line_break
|
|
&& current_line_break > MAX (sel, sel + n_added))
|
|
{
|
|
last_changed = LINE_START (line_starts + 1, current_lineno) - 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
{
|
|
int lh_first_changed = -1;
|
|
|
|
if (TE_STYLIZED_P (te)
|
|
&& TE_TX_SIZE_X (te) == CWC (-1))
|
|
lh_first_changed = calclhtab (te);
|
|
|
|
if (lh_first_changed != -1)
|
|
{
|
|
if (first_changed == -1)
|
|
first_changed = lh_first_changed;
|
|
else
|
|
first_changed = MIN (lh_first_changed, first_changed);
|
|
last_changed = length;
|
|
}
|
|
}
|
|
|
|
if (first_changed == -1)
|
|
first_changed = sel;
|
|
|
|
if (last_changed == -1
|
|
|| last_changed < first_changed)
|
|
last_changed = first_changed + n_added;
|
|
|
|
if (first_changed_out)
|
|
*first_changed_out = first_changed;
|
|
if (last_changed_out)
|
|
*last_changed_out = last_changed;
|
|
}
|
|
|
|
P1 (PUBLIC pascal trap, void, TECalText, TEHandle, te)
|
|
{
|
|
/* don't do this check because people call this caltext when the TE
|
|
has been frobbed and is in a wacky state */
|
|
/* TE_SLAM (te); */
|
|
TE_LENGTH_X (te) = CW (GetHandleSize (TE_HTEXT (te)));
|
|
ROMlib_caltext (te, 0, 32767, NULL, NULL);
|
|
TE_SLAM (te);
|
|
}
|
|
|
|
P3 (PUBLIC pascal trap, int16, TEFeatureFlag,
|
|
int16, feature, int16, action, TEHandle, te)
|
|
{
|
|
switch (feature)
|
|
{
|
|
case teFAutoScroll:
|
|
if (action == teBitTest)
|
|
return ((TE_FLAGS (te) & TEAUTOVIEWBIT)
|
|
? teBitSet
|
|
: teBitClear);
|
|
TEAutoView (action == teBitSet, te);
|
|
break;
|
|
|
|
case teFOutlineHilite:
|
|
/* #### implement outline hilite */
|
|
|
|
case teFTextBuffering:
|
|
case teFInlineInput:
|
|
case teFUseTextServices:
|
|
warning_unimplemented ("unable to handle te feature flag `%d'",
|
|
feature);
|
|
return teBitClear;
|
|
}
|
|
|
|
return action;
|
|
}
|
|
|
|
int16
|
|
ROMlib_call_TEDoText (TEPtr tp, int16 first, int16 last, int16 what)
|
|
{
|
|
register int16 myd0;
|
|
|
|
if ((a0trap INTEGERRET (*) (void)) MR (TEDoText) == (void *) P_ROMlib_dotext)
|
|
myd0 = C_ROMlib_dotext (tp, first, last, what);
|
|
else
|
|
{
|
|
ROMlib_hook (te_dotextnumber);
|
|
{
|
|
int32 saved2, saved3, saved4, saved7, savea2, savea3;
|
|
|
|
saved2 = EM_D2;
|
|
saved3 = EM_D3;
|
|
saved4 = EM_D4;
|
|
saved7 = EM_D7;
|
|
savea2 = EM_A2;
|
|
savea3 = EM_A3;
|
|
EM_A3 = (LONGINT) (long) US_TO_SYN68K(tp);
|
|
EM_D3 = (LONGINT) first;
|
|
EM_D4 = (LONGINT) last;
|
|
EM_D7 = (LONGINT) what;
|
|
EM_A0 = (LONGINT) (long) CL ((long) TEDoText);
|
|
CALL_EMULATOR (EM_A0);
|
|
myd0 = EM_D0;
|
|
EM_D2 = saved2;
|
|
EM_D3 = saved3;
|
|
EM_D4 = saved4;
|
|
EM_D7 = saved7;
|
|
EM_A2 = savea2;
|
|
EM_A3 = savea3;
|
|
}
|
|
}
|
|
return myd0;
|
|
}
|