Пример #1
0
/*
 * markRegion - mark a region as selected/unselected
 */
static void markRegion( bool val )
{
    fcb         *cfcb;
    line        *cline;
    linenum     ln;
    linenum     s, e;

    if( SelRgn.start.line > SelRgn.end.line ) {
        s = SelRgn.end.line;
        e = SelRgn.start.line;
    } else {
        s = SelRgn.start.line;
        e = SelRgn.end.line;
    }

    if( CGimmeLinePtr( s, &cfcb, &cline ) ) {
        return;
    }
    ln= e - s;
    for( ;; ) {
        cline->u.ld.hilite = val;
        ln--;
        if( ln < 0 ) {
            break;
        }
        if( CGimmeNextLinePtr( &cfcb, &cline ) ) {
            break;
        }
    }

} /* markRegion */
Пример #2
0
/*
 * GetHiddenLineCount - get number of hidden lines in a range
 */
linenum GetHiddenLineCount( linenum s, linenum e )
{
    line        *cline;
    fcb         *cfcb;
    int         i;
    linenum     cnt, tmp;

    if( s > e ) {
        tmp = s;
        s = e;
        e = tmp;
    }
    i = CGimmeLinePtr( s, &cfcb, &cline );
    if( i ) {
        return( 0L );
    }
    cnt = 0L;
    while( s <= e ) {
        if( cline->u.ld.hidden ) {
            cnt++;
        }
        s++;
        i = CGimmeNextLinePtr( &cfcb, &cline );
        if( i ) {
            break;
        }
    }
    return( cnt );

} /* GetHiddenLineCount */
Пример #3
0
/*
 * GetHiddenRange - get range of lines hidden around a given line
 */
void GetHiddenRange( linenum l, linenum *s, linenum *e )
{
    line        *cline, *oline;
    fcb         *cfcb, *ofcb;
    int         i;

    (*s) = (*e) = l;

    i = CGimmeLinePtr( l, &ofcb, &oline );
    if( i ) {
        return;
    }

    /*
     * go back
     */
    cfcb = ofcb;
    cline = oline;
    for( ;; ) {
        i = GimmePrevLinePtr( &cfcb, &cline );
        if( i ) {
            break;
        }
        if( cline->u.ld.hidden ) {
            (*s)--;
            continue;
        } else {
            break;
        }
    }

    /*
     * go forwards
     */
    cfcb = ofcb;
    cline = oline;
    for( ;; ) {
        i = CGimmeNextLinePtr( &cfcb, &cline );
        if( i ) {
            break;
        }
        if( cline->u.ld.hidden ) {
            (*e)++;
            continue;
        } else {
            break;
        }
    }

} /* GetHiddenRange */
Пример #4
0
static void getLiteral( ss_block *ss_new, char *start, int skip )
{
    char    *text;
    char    lastchar = '\0';
    bool    empty;
    bool    multiLine = flags.inString;
    line    *line;
    fcb     *fcb;
    char    *data;
    vi_rc   rc;

    empty = true;
    for( text = start + skip; *text != '\0'; ++text ) {
        if( text[0] == '\'' ) {
            if( text[1] != '\'' )
                break;
            ++text;
        }
        empty = false;
    }
    flags.inString = false;
    if( *text == '\0' ) {
        // if next line a continuation line, then flag flags.inString, else
        // flag unterminated string
        rc = CGimmeLinePtr( thisLine + 1, &fcb, &line );
        for( ;; ) {
            if( rc != ERR_NO_ERR ) {
                break;
            }
            data = (line->u.ld.nolinedata) ? WorkLine->data : line->data;
            if( !iscomment( data[0] ) ) {
                break;
            }
            rc = CGimmeNextLinePtr( &fcb, &line );
        }
        ss_new->type = SE_INVALIDTEXT;
        if( rc == ERR_NO_ERR && !isInitialLine( line ) ) {
            ss_new->type = SE_STRING;
            flags.inString = true;
        }
    } else {
        text++;
        lastchar = tolower( *text );
        switch( lastchar ) {
        case 'c':
            text++;
            ss_new->type = SE_STRING;
            break;
        case 'x':
            text++;
            ss_new->type = SE_HEX;
            break;
        case 'o':
            text++;
            ss_new->type = SE_OCTAL;
            break;
        default:
            // hard to say if invalid or not - take a guess
            if( islower( *text ) ) {
                text++;
                ss_new->type = SE_INVALIDTEXT;
            } else {
                ss_new->type = SE_STRING;
            }
            break;
        }
    }
    ss_new->len = text - start;
    if( empty && !multiLine ) {
        ss_new->type = SE_INVALIDTEXT;
    }
}
Пример #5
0
/*
 * GenericJoinCurrentLineToNext
 */
