fl_text_buffer.cxx

来自「SRI international 发布的OAA框架软件」· CXX 代码 · 共 1,884 行 · 第 1/5 页

CXX
1,884
字号
      if (sp < searchString) { *foundPos = bp+1; return 1; }
    } while ((matchCase ? character(bp--) == *sp-- :
                         toupper(character(bp--)) == toupper(*sp--))
             && bp >= 0);
    startPos--;
  }
  return 0;
}

/*
** Search forwards in buffer for characters in "searchChars", starting
** with the character "startPos", and returning the result in "foundPos"
** returns 1 if found, 0 if not.
*/
int Fl_Text_Buffer::findchars_forward( int startPos, const char *searchChars,
                                    int *foundPos ) {
  int pos, gapLen = mGapEnd - mGapStart;
  const char *c;

  pos = startPos;
  while ( pos < mGapStart ) {
    for ( c = searchChars; *c != '\0'; c++ ) {
      if ( mBuf[ pos ] == *c ) {
        *foundPos = pos;
        return 1;
      }
    }
    pos++;
  }
  while ( pos < mLength ) {
    for ( c = searchChars; *c != '\0'; c++ ) {
      if ( mBuf[ pos + gapLen ] == *c ) {
        *foundPos = pos;
        return 1;
      }
    }
    pos++;
  }
  *foundPos = mLength;
  return 0;
}

/*
** Search backwards in buffer for characters in "searchChars", starting
** with the character BEFORE "startPos", returning the result in "foundPos"
** returns 1 if found, 0 if not.
*/
int Fl_Text_Buffer::findchars_backward( int startPos, const char *searchChars,
                                     int *foundPos ) {
  int pos, gapLen = mGapEnd - mGapStart;
  const char *c;

  if ( startPos == 0 ) {
    *foundPos = 0;
    return 0;
  }
  pos = startPos == 0 ? 0 : startPos - 1;
  while ( pos >= mGapStart ) {
    for ( c = searchChars; *c != '\0'; c++ ) {
      if ( mBuf[ pos + gapLen ] == *c ) {
        *foundPos = pos;
        return 1;
      }
    }
    pos--;
  }
  while ( pos >= 0 ) {
    for ( c = searchChars; *c != '\0'; c++ ) {
      if ( mBuf[ pos ] == *c ) {
        *foundPos = pos;
        return 1;
      }
    }
    pos--;
  }
  *foundPos = 0;
  return 0;
}

/*
** 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 0, if substitution is no longer possible
** because all non-printable characters are already in use.
*/
int Fl_Text_Buffer::substitute_null_characters( char *string, int len ) {
  char histogram[ 256 ];

  /* Find out what characters the string contains */
  histogramCharacters( string, len, histogram, 1 );

  /* 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 0 */
  if ( histogram[ ( unsigned char ) mNullSubsChar ] != 0 ) {
    char * bufString;
    char newSubsChar;
    bufString = (char*)text();
    histogramCharacters( bufString, mLength, histogram, 0 );
    newSubsChar = chooseNullSubsChar( histogram );
    if ( newSubsChar == '\0' )
      return 0;
    subsChars( bufString, mLength, mNullSubsChar, newSubsChar );
    remove_( 0, mLength );
    insert_( 0, bufString );
    free( (void *) bufString );
    mNullSubsChar = newSubsChar;
  }

  /* If the string contains null characters, substitute them with the
     buffer's null substitution character */
  if ( histogram[ 0 ] != 0 )
    subsChars( string, len, '\0', mNullSubsChar );
  return 1;
}

/*
** 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 Fl_Text_Buffer::unsubstitute_null_characters( char *string ) {
  register char * c, subsChar = mNullSubsChar;

  if ( subsChar == '\0' )
    return;
  for ( c = string; *c != '\0'; c++ )
    if ( *c == subsChar )
      * c = '\0';
}

/*
** 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[ 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).
*/
int Fl_Text_Buffer::insert_( int pos, const char *s ) {
  int insertedLength = strlen( s );

  /* 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 ( insertedLength > mGapEnd - mGapStart )
    reallocate_with_gap( pos, insertedLength + PREFERRED_GAP_SIZE );
  else if ( pos != mGapStart )
    move_gap( pos );

  /* Insert the new text (pos now corresponds to the start of the gap) */
  memcpy( &mBuf[ pos ], s, insertedLength );
  mGapStart += insertedLength;
  mLength += insertedLength;
  update_selections( pos, 0, insertedLength );

  if (mCanUndo) {
    if ( undowidget==this && undoat==pos && undoinsert ) {
      undoinsert += insertedLength;
    }
    else {
      undoinsert = insertedLength;
      undoyankcut = (undoat==pos) ? undocut : 0 ;
    }
    undoat = pos+insertedLength;
    undocut = 0;
    undowidget = this;
  }

  return insertedLength;
}

