This is buffer.c in view mode; [Download] [Up]
/* * Copyright (c) 1992, 1995 John E. Davis (davis@space.mit.edu) * All Rights Reserved. */ #include <config.h> #include <stdio.h> #include <setjmp.h> #if defined (msdos) || defined (__os2_16__) #include <process.h> #include <dos.h> #endif #include <limits.h> #include <string.h> #include "buffer.h" #include "window.h" #include "file.h" #include "ins.h" #include "misc.h" #include "paste.h" #include "sysdep.h" #ifdef HAS_SUBPROCESSES #include "jprocess.h" #endif extern int Goal_Column; typedef struct { jmp_buf b; } jmp_buf_struct; extern jmp_buf_struct Jump_Buffer, *Jump_Buffer_Ptr; typedef struct Buffer_List_Type { Buffer *buf; struct Buffer_List_Type *next; } Buffer_List_Type; Buffer_List_Type *Buffer_Stack; /* a filo */ #ifndef ULONG_MAX #define MAX_LONG (0xFFFFFFFFL | (0xFFFFFFFFL << (sizeof(long) / 8))) #else #define MAX_LONG ULONG_MAX #endif Buffer *CBuf; Line *CLine; Buffer_Local_Type Buffer_Local = { 8, 0 }; int Number_One = 1; /* these should be const but */ int Number_Zero = 0; /* some compilers complain */ int Number_Two = 2; int Number_Ten = 10; char *Read_Only_Error = (char *) "Buffer is read only!"; unsigned int LineNum = 1; unsigned int Max_LineNum; int Point = 0; /* move point to top of buffer */ int bob() { CLine = CBuf->beg; Point = 0; LineNum = 1; return(1); } int eob() /* point to end of buffer */ { CLine = CBuf->end; LineNum = Max_LineNum; if (CLine == NULL) { Point = 0; return(0); } Point = CLine->len - 1; if (Point < 0) { Point = 0; return(1); } if ((CLine->data[Point] != '\n') || (CBuf == MiniBuffer)) Point++; return(1); } int bol() { Point = 0; Goal_Column = 1; return(1); } int eol() { int newline = 1; if (CLine != NULL) { Point = CLine->len - 1; if (Point < 0) { Point = 0; return(0); } if (((CLine->data)[Point] != '\n') || (CBuf == MiniBuffer)) newline = 0; if (!newline) Point++; } else Point = 0; return(1); } int bobp() /* returns 1 if top line of buffer, 0 otherwise */ { if ((CBuf->beg == CLine) && (Point == 0)) return(1); else return(0); } int eolp() { int len; if (CLine == NULL) return(1); len = CLine->len; if (len == 0) return(1); if (Point < len - 1) return(0); if (CBuf == MiniBuffer) { if (Point < len) return 0; else return (1); } /* Point is either len or len - 1 */ if ((CLine->data)[len-1] == '\n') return (1); if (Point == len) return(1); Point = len - 1; return(0); } int eobp() { if (CLine != CBuf->end) return(0); return(eolp()); } int bolp() { if (Point) return(0); else return(1); } /* Attempt to goback n lines, return actual number. */ int prevline(int *n) { int i = 0; Line *prev; Point = 0; /* return to beginning of this line */ while (i < *n) { prev = CLine->prev; while((prev != NULL) && (prev->len == 0)) prev = prev->prev; if (prev == NULL) break; i++; CLine = prev; } if (i) eol(); LineNum -= (unsigned int) i; return(i); } int nextline(int *np) { register Line *next; register int i = 0, n = *np; while(i < n) { next = CLine->next; if (next == NULL) break; CLine = next; i++; } if (i) Point = 0; LineNum += (unsigned int) i; return(i); } /* The algorithm: go to Point = len - 1. Then forward a line counted as 1 */ int forwchars(int *np) { int len, total = 0; unsigned char *p; Line *next; int n = *np; if (n < 0) return 0; if (CBuf == MiniBuffer) { total = CLine->len - Point; if (n > total) n = total; Point += n; return n; } while(1) { len = CLine->len; /* if (Point == len) return(total); */ p = CLine->data + Point; while(n && (Point < len) && (*p != '\n')) { Point++; n--; p++; total++; } if (!n) return(total); if ((Point < len) && (*p == '\n')) { total++; n--; } if (NULL == (next = CLine->next)) { if ((Point < len) && (*p == '\n')) total--; return(total); } Point = 0; CLine = next; LineNum++; } } int backwchars(int *np) { int total = 0; int n = *np; if (n < 0) return 0; if (CBuf == MiniBuffer) { if (n > Point) n = Point; Point -= n; return (n); } do { if (n <= Point) { total += n; Point = Point - n; return(total); } n = n - Point - 1; /* Point + newline */ total += Point + 1; /* ditto */ } while(prevline(&Number_One)); return(total - 1); } /* assuming 8 bit bytes */ #define BUNCH_SIZE 8 * sizeof(long) static unsigned char NewLine_Buffer[1] = { '\n' }; typedef struct Bunch_Lines_Type { struct Bunch_Lines_Type *next; unsigned long flags; /* describes which are free */ Line lines[BUNCH_SIZE]; } Bunch_Lines_Type; static int Next_Free_Offset = BUNCH_SIZE; static int Last_Free_Offset; static Bunch_Lines_Type *Last_Free_Group; static Bunch_Lines_Type *Bunch_Lines; static unsigned int Number_Freed; /* amount of Lines available */ static Line *create_line_from_bunch(void) { register Bunch_Lines_Type *b, *bsave; Line *l; unsigned long flags; int count; if (Last_Free_Group != NULL) { l = &Last_Free_Group->lines[Last_Free_Offset]; flags = ((unsigned long) 1L << Last_Free_Offset); if ((Last_Free_Group->flags & flags) == 0) { exit_error("create group: internal error 1", 1); } Last_Free_Group->flags &= ~flags; Last_Free_Group = NULL; Number_Freed--; return (l); } if (Next_Free_Offset < BUNCH_SIZE) { flags = ((unsigned long) 1L << Next_Free_Offset); if ((Bunch_Lines->flags & flags) == 0) { exit_error("free group: internal error 2", 1); } Bunch_Lines->flags &= ~flags; Number_Freed--; return(&Bunch_Lines->lines[Next_Free_Offset++]); } /* search list */ b = Bunch_Lines; if (b != NULL) { b = b->next; } if ((b != NULL) && Number_Freed) { bsave = b; do { if (b->flags) { flags = b->flags; count = 0; while ((flags & 1) == 0) { flags = flags >> 1; count++; } l = &b->lines[count]; flags = (unsigned long) 1 << count; if ((b->flags & flags) == 0) { exit_error("free group: internal error 2", 1); } b->flags &= ~flags; Number_Freed--; return (l); } b = b->next; } while (b != bsave); } /* failed so now malloc new bunch */ if (NULL != (b = (Bunch_Lines_Type *) SLMALLOC(sizeof(Bunch_Lines_Type)))) { if (Bunch_Lines == NULL) { Bunch_Lines = b; b->next = b; } else { b->next = Bunch_Lines->next; Bunch_Lines->next = b; Bunch_Lines = b; } b->flags = MAX_LONG; Next_Free_Offset = 1; b->flags &= ~(unsigned long) 1; Number_Freed += BUNCH_SIZE - 1; return(&b->lines[0]); } return(NULL); } static void destroy_bunch_line(Line *l) { #ifdef _MSC_VER Line *ll; #else register Line *ll; #endif register Bunch_Lines_Type *b, *bsave, *last, *next; static Bunch_Lines_Type *slast; if (slast != NULL) last = slast; else last = Bunch_Lines; b = bsave = last; do { ll = b->lines; if ( #if (defined (msdos) && !defined(__WATCOMC__) && !defined(__WIN32__)) || defined (__os2_16__) /* stupid DOS and its memory segmentation forces me to consider segment then offset */ (FP_SEG(ll) == FP_SEG(l)) && #endif ((ll <= l) && (l < ll + BUNCH_SIZE))) { while (ll != l) ll++; Last_Free_Offset = (int) (l - b->lines); if (b->flags & (1L << Last_Free_Offset)) { exit_error("free group: internal error 2", 1); } b->flags |= (unsigned long) 1L << Last_Free_Offset; /* if this whole structure is free, free it */ if (b->flags == MAX_LONG) { if (last == b) { while ((next = last->next) != b) last = next; } last->next = b->next; if (b == Bunch_Lines) { if (last == b) { last = NULL; /* last = last->next; if (last == b) last = NULL; */ } Bunch_Lines = last; Next_Free_Offset = BUNCH_SIZE; } SLFREE(b); if (last == b) last = NULL; b = NULL; Number_Freed -= BUNCH_SIZE - 1; slast = last; } else { Number_Freed++; } Last_Free_Group = b; if (Bunch_Lines == NULL) goto L1; return; } last = b; b = b->next; } while (b != bsave); L1: exit_error("destroy_bunch_line: internal error 1", 1); } Line *make_line1(int size) { Line *new_line; unsigned char *data = NULL; char buff[80]; unsigned int chunk; /* 4 byte chunks */ #if defined(msdos) && !defined(__WIN32__) chunk = (unsigned) (size + 3) & 0xFFFCU; #else chunk = ((unsigned) (size + 3)) & 0xFFFFFFFCU; #endif new_line = (Line *) create_line_from_bunch(); if (new_line != NULL) { if (size == 1) { data = NewLine_Buffer; chunk = 1; } else data = (unsigned char *) SLMALLOC(chunk); /* was chunk + 1 */ } if ((new_line == NULL) || (data == NULL)) { *Error_Buffer = 0; /* this is critical */ sprintf(buff, "Malloc Error in make_line: requested size: %d.", size); msg_error(buff); longjmp(Jump_Buffer_Ptr->b, 1); /* exit_error(buff); */ } new_line->data = data; new_line->len = 0; #ifdef KEEP_SPACE_INFO new_line->space = chunk; #endif #ifdef JED_LINE_ATTRIBUTES new_line->flags = 0; #endif return(new_line); } /* adds a new link to list of lines at current point */ unsigned char *make_line(int size) { Line *new_line; new_line = make_line1(size); /* if CLine is Null, then we are at the top of a NEW buffer. Make this explicit. */ if (CLine == NULL) { new_line -> prev = NULL; new_line -> next = NULL; CBuf -> beg = CBuf ->end = new_line; } else if (CLine == CBuf->end) /* at end of buffer */ { CBuf->end = new_line; new_line->next = NULL; new_line->prev = CLine; CLine->next = new_line; } else { new_line -> next = CLine -> next; if (CLine->next != NULL) CLine->next->prev = new_line; CLine->next = new_line; new_line->prev = CLine; } if (CLine == NULL) { Max_LineNum = LineNum = 1; } else { Max_LineNum++; LineNum++; } CLine = new_line; return(CLine->data); } void free_line(Line *line) { register unsigned char *dat = line->data; if (dat != NewLine_Buffer) SLFREE(dat); destroy_bunch_line(line); } /* deletes the line we are on and returns the prev one. It does not * delete the top line of the buffer. Furthermore, it does not * update any marks. */ int delete_line() { Line *n, *p, *tthis; p = CLine -> prev; if (p == NULL) return(1); n = CLine -> next; tthis = CLine; if (n == NULL) { CBuf->end = p; p->next = NULL; } else { p->next = n; n->prev = p; } free_line(tthis); CLine = p; LineNum--; Max_LineNum--; return(0); } unsigned char *remake_line(int size) { char buf[80]; unsigned char *d = CLine->data; unsigned int mask; #if defined(msdos) && !defined(__WIN32__) mask = 0xFFFCu; #else mask = 0xFFFFFFFCu; #endif size = (unsigned) (size + 3) & mask; /* 4 byte chunks */ if (d == NewLine_Buffer) { if (NULL != (d = (unsigned char *) SLMALLOC(size))) *d = '\n'; } else { #if 0 #ifndef KEEP_SPACE_INFO if (((CLine->len + 3) & mask) == size) return d; #endif #endif d = (unsigned char *) SLREALLOC(d, size); } if (d == NULL) { *Error_Buffer = 0; /* critical error */ sprintf(buf, "remake_line: realloc error!, size = %d", size); msg_error(buf); longjmp(Jump_Buffer_Ptr->b, 1); /* exit_error(buf); */ } #ifdef KEEP_SPACE_INFO CLine->space = size; #endif CLine->data = d; return(d); } void uniquely_name_buffer(char *trry) { Buffer *b; int exists, version = 0, n; char neew[48]; *CBuf->name = 0; strncpy(neew, trry, 45); neew[45] = 0; n = strlen(neew); while (1) { exists = 0; b = CBuf->next; while(b != CBuf) { if (!strcmp(neew, b->name)) exists = 1; b = b->next; } if (!exists) { strcpy(CBuf->name,neew); return; } version++; sprintf(neew + n, "<%d>", version); } } /* make a buffer and insert it in the list */ Buffer *make_buffer() { Buffer *newB; /* SLCALLOC used since it zeros region too */ newB = (Buffer *) SLCALLOC(sizeof(Buffer), 1); if (newB == (Buffer *) NULL) { exit_error("make_buffer: malloc error", 0); } MEMSET ((char *) newB, 0, sizeof(Buffer)); newB->keymap = Global_Map; newB->c_time = sys_time(); newB->tab = User_Vars.tab; #ifdef HAS_ABBREVS newB->abbrev_table_handle = -1; #endif if (CBuf == NULL) { newB->next = newB; newB->prev = newB; } else { newB->next = CBuf; newB->prev = CBuf->prev; CBuf->prev->next = newB; CBuf->prev = newB; } #ifdef pc_system newB->flags |= ADD_CR_ON_WRITE_FLAG; #endif newB->syntax_table = Default_Syntax_Table; return(newB); } /* if there is a window attached to this buffer, then there are problems * if we get to update() without attaching another one to it. So * beware! Always make sure CBuf is set too! kill_buffer command * takes care of this */ void delete_buffer(Buffer *buf) { Line *l,*n; Mark *m, *m1; while (buf->narrow != NULL) widen_buffer(buf); if (buf -> beg != NULL) for (l = buf -> beg; l != NULL; l = n) { n = l -> next; free_line(l); /* SLFREE( l->data); SLFREE( l); */ } m = buf->marks; while (m != NULL) { m1 = m->next; if (m == &buf->mark_array[buf->mark_ptr - 1]) { buf->mark_ptr--; } else SLFREE(m); m = m1; } m = buf->spots; while (m != NULL) { m1 = m->next; if (m == &buf->spot_array[buf->spot_ptr - 1]) { buf->spot_ptr--; } else SLFREE(m); m = m1; } if (buf->user_marks != NULL) free_user_marks (buf); if (buf->undo != NULL) delete_undo_ring(buf); #ifdef COLOR_COLUMNS if (buf->column_colors != NULL) SLFREE (buf->column_colors); #endif buf->prev->next = buf->next; buf->next->prev = buf->prev; #ifdef HAS_SUBPROCESSES if (buf->subprocess) jed_kill_process (buf->subprocess - 1); #endif SLFREE( buf); } /* need to make this exploit MaxLine info! */ void goto_line(int *np) { unsigned int n; unsigned int half1 = LineNum / 2; unsigned int half2 = (Max_LineNum + LineNum) / 2; int sn; if (*np <= 1) n = 0; else n = (unsigned int) *np; if (n < LineNum) { if (n > half1) { sn = (int) (LineNum - n); prevline(&sn); } else { bob(); sn = (int) n; if (sn-- > 0) nextline(&sn); } } else if (n < half2) { sn = (int) (n - LineNum); nextline(&sn); } else { eob(); sn = (int) (Max_LineNum - n); prevline(&sn); } } Line *dup_line(Line *l) { Line *neew; int n; unsigned char *p, *q; #ifdef KEEP_SPACE_INFO n = l->space; #else n = l->len; #endif neew = (Line *) SLMALLOC(sizeof(Line)); if ((neew == NULL) || (NULL == (neew->data = (unsigned char *) SLMALLOC(n)))) { exit_error("Malloc Error in dup_line.", 0); } neew->next = l->next; neew->prev = l->prev; neew->len = n; #ifdef KEEP_SPACE_INFO neew->space = l->space; #endif p = neew->data; q = l->data; while (n--) *p++ = *q++; return(neew); } Buffer *find_buffer(char *name) { Buffer *b; b = CBuf; do { if (!strcmp(b->name, name)) return(b); b = b->next; } while(b != CBuf); #ifdef __os2__ b = CBuf; do { if (!strcmpi(b->name, name)) return(b); b = b->next; } while(b != CBuf); #endif return(NULL); } int buffer_exists(Buffer *b) { Buffer *c = CBuf; do { if (b == c) return 1; c = c->next; } while (c != CBuf); return 0; } int switch_to_buffer(Buffer *buf) { /* save this buffer position */ CBuf->line = CLine; CBuf->point = Point; CBuf->linenum = LineNum; CBuf->max_linenum = Max_LineNum; /* local variables */ CBuf->tab = Buffer_Local.tab; CBuf->sd = Buffer_Local.sd; if (buf == CBuf) return(0); #if 0 buf->prev->next = buf->next; buf->next->prev = buf->prev; buf->next = CBuf; buf->prev = CBuf->prev; CBuf->prev->next = buf; CBuf->prev = buf; #endif /* now restore new buffer */ CBuf = buf; CLine = CBuf->line; Point = CBuf->point; /* Buffer local variables */ Buffer_Local.tab = CBuf->tab; Buffer_Local.sd = CBuf->sd; LineNum = CBuf->linenum; Max_LineNum = CBuf->max_linenum; if (CLine == NULL) { make_line(25); Point = 0; } CBuf->line = CLine; CBuf->point = Point; return(1); } /* we assume that file has already been expanded--- that is, canonical. */ Buffer *find_file_buffer(char *file) { Buffer *b; char *f; long n, m; #ifdef REAL_UNIX_SYSTEM int inode, device; get_inode_info (file, &device, &inode); #endif f = extract_file(file); n = f - file; b = CBuf; do { #ifdef REAL_UNIX_SYSTEM if ((device != -1) && (inode != -1) && (b->device != -1) && (b->inode != -1)) { if ((inode == b->inode) && (device == b->device) && !strcmp(b->file, f)) return b; } else { m = strlen(b->dir); if ((m == n) && (!strcmp(b->file,f)) && (!strncmp(b->dir, file, (int) n))) return b; } #else m = strlen(b->dir); # ifndef __os2__ if ((m == n) && (!strcmp(b->file, f)) && (!strncmp(b->dir, file, (int) n))) # else if ((m == n) && (!strcmpi(b->file,f)) && (!strncmpi(b->dir, file, (int) n))) # endif return(b); #endif b = b->next; } while (b != CBuf); return(NULL); } /* take a dir and a filename, expand them then put in buffer structure */ void buffer_filename(char *dir, char *file) { strcpy (CBuf->dir, dir); if ((file == NULL) || (*file == 0)) { file = extract_file(CBuf->dir); strcpy(CBuf->file, file); *file = 0; } else strcpy(CBuf->file, file); #ifdef REAL_UNIX_SYSTEM get_inode_info (CBuf->dir, &CBuf->device, &CBuf->inode); #endif uniquely_name_buffer(CBuf->file); } /* This kills all undo information! */ int erase_buffer() { Line *beg, *tthis; /* CLine = CBuf->end; */ beg = CBuf->beg; bob(); CLine = CLine->next; LineNum++; Suspend_Screen_Update = 1; while(CLine != NULL) { tthis = CLine; beg->next = tthis->next; tthis->prev = beg; update_marks(LDELETE, 1); CLine = tthis->next; Max_LineNum--; free_line(tthis); } CLine = CBuf->beg; LineNum = 1; Point = 0; update_marks(CDELETE, CLine->len); CLine->len = 0; /* CLine->next = NULL; */ if (CBuf->undo != NULL) delete_undo_ring(CBuf); CBuf->undo = NULL; CBuf->end = CLine; touch_screen_for_buffer(CBuf); return(1); } void mark_buffer_modified(int *flag) { unsigned long now; if (*flag) { if (CBuf->flags & BUFFER_TRASHED) return; now = sys_time(); CBuf->m_time = now; CBuf->flags |= BUFFER_TRASHED; return; } else CBuf->flags &= ~BUFFER_TRASHED; } void check_line() { if ((CLine->len == 1) && (*CLine->data == '\n') && (CLine->data != NewLine_Buffer)) { SLFREE(CLine->data); CLine->data = NewLine_Buffer; #ifdef KEEP_SPACE_INFO CLine->space = 1; #endif } }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.