diff options
Diffstat (limited to 'gc/cord/de.c')
-rw-r--r-- | gc/cord/de.c | 603 |
1 files changed, 0 insertions, 603 deletions
diff --git a/gc/cord/de.c b/gc/cord/de.c deleted file mode 100644 index fda7142..0000000 --- a/gc/cord/de.c +++ /dev/null @@ -1,603 +0,0 @@ -/* - * Copyright (c) 1993-1994 by Xerox Corporation. All rights reserved. - * - * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED - * OR IMPLIED. ANY USE IS AT YOUR OWN RISK. - * - * Permission is hereby granted to use or copy this program - * for any purpose, provided the above notices are retained on all copies. - * Permission to modify the code and to distribute modified code is granted, - * provided the above notices are retained, and a notice that the code was - * modified is included with the above copyright notice. - * - * Author: Hans-J. Boehm (boehm@parc.xerox.com) - */ -/* - * A really simple-minded text editor based on cords. - * Things it does right: - * No size bounds. - * Inbounded undo. - * Shouldn't crash no matter what file you invoke it on (e.g. /vmunix) - * (Make sure /vmunix is not writable before you try this.) - * Scrolls horizontally. - * Things it does wrong: - * It doesn't handle tabs reasonably (use "expand" first). - * The command set is MUCH too small. - * The redisplay algorithm doesn't let curses do the scrolling. - * The rule for moving the window over the file is suboptimal. - */ -/* Boehm, February 6, 1995 12:27 pm PST */ - -/* Boehm, May 19, 1994 2:20 pm PDT */ -#include <stdio.h> -#include "gc.h" -#include "cord.h" - -#ifdef THINK_C -#define MACINTOSH -#include <ctype.h> -#endif - -#if defined(__BORLANDC__) && !defined(WIN32) - /* If this is DOS or win16, we'll fail anyway. */ - /* Might as well assume win32. */ -# define WIN32 -#endif - -#if defined(WIN32) -# include <windows.h> -# include "de_win.h" -#elif defined(MACINTOSH) -# include <console.h> -/* curses emulation. */ -# define initscr() -# define endwin() -# define nonl() -# define noecho() csetmode(C_NOECHO, stdout) -# define cbreak() csetmode(C_CBREAK, stdout) -# define refresh() -# define addch(c) putchar(c) -# define standout() cinverse(1, stdout) -# define standend() cinverse(0, stdout) -# define move(line,col) cgotoxy(col + 1, line + 1, stdout) -# define clrtoeol() ccleol(stdout) -# define de_error(s) { fprintf(stderr, s); getchar(); } -# define LINES 25 -# define COLS 80 -#else -# include <curses.h> -# define de_error(s) { fprintf(stderr, s); sleep(2); } -#endif -#include "de_cmds.h" - -/* List of line number to position mappings, in descending order. */ -/* There may be holes. */ -typedef struct LineMapRep { - int line; - size_t pos; - struct LineMapRep * previous; -} * line_map; - -/* List of file versions, one per edit operation */ -typedef struct HistoryRep { - CORD file_contents; - struct HistoryRep * previous; - line_map map; /* Invalid for first record "now" */ -} * history; - -history now = 0; -CORD current; /* == now -> file_contents. */ -size_t current_len; /* Current file length. */ -line_map current_map = 0; /* Current line no. to pos. map */ -size_t current_map_size = 0; /* Number of current_map entries. */ - /* Not always accurate, but reset */ - /* by prune_map. */ -# define MAX_MAP_SIZE 3000 - -/* Current display position */ -int dis_line = 0; -int dis_col = 0; - -# define ALL -1 -# define NONE - 2 -int need_redisplay = 0; /* Line that needs to be redisplayed. */ - - -/* Current cursor position. Always within file. */ -int line = 0; -int col = 0; -size_t file_pos = 0; /* Character position corresponding to cursor. */ - -/* Invalidate line map for lines > i */ -void invalidate_map(int i) -{ - while(current_map -> line > i) { - current_map = current_map -> previous; - current_map_size--; - } -} - -/* Reduce the number of map entries to save space for huge files. */ -/* This also affects maps in histories. */ -void prune_map() -{ - line_map map = current_map; - int start_line = map -> line; - - current_map_size = 0; - for(; map != 0; map = map -> previous) { - current_map_size++; - if (map -> line < start_line - LINES && map -> previous != 0) { - map -> previous = map -> previous -> previous; - } - } -} -/* Add mapping entry */ -void add_map(int line, size_t pos) -{ - line_map new_map = GC_NEW(struct LineMapRep); - - if (current_map_size >= MAX_MAP_SIZE) prune_map(); - new_map -> line = line; - new_map -> pos = pos; - new_map -> previous = current_map; - current_map = new_map; - current_map_size++; -} - - - -/* Return position of column *c of ith line in */ -/* current file. Adjust *c to be within the line.*/ -/* A 0 pointer is taken as 0 column. */ -/* Returns CORD_NOT_FOUND if i is too big. */ -/* Assumes i > dis_line. */ -size_t line_pos(int i, int *c) -{ - int j; - size_t cur; - size_t next; - line_map map = current_map; - - while (map -> line > i) map = map -> previous; - if (map -> line < i - 2) /* rebuild */ invalidate_map(i); - for (j = map -> line, cur = map -> pos; j < i;) { - cur = CORD_chr(current, cur, '\n'); - if (cur == current_len-1) return(CORD_NOT_FOUND); - cur++; - if (++j > current_map -> line) add_map(j, cur); - } - if (c != 0) { - next = CORD_chr(current, cur, '\n'); - if (next == CORD_NOT_FOUND) next = current_len - 1; - if (next < cur + *c) { - *c = next - cur; - } - cur += *c; - } - return(cur); -} - -void add_hist(CORD s) -{ - history new_file = GC_NEW(struct HistoryRep); - - new_file -> file_contents = current = s; - current_len = CORD_len(s); - new_file -> previous = now; - if (now != 0) now -> map = current_map; - now = new_file; -} - -void del_hist(void) -{ - now = now -> previous; - current = now -> file_contents; - current_map = now -> map; - current_len = CORD_len(current); -} - -/* Current screen_contents; a dynamically allocated array of CORDs */ -CORD * screen = 0; -int screen_size = 0; - -# ifndef WIN32 -/* Replace a line in the curses stdscr. All control characters are */ -/* displayed as upper case characters in standout mode. This isn't */ -/* terribly appropriate for tabs. */ -void replace_line(int i, CORD s) -{ - register int c; - CORD_pos p; - size_t len = CORD_len(s); - - if (screen == 0 || LINES > screen_size) { - screen_size = LINES; - screen = (CORD *)GC_MALLOC(screen_size * sizeof(CORD)); - } -# if !defined(MACINTOSH) - /* A gross workaround for an apparent curses bug: */ - if (i == LINES-1 && len == COLS) { - s = CORD_substr(s, 0, CORD_len(s) - 1); - } -# endif - if (CORD_cmp(screen[i], s) != 0) { - move(i, 0); clrtoeol(); move(i,0); - - CORD_FOR (p, s) { - c = CORD_pos_fetch(p) & 0x7f; - if (iscntrl(c)) { - standout(); addch(c + 0x40); standend(); - } else { - addch(c); - } - } - screen[i] = s; - } -} -#else -# define replace_line(i,s) invalidate_line(i) -#endif - -/* Return up to COLS characters of the line of s starting at pos, */ -/* returning only characters after the given column. */ -CORD retrieve_line(CORD s, size_t pos, unsigned column) -{ - CORD candidate = CORD_substr(s, pos, column + COLS); - /* avoids scanning very long lines */ - int eol = CORD_chr(candidate, 0, '\n'); - int len; - - if (eol == CORD_NOT_FOUND) eol = CORD_len(candidate); - len = (int)eol - (int)column; - if (len < 0) len = 0; - return(CORD_substr(s, pos + column, len)); -} - -# ifdef WIN32 -# define refresh(); - - CORD retrieve_screen_line(int i) - { - register size_t pos; - - invalidate_map(dis_line + LINES); /* Prune search */ - pos = line_pos(dis_line + i, 0); - if (pos == CORD_NOT_FOUND) return(CORD_EMPTY); - return(retrieve_line(current, pos, dis_col)); - } -# endif - -/* Display the visible section of the current file */ -void redisplay(void) -{ - register int i; - - invalidate_map(dis_line + LINES); /* Prune search */ - for (i = 0; i < LINES; i++) { - if (need_redisplay == ALL || need_redisplay == i) { - register size_t pos = line_pos(dis_line + i, 0); - - if (pos == CORD_NOT_FOUND) break; - replace_line(i, retrieve_line(current, pos, dis_col)); - if (need_redisplay == i) goto done; - } - } - for (; i < LINES; i++) replace_line(i, CORD_EMPTY); -done: - refresh(); - need_redisplay = NONE; -} - -int dis_granularity; - -/* Update dis_line, dis_col, and dis_pos to make cursor visible. */ -/* Assumes line, col, dis_line, dis_pos are in bounds. */ -void normalize_display() -{ - int old_line = dis_line; - int old_col = dis_col; - - dis_granularity = 1; - if (LINES > 15 && COLS > 15) dis_granularity = 2; - while (dis_line > line) dis_line -= dis_granularity; - while (dis_col > col) dis_col -= dis_granularity; - while (line >= dis_line + LINES) dis_line += dis_granularity; - while (col >= dis_col + COLS) dis_col += dis_granularity; - if (old_line != dis_line || old_col != dis_col) { - need_redisplay = ALL; - } -} - -# if defined(WIN32) -# elif defined(MACINTOSH) -# define move_cursor(x,y) cgotoxy(x + 1, y + 1, stdout) -# else -# define move_cursor(x,y) move(y,x) -# endif - -/* Adjust display so that cursor is visible; move cursor into position */ -/* Update screen if necessary. */ -void fix_cursor(void) -{ - normalize_display(); - if (need_redisplay != NONE) redisplay(); - move_cursor(col - dis_col, line - dis_line); - refresh(); -# ifndef WIN32 - fflush(stdout); -# endif -} - -/* Make sure line, col, and dis_pos are somewhere inside file. */ -/* Recompute file_pos. Assumes dis_pos is accurate or past eof */ -void fix_pos() -{ - int my_col = col; - - if ((size_t)line > current_len) line = current_len; - file_pos = line_pos(line, &my_col); - if (file_pos == CORD_NOT_FOUND) { - for (line = current_map -> line, file_pos = current_map -> pos; - file_pos < current_len; - line++, file_pos = CORD_chr(current, file_pos, '\n') + 1); - line--; - file_pos = line_pos(line, &col); - } else { - col = my_col; - } -} - -#if defined(WIN32) -# define beep() Beep(1000 /* Hz */, 300 /* msecs */) -#elif defined(MACINTOSH) -# define beep() SysBeep(1) -#else -/* - * beep() is part of some curses packages and not others. - * We try to match the type of the builtin one, if any. - */ -#ifdef __STDC__ - int beep(void) -#else - int beep() -#endif -{ - putc('\007', stderr); - return(0); -} -#endif - -# define NO_PREFIX -1 -# define BARE_PREFIX -2 -int repeat_count = NO_PREFIX; /* Current command prefix. */ - -int locate_mode = 0; /* Currently between 2 ^Ls */ -CORD locate_string = CORD_EMPTY; /* Current search string. */ - -char * arg_file_name; - -#ifdef WIN32 -/* Change the current position to whatever is currently displayed at */ -/* the given SCREEN coordinates. */ -void set_position(int c, int l) -{ - line = l + dis_line; - col = c + dis_col; - fix_pos(); - move_cursor(col - dis_col, line - dis_line); -} -#endif /* WIN32 */ - -/* Perform the command associated with character c. C may be an */ -/* integer > 256 denoting a windows command, one of the above control */ -/* characters, or another ASCII character to be used as either a */ -/* character to be inserted, a repeat count, or a search string, */ -/* depending on the current state. */ -void do_command(int c) -{ - int i; - int need_fix_pos; - FILE * out; - - if ( c == '\r') c = '\n'; - if (locate_mode) { - size_t new_pos; - - if (c == LOCATE) { - locate_mode = 0; - locate_string = CORD_EMPTY; - return; - } - locate_string = CORD_cat_char(locate_string, (char)c); - new_pos = CORD_str(current, file_pos - CORD_len(locate_string) + 1, - locate_string); - if (new_pos != CORD_NOT_FOUND) { - need_redisplay = ALL; - new_pos += CORD_len(locate_string); - for (;;) { - file_pos = line_pos(line + 1, 0); - if (file_pos > new_pos) break; - line++; - } - col = new_pos - line_pos(line, 0); - file_pos = new_pos; - fix_cursor(); - } else { - locate_string = CORD_substr(locate_string, 0, - CORD_len(locate_string) - 1); - beep(); - } - return; - } - if (c == REPEAT) { - repeat_count = BARE_PREFIX; return; - } else if (c < 0x100 && isdigit(c)){ - if (repeat_count == BARE_PREFIX) { - repeat_count = c - '0'; return; - } else if (repeat_count != NO_PREFIX) { - repeat_count = 10 * repeat_count + c - '0'; return; - } - } - if (repeat_count == NO_PREFIX) repeat_count = 1; - if (repeat_count == BARE_PREFIX && (c == UP || c == DOWN)) { - repeat_count = LINES - dis_granularity; - } - if (repeat_count == BARE_PREFIX) repeat_count = 8; - need_fix_pos = 0; - for (i = 0; i < repeat_count; i++) { - switch(c) { - case LOCATE: - locate_mode = 1; - break; - case TOP: - line = col = file_pos = 0; - break; - case UP: - if (line != 0) { - line--; - need_fix_pos = 1; - } - break; - case DOWN: - line++; - need_fix_pos = 1; - break; - case LEFT: - if (col != 0) { - col--; file_pos--; - } - break; - case RIGHT: - if (CORD_fetch(current, file_pos) == '\n') break; - col++; file_pos++; - break; - case UNDO: - del_hist(); - need_redisplay = ALL; need_fix_pos = 1; - break; - case BS: - if (col == 0) { - beep(); - break; - } - col--; file_pos--; - /* fall through: */ - case DEL: - if (file_pos == current_len-1) break; - /* Can't delete trailing newline */ - if (CORD_fetch(current, file_pos) == '\n') { - need_redisplay = ALL; need_fix_pos = 1; - } else { - need_redisplay = line - dis_line; - } - add_hist(CORD_cat( - CORD_substr(current, 0, file_pos), - CORD_substr(current, file_pos+1, current_len))); - invalidate_map(line); - break; - case WRITE: - { - CORD name = CORD_cat(CORD_from_char_star(arg_file_name), - ".new"); - - if ((out = fopen(CORD_to_const_char_star(name), "wb")) == NULL - || CORD_put(current, out) == EOF) { - de_error("Write failed\n"); - need_redisplay = ALL; - } else { - fclose(out); - } - } - break; - default: - { - CORD left_part = CORD_substr(current, 0, file_pos); - CORD right_part = CORD_substr(current, file_pos, current_len); - - add_hist(CORD_cat(CORD_cat_char(left_part, (char)c), - right_part)); - invalidate_map(line); - if (c == '\n') { - col = 0; line++; file_pos++; - need_redisplay = ALL; - } else { - col++; file_pos++; - need_redisplay = line - dis_line; - } - break; - } - } - } - if (need_fix_pos) fix_pos(); - fix_cursor(); - repeat_count = NO_PREFIX; -} - -/* OS independent initialization */ - -void generic_init(void) -{ - FILE * f; - CORD initial; - - if ((f = fopen(arg_file_name, "rb")) == NULL) { - initial = "\n"; - } else { - initial = CORD_from_file(f); - if (initial == CORD_EMPTY - || CORD_fetch(initial, CORD_len(initial)-1) != '\n') { - initial = CORD_cat(initial, "\n"); - } - } - add_map(0,0); - add_hist(initial); - now -> map = current_map; - now -> previous = now; /* Can't back up further: beginning of the world */ - need_redisplay = ALL; - fix_cursor(); -} - -#ifndef WIN32 - -main(argc, argv) -int argc; -char ** argv; -{ - int c; - -#if defined(MACINTOSH) - console_options.title = "\pDumb Editor"; - cshow(stdout); - GC_init(); - argc = ccommand(&argv); -#endif - - if (argc != 2) goto usage; - arg_file_name = argv[1]; - setvbuf(stdout, GC_MALLOC_ATOMIC(8192), _IOFBF, 8192); - initscr(); - noecho(); nonl(); cbreak(); - generic_init(); - while ((c = getchar()) != QUIT) { - if (c == EOF) break; - do_command(c); - } -done: - move(LINES-1, 0); - clrtoeol(); - refresh(); - nl(); - echo(); - endwin(); - exit(0); -usage: - fprintf(stderr, "Usage: %s file\n", argv[0]); - fprintf(stderr, "Cursor keys: ^B(left) ^F(right) ^P(up) ^N(down)\n"); - fprintf(stderr, "Undo: ^U Write to <file>.new: ^W"); - fprintf(stderr, "Quit:^D Repeat count: ^R[n]\n"); - fprintf(stderr, "Top: ^T Locate (search, find): ^L text ^L\n"); - exit(1); -} - -#endif /* !WIN32 */ |