vi_rc GenericJoinCurrentLineToNext( bool remsp )
{
    line        *nline = CurrentLine;
    fcb         *nfcb = CurrentFcb;
    int         i, j, k;
    vi_rc       rc;

    /*
     * get next line data
     */
    rc = CGimmeNextLinePtr( &nfcb, &nline );
    if( rc != ERR_NO_ERR ) {
        return( rc );
    }
    if( CurrentLine->len + nline->len + 1 >= EditVars.MaxLine ) {
        return( ERR_LINE_FULL );
    }

    /*
     * now, copy in the data
     */
    StartUndoGroup( UndoStack );
    CurrentLineReplaceUndoStart();
    CurrentLineReplaceUndoEnd( true );
    GetCurrentLine();

    if( remsp ) {
        while( WorkLine->len > 0 && WorkLine->data[WorkLine->len - 1] == ' ' ) {
            WorkLine->data[WorkLine->len - 1] = 0;
            WorkLine->len--;
        }
        j = FindStartOfALine( nline ) - 1;
	    k = 0;
        if( !(j == 0 && nline->data[0] == ' ') ) {
            if( WorkLine->len != 0 ) {
                WorkLine->data[WorkLine->len] = ' ';
                k = WorkLine->len + 1;
            }
            for( i = j; i <= nline->len; i++ ) {
                WorkLine->data[k + i - j] = nline->data[i];
            }
        }
    } else {
        k = WorkLine->len;
        for( i = 0; i <= nline->len; i++ ) {
            WorkLine->data[k + i] = nline->data[i];
        }
    }
    WorkLine->len = strlen( WorkLine->data );
    ReplaceCurrentLine();

    /*
     * delete next line
     */
    rc = DeleteLineRange( CurrentPos.line + 1, CurrentPos.line + 1, 0 );
    if( rc != ERR_NO_ERR ) {
        return( rc );
    }
    EndUndoGroup( UndoStack );
    if( remsp ) {
        if( k < 2 ) {
            k = 2;
        }
        rc = GoToColumn( k - 1, CurrentLine->len );
        if( rc != ERR_NO_ERR ) {
            return( rc );
        }
    }
    DCDisplayAllLines();
    return( ERR_NO_ERR );

} /* GenericJoinCurrentLineToNext */
Пример #6
0
/*
 * doCompressExpand - convert tabs to spaces, and spaces to tabs
 */