/*
** 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).
*/
void Fl_Text_Buffer::remove_( int start, int end ) {
  /* if the gap is not contiguous to the area to remove, move it there */

  if (mCanUndo) {
    if ( undowidget==this && undoat==end && undocut ) {
      undobuffersize( undocut+end-start+1 );
      memmove( undobuffer+end-start, undobuffer, undocut );
      undocut += end-start;
    } 
    else {
      undocut = end-start;
      undobuffersize(undocut);
    }
    undoat = start;
    undoinsert = 0;
    undoyankcut = 0;
    undowidget = this;
  }

  if ( start > mGapStart ) {
    if (mCanUndo)
      memcpy( undobuffer, mBuf+(mGapEnd-mGapStart)+start, end-start );
    move_gap( start );
  }
  else if ( end < mGapStart ) {
    if (mCanUndo)
      memcpy( undobuffer, mBuf+start, end-start );
    move_gap( end );
  }
  else {
    int prelen = mGapStart - start;
    if (mCanUndo) {
      memcpy( undobuffer, mBuf+start, prelen );
      memcpy( undobuffer+prelen, mBuf+mGapEnd, end-start-prelen);
    }
  }

  /* expand the gap to encompass the deleted characters */
  mGapEnd += end - mGapStart;
  mGapStart -= mGapStart - start;

  /* update the length */
  mLength -= end - start;

  /* fix up any selections which might be affected by the change */
  update_selections( 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).
*/
void Fl_Text_Buffer::insert_column_( 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 *c, *outStr, *outPtr, *expText, *insLine;
  const char *line;
  const char  *replText;
  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*FL_TEXT_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 = line_start( startPos );
  nLines = countLines( insText ) + 1;
  insWidth = textWidth( insText, mTabDist, mNullSubsChar );
  end = line_end( skip_lines( start, nLines - 1 ) );
  replText = text_range( start, end );
  expText = expandTabs( replText, 0, mTabDist, mNullSubsChar,
                        &expReplLen );
  free( (void *) replText );
  free( (void *) expText );
  expText = expandTabs( insText, 0, mTabDist, mNullSubsChar,
                        &expInsLen );
  free( (void *) expText );
  outStr = (char *)malloc( expReplLen + expInsLen +
                           nLines * ( column + insWidth + FL_TEXT_MAX_EXP_CHAR_LEN ) + 1 );

  /* Loop over all lines in the buffer between start and end removing the
     text between rectStart and rectEnd and padding appropriately.  Trim
     trailing space from line (whitespace at the ends of lines otherwise
     tends to multiply, since additional padding is added to maintain it */
  outPtr = outStr;
  lineStart = start;
  insPtr = insText;
  for (;;) {
    lineEnd = line_end( lineStart );
    line = text_range( lineStart, lineEnd );
    insLine = copyLine( insPtr, &len );
    insPtr += len;
    insertColInLine( line, insLine, column, insWidth, mTabDist,
                     mUseTabs, mNullSubsChar, outPtr, &len, &endOffset );
    free( (void *) line );
    free( (void *) insLine );
    for ( c = outPtr + len - 1; c > outPtr && isspace( *c ); c-- )
      len--;
    outPtr += len;
    *outPtr++ = '\n';
    lineStart = lineEnd < mLength ? lineEnd + 1 : mLength;
    if ( *insPtr == '\0' )
      break;
    insPtr++;
  }
  if ( outPtr != outStr )
    outPtr--;   /* trim back off extra newline */
  *outPtr = '\0';

  /* replace the text between start and end with the new stuff */
  remove_( start, end );
  insert_( start, outStr );
  *nInserted = outPtr - outStr;
  *nDeleted = end - start;
  *endPos = start + ( outPtr - outStr ) - len + endOffset;
  free( (void *) outStr );
}

/*
** Delete a rectangle of text without calling the modify callbacks.  Returns
** the number of characters replacing those between start and end.  Note that
** in some pathological cases, deleting can actually increase the size of
** the buffer because of tab expansions.  "endPos" returns the buffer position
** of the point in the last line where the text was removed (as a hint for

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?