580 lines
12 KiB
C
580 lines
12 KiB
C
/*
|
|
This file is part of MOST.
|
|
|
|
Copyright (c) 1991, 1999, 2002, 2005-2018, 2019 John E. Davis
|
|
|
|
This program is free software; you can redistribute it and/or modify it
|
|
under the terms of the GNU General Public License as published by the Free
|
|
Software Foundation; either version 2 of the License, or (at your option)
|
|
any later version.
|
|
|
|
This program is distributed in the hope that it will be useful, but WITHOUT
|
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
more details.
|
|
|
|
You should have received a copy of the GNU General Public License along
|
|
with this program; if not, write to the Free Software Foundation, Inc., 675
|
|
Mass Ave, Cambridge, MA 02139, USA.
|
|
*/
|
|
#include "config.h"
|
|
|
|
#include <stdio.h>
|
|
|
|
#ifdef HAVE_STDLIB_H
|
|
# include <stdlib.h>
|
|
#endif
|
|
|
|
#include <string.h>
|
|
|
|
#include <slang.h>
|
|
#include "jdmacros.h"
|
|
|
|
#include "most.h"
|
|
#include "buffer.h"
|
|
#include "display.h"
|
|
#include "window.h"
|
|
#include "line.h"
|
|
#include "file.h"
|
|
|
|
int Most_W_Opt = 0;
|
|
|
|
unsigned char *Most_Beg; /* beginning of current buffer */
|
|
unsigned char *Most_Eob; /* end of current buffer */
|
|
|
|
Most_Buffer_Type *Most_Buf;
|
|
|
|
MOST_INT Most_Num_Lines;
|
|
|
|
MOST_UINT Most_C_Offset;
|
|
MOST_INT Most_C_Line;
|
|
|
|
/* p>p0 assumed */
|
|
#define BSKIP_CHAR(p,p0) \
|
|
(((Most_UTF8_Mode == 0) || (0 == ((*(p-1)) & 0x80))) \
|
|
? ((p)--) \
|
|
: ((p) = SLutf8_bskip_char ((p0), (p))))
|
|
|
|
static unsigned char *beg_of_line1(void)
|
|
{
|
|
unsigned char *pos;
|
|
unsigned char *cpos;
|
|
|
|
cpos = pos = Most_Beg + Most_C_Offset;
|
|
if (pos == Most_Beg) return pos;
|
|
|
|
if (pos != Most_Eob)
|
|
{
|
|
if (*pos == '\n')
|
|
{
|
|
pos--;/* Skip back over the new-line. */
|
|
while ((pos > Most_Beg)
|
|
&& (*pos != '\n'))
|
|
pos--;
|
|
|
|
if (*pos != '\n') return pos;
|
|
if (pos + 1 != cpos)
|
|
return pos + 1;
|
|
}
|
|
}
|
|
else BSKIP_CHAR (pos, Most_Beg);
|
|
|
|
if (*pos != '\n')
|
|
{
|
|
while ((pos > Most_Beg)
|
|
&& (*pos != '\n'))
|
|
pos--;
|
|
if (*pos != '\n') return Most_Beg;
|
|
return pos + 1;
|
|
}
|
|
|
|
/* from here on *pos == '\n' */
|
|
|
|
if (Most_S_Opt == 0) return pos + 1;
|
|
|
|
while ((pos > Most_Beg)
|
|
&& (*pos == '\n')) pos--;
|
|
pos += 2;
|
|
if (pos > cpos) pos = cpos;
|
|
return pos;
|
|
}
|
|
|
|
/* does not move point */
|
|
static unsigned char *end_of_line1(void)
|
|
{
|
|
register unsigned char *pos, *pmax;
|
|
int n, n2;
|
|
|
|
pos = Most_Beg + Most_C_Offset;
|
|
pmax = Most_Eob;
|
|
if (pos >= pmax) return pmax;
|
|
|
|
/* find the first '\n'. If we are wrapping lines, then do not go more
|
|
* than 3 times the display width.
|
|
*/
|
|
if (Most_W_Opt && SLtt_Screen_Cols)
|
|
{
|
|
pmax = pos + 3 * SLtt_Screen_Cols;
|
|
if (pmax > Most_Eob)
|
|
pmax = Most_Eob;
|
|
}
|
|
|
|
if (*pos != '\n')
|
|
{
|
|
/* This block is UTF-8 safe, because it only scans the buffer
|
|
* for a new-line, and doesn't count characters.
|
|
*/
|
|
n = pmax - pos;
|
|
n2 = n % 8;
|
|
pmax = pos + (n - 8);
|
|
|
|
while (pos <= pmax)
|
|
{
|
|
if (*pos == '\n') return pos;
|
|
if (*(pos + 1) == '\n') return pos + 1;
|
|
if (*(pos + 2) == '\n') return pos + 2;
|
|
if (*(pos + 3) == '\n') return pos + 3;
|
|
if (*(pos + 4) == '\n') return pos + 4;
|
|
if (*(pos + 5) == '\n') return pos + 5;
|
|
if (*(pos + 6) == '\n') return pos + 6;
|
|
if (*(pos + 7) == '\n') return pos + 7;
|
|
pos += 8;
|
|
}
|
|
pmax = pos + n2;
|
|
while ((pos < pmax) && (*pos != '\n')) pos++;
|
|
return(pos);
|
|
}
|
|
|
|
if (!Most_S_Opt) return (pos);
|
|
/* file */
|
|
/* if Most_Beg = "....abc\n\n\n\n\ndef..." then we are at some first \n. We
|
|
want to return the last '\n' unless we wre at the first '\n'. */
|
|
|
|
/* Here we are on a \n and NOT at the end of the buffer */
|
|
|
|
if ((pos > Most_Beg) && (*(pos - 1) != '\n')) return (pos);
|
|
|
|
while ((pos < Most_Eob) && (*pos == '\n')) pos++;
|
|
if (pos == Most_Eob) return pos;
|
|
if (pos != Most_Beg) pos--;
|
|
return pos;
|
|
/* if (pos == Most_Eob) return (pos - 1);
|
|
return pos; */
|
|
}
|
|
|
|
unsigned char *most_beg_of_line(void)
|
|
{
|
|
unsigned char *b;
|
|
unsigned int ncols;
|
|
unsigned char *e;
|
|
|
|
if (Most_W_Opt == 0) return beg_of_line1();
|
|
|
|
b = beg_of_line1 ();
|
|
e = end_of_line1 ();
|
|
ncols = SLtt_Screen_Cols;
|
|
if (Most_Show_Wrap_Marker)
|
|
ncols--;
|
|
while (1)
|
|
{
|
|
unsigned char *next_b = most_forward_columns (b, e, ncols);
|
|
if ((next_b == e) || (next_b == b))
|
|
break;
|
|
|
|
if (next_b >= Most_Beg + Most_C_Offset)
|
|
break;
|
|
|
|
b = next_b;
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
static unsigned char *end_of_line (unsigned char *b)
|
|
{
|
|
unsigned char *e, *b1;
|
|
int ncols;
|
|
|
|
e = end_of_line1();
|
|
if (Most_W_Opt == 0)
|
|
return e;
|
|
|
|
if (b == NULL) b = most_beg_of_line ();
|
|
|
|
ncols = SLtt_Screen_Cols;
|
|
if (Most_Show_Wrap_Marker)
|
|
ncols--;
|
|
|
|
b = most_forward_columns (b, e, ncols);
|
|
|
|
/* Do not wrap the line if the last character falls on the last column
|
|
* of the display.
|
|
*/
|
|
if (Most_Show_Wrap_Marker)
|
|
{
|
|
if ((Most_UTF8_Mode == 0) || ((*b & 0x80) == 0))
|
|
b1 = b + 1;
|
|
else
|
|
b1 = SLutf8_skip_char (b, Most_Eob);
|
|
|
|
if ((b1 <= e)
|
|
&& (b1 < Most_Eob))
|
|
{
|
|
if (*b1 == '\n')
|
|
b = b1;
|
|
else if ((*b1 == 033) && (Most_V_Opt == 0))
|
|
{
|
|
unsigned char ch = 033;
|
|
b1++;
|
|
while ((ch == 033) && (b1 < e) && (b1 < Most_Eob)
|
|
&& (0 == most_parse_color_escape (&b1, e, NULL)))
|
|
{
|
|
b = b1;
|
|
ch = *b1++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
MOST_INT most_forward_line (MOST_INT save)
|
|
{
|
|
MOST_INT m, n;
|
|
unsigned char *p;
|
|
unsigned char *pmax;
|
|
|
|
n = save;
|
|
pmax = Most_Eob;
|
|
|
|
if (n > 0)
|
|
{
|
|
if (Most_B_Opt)
|
|
{
|
|
m = (Most_Eob - (Most_Beg + Most_C_Offset)) / 16;
|
|
if (n > m) n = m;
|
|
Most_C_Offset += n * 16;
|
|
Most_C_Line += n;
|
|
return n;
|
|
}
|
|
|
|
p = NULL;
|
|
while (n--)
|
|
{
|
|
p = end_of_line (p);
|
|
Most_C_Offset = p - Most_Beg;
|
|
if (p == Most_Eob) return (save - (n + 1));
|
|
Most_C_Line++; Most_C_Offset++;
|
|
|
|
if (Most_Selective_Display)
|
|
{
|
|
/* Skip past lines with too much indentation to the start
|
|
* of a valid one.
|
|
*/
|
|
p = Most_Beg + Most_C_Offset;
|
|
while (p < pmax)
|
|
{
|
|
while ((p < pmax) && (*p <= ' ')) p++;
|
|
if (most_apparant_distance(p) < Most_Selective_Display)
|
|
break;
|
|
Most_C_Offset = (p - Most_Beg);
|
|
p = end_of_line (p);
|
|
if (p < pmax) p++;
|
|
}
|
|
Most_C_Offset = (p - Most_Beg);
|
|
}
|
|
p = Most_Beg + Most_C_Offset;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (Most_B_Opt)
|
|
{
|
|
m = Most_C_Offset / 16;
|
|
if (n < m) n = m;
|
|
Most_C_Offset += n * 16;
|
|
Most_C_Line += n;
|
|
return n;
|
|
}
|
|
else while (n++)
|
|
{
|
|
p = most_beg_of_line();
|
|
Most_C_Offset = (p - Most_Beg);
|
|
if (Most_C_Offset == 0) return (n - (save + 1));
|
|
Most_C_Line--;
|
|
Most_C_Offset--;
|
|
|
|
if (Most_Selective_Display)
|
|
{
|
|
/* Skip past lines with too much indentation to the start
|
|
* of a valid one.
|
|
*/
|
|
p = Most_Beg + Most_C_Offset;
|
|
while (p > Most_Beg)
|
|
{
|
|
/* skip all blank lines */
|
|
while ((p > Most_Beg) && (*p <= ' ')) p--;
|
|
pmax = p;
|
|
Most_C_Offset = pmax - Most_Beg;
|
|
p = most_beg_of_line ();
|
|
Most_C_Offset = p - Most_Beg;
|
|
while ((p < pmax) && (*p <= ' ')) p++;
|
|
if (most_apparant_distance(p) < Most_Selective_Display)
|
|
break;
|
|
Most_C_Offset = p - Most_Beg;
|
|
p = most_beg_of_line ();
|
|
if (p > Most_Beg) p--;
|
|
Most_C_Offset = p - Most_Beg;
|
|
}
|
|
Most_C_Offset = p - Most_Beg;
|
|
}
|
|
}
|
|
}
|
|
return(save);
|
|
}
|
|
|
|
/* Count lines in the region. A half line counts as 1 */
|
|
MOST_INT most_count_lines(unsigned char *beg, unsigned char *end)
|
|
{
|
|
MOST_INT save_line, n;
|
|
unsigned char *save_beg, *save_eob;
|
|
MOST_UINT save_pos;
|
|
int dn = 1000;
|
|
|
|
if (Most_B_Opt) return(1 + (MOST_INT)(end - beg) / 16);
|
|
|
|
save_line = Most_C_Line; save_beg = Most_Beg; save_eob = Most_Eob;
|
|
save_pos = Most_C_Offset;
|
|
|
|
Most_Beg = beg; Most_Eob = end;
|
|
Most_C_Offset = 0;
|
|
|
|
n = 1;
|
|
while((dn = most_forward_line(dn)) != 0) n += dn;
|
|
|
|
Most_C_Offset = save_pos;
|
|
Most_Eob = save_eob;
|
|
Most_Beg = save_beg;
|
|
Most_C_Line = save_line;
|
|
return(n);
|
|
}
|
|
|
|
void most_goto_line (MOST_INT line)
|
|
{
|
|
MOST_INT dif_c, dif_b, dif_t;
|
|
|
|
if (line < 1) line = 1;
|
|
most_read_to_line(line);
|
|
if (line > Most_Num_Lines) line = Most_Num_Lines;
|
|
|
|
if (Most_B_Opt)
|
|
{
|
|
Most_C_Offset = (16 * (line - 1));
|
|
Most_C_Line = line;
|
|
return;
|
|
}
|
|
|
|
dif_c = line - Most_C_Line;
|
|
dif_b = line - Most_Num_Lines;
|
|
dif_t = line - 1;
|
|
|
|
/* 4 possibilites */
|
|
if (dif_c <= 0)
|
|
{
|
|
if (dif_t < -dif_c) /* go from top */
|
|
{
|
|
Most_C_Line = 1;
|
|
Most_C_Offset = 0;
|
|
(void) most_forward_line(dif_t);
|
|
}
|
|
else /* from curr back */
|
|
{
|
|
(void) most_forward_line(dif_c);
|
|
}
|
|
}
|
|
else if (dif_c > 0)
|
|
{
|
|
if ((dif_c + dif_b) < 0) /* go from curr */
|
|
{
|
|
(void) most_forward_line(dif_c);
|
|
}
|
|
else
|
|
{
|
|
Most_C_Line = Most_Num_Lines;
|
|
Most_C_Offset = (Most_Eob - Most_Beg);
|
|
(void) most_forward_line(dif_b);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* return line the point is on without the final '\n's */
|
|
int most_extract_line(unsigned char **beg, unsigned char **end)
|
|
{
|
|
*beg = most_beg_of_line();
|
|
*end = end_of_line (*beg);
|
|
|
|
return 0;
|
|
}
|
|
|
|
MOST_INT most_what_line(unsigned char *pos)
|
|
{
|
|
unsigned int save_pos;
|
|
MOST_INT save_line, dir;
|
|
MOST_INT dif_c, dif_b,dif_t;
|
|
int ret;
|
|
|
|
if (Most_B_Opt)
|
|
{
|
|
return (1 + (pos - Most_Beg)/16);
|
|
}
|
|
|
|
if (Most_Selective_Display)
|
|
{
|
|
return most_count_lines (Most_Beg, pos);
|
|
}
|
|
|
|
save_pos = Most_C_Offset;
|
|
save_line = Most_C_Line;
|
|
|
|
dif_c = pos - (Most_Beg + Most_C_Offset);
|
|
dif_b = pos - Most_Eob;
|
|
dif_t = pos - Most_Beg;
|
|
|
|
/* 4 possibilites */
|
|
if (dif_c <= 0)
|
|
{
|
|
if (dif_t < -dif_c) /* go from top */
|
|
{
|
|
Most_C_Line = 1;
|
|
Most_C_Offset = 0;
|
|
dir = 1;
|
|
}
|
|
else /* from curr back */
|
|
{
|
|
dir = -1;
|
|
}
|
|
}
|
|
else /* (dif_c > 0) */
|
|
{
|
|
if ((dif_c + dif_b) < 0) /* go from curr */
|
|
{
|
|
dir = 1;
|
|
}
|
|
else
|
|
{
|
|
Most_C_Line = Most_Num_Lines;
|
|
Most_C_Offset = Most_Eob - Most_Beg;
|
|
dir = -1;
|
|
}
|
|
}
|
|
if (dir == 1)
|
|
{
|
|
while (1)
|
|
{
|
|
unsigned char *cpos;
|
|
|
|
cpos = end_of_line (NULL);
|
|
Most_C_Offset = cpos - Most_Beg;
|
|
|
|
if (cpos >= pos)
|
|
break;
|
|
|
|
Most_C_Offset++;
|
|
Most_C_Line++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
while (1)
|
|
{
|
|
unsigned char *cpos;
|
|
|
|
cpos = most_beg_of_line ();
|
|
Most_C_Offset = cpos - Most_Beg;
|
|
if (pos >= cpos)
|
|
break;
|
|
Most_C_Line--;
|
|
Most_C_Offset--;
|
|
}
|
|
}
|
|
|
|
ret = Most_C_Line;
|
|
Most_C_Offset = save_pos;
|
|
Most_C_Line = save_line;
|
|
return(ret);
|
|
}
|
|
|
|
/* given a buffer position, find the line and column */
|
|
void most_find_row_column(unsigned char *pos, MOST_INT *r, MOST_INT *c)
|
|
{
|
|
unsigned int save_offset;
|
|
MOST_INT save_line;
|
|
|
|
if (pos <= Most_Beg)
|
|
{
|
|
*r = 1;
|
|
*c = 1;
|
|
return;
|
|
}
|
|
|
|
save_line = Most_C_Line;
|
|
save_offset = Most_C_Offset;
|
|
*r = most_what_line(pos);
|
|
|
|
if (Most_B_Opt)
|
|
{
|
|
*c = (int) (pos - Most_Beg) - (*r - 1) * 16 + 1;
|
|
return;
|
|
}
|
|
Most_C_Line = *r;
|
|
Most_C_Offset = pos - Most_Beg;
|
|
|
|
/* Now we have found the line it is on so.... */
|
|
(void) most_beg_of_line();
|
|
*c = 1 + most_apparant_distance (pos);
|
|
|
|
Most_C_Line = save_line;
|
|
Most_C_Offset = save_offset;
|
|
}
|
|
|
|
Most_Buffer_Type *most_switch_to_buffer(Most_Buffer_Type *nnew)
|
|
{
|
|
Most_Buffer_Type *old;
|
|
old = Most_Buf;
|
|
Most_Buf = nnew;
|
|
Most_Beg = Most_Buf->beg;
|
|
Most_Eob = Most_Buf->end;
|
|
return old;
|
|
}
|
|
|
|
Most_Buffer_Type *most_create_buffer(char *file)
|
|
{
|
|
Most_Buffer_Type *buf;
|
|
|
|
buf = (Most_Buffer_Type *) MOSTMALLOC(sizeof(Most_Buffer_Type));
|
|
memset ((char *) buf, 0, sizeof(Most_Buffer_Type));
|
|
strcpy(buf->file,file);
|
|
return(buf);
|
|
}
|
|
|
|
unsigned char *most_malloc(unsigned int n)
|
|
{
|
|
unsigned char *b = (unsigned char *) SLMALLOC(n);
|
|
if (b == NULL)
|
|
{
|
|
most_exit_error("malloc: Memory Allocation Error.");
|
|
}
|
|
return b;
|
|
}
|
|
|
|
unsigned char *most_realloc(unsigned char *p, unsigned int n)
|
|
{
|
|
unsigned char *b = (unsigned char *) SLREALLOC(p, n);
|
|
if (b == NULL)
|
|
{
|
|
most_exit_error("malloc: Memory Allocation Error.");
|
|
}
|
|
return b;
|
|
}
|