static vi_rc doCompressExpand( bool compress )
{
    int         k;
    long        bytes_saved = 0;
    long        bytes_added = 0;
    long        otabcnt;
    linenum     linecnt = 0;
    char        *tmp;
    vi_rc       rc;

    /*
     * init
     */
    rc = ModificationTest();
    if( rc != ERR_NO_ERR ) {
        return( rc );
    }
    rc = SaveAndResetFilePos( 1 );
    if( rc != ERR_NO_ERR ) {
        return( rc );
    }
    tmp = StaticAlloc();

    /*
     * process all lines
     */
    TabCnt = 0;
    for( ;; ) {

        if( compress ) {
            otabcnt = TabCnt;
            ExpandTabsInABuffer( CurrentLine->data, CurrentLine->len, tmp, EditVars.MaxLine );
            TabCnt = otabcnt;
            k = strlen( tmp );
            ConvertSpacesToTabsUpToColumn( k, tmp, k, WorkLine->data, EditVars.MaxLine );
            WorkLine->len = strlen( WorkLine->data );
            bytes_saved += CurrentLine->len - WorkLine->len;
        } else {
            ExpandTabsInABuffer( CurrentLine->data, CurrentLine->len, WorkLine->data, EditVars.MaxLine );
            WorkLine->len = strlen( WorkLine->data );
            bytes_added += WorkLine->len - CurrentLine->len;
        }
        ReplaceCurrentLine();

        /*
         * get next line
         */
        linecnt++;
        rc = CGimmeNextLinePtr( &CurrentFcb, &CurrentLine );
        if( rc != ERR_NO_ERR ) {
            if( rc == ERR_NO_MORE_LINES ) {
                break;
            }
            RestoreCurrentFilePos();
            StaticFree( tmp );
            return( rc );
        }

    }

    StaticFree( tmp );
    RestoreCurrentFilePos();

    Modified( TRUE );
    DCDisplayAllLines();
    Message1( "%l lines processed in \"%s\"", linecnt, CurrentFile->name );
    if( compress ) {
        Message2( " %l tabs added (%l bytes saved)", TabCnt, bytes_saved );
    } else {
        Message2( " %l tabs removed (%l bytes added)", TabCnt, bytes_added );
    }
    return( DO_NOT_CLEAR_MESSAGE_WINDOW );

} /* doCompressExpand */
Пример #7
0
void InitRexxFlags( linenum line_no )
{
    fcb     *fcb;
    char    *text;
    char    *starttext;
    line    *thisline;
    line    *topline;
    char    topChar;
    vi_rc   rc;
    bool    withinQuotes = false;
    line    *line;
    bool    inBlock = false;

    flags.inCComment = false;
    flags.inCPPComment = false;
    flags.inString = false;
    flags.inPreprocessor = false;

    CGimmeLinePtr( line_no, &fcb, &thisline );
    line = thisline;
    while( (rc = GimmePrevLinePtr( &fcb, &line )) == ERR_NO_ERR ) {
        if( line->data[line->len - 1] != '\\' ) {
            break;
        }
        inBlock = true;
    }

    if( rc == ERR_NO_ERR ) {
        topline = line;
        if( inBlock ) {
            CGimmeNextLinePtr( &fcb, &line );
        }
    } else {
        topline = NULL;
        if( inBlock ) {
            CGimmeLinePtr( 1, &fcb, &line );
        } else {
            return;
        }
    }

    if( inBlock ) {
        // jot down whether it started with #
        text = line->data;
        while( *text != '\0' && isspace( *text ) ) {
            text++;
        }
        topChar = *text;

        // parse down through lines, noticing /*, */ and "
        while( line != thisline ) {
            for( text = line->data; ; ++text ) {
                for( ; *text != '\0' && *text != '/'; ++text ) {
                    if( text[0] == '"' ) {
                        if( !withinQuotes ) {
                            withinQuotes = true;
                        } else if( text[-1] != '\\' || text[-2] == '\\' ) {
                            withinQuotes = false;
                        }
                    }
                }
                if( text[0] == '\0' ) {
                    break;
                }
                if( !withinQuotes ) {
                    if( text[-1] == '/' ) {
                        flags.inCPPComment = true;
                    } else if( text[1] == '*' ) {
                        flags.inCComment = true;
                        lenCComment = 100;
                    }
                }
                if( text[-1] == '*' && !withinQuotes ) {
                    flags.inCComment = false;
                }
            }
            rc = CGimmeNextLinePtr( &fcb, &line );
        }

        // if not in a comment (and none above), we may be string or pp
        if( !flags.inCComment ) {
            if( topChar == '#' && !EditFlags.PPKeywordOnly ) {
                flags.inPreprocessor = true;
            }
            if( withinQuotes ) {
                flags.inString = true;
            }
        }
    }

    if( topline == NULL ) {
        return;
    }

    if( !flags.inCComment ) {
        // keep going above multi-line thing till hit /* or */
        line = topline;
        do {
            starttext = line->data;
            for( text = starttext + line->len; ; --text ) {
                while( text != starttext && *text != '/' ) {
                    text--;
                }
                if( text[1] == '*' && text[0] == '/' && text[-1] != '/' ) {
                    if( text == starttext ) {
                        flags.inCComment = true;
                        lenCComment = 100;
                        return;
                    }
                    withinQuotes = false;
                    do {
                        text--;
                        if( text[0] == '"' ) {
                            if( !withinQuotes ) {
                                withinQuotes = true;
                            } else if( text[-1] != '\\' || text[-2] == '\\' ) {
                                withinQuotes = false;
                            }
                        }
                    } while( text != starttext );
                    if( withinQuotes ) {
                        flags.inString = true;
                    } else {
                        flags.inCComment = true;
                        lenCComment = 100;
                    }
                    return;
                }
                if( text == starttext ) {
                    break;
                }
                if( text[-1] == '*' ) {
                    // we may actually be in a string, but that's extreme
                    // (if this becomes a problem, count the "s to beginning
                    // of line, check if multiline, etc. etc.)
                    return;
                }
            }
            rc = GimmePrevLinePtr( &fcb, &line );
        } while( rc == ERR_NO_ERR );
    }
}
Пример #8
0
/*
 * Shift - shove a tab in/out over a line range
 */
vi_rc Shift( linenum s, linenum e, char dir, bool msgflag )
{
    int         shv;
    linenum     fullcnt = 0;
    vi_rc       rc;

    /*
     * set up undo
     */
    if( rc = ModificationTest() ) {
        return( rc );
    }
    rc = UndoReplaceLines( s, e );
    if( rc != ERR_NO_ERR ) {
        return( rc );
    }

    /*
     * now, point to start line
     */
    rc = SaveAndResetFilePos( s );
    if( rc != ERR_NO_ERR ) {
        return( rc );
    }

    /*
     * process all lines
     */
    for( CurrentPos.line = s; CurrentPos.line <= e; CurrentPos.line++ ) {

        /*
         * Add/Subtract leading tab space
         */
        GetCurrentLine();
        shv = ShiftWidth;
        if( dir != '>' ) {
            shv *= -1;
        }
        if( AddLeadingTabSpace( &WorkLine->len, WorkLine->data, shv ) ) {
            ++fullcnt;
        }
        ReplaceCurrentLine();

        if( CurrentPos.line != e ) {
            rc = CGimmeNextLinePtr( &CurrentFcb, &CurrentLine );
            if( rc != ERR_NO_ERR ) {
                RestoreCurrentFilePos();
                return( rc );
            }
        }

    }

    /*
     * done, say so and go back
     */
    RestoreCurrentFilePos();
    if( msgflag ) {
        Message1( "%l lines %c'ed", e - s + 1, dir );
        if( fullcnt > 0 ) {
            Message2( "%l full lines not processed", fullcnt );
        }
    }
    if( CurrentPos.line >= s && CurrentPos.line <= e ) {
        CheckCurrentColumn();
    }
    DCDisplayAllLines();
    SetWindowCursor();
    Modified( TRUE );
    return( DO_NOT_CLEAR_MESSAGE_WINDOW );

} /* Shift */
Пример #9
0
void InitPerlFlags( linenum line_no )
{
    fcb     *fcb;
    char    *text;
    line    *thisline;
//    line    *topline;
    vi_rc   rc;
    bool    withinQuotes = false;
    line    *line;
    bool    inBlock = false;

    flags.inString = false;
    flags.beforeRegExp = true;
    flags.doubleRegExp = false;

    CGimmeLinePtr( line_no, &fcb, &thisline );
    line = thisline;
    rc = GimmePrevLinePtr( &fcb, &line );
    while( rc == ERR_NO_ERR ) {
        if( line->data[line->len - 1] != '\\' ) {
            break;
        }
        inBlock = true;
        rc = GimmePrevLinePtr( &fcb, &line );
    }

    if( rc == ERR_NO_ERR ) {
//        topline = line;
        if( inBlock ) {
            CGimmeNextLinePtr( &fcb, &line );
        }
    } else {
//        topline = NULL;
        if( inBlock ) {
            CGimmeLinePtr( 1, &fcb, &line );
        } else {
            return;
        }
    }

    if( inBlock ) {
        // parse down through lines, noticing "
        while( line != thisline ) {
            text = line->data;
            while( *text ) {
                if( *text == '"' ) {
                    if( !withinQuotes ) {
                        withinQuotes = true;
                    } else if( *(text - 1) != '\\' || *(text - 2) == '\\' ) {
                        withinQuotes = false;
                    }
                }
                text++;
            }
            rc = CGimmeNextLinePtr( &fcb, &line );
        }

        if( withinQuotes ) {
            flags.inString = true;
        }
    }
}
Пример #10
0
/*
 * FindRegularExpression - do a forward search for a regular expression
 */
vi_rc FindRegularExpression( char *pat, i_mark *pos1, char **linedata,
                             linenum termline, find_type flags )
{
    vi_rc       rc;
    int         found;
    linenum     ilineno = 0;
    bool        wrapped = false;
    char        *data;
    line        *cline;
    fcb         *cfcb;
    int         scol;
    linenum     sline;

    /*
     * initialize for search
     */
    if( wrapMsgPrinted ) {
        wrapMsgPrinted = false;
        ClearWindow( message_window_id );
    }
    sline = pos1->line;
    if( flags & FINDFL_WRAP ) {
        ilineno = sline;
    }
    rc = CGimmeLinePtr( sline, &cfcb, &cline );
    if( rc != ERR_NO_ERR ) {
        return( rc );
    }
    scol = pos1->column;
    if( pat != NULL ) {
        rc = CurrentRegComp( pat );
        if( rc != ERR_NO_ERR ) {
            return( rc );
        }
    }

    /*
     * loop until string found
     */
    data = &cline->data[scol];
    while( (found = RegExec( CurrentRegularExpression, data, (data == cline->data) )) == 0 ) {
        if( RegExpError != ERR_NO_ERR ) {
            return( RegExpError );
        }
        /*
         * get next line
         */
        rc = CGimmeNextLinePtr( &cfcb, &cline );
        if( rc == ERR_NO_ERR ) {
            ++sline;
        } else if( rc == ERR_NO_MORE_LINES ) {
            if( (flags & FINDFL_WRAP) == 0 ) {
                return( ERR_FIND_END_OF_FILE );
            } else {
                Message1( wrapMsg, "bottom" );
                MyBeep();
                wrapMsgPrinted = true;
            }
            if( wrapped ) {
                return( ERR_FIND_NOT_FOUND );
            }
            sline = 1;
            rc = CGimmeLinePtr( sline, &cfcb, &cline );
            if( rc != ERR_NO_ERR ) {
                return( rc );
            }
            wrapped = true;
        } else {
            return( rc );
        }
        if( sline > termline ) {
            return( ERR_FIND_PAST_TERM_LINE );
        }
        if( wrapped ) {
            if( sline > ilineno ) {
                return( ERR_FIND_NOT_FOUND );
            }
        }
        scol = 0;
        data = cline->data;
    }
    *linedata = cline->data;
    pos1->column = GetCurrRegExpColumn( cline->data );
    pos1->line = sline;
    return( ERR_NO_ERR );

} /* FindRegularExpression */
Пример #11
0
vi_rc DCUpdate( void )
{
    vi_rc           rc;
    int             i, nlines;
    fcb             *fcb;
    line            *line;
    dc              dc;
    bool            firstLine, firstTilde;
    linenum         line_no;
    int             displayOffset;
    char            *displayText;
#ifdef __WIN__
    HDC             hdc_wnd;
#ifdef BITBLT_BUFFER_DISPLAY
    HDC             hdc_mem;
    HBITMAP         hbitmap;
    type_style      *ws;
#endif
#else
    bool            hasMouse;
    unsigned int    hdc_wnd = 0;
#endif

    if( EditFlags.Quiet || CurrentInfo == NULL ) {
        return( ERR_NO_ERR );
    }

#ifdef __WIN__
    MyHideCaret( CurrentWindow );
    hdc_wnd = GetDC( CurrentWindow );
#ifdef BITBLT_BUFFER_DISPLAY
    hdc_mem = CreateCompatibleDC( hdc_wnd );
    ws = &(SEType[SE_WHITESPACE]);
    hbitmap = CreateCompatibleBitmap( hdc_wnd,
                    WindowAuxInfo( CurrentWindow, WIND_INFO_WIDTH ),
                    FontHeight( ws->font ) );
    SelectObject( hdc_mem, hbitmap );
    SelectObject( hdc_mem, ColorBrush( ws->background ) );
#endif
#else
    hasMouse = DisplayMouse( false );
#endif

    rc = CGimmeLinePtr( LeftTopPos.line, &fcb, &line );
    if( rc != ERR_NO_ERR ) {
        return( rc );
    }

    nlines = CurrentInfo->dc_size;
    dc = CurrentInfo->dc;
    firstLine = true;
    firstTilde = true;
    for( i = 0, line_no = LeftTopPos.line; i < nlines; i++, line_no++ ) {
        if( dc->display ) {
            if( line ) {
                if( firstLine ) {
                    if( dc->valid ) {
                         // major speedup
                         SSInitLanguageFlagsGivenValues( &(dc->flags) );
                    } else {
                        SSInitLanguageFlags( line_no );
                    }
                    firstLine = false;
                }

                displayText = line->data;
                if( line->u.ld.nolinedata ) {
                    if( WorkLine->len >= 0 ) {
                        displayText = WorkLine->data;
                    } else {
                        displayText = "*** ERR NULL DATA ***";
                    }
                }
                displayOffset = VirtualLineLen( displayText );
                if( displayOffset > LeftTopPos.column ) {
                    displayOffset = LeftTopPos.column;
                }
            } else {
                if( EditFlags.DrawTildes ) {
                    displayText = "~";
                } else {
                    displayText = "";
                    if( firstTilde ) {
                        displayText = EditVars.FileEndString;
                        firstTilde = false;
                    }
                }
                displayOffset = 0;
            }
#ifdef BITBLT_BUFFER_DISPLAY
            DisplayLineInWindowWithSyntaxStyle( CurrentWindow, i + 1,
                                line, line_no, displayText, displayOffset,
                                hdc_wnd,
                                hdc_mem );
#else
            DisplayLineInWindowWithSyntaxStyle( CurrentWindow, i + 1,
                                line, line_no, displayText, displayOffset,
                                hdc_wnd );
#endif
            dc->display = false;
        } else {
            // just in case displaying 2+ blocks in one update
            firstLine = true;
        }
        if( line ) {
            rc = CGimmeNextLinePtr( &fcb, &line );
        }
        if( rc != ERR_NO_ERR && rc != ERR_NO_MORE_LINES ) {
            return( rc );
        }
        dc++;
    }
#ifdef __WIN__
#ifdef BITBLT_BUFFER_DISPLAY
    DeleteDC( hdc_mem );
    DeleteObject( hbitmap );
#endif
    ReleaseDC( CurrentWindow, hdc_wnd );
    MyShowCaret( CurrentWindow );
#else
    DisplayMouse( hasMouse );
#endif
    return( ERR_NO_ERR );
}
Пример #12
0
/*
 * ProcessEx - process an ex command
 */
