/* 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 #ifdef HAVE_STDLIB_H # include #endif #include #include #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; }