📄 textbuf.c
字号:
/*** Find the first character of the line "nLines" forward from "startPos"** in "buf" and return its position*/int BufCountForwardNLines(textBuffer *buf, int startPos, int nLines){ int pos, gapLen = buf->gapEnd - buf->gapStart; int lineCount = 0; if (nLines == 0) return startPos; pos = startPos; while (pos < buf->gapStart) { if (buf->buf[pos++] == '\n') { lineCount++; if (lineCount == nLines) return pos; } } while (pos < buf->length) { if (buf->buf[pos++ + gapLen] == '\n') { lineCount++; if (lineCount >= nLines) return pos; } } return pos;}/*** Find the position of the first character of the line "nLines" backwards** from "startPos" (not counting the character pointed to by "startpos" if** that is a newline) in "buf". nLines == 0 means find the beginning of** the line*/int BufCountBackwardNLines(textBuffer *buf, int startPos, int nLines){ int pos, gapLen = buf->gapEnd - buf->gapStart; int lineCount = -1; pos = startPos - 1; if (pos <= 0) return 0; while (pos >= buf->gapStart) { if (buf->buf[pos + gapLen] == '\n') { if (++lineCount >= nLines) return pos + 1; } pos--; } while (pos >= 0) { if (buf->buf[pos] == '\n') { if (++lineCount >= nLines) return pos + 1; } pos--; } return 0;}/*** Search forwards in buffer "buf" for characters in "searchChars", starting** with the character "startPos", and returning the result in "foundPos"** returns True if found, False if not.*/int BufSearchForward(textBuffer *buf, int startPos, const char *searchChars, int *foundPos){ int pos, gapLen = buf->gapEnd - buf->gapStart; const char *c; pos = startPos; while (pos < buf->gapStart) { for (c=searchChars; *c!='\0'; c++) { if (buf->buf[pos] == *c) { *foundPos = pos; return True; } } pos++; } while (pos < buf->length) { for (c=searchChars; *c!='\0'; c++) { if (buf->buf[pos + gapLen] == *c) { *foundPos = pos; return True; } } pos++; } *foundPos = buf->length; return False;}/*** Search backwards in buffer "buf" for characters in "searchChars", starting** with the character BEFORE "startPos", returning the result in "foundPos"** returns True if found, False if not.*/int BufSearchBackward(textBuffer *buf, int startPos, const char *searchChars, int *foundPos){ int pos, gapLen = buf->gapEnd - buf->gapStart; const char *c; if (startPos == 0) { *foundPos = 0; return False; } pos = startPos == 0 ? 0 : startPos - 1; while (pos >= buf->gapStart) { for (c=searchChars; *c!='\0'; c++) { if (buf->buf[pos + gapLen] == *c) { *foundPos = pos; return True; } } pos--; } while (pos >= 0) { for (c=searchChars; *c!='\0'; c++) { if (buf->buf[pos] == *c) { *foundPos = pos; return True; } } pos--; } *foundPos = 0; return False;}/*** A horrible design flaw in NEdit (from the very start, before we knew that** NEdit would become so popular), is that it uses C NULL terminated strings** to hold text. This means editing text containing NUL characters is not** possible without special consideration. Here is the special consideration.** The routines below maintain a special substitution-character which stands** in for a null, and translates strings an buffers back and forth from/to** the substituted form, figure out what to substitute, and figure out** when we're in over our heads and no translation is possible.*//*** The primary routine for integrating new text into a text buffer with** substitution of another character for ascii nuls. This substitutes null** characters in the string in preparation for being copied or replaced** into the buffer, and if neccessary, adjusts the buffer as well, in the** event that the string contains the character it is currently using for** substitution. Returns False, if substitution is no longer possible** because all non-printable characters are already in use.*/int BufSubstituteNullChars(char *string, int length, textBuffer *buf){ char histogram[256]; /* Find out what characters the string contains */ histogramCharacters(string, length, histogram, True); /* Does the string contain the null-substitute character? If so, re- histogram the buffer text to find a character which is ok in both the string and the buffer, and change the buffer's null-substitution character. If none can be found, give up and return False */ if (histogram[(unsigned char)buf->nullSubsChar] != 0) { char *bufString, newSubsChar; bufString = BufGetAll(buf); histogramCharacters(bufString, buf->length, histogram, False); newSubsChar = chooseNullSubsChar(histogram); if (newSubsChar == '\0') { XtFree(bufString); return False; } subsChars(bufString, buf->length, buf->nullSubsChar, newSubsChar); delete(buf, 0, buf->length); insert(buf, 0, bufString); XtFree(bufString); buf->nullSubsChar = newSubsChar; } /* If the string contains null characters, substitute them with the buffer's null substitution character */ if (histogram[0] != 0) subsChars(string, length, '\0', buf->nullSubsChar); return True;}/*** Convert strings obtained from buffers which contain null characters, which** have been substituted for by a special substitution character, back to** a null-containing string. There is no time penalty for calling this** routine if no substitution has been done.*/void BufUnsubstituteNullChars(char *string, textBuffer *buf){ register char *c, subsChar = buf->nullSubsChar; if (subsChar == '\0') return; for (c=string; *c != '\0'; c++) if (*c == subsChar) *c = '\0';}/* ** Compares len Bytes contained in buf starting at Position pos with** the contens of cmpText. Returns 0 if there are no differences, ** != 0 otherwise.***/int BufCmp(textBuffer * buf, int pos, int len, const char *cmpText){ int posEnd; int part1Length; int result; posEnd = pos + len; if (posEnd > buf->length) { return (1); } if (pos < 0) { return (-1); } if (posEnd <= buf->gapStart) { return (strncmp(&(buf->buf[pos]), cmpText, len)); } else if (pos >= buf->gapStart) { return (strncmp (&buf->buf[pos + (buf->gapEnd - buf->gapStart)], cmpText, len)); } else { part1Length = buf->gapStart - pos; result = strncmp(&buf->buf[pos], cmpText, part1Length); if (result) { return (result); } return (strncmp(&buf->buf[buf->gapEnd], &cmpText[part1Length], len - part1Length)); }}/*** Create a pseudo-histogram of the characters in a string (don't actually** count, because we don't want overflow, just mark the character's presence** with a 1). If init is true, initialize the histogram before acumulating.** if not, add the new data to an existing histogram.*/static void histogramCharacters(const char *string, int length, char hist[256], int init){ int i; const char *c; if (init) for (i=0; i<256; i++) hist[i] = 0; for (c=string; c < &string[length]; c++) hist[*((unsigned char *)c)] |= 1;}/*** Substitute fromChar with toChar in string.*/static void subsChars(char *string, int length, char fromChar, char toChar){ char *c; for (c=string; c < &string[length]; c++) if (*c == fromChar) *c = toChar;}/*** Search through ascii control characters in histogram in order of least** likelihood of use, find an unused character to use as a stand-in for a** null. If the character set is full (no available characters outside of** the printable set, return the null character.*/static char chooseNullSubsChar(char hist[256]){#define N_REPLACEMENTS 25 static char replacements[N_REPLACEMENTS] = {1,2,3,4,5,6,14,15,16,17,18,19, 20,21,22,23,24,25,26,28,29,30,31,11,7}; int i; for (i = 0; i < N_REPLACEMENTS; i++) if (hist[(unsigned char)replacements[i]] == 0) return replacements[i]; return '\0';} /*** Internal (non-redisplaying) version of BufInsert. Returns the length of** text inserted (this is just strlen(text), however this calculation can be** expensive and the length will be required by any caller who will continue** on to call redisplay). pos must be contiguous with the existing text in** the buffer (i.e. not past the end).*/static int insert(textBuffer *buf, int pos, const char *text){ int length = strlen(text); /* Prepare the buffer to receive the new text. If the new text fits in the current buffer, just move the gap (if necessary) to where the text should be inserted. If the new text is too large, reallocate the buffer with a gap large enough to accomodate the new text and a gap of PREFERRED_GAP_SIZE */ if (length > buf->gapEnd - buf->gapStart) reallocateBuf(buf, pos, length + PREFERRED_GAP_SIZE); else if (pos != buf->gapStart) moveGap(buf, pos); /* Insert the new text (pos now corresponds to the start of the gap) */ memcpy(&buf->buf[pos], text, length); buf->gapStart += length; buf->length += length; updateSelections(buf, pos, 0, length); return length;}/*** Internal (non-redisplaying) version of BufRemove. Removes the contents** of the buffer between start and end (and moves the gap to the site of** the delete).*/static void delete(textBuffer *buf, int start, int end){ /* if the gap is not contiguous to the area to remove, move it there */ if (start > buf->gapStart) moveGap(buf, start); else if (end < buf->gapStart) moveGap(buf, end); /* expand the gap to encompass the deleted characters */ buf->gapEnd += end - buf->gapStart; buf->gapStart -= buf->gapStart - start; /* update the length */ buf->length -= end - start; /* fix up any selections which might be affected by the change */ updateSelections(buf, start, end-start, 0);}/*** Insert a column of text without calling the modify callbacks. Note that** in some pathological cases, inserting can actually decrease the size of** the buffer because of spaces being coalesced into tabs. "nDeleted" and** "nInserted" return the number of characters deleted and inserted beginning** at the start of the line containing "startPos". "endPos" returns buffer** position of the lower left edge of the inserted column (as a hint for** routines which need to set a cursor position).*/static void insertCol(textBuffer *buf, int column, int startPos, const char *insText, int *nDeleted, int *nInserted, int *endPos){ int nLines, start, end, insWidth, lineStart, lineEnd; int expReplLen, expInsLen, len, endOffset; char *outStr, *outPtr, *line, *replText, *expText, *insLine; const char *insPtr; if (column < 0) column = 0; /* Allocate a buffer for the replacement string large enough to hold possibly expanded tabs in both the inserted text and the replaced area, as well as per line: 1) an additional 2*MAX_EXP_CHAR_LEN characters for padding where tabs and control characters cross the column of the selection, 2) up to "column" additional spaces per line for padding out to the position of "column", 3) padding up to the width of the inserted text if that must be padded to align the text beyond the inserted column. (Space for additional newlines if the inserted text extends beyond the end of the buffer is counted with the length of insText) */ start = BufStartOfLine(buf, startPos); nLines = countLines(insText) + 1; insWidth = textWidth(insText, buf->tabDist, buf->nullSubsChar); end = BufEndOfLine(buf, BufCountForwardNLines(buf, start, nLines-1)); replText = BufGetRange(buf, start, end); expText = expandTabs(replText, 0, buf->tabDist, buf->nullSubsChar, &expReplLen); XtFree(replText); XtFree(expText);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -