5 * 14407 SW Teal Blvd. #C
11 /* This file contains some of the EX commands - mostly ones that deal with
12 * files, options, etc. -- anything except text.
21 /* print the selected lines with info on the blocks */
23 void cmd_debug(frommark
, tomark
, cmd
, bang
, extra
)
35 /* scan lnum[] to determine which block its in */
36 l
= markline(frommark
);
37 for (i
= 1; l
> lnum
[i
]; i
++)
43 /* fetch text of the block containing that line */
46 /* calculate its length */
47 if (scan
[BLKSIZE
- 1])
56 /* print block stats */
57 msg("##### hdr[%d]=%d, lnum[%d-1]=%ld, lnum[%d]=%ld (%ld lines)",
58 i
, hdr
.n
[i
], i
, lnum
[i
-1], i
, lnum
[i
], lnum
[i
] - lnum
[i
- 1]);
59 msg("##### len=%d, buf=0x%lx, %sdirty",
60 len
, scan
, ((int *)scan
)[MAXBLKS
+ 1] ? "" : "not ");
73 } while (i
< MAXBLKS
&& lnum
[i
] && lnum
[i
- 1] < markline(tomark
));
77 /* This function checks a lot of conditions to make sure they aren't screwy */
79 void cmd_validate(frommark
, tomark
, cmd
, bang
, extra
)
88 int nlcnt
; /* used to count newlines */
89 int len
; /* counts non-NUL characters */
94 msg("lnum[0] = %ld", lnum
[0]);
97 /* check each block */
98 for (i
= 1; lnum
[i
] <= nlines
; i
++)
101 if (scan
[BLKSIZE
- 1])
103 msg("block %d has no NUL at the end", i
);
107 for (nlcnt
= len
= 0; *scan
; scan
++, len
++)
114 if (scan
[-1] != '\n')
116 msg("block %d doesn't end with '\\n' (length %d)", i
, len
);
118 if (bang
|| nlcnt
!= lnum
[i
] - lnum
[i
- 1])
120 msg("block %d (line %ld?) has %d lines, but should have %ld",
121 i
, lnum
[i
- 1] + 1L, nlcnt
, lnum
[i
] - lnum
[i
- 1]);
127 /* check lnum again */
128 if (lnum
[i
] != INFINITY
)
130 msg("hdr.n[%d] = %d, but lnum[%d] = %ld",
131 i
, hdr
.n
[i
], i
, lnum
[i
]);
134 msg("# = \"%s\", %% = \"%s\"", prevorig
, origname
);
135 msg("V_from=%ld.%d, cursor=%ld.%d", markline(V_from
), markidx(V_from
), markline(cursor
), markidx(cursor
));
141 void cmd_mark(frommark
, tomark
, cmd
, bang
, extra
)
148 /* validate the name of the mark */
153 /* valid mark names are lowercase ascii characters */
154 if (!isascii(*extra
) || !islower(*extra
) || extra
[1])
156 msg("Invalid mark name");
160 mark
[*extra
- 'a'] = tomark
;
164 void cmd_write(frommark
, tomark
, cmd
, bang
, extra
)
172 int append
; /* boolean: write in "append" mode? */
177 /* if writing to a filter, then let filter() handle it */
180 filter(frommark
, tomark
, extra
+ 1, FALSE
);
184 /* if all lines are to be written, use tmpsave() */
185 if (frommark
== MARK_FIRST
&& tomark
== MARK_LAST
&& cmd
== CMD_WRITE
)
187 tmpsave(extra
, bang
);
191 /* see if we're going to do this in append mode or not */
193 if (extra
[0] == '>' && extra
[1] == '>')
199 /* either the file must not exist, or we must have a ! or be appending */
200 if (access(extra
, 0) == 0 && !bang
&& !append
)
202 msg("File already exists - Use :w! to overwrite");
206 /* else do it line-by-line, like cmd_print() */
210 fd
= open(extra
, O_WRONLY
|O_APPEND
);
212 fd
= open(extra
, O_WRONLY
);
221 fd
= -1; /* so we know the file isn't open yet */
226 fd
= creat(extra
, FILEPERMS
);
229 msg("Can't write to \"%s\"", extra
);
233 for (l
= markline(frommark
); l
<= markline(tomark
); l
++)
235 /* get the next line */
241 if (twrite(fd
, scan
, i
) < i
)
247 rptlines
= markline(tomark
) - markline(frommark
) + 1;
248 rptlabel
= "written";
254 void cmd_shell(frommark
, tomark
, cmd
, bang
, extra
)
255 MARK frommark
, tomark
;
260 static char prevextra
[80];
262 /* special case: ":sh" means ":!sh" */
263 if (cmd
== CMD_SHELL
)
266 frommark
= tomark
= 0L;
269 /* if extra is "!", substitute previous command */
274 msg("No previous shell command to substitute for '!'");
279 else if (cmd
== CMD_BANG
&& strlen(extra
) < sizeof(prevextra
) - 1)
281 strcpy(prevextra
, extra
);
284 /* warn the user if the file hasn't been saved yet */
285 if (*o_warn
&& tstflag(file
, MODIFIED
))
291 msg("Warning: \"%s\" has been modified but not yet saved", origname
);
294 /* if no lines were specified, just run the command */
300 else /* pipe lines from the file through the command */
302 filter(frommark
, tomark
, extra
, TRUE
);
305 /* resume curses quietly for MODE_EX, but noisily otherwise */
306 resume_curses(mode
== MODE_EX
);
311 void cmd_global(frommark
, tomark
, cmd
, bang
, extra
)
312 MARK frommark
, tomark
;
315 char *extra
; /* rest of the command line */
317 char *cmdptr
; /* the command from the command line */
318 char cmdln
[100]; /* copy of the command from the command line */
319 char *line
; /* a line from the file */
320 long l
; /* used as a counter to move through lines */
321 long lqty
; /* quantity of lines to be scanned */
322 long nchanged
; /* number of lines changed */
323 regexp
*re
; /* the compiled search expression */
325 /* can't nest global commands */
328 msg("Can't nest global commands.");
333 /* ":g! ..." is the same as ":v ..." */
339 /* make sure we got a search pattern */
340 if (*extra
!= '/' && *extra
!= '?')
342 msg("Usage: %c /regular expression/ command", cmd
== CMD_GLOBAL
? 'g' : 'v');
346 /* parse & compile the search pattern */
347 cmdptr
= parseptrn(extra
);
350 msg("Can't use empty regular expression with '%c' command", cmd
== CMD_GLOBAL
? 'g' : 'v');
353 re
= regcomp(extra
+ 1);
356 /* regcomp found & described an error */
360 /* for each line in the range */
364 /* NOTE: we have to go through the lines in a forward order,
365 * otherwise "g/re/p" would look funny. *BUT* for "g/re/d"
366 * to work, simply adding 1 to the line# on each loop won't
367 * work. The solution: count lines relative to the end of
368 * the file. Think about it.
370 for (l
= nlines
- markline(frommark
),
371 lqty
= markline(tomark
) - markline(frommark
) + 1L,
373 lqty
> 0 && nlines
- l
>= 0 && nchanged
>= 0L;
377 line
= fetchline(nlines
- l
);
379 /* if it contains the search pattern... */
380 if ((!regexec(re
, line
, 1)) == (cmd
!= CMD_GLOBAL
))
382 /* move the cursor to that line */
383 cursor
= MARK_AT_LINE(nlines
- l
);
385 /* do the ex command (without mucking up
386 * the original copy of the command line)
388 strcpy(cmdln
, cmdptr
);
391 nchanged
+= rptlines
;
397 /* free the regexp */
406 void cmd_file(frommark
, tomark
, cmd
, bang
, extra
)
407 MARK frommark
, tomark
;
413 /* if we're given a new filename, use it as this file's name */
416 strcpy(origname
, extra
);
418 setflag(file
, NOTEDITED
);
424 msg("\"%s\" %s%s%s %ld lines, line %ld [%ld%%]",
426 msg("\"%s\" %s%s %ld lines, line %ld [%ld%%]",
428 *origname
? origname
: "[NO FILE]",
429 tstflag(file
, MODIFIED
) ? "[MODIFIED]" : "",
431 tstflag(file
, NOTEDITED
) ?"[NOT EDITED]":"",
433 tstflag(file
, READONLY
) ? "[READONLY]" : "",
436 markline(frommark
) * 100 / nlines
);
439 else if (markline(frommark
) != markline(tomark
))
441 msg("range \"%ld,%ld\" contains %ld lines",
444 markline(tomark
) - markline(frommark
) + 1L);
449 msg("%ld", markline(frommark
));
455 void cmd_edit(frommark
, tomark
, cmd
, bang
, extra
)
456 MARK frommark
, tomark
;
461 long line
= 1L; /* might be set to prevline */
463 char *init
= (char *)0;
467 /* if ":vi", then switch to visual mode, and if no file is named
468 * then don't switch files.
470 if (cmd
== CMD_VISUAL
)
480 /* Editing previous file? Then start at previous line */
481 if (!strcmp(extra
, prevorig
))
487 /* if we were given an explicit starting line, then start there */
490 for (init
= ++extra
; !isspace(*extra
); extra
++)
493 while (isspace(*extra
))
506 #endif /* not CRUNCH */
512 if (line
<= nlines
&& line
>= 1L)
514 cursor
= MARK_AT_LINE(line
);
525 msg("Use edit! to abort changes, or w to save changes");
527 /* so we can say ":e!#" next time... */
528 strcpy(prevorig
, extra
);
533 /* This code is also used for rewind -- GB */
536 void cmd_next(frommark
, tomark
, cmd
, bang
, extra
)
537 MARK frommark
, tomark
;
545 /* if extra stuff given, use ":args" to define a new args list */
546 if (cmd
== CMD_NEXT
&& extra
&& *extra
)
548 cmd_args(frommark
, tomark
, cmd
, bang
, extra
);
551 /* move to the next arg */
556 else if (cmd
== CMD_PREVIOUS
)
560 else /* cmd == CMD_REWIND */
564 if (i
< 0 || i
>= nargs
)
566 msg("No %sfiles to edit", cmd
== CMD_REWIND
? "" : "more ");
570 /* find & isolate the name of the file to edit */
571 for (j
= i
, scan
= args
; j
> 0; j
--)
578 /* switch to the next file */
586 msg("Use :%s! to abort changes, or w to save changes",
587 cmd
== CMD_NEXT
? "next" :
588 cmd
== CMD_PREVIOUS
? "previous" :
593 /* also called from :wq -- always writes back in this case */
596 void cmd_xit(frommark
, tomark
, cmd
, bang
, extra
)
597 MARK frommark
, tomark
;
602 static long whenwarned
; /* when the user was last warned of extra files */
605 /* if there are more files to edit, then warn user */
606 if (argno
>= 0 && argno
+ 1 < nargs
&& whenwarned
!= changes
&& (!bang
|| cmd
!= CMD_QUIT
))
608 msg("More files to edit -- Use \":n\" to go to next file");
609 whenwarned
= changes
;
615 oldflag
= *o_autowrite
;
616 *o_autowrite
= FALSE
;
623 msg("Use q! to abort changes, or wq to save changes");
625 *o_autowrite
= oldflag
;
629 /* else try to save this file */
630 oldflag
= tstflag(file
, MODIFIED
);
631 if (cmd
== CMD_WQUIT
)
632 setflag(file
, MODIFIED
);
639 msg("Could not save file -- use quit! to abort changes, or w filename");
642 clrflag(file
, MODIFIED
);
648 void cmd_args(frommark
, tomark
, cmd
, bang
, extra
)
649 MARK frommark
, tomark
;
657 int scrolled
= FALSE
;
660 /* if no extra names given, or just current name, then report the args
663 if (!extra
|| !*extra
)
665 /* empty args list? */
666 if (nargs
== 1 && !*args
)
671 /* list the arguments */
672 for (scan
= args
, col
= arg
= 0;
674 scan
+= width
+ 1, col
+= width
, arg
++)
676 width
= strlen(scan
);
677 if (col
+ width
>= COLS
- 4)
701 /* write a trailing newline */
702 if ((mode
== MODE_EX
|| mode
== MODE_COLON
|| scrolled
) && col
)
708 else /* new args list given */
710 for (scan
= args
, nargs
= 1; *extra
; )
715 while (isspace(*extra
))
731 /* reset argno to before the first, so :next will go to first */
736 msg("%d files to edit", nargs
);
743 void cmd_cd(frommark
, tomark
, cmd
, bang
, extra
)
744 MARK frommark
, tomark
;
752 /* if current file is modified, and no '!' was given, then error */
753 if (tstflag(file
, MODIFIED
) && !bang
)
755 msg("File modified; use \"cd! %s\" to switch anyway", extra
);
759 /* default directory name is $HOME */
762 extra
= getenv("HOME");
765 msg("environment variable $HOME not set");
770 /* go to the directory */
771 if (chdir(extra
) < 0)
779 void cmd_map(frommark
, tomark
, cmd
, bang
, extra
)
780 MARK frommark
, tomark
;
788 static char *fnames
[NFKEYS
] =
790 "#10", "#1", "#2", "#3", "#4",
791 "#5", "#6", "#7", "#8", "#9",
792 # ifndef NO_SHIFT_FKEY
793 "#10s", "#1s", "#2s", "#3s", "#4s",
794 "#5s", "#6s", "#7s", "#8s", "#9s",
795 # ifndef NO_CTRL_FKEY
796 "#10c", "#1c", "#2c", "#3c", "#4c",
797 "#5c", "#6c", "#7c", "#8c", "#9c",
799 "#10a", "#1a", "#2a", "#3a", "#4a",
800 "#5a", "#6a", "#7a", "#8a", "#9a",
808 /* "map" with no extra will dump the map table contents */
814 dumpkey(bang
? WHEN_EX
|WHEN_VIINP
|WHEN_VIREP
: WHEN_VIINP
|WHEN_VIREP
, TRUE
);
819 dumpkey(bang
? WHEN_VIINP
|WHEN_VIREP
: WHEN_VICMD
, FALSE
);
824 /* "extra" is key to map, followed by what it maps to */
826 /* handle quoting inside the "raw" string */
827 for (build
= mapto
= extra
;
828 *mapto
&& (*mapto
!= ' ' && *mapto
!= '\t');
831 if (*mapto
== ctrl('V') && mapto
[1])
837 /* skip whitespace, and mark the end of the "raw" string */
838 while ((*mapto
== ' ' || *mapto
== '\t'))
844 /* strip ^Vs from the "cooked" string */
845 for (scan
= build
= mapto
; *scan
; *build
++ = *scan
++)
847 if (*scan
== ctrl('V') && scan
[1])
855 /* if the mapped string is '#' and a number, then assume
856 * the user wanted that function key
858 if (extra
[0] == '#' && isdigit(extra
[1]))
860 key
= atoi(extra
+ 1) % 10;
861 # ifndef NO_SHIFT_FKEY
862 build
= extra
+ strlen(extra
) - 1;
865 # ifndef NO_CTRL_FKEY
866 else if (*build
== 'c')
869 else if (*build
== 'a')
875 mapkey(FKEY
[key
], mapto
, bang
? WHEN_VIINP
|WHEN_VIREP
: WHEN_VICMD
, fnames
[key
]);
877 msg("This terminal has no %s key", fnames
[key
]);
882 if (cmd
== CMD_ABBR
|| cmd
== CMD_UNABBR
)
884 mapkey(extra
, mapto
, bang
? WHEN_EX
|WHEN_VIINP
|WHEN_VIREP
: WHEN_VIINP
|WHEN_VIREP
, "abbr");
889 mapkey(extra
, mapto
, bang
? WHEN_VIINP
|WHEN_VIREP
: WHEN_VICMD
, (char *)0);
896 void cmd_set(frommark
, tomark
, cmd
, bang
, extra
)
897 MARK frommark
, tomark
;
904 dumpopts(FALSE
);/* "FALSE" means "don't dump all" - only set */
906 else if (!strcmp(extra
, "all"))
908 dumpopts(TRUE
); /* "TRUE" means "dump all" - even unset vars */
914 /* That option may have affected the appearence of text */
920 void cmd_tag(frommark
, tomark
, cmd
, bang
, extra
)
921 MARK frommark
, tomark
;
926 int fd
; /* file descriptor used to read the file */
927 char *scan
; /* used to scan through the tmpblk.c */
929 char *cmp
; /* char of tag name we're comparing, or NULL */
930 char *end
; /* marks the end of chars in tmpblk.c */
935 char wasmagic
; /* preserves the original state of o_magic */
937 static char prevtag
[30];
939 /* if no tag is given, use the previous tag */
940 if (!extra
|| !*extra
)
944 msg("No previous tag");
951 strncpy(prevtag
, extra
, sizeof prevtag
);
952 prevtag
[sizeof prevtag
- 1] = '\0';
955 #ifndef INTERNAL_TAGS
956 /* use "ref" to look up the tag info for this tag */
957 sprintf(tmpblk
.c
, "ref -t %s%s %s", (*origname
? "-f" : ""),origname
, prevtag
);
958 fd
= rpipe(tmpblk
.c
, 0);
961 msg("Can't run \"%s\"", tmpblk
.c
);
965 /* try to read the tag info */
966 for (scan
= tmpblk
.c
;
967 (i
= tread(fd
, scan
, scan
- tmpblk
.c
+ BLKSIZE
)) > 0;
973 /* close the pipe. abort if error */
974 if (rpclose(fd
) != 0 || scan
< tmpblk
.c
+ 3)
976 msg("tag \"%s\" not found", extra
);
980 #else /* use internal code to look up the tag */
981 /* open the tags file */
982 fd
= open(TAGS
, O_RDONLY
);
989 /* Hmmm... this would have been a lot easier with <stdio.h> */
991 /* find the line with our tag in it */
992 for(scan
= end
= tmpblk
.c
, cmp
= extra
; ; scan
++)
994 /* read a block, if necessary */
997 end
= tmpblk
.c
+ tread(fd
, tmpblk
.c
, BLKSIZE
);
1001 msg("tag \"%s\" not found", extra
);
1007 /* if we're comparing, compare... */
1010 /* matched??? wow! */
1011 if (!*cmp
&& *scan
== '\t')
1015 if (*cmp
++ != *scan
)
1017 /* failed! skip to newline */
1022 /* if we're skipping to newline, do it fast! */
1025 while (scan
< end
&& *scan
!= '\n')
1036 /* found it! get the rest of the line into memory */
1037 for (cmp
= tmpblk
.c
, scan
++; scan
< end
&& *scan
!= '\n'; )
1043 tread(fd
, cmp
, BLKSIZE
- (int)(cmp
- tmpblk
.c
));
1048 /* we can close the tags file now */
1050 #endif /* INTERNAL_TAGS */
1052 /* extract the filename from the line, and edit the file */
1053 for (scan
= tmpblk
.c
; *scan
!= '\t'; scan
++)
1057 if (strcmp(origname
, tmpblk
.c
) != 0)
1059 if (!tmpabort(bang
))
1061 msg("Use :tag! to abort changes, or :w to save changes");
1067 /* move to the desired line (or to line 1 if that fails) */
1069 wasmagic
= *o_magic
;
1072 cursor
= MARK_FIRST
;
1073 linespec(scan
, &cursor
);
1074 if (cursor
== MARK_UNSET
)
1076 cursor
= MARK_FIRST
;
1077 msg("Tag's address is out of date");
1080 *o_magic
= wasmagic
;
1088 /* describe this version of the program */
1090 void cmd_version(frommark
, tomark
, cmd
, bang
, extra
)
1105 msg("Compiled by %s", COMPILED_BY
);
1114 /* make a .exrc file which describes the current configuration */
1116 void cmd_mkexrc(frommark
, tomark
, cmd
, bang
, extra
)
1125 /* the default name for the .exrc file EXRC */
1131 /* create the .exrc file */
1132 fd
= creat(extra
, FILEPERMS
);
1135 msg("Couldn't create a new \"%s\" file", extra
);
1141 savemaps(fd
, FALSE
);
1152 /* close the file */
1154 msg("Configuration saved");
1160 void cmd_digraph(frommark
, tomark
, cmd
, bang
, extra
)
1167 do_digraph(bang
, extra
);
1173 static char errfile
[256]; /* the name of a file containing an error */
1174 static long errline
; /* the line number for an error */
1175 static int errfd
= -2; /* fd of the errlist file */
1177 /* This static function tries to parse an error message.
1179 * For most compilers, the first word is taken to be the name of the erroneous
1180 * file, and the first number after that is taken to be the line number where
1181 * the error was detected. The description of the error follows, possibly
1182 * preceded by an "error ... :" or "warning ... :" label which is skipped.
1184 * For Coherent, error messages look like "line#: filename: message".
1186 * For non-error lines, or unparsable error lines, this function returns NULL.
1187 * Normally, though, it alters errfile and errline, and returns a pointer to
1190 static char *parse_errmsg(text
)
1195 # if COHERENT || TOS /* any Mark Williams compiler */
1196 /* Get the line number. If no line number, then ignore this line. */
1197 errline
= atol(text
);
1201 /* Skip to the start of the filename */
1202 while (*text
&& *text
++ != ':')
1208 /* copy the filename to errfile */
1209 for (cpy
= errfile
; *text
&& (*cpy
++ = *text
++) != ':'; )
1217 # else /* not a Mark Williams compiler */
1220 /* the error message is the whole line, by default */
1223 /* skip leading garbage */
1224 while (*text
&& !isalnum(*text
))
1229 /* copy over the filename */
1231 while(isalnum(*text
) || *text
== '.')
1237 /* ignore the name "Error" and filenames that contain a '/' */
1238 if (*text
== '/' || !*errfile
|| !strcmp(errfile
+ 1, "rror") || access(errfile
, 0) < 0)
1243 /* skip garbage between filename and line number */
1244 while (*text
&& !isdigit(*text
))
1249 /* if the number is part of a larger word, then ignore this line */
1250 if (*text
&& isalpha(text
[-1]))
1255 /* get the error line */
1257 while (isdigit(*text
))
1260 errline
+= (*text
- '0');
1264 /* any line which lacks a filename or line number should be ignored */
1265 if (!errfile
[0] || !errline
)
1270 /* locate the beginning of the error description */
1271 while (*text
&& !isspace(*text
))
1278 /* skip "error #:" and "warning #:" clauses */
1279 if (!strncmp(text
+ 1, "rror ", 5)
1280 || !strncmp(text
+ 1, "arning ", 7)
1281 || !strncmp(text
+ 1, "atal error", 10))
1286 } while (*text
&& *text
!= ':');
1291 /* anything other than whitespace or a colon is important */
1292 if (!isspace(*text
) && *text
!= ':')
1298 /* else keep looking... */
1303 # endif /* not COHERENT */
1307 void cmd_errlist(frommark
, tomark
, cmd
, bang
, extra
)
1308 MARK frommark
, tomark
;
1313 static long endline
;/* original number of lines in this file */
1314 static long offset
; /* offset of the next line in the errlist file */
1318 /* if a new errlist file is named, open it */
1319 if (extra
&& extra
[0])
1321 /* close the old one */
1327 /* open the new one */
1328 errfd
= open(extra
, O_RDONLY
);
1334 /* open the default file */
1335 errfd
= open(ERRLIST
, O_RDONLY
);
1340 /* do we have an errlist file now? */
1343 msg("There is no errlist file");
1348 /* find the next error message in the file */
1351 /* read the next line from the errlist */
1352 lseek(errfd
, offset
, 0);
1353 if (tread(errfd
, tmpblk
.c
, (unsigned)BLKSIZE
) <= 0)
1355 msg("No more errors");
1361 for (i
= 0; tmpblk
.c
[i
] != '\n'; i
++)
1366 /* look for an error message in the line */
1367 errmsg
= parse_errmsg(tmpblk
.c
);
1375 /* switch to the file containing the error, if this isn't it */
1376 if (strcmp(origname
, errfile
))
1378 if (!tmpabort(bang
))
1380 msg("Use :er! to abort changes, or :w to save changes");
1387 else if (endline
== 0L)
1392 /* go to the line where the error was detected */
1393 cursor
= MARK_AT_LINE(errline
+ (nlines
- endline
));
1394 if (cursor
> MARK_LAST
)
1398 if (mode
== MODE_VI
)
1400 redraw(cursor
, FALSE
);
1403 /* display the error message */
1405 msg("%.70s", errmsg
);
1407 if (nlines
> endline
)
1409 msg("line %ld(+%ld): %.60s", errline
, nlines
- endline
, errmsg
);
1411 else if (nlines
< endline
)
1413 msg("line %ld(-%ld): %.60s", errline
, endline
- nlines
, errmsg
);
1417 msg("line %ld: %.65s", errline
, errmsg
);
1421 /* remember where the NEXT error line will start */
1427 void cmd_make(frommark
, tomark
, cmd
, bang
, extra
)
1428 MARK frommark
, tomark
;
1435 /* if the file hasn't been saved, then complain unless ! */
1436 if (tstflag(file
, MODIFIED
) && !bang
)
1438 msg("\"%s\" not saved yet", origname
);
1442 /* build the command */
1443 sprintf(buf
.c
, "%s %s %s%s", (cmd
== CMD_CC
? o_cc
: o_make
), extra
, REDIRECT
, ERRLIST
);
1447 /* close the old errlist file, if any */
1454 /* run the command, with curses temporarily disabled */
1457 resume_curses(mode
== MODE_EX
);
1458 if (mode
== MODE_COLON
)
1461 /* run the "errlist" command */
1462 cmd_errlist(MARK_UNSET
, MARK_UNSET
, cmd
, bang
, ERRLIST
);
1470 /* figure out the number of text colors we use with this configuration */
1485 /* the attribute bytes used in each of "when"s */
1486 static char bytes
[NCOLORS
];
1490 char *word
; /* a legal word */
1491 int type
; /* what type of word this is */
1492 int val
; /* some other value */
1496 {"normal", 1, A_NORMAL
}, /* all "when" names must come */
1497 {"standout", 1, A_STANDOUT
}, /* at the top of the list. */
1498 {"bold", 1, A_BOLD
}, /* The first 3 must be normal,*/
1499 {"underlined", 1, A_UNDERLINE
}, /* standout, and bold; the */
1500 {"italics", 1, A_ALTCHARSET
}, /* remaining names follow. */
1502 {"popup", 1, A_POPUP
},
1505 {"visible", 1, A_VISIBLE
},
1508 {"black", 3, 0x00}, /* The color names start right*/
1509 {"blue", 3, 0x01}, /* after the "when" names. */
1513 {"magenta", 3, 0x05},
1516 {"yellow", 3, 0x0E}, /* bright brown */
1517 {"gray", 3, 0x08}, /* bright black? of course! */
1520 {"bright", 2, 0x08},
1522 {"blinking", 2, 0x80},
1525 {"s", 1, A_STANDOUT
},
1527 {"u", 1, A_UNDERLINE
},
1528 {"i", 1, A_ALTCHARSET
},
1531 {"menu", 1, A_POPUP
},
1534 {"v", 1, A_VISIBLE
},
1540 void cmd_color(frommark
, tomark
, cmd
, bang
, extra
)
1541 MARK frommark
, tomark
;
1548 int nowbg
; /* BOOLEAN: is the next color background? */
1555 /* if no args are given, then report the current colors */
1558 /* if no colors are set, then say so */
1561 msg("no colors have been set");
1565 /* report all five color combinations */
1566 for (i
= 0; i
< NCOLORS
; i
++)
1569 qaddstr(words
[i
].word
);
1571 if (bytes
[i
] & 0x80)
1572 qaddstr("blinking ");
1573 switch (bytes
[i
] & 0xf)
1575 case 0x08: qaddstr("gray"); break;
1576 case 0x0e: qaddstr("yellow"); break;
1577 case 0x0f: qaddstr("bright white");break;
1579 if (bytes
[i
] & 0x08)
1581 qaddstr(words
[(bytes
[i
] & 0x07) + NCOLORS
].word
);
1584 qaddstr(words
[((bytes
[i
] >> 4) & 0x07) + NCOLORS
].word
);
1592 /* The default background color is the same as "normal" chars.
1593 * There is no default foreground color.
1596 attrbyte
= bytes
[0] & 0x70;
1599 /* parse each word in the "extra" text */
1600 for (scan
= extra
; *extra
; extra
= scan
)
1602 /* locate the end of the word */
1603 while (*scan
&& *scan
!= ' ')
1608 /* skip whitespace at the end of the word */
1614 /* lookup the word */
1615 for (i
= 0; words
[i
].word
&& strcmp(words
[i
].word
, extra
); i
++)
1619 /* if not a word, then complain */
1622 msg("Invalid color name: %s", extra
);
1626 /* process the word */
1627 switch (words
[i
].type
)
1630 cmode
= words
[i
].val
;
1634 attrbyte
|= words
[i
].val
;
1639 attrbyte
= ((attrbyte
& ~0x70) | ((words
[i
].val
& 0x07) << 4));
1641 attrbyte
|= words
[i
].val
;
1647 /* if nowbg isn't set now, then we were never given a foreground color */
1650 msg("usage: color [when] [\"bright\"] [\"blinking\"] foreground [background]");
1654 /* the first ":color" command MUST define the "normal" colors */
1658 /* we should now have a cmode and an attribute byte... */
1661 setcolor(cmode
, attrbyte
);
1663 /* remember what we just did */
1664 bytes
[cmode
] = attrbyte
;
1666 /* if the other colors haven't been set yet, then set them to defaults */
1669 /* standout is the opposite of normal */
1670 bytes
[1] = ((attrbyte
<< 4) & 0x70 | (attrbyte
>> 4) & 0x07);
1671 setcolor(A_STANDOUT
, bytes
[1]);
1673 /* if "normal" isn't bright, then bold defaults to normal+bright
1674 * else bold defaults to bright white.
1676 bytes
[2] = attrbyte
| ((attrbyte
& 0x08) ? 0x0f : 0x08);
1677 setcolor(A_BOLD
, bytes
[2]);
1679 /* all others default to the "standout" colors, without blinking */
1680 for (i
= 3; i
< NCOLORS
; i
++)
1682 bytes
[i
] = (bytes
[1] & 0x7f);
1683 setcolor(words
[i
].val
, bytes
[i
]);
1687 /* force a redraw, so we see the new colors */
1688 redraw(MARK_UNSET
, FALSE
);
1694 int fd
; /* file descriptor to write colors to */
1699 /* if no colors are set, then return */
1705 /* save all five color combinations */
1706 for (i
= 0; i
< NCOLORS
; i
++)
1708 strcpy(buf
, "color ");
1709 strcat(buf
, words
[i
].word
);
1711 if (bytes
[i
] & 0x80)
1712 strcat(buf
, "blinking ");
1713 switch (bytes
[i
] & 0xf)
1715 case 0x08: strcat(buf
, "gray"); break;
1716 case 0x0e: strcat(buf
, "yellow"); break;
1717 case 0x0f: strcat(buf
, "bright white");break;
1719 if (bytes
[i
] & 0x08)
1720 strcat(buf
, "light ");
1721 strcat(buf
, words
[(bytes
[i
] & 0x07) + NCOLORS
].word
);
1723 strcat(buf
, " on ");
1724 strcat(buf
, words
[((bytes
[i
] >> 4) & 0x07) + NCOLORS
].word
);
1726 twrite(fd
, buf
, (unsigned)strlen(buf
));
1732 /* temporarily suspend elvis */
1734 void cmd_suspend(frommark
, tomark
, cmd
, bang
, extra
)
1741 void (*func
)(); /* stores the previous setting of SIGTSTP */
1744 /* the Bourne shell can't handle ^Z */
1745 if (!strcmp(o_shell
, "/bin/sh"))
1747 msg("The /bin/sh shell doesn't support ^Z");
1753 if (tstflag(file
, MODIFIED
))
1755 addstr("Warning: \"");
1757 addstr("\" modified but not yet saved");
1762 func
= signal(SIGTSTP
, SIG_DFL
);
1765 /* the process stops and resumes here */
1767 signal(SIGTSTP
, func
);
1768 resume_curses(TRUE
);
1769 if (mode
== MODE_VI
|| mode
== MODE_COLON
)
1770 redraw(MARK_UNSET
, FALSE
);