+
+#define DEF_EDITOR "vi"
+
+/*
+ * Invoke an editor on the given file. Which editor to use might change
+ * installation to installation. For now, we use "vi". In any event,
+ * the environment variable "EDITOR" overrides any default.
+ */
+
+public edit(filename)
+String filename;
+{
+ extern String getenv();
+ String ed, src, s;
+ Symbol f;
+ Address addr;
+ char lineno[10];
+
+ ed = getenv("EDITOR");
+ if (ed == nil) {
+ ed = DEF_EDITOR;
+ }
+ src = findsource((filename != nil) ? filename : cursource);
+ if (src == nil) {
+ f = which(identname(filename, true));
+ if (not isblock(f)) {
+ error("can't read \"%s\"", filename);
+ }
+ addr = firstline(f);
+ if (addr == NOADDR) {
+ error("no source for \"%s\"", filename);
+ }
+ src = srcfilename(addr);
+ s = findsource(src);
+ if (s != nil) {
+ src = s;
+ }
+ sprintf(lineno, "+%d", srcline(addr));
+ } else {
+ sprintf(lineno, "+1");
+ }
+ if (streq(ed, "vi") or streq(ed, "ex")) {
+ call(ed, stdin, stdout, lineno, src, nil);
+ } else {
+ call(ed, stdin, stdout, src, nil);
+ }
+}
+
+/*
+ * Strip away portions of a given pattern not part of the regular expression.
+ */
+
+private String getpattern (pattern)
+String pattern;
+{
+ register char *p, *r;
+
+ p = pattern;
+ while (*p == ' ' or *p == '\t') {
+ ++p;
+ }
+ r = p;
+ while (*p != '\0') {
+ ++p;
+ }
+ --p;
+ if (*p == '\n') {
+ *p = '\0';
+ --p;
+ }
+ if (*p == *r) {
+ *p = '\0';
+ --p;
+ }
+ return r + 1;
+}
+
+/*
+ * Search the current file for a regular expression.
+ */
+
+public search (direction, pattern)
+char direction;
+String pattern;
+{
+ register String p;
+ register File f;
+ String re, err;
+ Lineno line;
+ boolean matched;
+ char buf[512];
+
+ if (cursource == nil) {
+ beginerrmsg();
+ fprintf(stderr, "no source file\n");
+ } else {
+ if (cursource != prevsource) {
+ skimsource();
+ }
+ if (lastlinenum == 0) {
+ beginerrmsg();
+ fprintf(stderr, "couldn't read \"%s\"\n", cursource);
+ } else {
+ re = getpattern(pattern);
+ /* circf = 0; */
+ if (re != nil and *re != '\0') {
+ err = re_comp(re);
+ if (err != nil) {
+ error(err);
+ }
+ }
+ matched = false;
+ f = srcfp;
+ line = cursrcline;
+ do {
+ if (direction == '/') {
+ ++line;
+ if (line > lastlinenum) {
+ line = 1;
+ }
+ } else {
+ --line;
+ if (line < 1) {
+ line = lastlinenum;
+ }
+ }
+ fseek(f, srcaddr(line), L_SET);
+ p = buf;
+ *p = getc(f);
+ while ((*p != '\n') and (*p != EOF)) {
+ ++p;
+ *p = getc(f);
+ }
+ *p = '\0';
+ matched = (boolean) re_exec(buf);
+ } while (not matched and line != cursrcline);
+ if (not matched) {
+ beginerrmsg();
+ fprintf(stderr, "no match\n");
+ } else {
+ printlines(line, line);
+ cursrcline = line;
+ }
+ }
+ }
+}
+
+public integer srcwindowlen ()
+{
+ Node s;
+
+ s = findvar(identname("$listwindow", true));
+ if (s == nil)
+ return 10;
+ eval(s);
+ return pop(integer);
+}
+
+/*
+ * Compute a small window around the given line.
+ */
+
+public getsrcwindow (line, l1, l2)
+Lineno line, *l1, *l2;
+{
+ integer size;
+
+ size = srcwindowlen();
+ *l1 = line - (size div 2);
+ if (*l1 < 1) {
+ *l1 = 1;
+ }
+ *l2 = *l1 + size;
+ if (lastlinenum != LASTLINE and *l2 > lastlinenum) {
+ *l2 = lastlinenum;
+ }
+}