home *** CD-ROM | disk | FTP | other *** search
- /* cmd2.c */
-
- /* Author:
- * Steve Kirkendall
- * 16820 SW Tallac Way
- * Beaverton, OR 97006
- * kirkenda@jove.cs.pdx.edu, or ...uunet!tektronix!psueea!jove!kirkenda
- */
-
-
- /* This file contains some of the commands - mostly ones that change text */
-
- #include "config.h"
- #include "vi.h"
- #include "regexp.h"
-
-
- /*ARGSUSED*/
- void cmd_substitute(frommark, tomark, cmd, bang, extra)
- MARK frommark;
- MARK tomark;
- CMD cmd;
- int bang;
- char *extra; /* rest of the command line */
- {
- char *line; /* a line from the file */
- regexp *re; /* the compiled search expression */
- char *subst; /* the substitution string */
- char *opt; /* substitution options */
- int optp; /* boolean option: print when done? */
- int optg; /* boolean option: substitute globally in line? */
- long l; /* a line number */
- char *s, *d; /* used during subtitutions */
- long chline; /* # of lines changed */
- long chsub; /* # of substitutions made */
-
-
- /* make sure we got a search pattern */
- if (*extra != '/' && *extra != '?')
- {
- msg("Usage: s/regular expression/new text/");
- return;
- }
-
- /* parse & compile the search pattern */
- subst = parseptrn(extra);
- re = regcomp(extra + 1);
- if (!re)
- {
- return;
- }
-
- /* parse the substitution string & find the option string */
- for (opt = subst; *opt && (*opt != *extra || opt[-1] == '\\'); opt++)
- {
- }
- if (*opt)
- {
- *opt++ = '\0';
- }
-
- /* analyse the option string */
- optp = optg = 0;
- while (*opt)
- {
- switch (*opt++)
- {
- case 'p': optp = 1; break;
- case 'g': optg = 1; break;
- case ' ':
- case '\t': break;
- default:
- msg("Subst options are p and g -- not %c", opt[-1]);
- return;
- }
- }
-
- ChangeText
- {
- /* reset the change counters */
- chline = chsub = 0L;
-
- /* for each selected line */
- for (l = markline(frommark); l <= markline(tomark); l++)
- {
- /* fetch the line */
- line = fetchline(l);
-
- /* if it contains the search pattern... */
- if (regexec(re, line, TRUE))
- {
- /* increment the line change counter */
- chline++;
-
- /* initialize the pointers */
- s = line;
- d = tmpblk.c;
-
- /* do once or globally ... */
- do
- {
- /* increment the substitution change counter */
- chsub++;
-
- /* this may be the first line to redraw */
- redrawrange(l, l + 1L, l + 1L);
-
- /* copy stuff from before the match */
- while (s < re->startp[0])
- {
- *d++ = *s++;
- }
-
- /* subtitute for the matched part */
- regsub(re, subst, d);
- s = re->endp[0];
- d += strlen(d);
-
- } while (optg && regexec(re, s, FALSE));
-
- /* copy stuff from after the match */
- while (*d++ = *s++) /* yes, ASSIGNMENT! */
- {
- }
-
- /* replace the old version of the line with the new */
- changeline(l, tmpblk.c);
-
- /* if supposed to print it, do so */
- if (optp)
- {
- addstr(tmpblk.c);
- addch('\n');
- exrefresh();
- }
- }
- }
- }
-
- /* report what happened */
- if (chsub == 0)
- {
- msg("Substitution failed");
- }
-
- /* tweak for redrawing */
- if (chline > 1 || redrawafter && redrawafter != markline(cursor))
- {
- mustredraw = TRUE;
- }
-
- /* free the regexp */
- free(re);
-
- /* Reporting */
- if (chline >= *o_report)
- {
- msg("%ld substitutions on %ld lines", chsub, chline);
- }
- rptlines = 0;
- }
-
-
-
-
- /*ARGSUSED*/
- void cmd_delete(frommark, tomark, cmd, bang, extra)
- MARK frommark;
- MARK tomark;
- CMD cmd;
- int bang;
- char *extra;
- {
- MARK curs2; /* al altered form of the cursor */
-
- /* choose your cut buffer */
- if (*extra == '"')
- {
- extra++;
- }
- if (*extra)
- {
- cutname(*extra);
- }
-
- /* make sure we're talking about whole lines here */
- frommark = frommark & ~(BLKSIZE - 1);
- tomark = (tomark & ~(BLKSIZE - 1)) + BLKSIZE;
-
- /* yank the lines */
- cut(frommark, tomark);
-
- /* if CMD_DELETE then delete the lines */
- if (cmd != CMD_YANK)
- {
- curs2 = cursor;
- ChangeText
- {
- /* delete the lines */
- delete(frommark, tomark);
- }
- if (curs2 > tomark)
- {
- cursor = curs2 - tomark + frommark;
- }
- else if (curs2 > frommark)
- {
- cursor = frommark;
- }
- }
- }
-
-
- /*ARGSUSED*/
- void cmd_append(frommark, tomark, cmd, bang, extra)
- MARK frommark;
- MARK tomark;
- CMD cmd;
- int bang;
- char *extra;
- {
- long l; /* line counter */
-
- ChangeText
- {
- /* if we're doing a change, delete the old version */
- if (cmd == CMD_CHANGE)
- {
- /* delete 'em */
- cmd_delete(frommark, tomark, cmd, bang, extra);
- }
-
- /* new lines start at the frommark line, or after it */
- l = markline(frommark);
- if (cmd == CMD_APPEND)
- {
- l++;
- }
-
- /* get lines until no more lines, or "." line, and insert them */
- while (vgets('\0', tmpblk.c, BLKSIZE) >= 0)
- {
- addch('\n');
- if (!strcmp(tmpblk.c, "."))
- {
- break;
- }
-
- addline(l, tmpblk.c);
- l++;
- }
- }
-
- /* on the odd chance that we're calling this from vi mode ... */
- redraw(MARK_UNSET, FALSE);
- }
-
-
- /*ARGSUSED*/
- void cmd_put(frommark, tomark, cmd, bang, extra)
- MARK frommark;
- MARK tomark;
- CMD cmd;
- int bang;
- char *extra;
- {
- /* choose your cut buffer */
- if (*extra == '"')
- {
- extra++;
- }
- if (*extra)
- {
- cutname(*extra);
- }
-
- /* paste it */
- ChangeText
- {
- cursor = paste(frommark, !bang, FALSE);
- }
- }
-
-
- /*ARGSUSED*/
- void cmd_join(frommark, tomark, cmd, bang, extra)
- MARK frommark;
- MARK tomark;
- CMD cmd;
- int bang;
- char *extra;
- {
- long l;
- char *scan;
- int len; /* length of the new line */
-
- /* if only one line is specified, assume the following one joins too */
- if (markline(frommark) == nlines)
- {
- msg("Nothing to join with this line");
- return;
- }
- if (markline(frommark) == markline(tomark))
- {
- tomark = m_down(tomark, 1L);
- }
-
- /* get the first line */
- l = markline(frommark);
- strcpy(tmpblk.c, fetchline(l++));
- len = strlen(tmpblk.c);
-
- /* build the longer line */
- while (l <= markline(tomark))
- {
- /* get the next line */
- scan = fetchline(l++);
-
- /* remove any leading whitespace */
- while (*scan == '\t' || *scan == ' ')
- {
- scan++;
- }
-
- /* see if the line will fit */
- if (strlen(scan) + len + 1 > BLKSIZE)
- {
- msg("Can't join -- the resulting line would be too long");
- return;
- }
-
- /* catenate it, with a space in between */
- tmpblk.c[len++] = ' ';
- strcpy(tmpblk.c + len, scan);
- len += strlen(scan);
- }
-
- /* make the change */
- ChangeText
- {
- frommark &= ~(BLKSIZE - 1);
- tomark &= ~(BLKSIZE - 1);
- tomark += BLKSIZE;
- delete(frommark, tomark);
- addline(markline(frommark), tmpblk.c);
- }
- }
-
-
-
- /*ARGSUSED*/
- void cmd_shift(frommark, tomark, cmd, bang, extra)
- MARK frommark;
- MARK tomark;
- CMD cmd;
- int bang;
- char *extra;
- {
- long l; /* line number counter */
- int oldidx; /* number of chars previously used for indent */
- int newidx; /* number of chars in the new indent string */
- int oldcol; /* previous indent amount */
- int newcol; /* new indent amount */
- char *text; /* pointer to the old line's text */
-
- /* figure out how much of the screen we must redraw (for vi mode) */
- if (markline(frommark) != markline(tomark))
- {
- mustredraw = TRUE;
- redrawrange(markline(frommark), markline(tomark) + 1L, markline(tomark) + 1L);
- }
-
- ChangeText
- {
- /* for each line to shift... */
- for (l = markline(frommark); l <= markline(tomark); l++)
- {
- /* get the line - ignore empty lines unless ! mode */
- text = fetchline(l);
- if (!*text && !bang)
- continue;
-
- /* calc oldidx and oldcol */
- for (oldidx = 0, oldcol = 0;
- text[oldidx] == ' ' || text[oldidx] == '\t';
- oldidx++)
- {
- if (text[oldidx] == ' ')
- {
- oldcol += 1;
- }
- else
- {
- oldcol += *o_tabstop - (oldcol % *o_tabstop);
- }
- }
-
- /* calc newcol */
- if (cmd == CMD_SHIFTR)
- {
- newcol = oldcol + (*o_shiftwidth & 0xff);
- }
- else
- {
- newcol = oldcol - (*o_shiftwidth & 0xff);
- if (newcol < 0)
- newcol = 0;
- }
-
- /* if no change, then skip to next line */
- if (oldcol == newcol)
- continue;
-
- /* build a new indent string */
- newidx = 0;
- while (newcol >= *o_tabstop)
- {
- tmpblk.c[newidx++] = '\t';
- newcol -= *o_tabstop;
- }
- while (newcol > 0)
- {
- tmpblk.c[newidx++] = ' ';
- newcol--;
- }
- tmpblk.c[newidx] = '\0';
-
- /* change the old indent string into the new */
- change(MARK_AT_LINE(l), MARK_AT_LINE(l) + oldidx, tmpblk.c);
- }
- }
-
- /* Reporting... */
- rptlines = markline(tomark) - markline(frommark) + 1L;
- if (cmd == CMD_SHIFTR)
- {
- rptlabel = ">ed";
- }
- else
- {
- rptlabel = "<ed";
- }
- }
-
-
- /*ARGSUSED*/
- void cmd_read(frommark, tomark, cmd, bang, extra)
- MARK frommark;
- MARK tomark;
- CMD cmd;
- int bang;
- char *extra;
- {
- long l; /* line number counter - where new lines go */
- int fd, rc; /* used while reading from the file */
- char *scan; /* used for finding newlines */
- char *line; /* points to the start of a line */
- int prevrc; /* used to detect abnormal EOF */
-
- /* special case: if ":r !cmd" then let the filter() function do it */
- if (bang || extra[0] == '!')
- {
- if (extra[0] == '!')
- {
- extra++;
- }
- frommark = (frommark & ~(BLKSIZE - 1)) + BLKSIZE;
- filter(frommark, MARK_UNSET, extra);
- return;
- }
-
- /* first line goes after the selected line */
- l = markline(frommark) + 1;
-
- /* open the file */
- fd = open(extra, O_RDONLY);
- if (fd < 0)
- {
- msg("Can't open \"%s\"", extra);
- return;
- }
-
- /* get blocks from the file, and add each line in the block */
- ChangeText
- {
- /* NOTE! lint worries needlessly about the order of evaluation
- * of the 'rc' expressions in the test clause of this for(;;){}
- */
- for (prevrc = rc = 0;
- (rc = rc + tread(fd, tmpblk.c + rc, BLKSIZE - rc)) > 0;
- prevrc = rc)
- {
- /* if we couldn't read anything, we damn well better have \n */
- if (prevrc == rc)
- {
- if (rc == BLKSIZE)
- {
- rc--;
- }
- if (tmpblk.c[rc - 1] != '\n' || rc <= 0)
- {
- tmpblk.c[rc++] = '\n';
- }
- }
-
- /* for each complete line in this block, add it */
- for (line = scan = tmpblk.c; rc > 0; rc--, scan++)
- {
- if (*scan == '\n')
- {
- *scan = '\0';
- addline(l, line);
- l++;
- line = scan + 1;
- }
- else if (!*scan)
- {
- /* protect against NUL chars in file */
- *scan = 0x80;
- }
- }
-
- /* any extra chars are shifted to the start of the buffer */
- rc = scan - line;
- for (scan = tmpblk.c; scan < tmpblk.c + rc; )
- {
- *scan++ = *line++;
- }
- }
- }
-
- /* close the file */
- close(fd);
-
- /* Reporting... */
- rptlines = l - markline(frommark) - 1L;
- rptlabel = "read";
- }
-
-
- /*ARGSUSED*/
- void cmd_list(frommark, tomark, cmd, bang, extra)
- MARK frommark;
- MARK tomark;
- CMD cmd;
- int bang;
- char *extra;
- {
- long l; /* line number counter */
- register char *scan; /* used for moving through the line */
-
- for (l = markline(frommark); l <= markline(tomark); l++)
- {
- /* list the line */
- scan = fetchline(l);
-
- while (*scan)
- {
- /* if the char is non-printable, write it as \000 */
- if (*scan < ' ' || *scan > '~')
- {
- /* build the \000 form & write it */
- addch('\\');
- addch('0' + ((*scan >> 6) & 3));
- addch('0' + ((*scan >> 3) & 7));
- addch('0' + (*scan & 7));
- }
- else
- {
- addch(*scan);
- }
- scan++;
- }
-
- /* write a $ and a \n */
- addstr("$\n");
- exrefresh();
- }
- }
-
-
- /*ARGSUSED*/
- void cmd_undo(frommark, tomark, cmd, bang, extra)
- MARK frommark;
- MARK tomark;
- CMD cmd;
- int bang;
- char *extra;
- {
- undo();
- }
-
-
- /* print the selected lines */
- /*ARGSUSED*/
- void cmd_print(frommark, tomark, cmd, bang, extra)
- MARK frommark;
- MARK tomark;
- CMD cmd;
- int bang;
- char *extra;
- {
- register char *scan;
- register long l;
- register int col;
-
- for (l = markline(frommark); l <= markline(tomark); l++)
- {
- /* get the next line & display it */
- for (col = 0, scan = fetchline(l); *scan; scan++)
- {
- /* expand tabs to the proper width */
- if (*scan == '\t')
- {
- do
- {
- qaddch(' ');
- col++;
- } while (col % *o_tabstop != 0);
- }
- else
- {
- qaddch(*scan);
- }
-
- /* wrap at the edge of the screen */
- if (!has_AM && col >= COLS)
- {
- addch('\n');
- col = 0;
- }
- }
- addch('\n');
- exrefresh();
- }
- }
-
-
- /* move or copy selected lines */
- /*ARGSUSED*/
- void cmd_move(frommark, tomark, cmd, bang, extra)
- MARK frommark;
- MARK tomark;
- CMD cmd;
- int bang;
- char *extra;
- {
- MARK destmark;
-
- /* parse the destination linespec. No defaults. Line 0 is okay */
- destmark = cursor;
- if (!strcmp(extra, "0"))
- {
- destmark = 0L;
- }
- else if (linespec(extra, &destmark) == extra || !destmark)
- {
- msg("invalid destination address");
- return;
- }
-
- /* flesh the marks out to encompass whole lines */
- frommark &= ~(BLKSIZE - 1);
- tomark = (tomark & ~(BLKSIZE - 1)) + BLKSIZE;
- destmark = (destmark & ~(BLKSIZE - 1)) + BLKSIZE;
-
- /* make sure the destination is valid */
- if (cmd == CMD_MOVE && destmark >= frommark && destmark < tomark)
- {
- msg("invalid destination address");
- }
-
- /* Do it */
- ChangeText
- {
- /* save the text to a cut buffer */
- cutname('\0');
- cut(frommark, tomark);
-
- /* if we're not copying, delete the old text & adjust destmark */
- if (cmd != CMD_COPY)
- {
- delete(frommark, tomark);
- if (destmark >= frommark)
- {
- destmark -= (tomark - frommark);
- }
- }
-
- /* add the new text */
- paste(destmark, FALSE, FALSE);
- }
-
- /* move the cursor to the last line of the moved text */
- cursor = destmark + (tomark - frommark) - BLKSIZE;
- if (cursor < MARK_FIRST || cursor >= MARK_LAST + BLKSIZE)
- {
- cursor = MARK_LAST;
- }
-
- /* Reporting... */
- rptlabel = ( (cmd == CMD_COPY) ? "copied" : "moved" );
- }
-
-
-
- /* execute EX commands from a file */
- /*ARGSUSED*/
- void cmd_source(frommark, tomark, cmd, bang, extra)
- MARK frommark;
- MARK tomark;
- CMD cmd;
- int bang;
- char *extra;
- {
- /* must have a filename */
- if (!*extra)
- {
- msg("\"source\" requires a filename");
- return;
- }
-
- doexrc(extra);
- }
-