vi_rc ProcessEx( linenum n1, linenum n2, bool n2f, int tkn, const char *data )
{
    vi_rc       rc = ERR_INVALID_COMMAND, i;
    char        word[MAX_STR];
    linenum     addr, tlines;
    fcb         *cfcb;
    line        *cline;
    fcb_list    fcblist;

    GetNextWord1( data, word );
    data = word;
    if( GetAddress( &data, &addr ) != ERR_NO_ERR ) {
        addr = -1;
    }
    tlines = n2 - n1 + 1;

    switch( tkn ) {
    case EX_T_APPEND:
        if( !EditFlags.ExMode ) {
            return( ERR_ONLY_VALID_IN_EX_MODE );
        }
        if( !n2f ) {
            rc = Append( n1, true );
        }
        break;
    case EX_T_CHANGE:
        if( !EditFlags.ExMode ) {
            return( ERR_ONLY_VALID_IN_EX_MODE );
        }
        StartUndoGroup( UndoStack );
        rc = DeleteLineRange( n1, n2, 0 );
        if( rc != ERR_NO_ERR ) {
            EndUndoGroup( UndoStack );
            break;
        }
        rc = Append( n1 - 1, false );
        if( rc != ERR_NO_ERR ) {
            EndUndoGroup( UndoStack );
            break;
        }
        break;
    case EX_T_COPY:
        if( addr < 0 || IsPastLastLine( addr ) ) {
            return( ERR_INVALID_ADDRESS );
        }
        i = GetCopyOfLineRange( n1, n2, &fcblist );
        if( i ) {
            break;
        }
        rc = InsertLines( addr, &fcblist, UndoStack );
        GoToLineNoRelCurs( addr );
        if( rc == ERR_NO_ERR ) {
            Message1( strCmmsg, tlines, "copied", addr );
        }
        break;
    case EX_T_INSERT:
        if( !EditFlags.ExMode ) {
            return( ERR_ONLY_VALID_IN_EX_MODE );
        }
        if( !n2f ) {
            rc = Append( n1 - 1, true );
        }
        break;
    case EX_T_JOIN:
        if( SaveAndResetFilePos( n1 ) != ERR_NO_ERR ) {
            rc = ERR_NO_SUCH_LINE;
            break;
        }
        if( tlines == 1 ) {
            n2 = n1 + 1;
            tlines = 2;
        }
        SetRepeatCount( tlines - 1 );
        rc = JoinCurrentLineToNext();
        RestoreCurrentFilePos();
        GoToLineNoRelCurs( n1 );
        if( rc == ERR_NO_ERR ) {
            Message1( "lines %l to %l joined", n1, n2 );
        }
        break;
    case EX_T_LIST:
        if( !EditFlags.ExMode ) {
            return( ERR_ONLY_VALID_IN_EX_MODE );
        }
        for( rc = CGimmeLinePtr( n1, &cfcb, &cline ); rc == ERR_NO_ERR; rc = CGimmeNextLinePtr( &cfcb, &cline ) ) {
            if( EditFlags.LineNumbers ) {
                MyPrintf( "%M %s\n", n1, cline->data );
            } else {
                MyPrintf( "%s\n", cline->data );
            }
            if( n1 >= n2 ) {
                break;
            }
            n1++;
        }
        break;
    case EX_T_MARK:
        rc = SetGenericMark( n1, 1, C2VIKEY( word[0] ) );
        break;
    case EX_T_MOVE:
        if( addr < 0 || IsPastLastLine( addr ) ) {
            return( ERR_INVALID_ADDRESS );
        }
        SavebufNumber = WORK_SAVEBUF;
        StartUndoGroup( UndoStack );
        rc = DeleteLineRange( n1, n2, SAVEBUF_FLAG );

        if( SavebufNumber != WORK_SAVEBUF ) {
            /* if this changes, the command will fail
             * this could be caused by checking out a read-only file
             * so fix the deleted text and give an error message
             */
            DoUndo();
            return( ERR_INVALID_COMMAND );
        }
        if( rc != ERR_NO_ERR ) {
            EndUndoGroup( UndoStack );
            break;
        }
        if( addr > n2 ) {
            addr -= tlines;
        } else if( addr >= n1 && addr <= n2 ) {
            addr = n1;
        }
        rc = InsertLines( addr, &WorkSavebuf->u.fcbs, UndoStack );
        EndUndoGroup( UndoStack );
        GoToLineNoRelCurs( addr );
        if( rc == ERR_NO_ERR ) {
            Message1( strCmmsg, tlines, "moved", addr );
        }
        break;
    case EX_T_UNDO:
        rc = DoUndo();
        break;
    case EX_T_UNDO_DMT:
        rc = DoUndoUndo();
        break;
    case EX_T_EQUALS:
        Message1( "%l", n1 );
        rc = ERR_NO_ERR;
        break;
    case EX_T_VERSION:
        rc = DoVersion();
        break;
    case EX_T_VISUAL:
    case EX_T_VISUAL_DMT:
        if( EditFlags.LineDisplay ) {
            ScreenPage( -1 );
            EditFlags.ExMode = false;
            EditFlags.LineDisplay = false;
            EditFlags.ClockActive = true;
            ReDisplayScreen();
            DoVersion();
        }
        if( word[0] != '\0' ) {
            rc = EditFile( word, ( tkn == EX_T_VISUAL_DMT ) );
        } else {
            rc = ERR_NO_ERR;
        }
        break;
    }
    return( rc );

} /* ProcessEx */