rust-most/vendor/most-5.1.0/src/buffer.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;
}