/* * FindFcbWithLine - find the fcb with the specified line */ vi_rc FindFcbWithLine( linenum lineno, file *cfile, fcb **fb ) { bool lastflag = false; fcb *tfcb, *ofcb; vi_rc rc; /* * are we looking for the last line? */ if( lineno < 0 ) { lastflag = true; lineno = MAX_LONG; } if( lineno < 1 ) { return( ERR_NO_SUCH_LINE ); } if( cfile == NULL ) { return( ERR_NO_FILE ); } /* * run through all possible fcb's */ tfcb = cfile->fcbs.head; if( tfcb == NULL ) { return( ERR_NO_SUCH_LINE ); } for( ;; ) { if( tfcb->end_line >= lineno ) { *fb = tfcb; FetchFcb( tfcb ); return( ERR_NO_ERR ); } ofcb = tfcb; tfcb = ofcb->next; if( tfcb == NULL ) { if( !cfile->bytes_pending ) { if( lastflag ) { *fb = ofcb; FetchFcb( ofcb ); return( ERR_NO_ERR ); } return( ERR_NO_SUCH_LINE ); } if( EditFlags.Verbose ) { Message1( "At line %l", ofcb->end_line ); } rc = ReadFcbData( cfile, NULL ); if( rc != ERR_NO_ERR && rc != END_OF_FILE ) { return( rc ); } tfcb = cfile->fcbs.tail; } } } /* FindFcbWithLine */
/* * GimmeNextLinePtr - get pointer to next line */ vi_rc GimmeNextLinePtr( file *cfile, fcb **cfcb, line **cline ) { vi_rc rc; fcb *ofcb; /* * get next line pointer; if not null, go back */ *cline = (*cline)->next; if( *cline != NULL ) { return( ERR_NO_ERR ); } /* * get next fcb pointer; if not null, get first line and go back */ *cfcb = (*cfcb)->next; if( *cfcb != NULL ) { FetchFcb( *cfcb ); *cline = (*cfcb)->lines.head; return( ERR_NO_ERR ); } /* * get next fcb if can; then get first line and go back */ if( cfile->bytes_pending ) { ofcb = cfile->fcbs.tail; rc = ReadFcbData( cfile ); if( rc > ERR_NO_ERR ) { return( rc ); } *cfcb = cfile->fcbs.tail; if( *cfcb != ofcb ) { while( (*cfcb)->prev != ofcb ) { *cfcb = (*cfcb)->prev; } } FetchFcb( *cfcb ); *cline = (*cfcb)->lines.head; return( ERR_NO_ERR ); } /* * no such line */ *cfcb = NULL; *cline = NULL; return( ERR_NO_MORE_LINES ); } /* GimmeNextLinePtr */
/* * GimmePrevLinePtr - get pointer to previous line */ vi_rc GimmePrevLinePtr( fcb **cfcb, line **cline ) { /* * get next line pointer; if not null, go back */ *cline = (*cline)->prev; if( *cline != NULL ) { return( ERR_NO_ERR ); } /* * get next fcb pointer; if not null, get first line and go back */ *cfcb = (*cfcb)->prev; if( *cfcb != NULL ) { FetchFcb( *cfcb ); *cline = (*cfcb)->lines.tail; return( ERR_NO_ERR ); } /* * no such line */ *cfcb = NULL; *cline = NULL; return( ERR_NO_MORE_LINES ); } /* GimmePrevLinePtr */
/* * ReplaceCurrentLine - replace current line with work line */ vi_rc ReplaceCurrentLine( void ) { int extra; line *tmp; /* * add extra space to fcb */ FetchFcb( CurrentFcb ); extra = WorkLine->len - CurrentLine->len; CurrentFcb->byte_cnt += extra; CurrentFcb->nullfcb = false; /* * copy new data in */ tmp = LineAlloc( WorkLine->data, WorkLine->len ); tmp->u.ld.mark = CurrentLine->u.ld.mark; ReplaceLLItem( (ss **)&CurrentFcb->lines.head, (ss **)&CurrentFcb->lines.tail, (ss *)CurrentLine, (ss *)tmp ); MemFree( CurrentLine ); CurrentLine = tmp; WorkLine->len = -1; return( CheckCurrentFcbCapacity() ); } /* ReplaceCurrentLine */
/* * duplicateFcb - do just that */ static void duplicateFcb( fcb *cfcb, fcb **dfcb ) { line *cline, *nline; /* * get fcb and create a new one */ FetchFcb( cfcb ); cfcb->non_swappable = TRUE; *dfcb = FcbAlloc( NULL ); (*dfcb)->start_line = cfcb->start_line; (*dfcb)->end_line = cfcb->end_line; (*dfcb)->byte_cnt = cfcb->byte_cnt; (*dfcb)->lines.head = (*dfcb)->lines.tail = NULL; /* * copy all lines */ for( cline = cfcb->lines.head; cline != NULL; cline = cline->next ) { nline = LineAlloc( cline->data, cline->len ); AddLLItemAtEnd( (ss **)&((*dfcb)->lines.head), (ss **)&((*dfcb)->lines.tail), (ss *)nline ); } cfcb->non_swappable = FALSE; (*dfcb)->non_swappable = FALSE; } /* duplicateFcb */
/* * CheckCurrentFcbCapacity - check if fcb has exceeded its capacity; if so, * split it */ vi_rc CheckCurrentFcbCapacity( void ) { int bc, bl; line *cl; linenum l; vi_rc rc; /* * check if fcb is full */ if( FcbSize( CurrentFcb ) <= MAX_IO_BUFFER ) { return( ERR_NO_ERR ); } FetchFcb( CurrentFcb ); /* * can't take it, so split it */ cl = CurrentFcb->lines.head; bl = CurrentFcb->byte_cnt / 2; l = CurrentFcb->start_line; for( bc = cl->len + 1; bc < bl; bc += cl->len + 1 ) { cl = cl->next; l++; } rc = SplitFcbAtLine( l, CurrentFile, CurrentFcb ); if( rc != ERR_NO_ERR ) { return( rc ); } /* * check if current line is in new fcb, if so, switch to new fcb; * as well, new fcb had better have the same display status as the old */ CurrentFcb->next->on_display = CurrentFcb->on_display; if( CurrentPos.line > CurrentFcb->end_line ) { CurrentFcb = CurrentFcb->next; FetchFcb( CurrentFcb ); } return( ERR_NO_ERR ); } /* CheckCurrentFcbCapacity */
/* * CreateNullLine - put a single null line in an fcb */ void CreateNullLine( fcb *cfcb ) { line *cline; cline = LineAlloc( NULL, 0 ); FetchFcb( cfcb ); AddLLItemAtEnd( (ss **)&(cfcb->lines.head), (ss **)&(cfcb->lines.tail), (ss *)cline ); cfcb->byte_cnt = 1; cfcb->start_line = cfcb->end_line = 1; cfcb->nullfcb = TRUE; } /* CreateNullLine */
/* * JoinFcbs - join two fcbs */ static vi_rc JoinFcbs( fcb *fcb1, fcb *fcb2 ) { unsigned j, k; /* * see if we can merge them */ if( fcb1->end_line != (fcb2->start_line - 1) ) { return( COULD_NOT_MERGE_FCBS ); } j = FcbSize( fcb1 ); k = FcbSize( fcb2 ); if( j + k > (unsigned) MAX_IO_BUFFER ) { return( COULD_NOT_MERGE_FCBS ); } /* * get fcb's if swapped */ FetchFcb( fcb1 ); fcb1->non_swappable = TRUE; FetchFcb( fcb2 ); fcb1->non_swappable = FALSE; /* * update byte count and line numbers */ fcb1->byte_cnt += fcb2->byte_cnt; fcb1->end_line = fcb2->end_line; /* * merge the two sets of lines */ fcb1->lines.tail->next = fcb2->lines.head; fcb2->lines.head->prev = fcb1->lines.tail; fcb1->lines.tail = fcb2->lines.tail; return( ERR_NO_ERR ); } /* JoinFcbs */
/* * SwitchSavebuf - switch current save buffer */ vi_rc SwitchSavebuf( void ) { int buf, i; linenum lcnt; savebuf *tmp; char *data; fcb *cfcb; /* * validate savebuf */ buf = -1; for( i = 0; i < MAX_SAVEBUFS; i++ ) { if( LastEvent == SavebufBound[i] ){ buf = i; break; } } if( buf < 0 ) { return( ERR_NO_ERR ); } CurrentSavebuf = buf; tmp = &Savebufs[buf]; data = NULL; switch( tmp->type ) { case SAVEBUF_NOP: Message1( "Buffer %d now active. (empty buffer)", buf + 1 ); return( DO_NOT_CLEAR_MESSAGE_WINDOW ); case SAVEBUF_LINE: data = tmp->u.data; Message1( "Buffer %d active, %d characters:", buf + 1, strlen( tmp->u.data ) ); break; case SAVEBUF_FCBS: cfcb = tmp->u.fcbs.head; FetchFcb( cfcb ); data = cfcb->lines.head->data; lcnt = 0; for( ; cfcb != NULL; cfcb = cfcb->next ) { lcnt += cfcb->end_line - cfcb->start_line + 1; } Message1( "Buffer %d active, %l lines:", buf + 1, lcnt ); break; } Message2( "\"%s\"", data ); return( DO_NOT_CLEAR_MESSAGE_WINDOW ); } /* SwitchSavebuf */
/* * GimmeLinePtrFromFcb - get a line pointer from a specified fcb */ vi_rc GimmeLinePtrFromFcb( linenum lineno, fcb *cfcb , line **res ) { linenum linecnt; line *tmp; if( lineno < 1 ) { return( ERR_NO_SUCH_LINE ); } FetchFcb( cfcb ); linecnt = cfcb->start_line; tmp = cfcb->lines.head; while( linecnt != lineno ) { linecnt++; tmp = tmp->next; } *res = tmp; return( ERR_NO_ERR ); } /* GimmeLinePtrFromFcb */
/* * AddNewLineAroundCurrent - put a new line on either side of the current line */ void AddNewLineAroundCurrent( char *data, int copylen, insert_dir dir ) { bool wasnull; /* * if inserting into a null fcb, clean it up */ FetchFcb( CurrentFcb ); wasnull = CurrentFcb->nullfcb; if( wasnull ) { MemFree( CurrentFcb->lines.head ); CurrentFcb->lines.head = CurrentFcb->lines.tail = NULL; CurrentFcb->nullfcb = FALSE; CurrentFcb->byte_cnt = 0; CurrentFcb->end_line = 0; } /* * add the line */ InsertNewLine( CurrentLine, &CurrentFcb->lines, data, copylen,dir ); CurrentFcb->byte_cnt += copylen + 1; CurrentFcb->end_line += 1; /* * update line info */ if( wasnull ) { CurrentLine = CurrentFcb->lines.head; SetCurrentLineNumber( 1 ); } else { if( dir == INSERT_BEFORE ) { SetCurrentLineNumber( CurrentPos.line + 1 ); } UpdateLineNumbers( 1L, CurrentFcb->next ); } CheckCurrentFcbCapacity(); } /* AddNewLineAroundCurrent */
/* * GetSavebufString - get a string made up of stuff in a savebuf */ vi_rc GetSavebufString( char **data ) { #ifdef __WIN__ savebuf clip; #endif savebuf *tmp; fcb *cfcb; line *cline; vi_rc rc; long len; /* * fetch the savebuf */ rc = DoSavebufNumber(); if( rc != GOT_A_SAVEBUF ) { if( rc == ERR_NO_ERR ) { rc = DO_NOT_CLEAR_MESSAGE_WINDOW; } return( rc ); } #ifdef __WIN__ if( SavebufNumber == CLIPBOARD_SAVEBUF ) { rc = GetClipboardSavebuf( &clip ); if( rc != ERR_NO_ERR ) { return( rc ); } tmp = &clip; } else #endif if( SavebufNumber >= MAX_SAVEBUFS ) { tmp = &SpecialSavebufs[SavebufNumber - MAX_SAVEBUFS]; } else { tmp = &Savebufs[SavebufNumber]; } SavebufNumber = NO_SAVEBUF; /* * get length of stuff */ len = 0L; switch( tmp->type ) { case SAVEBUF_NOP: return( ERR_EMPTY_SAVEBUF ); case SAVEBUF_LINE: len = strlen( tmp->u.data ); break; case SAVEBUF_FCBS: for( cfcb = tmp->u.fcbs.head; cfcb != NULL; cfcb = cfcb->next ) { len += FcbSize( cfcb ); } break; } rc = ERR_NO_ERR; if( len > MAX_STR * 4 ) { rc = ERR_SAVEBUF_TOO_BIG; } else { *data = MemAlloc( len ); switch( tmp->type ) { case SAVEBUF_LINE: strcpy( *data, tmp->u.data ); break; case SAVEBUF_FCBS: **data = '\0'; for( cfcb = tmp->u.fcbs.head; cfcb != NULL; cfcb = cfcb->next ) { FetchFcb( cfcb ); for( cline = cfcb->lines.head; cline != NULL; cline = cline->next ) { strcat( *data, cline->data ); strcat( *data, "\\n" ); } } break; } } #ifdef __WIN__ if( tmp == &clip ) { freeSavebuf( &clip ); } #endif return( rc ); } /* GetSavebufString */
/* * SplitFcbAtLine - split a fcb at specified line (specified line goes in * new one) - line 1 causes new fcb to be created at start */ vi_rc SplitFcbAtLine( linenum lne, file *f, fcb *fb ) { linenum sline; int bytecnt = 0; line *cl, *pl; fcb *cfcb; /* * if at start line or end line + 1, no splitting possible */ if( lne == fb->start_line ) { return( NO_SPLIT_CREATED_AT_START_LINE ); } if( lne == fb->end_line + 1 ) { return( NO_SPLIT_CREATED_AT_END_LINE ); } /* * check if we tried to split at line that is not in fcb; */ if( lne > fb->end_line ) { return( ERR_NO_SUCH_LINE ); } /* * get fcb to split, and make sure that it isn't swapped while * we use it */ FetchFcb( fb ); fb->non_swappable = TRUE; /* * get position */ cl = fb->lines.head; for( sline = fb->start_line; sline != lne; sline++ ) { bytecnt += cl->len + 1; cl = cl->next; } /* * add the new fcb */ pl = cl->prev; cfcb = FcbAlloc( f ); InsertLLItemAfter( (ss **)&(f->fcbs.tail), (ss *)fb, (ss *)cfcb ); /* * reset line data for new fcb */ cfcb->start_line = lne; cfcb->end_line = fb->end_line; cfcb->lines.head = cl; cfcb->lines.head->prev = NULL; cfcb->lines.tail = fb->lines.tail; cfcb->byte_cnt = fb->byte_cnt - bytecnt; /* * reset line data for original fcb */ fb->end_line = lne - 1; fb->lines.tail = pl; fb->lines.tail->next = NULL; fb->byte_cnt = bytecnt; /* * check for locked fcb */ if( fb->globalmatch ) { /* * make sure original one should stay locked */ fb->globalmatch = FALSE; for( cl = fb->lines.head; cl != NULL; cl = cl->next ) { if( cl->inf.ld.globmatch ) { fb->globalmatch = TRUE; break; } } /* * see if new one needs to be locked */ for( cl = cfcb->lines.head; cl != NULL; cl = cl->next ) { if( cl->inf.ld.globmatch ) { cfcb->globalmatch = TRUE; break; } } } /* * release fcbs */ fb->non_swappable = FALSE; cfcb->non_swappable = FALSE; return( ERR_NO_ERR ); } /* SplitFcbAtLine */
/* * Global - perform global command */ vi_rc Global( linenum n1, linenum n2, const char *data, int dmt ) { char *sstr, *linedata; bool match; vi_rc rc; vi_rc rc1; long changecnt = 0; linenum ll; fcb *cfcb; line *cline; regexp crx; i_mark pos; /* * get search string and command */ rc = ModificationTest(); if( rc != ERR_NO_ERR ) { return( rc ); } sstr = alloca( MAX_INPUT_LINE ); if( sstr == NULL ) { return( ERR_NO_STACK ); } data = SkipLeadingSpaces( data ); data = GetNextWord( data, sstr, SingleSlash ); if( *sstr == '\0' ) { return( ERR_INVALID_GLOBAL_CMD ); } if( *data == '/' ) ++data; // skip one slash character data = SkipLeadingSpaces( data ); /* * verify last line */ if( n2 > CurrentFile->fcbs.tail->end_line ) { rc = CFindLastLine( &ll ); if( rc != ERR_NO_ERR ) { return( rc ); } if( n2 > ll ) { return( ERR_INVALID_LINE_RANGE ); } } /* * set for start of search */ if( EditFlags.Verbose && EditFlags.EchoOn ) { ClearWindow( MessageWindow ); } rc = CurrentRegComp( sstr ); if( rc != ERR_NO_ERR ) { return( rc ); } SaveCurrentFilePos(); StartUndoGroup( UndoStack ); EditFlags.DisplayHold = true; /* * pass one - find all matches */ for( pos.line = n1; pos.line <= n2; pos.line++ ) { /* * go thorugh file, marking global lines */ pos.column = 0; rc = FindRegularExpression( NULL, &pos, &linedata, n2, 0 ); if( rc != ERR_NO_ERR ) { if( rc == ERR_FIND_PAST_TERM_LINE || rc == ERR_FIND_NOT_FOUND || rc == ERR_FIND_END_OF_FILE ) { break; } RestoreCurrentFilePos(); EditFlags.DisplayHold = false; return( rc ); } if( pos.line > n2 ) { break; } /* * go to appropriate spot in file */ rc = GoToLineNoRelCurs( pos.line ); if( rc != ERR_NO_ERR ) { RestoreCurrentFilePos(); EditFlags.DisplayHold = false; return( rc ); } /* * mark fcb and line for a match */ CurrentFcb->globalmatch = true; CurrentLine->u.ld.globmatch = true; if( EditFlags.Verbose && EditFlags.EchoOn ) { // WPrintfLine( MessageWindow,1,"Match on line %l",clineno ); Message1( "Match on line %l", pos.line ); } } /* * negate range, if needed */ if( dmt ) { /* * run through each line, flipping globmatch flag on lines */ CGimmeLinePtr( n1, &CurrentFcb, &CurrentLine ); match = false; for( CurrentPos.line = n1; CurrentPos.line <= n2; CurrentPos.line++ ) { if( CurrentLine->u.ld.globmatch ) { CurrentLine->u.ld.globmatch = false; } else { match = true; CurrentLine->u.ld.globmatch = true; } CurrentLine = CurrentLine->next; if( CurrentLine == NULL ) { CurrentFcb->globalmatch = match; CurrentFcb = CurrentFcb->next; FetchFcb( CurrentFcb ); CurrentLine = CurrentFcb->lines.head; match = false; } } } /* * Pass 2: do all changes */ rc = ERR_NO_ERR; EditFlags.GlobalInProgress = true; memcpy( &crx, CurrentRegularExpression, sizeof( crx ) ); for( CurrentFcb = CurrentFile->fcbs.head; CurrentFcb != NULL; CurrentFcb = CurrentFcb->next ) { if( !CurrentFcb->globalmatch ) continue; FetchFcb( CurrentFcb ); CurrentPos.line = CurrentFcb->start_line; for( CurrentLine = CurrentFcb->lines.head; CurrentLine != NULL; CurrentLine = CurrentLine->next, CurrentPos.line++ ) { if( !CurrentLine->u.ld.globmatch ) continue; CurrentLine->u.ld.globmatch = false; changecnt++; CurrentPos.column = 1; ProcessingMessage( CurrentPos.line ); /* * build command line */ rc = RunCommandLine( data ); if( rc > ERR_NO_ERR ) { break; } } if( rc > ERR_NO_ERR ) { break; } CurrentFcb->globalmatch = false; } /* * we have an error, so fix up fcbs */ if( rc > ERR_NO_ERR ) { for( cfcb = CurrentFile->fcbs.head; cfcb != NULL; cfcb = cfcb->next ) { if( cfcb->globalmatch ) { cfcb->globalmatch = false; cfcb->non_swappable = false; for( cline = cfcb->lines.head; cline != NULL; cline = cline->next ) { cline->u.ld.globmatch = false; } } } } /* * display results */ EditFlags.GlobalInProgress = false; EditFlags.DisplayHold = false; EndUndoGroup( UndoStack ); RestoreCurrentFilePos(); rc1 = SetCurrentLine( CurrentPos.line ); if( rc1 != ERR_NO_ERR ) { if( rc1 == ERR_NO_SUCH_LINE ) { SetCurrentLine( 1 ); } else { return( rc1 ); } } Message1( "%l matches found",changecnt ); DCDisplayAllLines(); return( rc ); } /* Global */
/* * DoGenericFilter - filter some crap */ vi_rc DoGenericFilter( linenum s, linenum e, const char *cmd ) { fcb *cfcb, *tfcb; line *cline; vi_rc rc; char filtin[_MAX_PATH], filtout[_MAX_PATH]; fcb_list fcblist; int fh; rc = ModificationTest(); if( rc != ERR_NO_ERR ) { return( rc ); } /* * filter on a line */ rc = GetCopyOfLineRange( s, e, &fcblist ); if( rc != ERR_NO_ERR ) { return( rc ); } /* * get file */ MakeTmpPath( filtin, FILTER_FILE_NAME ); fh = mkstemp( filtin ); if( fh == -1 ) return( ERR_FILE_OPEN ); /* * now, dump this crap to a tmp file */ for( cfcb = fcblist.head; cfcb != NULL; cfcb = tfcb ) { FetchFcb( cfcb ); for( cline = cfcb->lines.head; cline != NULL; cline = cline->next ) { write( fh, cline->data, strlen( cline->data ) ); #if defined( __UNIX__ ) write( fh, "\n", 1 ); #else write( fh, "\r\n", 2 ); #endif } tfcb = cfcb->next; FcbFree( cfcb ); } close( fh ); MakeTmpPath( filtout, FILTER_FILE_NAME ); fh = mkstemp( filtout ); if( fh == -1 ) { remove( filtin ); return( ERR_FILE_OPEN ); } close( fh ); /* * shell out to the given command */ ExecCmd( filtin, filtout, cmd ); StartUndoGroup( UndoStack ); rc = DeleteLineRange( s, e, 0 ); if( rc == ERR_NO_ERR ) { ReadAFile( s - 1, filtout ); Message1( "%l lines filtered through %s", e - s + 1, cmd ); } EndUndoGroup( UndoStack ); /* * cleanup */ if( rc == ERR_NO_ERR ) { rc = DO_NOT_CLEAR_MESSAGE_WINDOW; } remove( filtin ); remove( filtout ); return( rc ); } /* DoGenericFilter */
/* * InsertLinesAtCursor - insert a set of lines at current pos. in file */ vi_rc InsertLinesAtCursor( fcb_list *fcblist, undo_stack *us ) { fcb *cfcb; linenum e; int lastLineLen; char *source; line *tLine; vi_rc rc; rc = ModificationTest(); if( rc != ERR_NO_ERR ) { return( rc ); } /* * find the number of lines inserted */ e = 0; for( cfcb = fcblist->head; cfcb != NULL; cfcb = cfcb->next ) { e += (cfcb->end_line - cfcb->start_line + 1); } // add chars from right of cursor to end of last line of buffer source = CurrentLine->data + CurrentPos.column - 1; lastLineLen = fcblist->tail->lines.tail->len; fcblist->tail->lines.tail->len += CurrentLine->len - CurrentPos.column + 1; fcblist->tail->byte_cnt += CurrentLine->len - CurrentPos.column + 1; tLine = fcblist->tail->lines.tail->prev; fcblist->tail->lines.tail = MemReAlloc( fcblist->tail->lines.tail, sizeof( line ) + fcblist->tail->lines.tail->len + 1 ); if( tLine ) { tLine->next = fcblist->tail->lines.tail; } strcpy( fcblist->tail->lines.tail->data + lastLineLen, source ); StartUndoGroup( us ); // create new current line in work line CurrentLineReplaceUndoStart(); GetCurrentLine(); WorkLine->len = CurrentPos.column + fcblist->head->lines.head->len - 1; strcpy( WorkLine->data + CurrentPos.column - 1, fcblist->head->lines.head->data ); // replace current line ReplaceCurrentLine(); CurrentLineReplaceUndoEnd( true ); // remove first line of buffer FetchFcb( fcblist->head ); fcblist->head->non_swappable = true; fcblist->head->start_line++; fcblist->head->byte_cnt -= fcblist->head->lines.head->len + 1; tLine = fcblist->head->lines.head; fcblist->head->lines.head = fcblist->head->lines.head->next; fcblist->head->lines.head->prev = NULL; MemFree( tLine ); fcblist->head->non_swappable = false; // add rest of lines of buffer & done if( fcblist->head->lines.head) { InsertLines( CurrentPos.line, fcblist, us ); } EndUndoGroup( us ); // if are indeed linebased, move cursor as well if( !EditFlags.LineBased ) { GoToLineNoRelCurs( CurrentPos.line + e - 1 ); GoToColumnOnCurrentLine( lastLineLen + 1 ); } return( ERR_NO_ERR ); } /* InsertLinesAtCursor */
/* * AddFcbsToClipboard - add all lines in a given set of fcbs to the clipboard */ int AddFcbsToClipboard( fcb_list *fcblist ) { fcb *cfcb; line *cline; char _HUGE_ *ptr; long size; int i; GLOBALHANDLE hglob; bool crlf_left_to_write = false; if( !openClipboardForWrite() ) { return( ERR_CLIPBOARD ); } /* * compute the number of bytes in total */ size = 1; // for trailing null char for( cfcb = fcblist->head; cfcb != NULL; cfcb = cfcb->next ) { size += (long)cfcb->byte_cnt + (long)(cfcb->end_line-cfcb->start_line + 1); if( cfcb == fcblist->tail ) { break; } } /* * get the memory to store this stuff */ hglob = GlobalAlloc( GMEM_MOVEABLE, size ); if( hglob == NULL ) { CloseClipboard(); return( ERR_CLIPBOARD ); } ptr = GetPtrGlobalLock( hglob ); if( ptr == NULL ) { CloseClipboard(); return( ERR_CLIPBOARD ); } /* * copy all lines into this pointer */ for( cfcb = fcblist->head; cfcb != NULL; cfcb = cfcb->next ) { FetchFcb( cfcb ); for( cline = cfcb->lines.head; cline != NULL; cline = cline->next ) { // one CR,LF left to write? if( crlf_left_to_write ) { // yes: write it crlf_left_to_write = false; *ptr = CR; INC_POINTER( ptr ); *ptr = LF; INC_POINTER( ptr ); } for( i = 0; i < cline->len; i++ ) { *ptr = cline->data[i]; INC_POINTER( ptr ); } // remember to write one CR,LF next time crlf_left_to_write = true; } if( cfcb == fcblist->tail ) { break; } } // the last CR,LF is omitted *ptr = 0; GlobalUnlock( hglob ); SetClipboardData( CF_TEXT, hglob ); CloseClipboard(); return( ERR_NO_ERR ); } /* AddFcbsToClipboard */
/* * CurrentLineReplaceUndoEnd - actually add the undo */ void CurrentLineReplaceUndoEnd( int endgrp ) { fcb *cfcb, *nfcb; undo *top, *delrec; fcb_list fcblist; if( !EditFlags.Undo || UndoStack == NULL ) { return; } /* * see if we can merge this with the last undo record * (provided we are in an open undo group) * * we need the following undo sequence: * END_UNDO_GROUP * UNDO_INSERT_LINES * - must have end line one less than the current line * UNDO_DELETE_FCBS * - must have last line to insert being two less * than the current (since then the undo for * the current would be on the line ONE less than * the current); */ if( endgrp && UndoStack->OpenUndo > 0 ) { top = UndoStack->stack[UndoStack->current]; if( top != NULL && top->type == END_UNDO_GROUP ) { top = top->next; if( top != NULL && top->type == UNDO_INSERT_LINES ) { if( top->data.del_range.end == CurrentPos.line - 1 ) { delrec = top; top = top->next; if( top != NULL && top->type == UNDO_DELETE_FCBS ) { cfcb = top->data.fcbs.tail; if( cfcb->end_line == CurrentPos.line - 2 ) { /* * FINALLY, we can add it. either * add to current fcb or add a new * fcb */ if( (FcbSize( cfcb ) + lineSave->len + 4) <= MAX_IO_BUFFER ) { FetchFcb( cfcb ); InsertLLItemAfter( (ss **)&cfcb->lines.tail, (ss *)cfcb->lines.tail, (ss *)lineSave ); cfcb->byte_cnt += lineSave->len + 1; cfcb->end_line++; } else { nfcb = singleLineFcb(); nfcb->start_line = nfcb->end_line = cfcb->end_line + 1; InsertLLItemAfter( (ss **)&(top->data.fcbs.tail), (ss *)cfcb, (ss *)nfcb ); nfcb->non_swappable = FALSE; } delrec->data.del_range.end++; Modified( TRUE ); return; } } } } } } /* * create an fcb with a single line */ cfcb = singleLineFcb(); /* * build undo action */ fcblist.head = cfcb; fcblist.tail = cfcb; StartUndoGroupWithPosition( UndoStack, cLine, pageTop, cCol ); UndoDeleteFcbs( CurrentPos.line - 1, &fcblist, UndoStack ); UndoInsert( CurrentPos.line, CurrentPos.line, UndoStack ); if( endgrp ) { EndUndoGroup( UndoStack ); } Modified( TRUE ); cfcb->non_swappable = FALSE; } /* CurrentLineReplaceUndoEnd */