commit 4cd0864
shrub
·
2026-07-01 19:41:54 +0000 UTC
parent 4cd0864
initial commit
38 files changed,
+4605,
-0
+8,
-0
1@@ -0,0 +1,8 @@
2+AlignEscapedNewlines: DontAlign
3+AlwaysBreakAfterDefinitionReturnType: All
4+BreakBeforeBraces: Linux
5+ColumnLimit: 0
6+IndentWidth: 8
7+SortIncludes: false
8+TabWidth: 8
9+UseTab: ForIndentation
A
NOTICE
+21,
-0
1@@ -0,0 +1,21 @@
2+$Header: NOTICE,v 6.2 88/04/29 11:43:22 ceriel Exp $
3+
4+The software and documentation contained within this
5+directory is copyright (c) Ceriel J.H. Jacobs, 1988.
6+
7+Permission is granted to reproduce and distribute
8+this software as long as no fee is charged and
9+this notice is included.
10+
11+Other rights are reserved except as explicitly
12+granted by written permission from the author.
13+
14+ Ceriel J.H. Jacobs
15+ Dept. of Maths and Computer Science
16+ Vrije Universiteit
17+ De Boelelaan 1081
18+ 1081 HV Amsterdam
19+ The Netherlands
20+ email :
21+ ceriel@cs.vu.nl
22+
A
README
+62,
-0
1@@ -0,0 +1,62 @@
2+yap
3+===
4+
5+this is yap, or yet another pager. it's really old, from minix 2.0, i
6+believe. i've modernized it, removed legacy compatibilty codepaths to ancient systems
7+(many of which are listed in the original readme, see below), removed other
8+code that is useless in the modern day (it had it's own mini virtual memory system! things
9+were different back then), swapped from termcap to terminfo, made it somewhat UTF-8 aware
10+, and added some basic ansi escape code support, so things like git diff work. i have also
11+fixed a lot of compilation errors, old code doesn't play nice with modern compilers. i have
12+also attempted to somewhat modernize the code style.
13+
14+it uses ninja to build. you will also need some terminfo implementation, and a reasonably
15+modern somewhat posix POSIX system.
16+
17+ ninja
18+ ninja install
19+
20+the original readme is below:
21+----------------------------------------------------
22+
23+$Header: READ_ME,v 6.2 88/04/29 11:43:35 ceriel Exp $
24+
25+This directory contains the sources of YAP, Yet Another Pager.
26+It can do most of the things more(1) can, and much much more.
27+
28+Yap has been tested on the following systems:
29+
30+- DEC PDP 11/44 running V7
31+- DEC PDP 11/60 running V7
32+- DEC VAX 11/750 running 4.1BSD
33+- IBM PC/XT running PC/IX
34+- NCR Minitower running a System V
35+- Several 68k systems
36+- SUN-3 and SUN-4
37+
38+On other systems, you might have some problems getting yap to run, but then
39+again, you might not. You can always ask me for help, and maybe even get it.
40+If you make any changes, please
41+ - tell me about them
42+ - mark them clearly, preferably through conditional compilation.
43+
44+What you need to run yap:
45+
46+- you need termlib/termcap.
47+ It probably is'nt too hard to adapt yap to terminfo.
48+ It might even work unchanged, but I don't know about that. We don't have
49+ terminfo or the system V curses.
50+ If you adapt yap to terminfo, I would sure like to get the changes you made,
51+ so please send them to me (email address at the bottom of this note);
52+- you also need regex(III) (Either Berkeley style or USG will do).
53+ If you do not have it, you should define NOREGEX, which gives you
54+ simpleminded searches without meta-characters.
55+
56+How to install yap:
57+
58+- edit Makefile (easy)
59+- edit in_all.h (easy)
60+- type "make install"
61+
62+ Ceriel Jacobs, Vrije Universiteit Amsterdam
63+ ceriel@cs.vu.nl
A
ansi.c
+75,
-0
1@@ -0,0 +1,75 @@
2+#include "in_all.h"
3+#include "ansi.h"
4+
5+static int
6+consume_csi(const char *s, const char **next, enum ansi_kind *kind)
7+{
8+ const unsigned char *p = (const unsigned char *)s + 2;
9+
10+ while (*p >= 0x30 && *p <= 0x3f) {
11+ p++;
12+ }
13+ while (*p >= 0x20 && *p <= 0x2f) {
14+ p++;
15+ }
16+ if (*p >= 0x40 && *p <= 0x7e) {
17+ *kind = (*p == 'm') ? ANSI_SGR : ANSI_DISCARD;
18+ *next = (const char *)p + 1;
19+ return 1;
20+ }
21+ return 0;
22+}
23+
24+static int
25+consume_string(const char *s, const char **next)
26+{
27+ const unsigned char *p = (const unsigned char *)s + 2;
28+
29+ while (*p) {
30+ if (*p == '\a') {
31+ *next = (const char *)p + 1;
32+ return 1;
33+ }
34+ if (*p == '\x1b' && p[1] == '\\') {
35+ *next = (const char *)p + 2;
36+ return 1;
37+ }
38+ p++;
39+ }
40+ return 0;
41+}
42+
43+static int
44+consume_esc(const char *s, const char **next)
45+{
46+ const unsigned char *p = (const unsigned char *)s + 1;
47+
48+ while (*p >= 0x20 && *p <= 0x2f) {
49+ p++;
50+ }
51+ if (*p >= 0x30 && *p <= 0x7e) {
52+ *next = (const char *)p + 1;
53+ return 1;
54+ }
55+ return 0;
56+}
57+
58+int
59+ansi_escape(const char *s, const char **next, enum ansi_kind *kind)
60+{
61+ *kind = ANSI_NONE;
62+ *next = s;
63+ if ((unsigned char)s[0] != 0x1b || s[1] == '\0') {
64+ return 0;
65+ }
66+ if (s[1] == '[') {
67+ return consume_csi(s, next, kind);
68+ }
69+ if (s[1] == ']' || s[1] == 'P' || s[1] == 'X' || s[1] == '^' ||
70+ s[1] == '_') {
71+ *kind = ANSI_DISCARD;
72+ return consume_string(s, next);
73+ }
74+ *kind = ANSI_DISCARD;
75+ return consume_esc(s, next);
76+}
A
ansi.h
+12,
-0
1@@ -0,0 +1,12 @@
2+#ifndef ANSI_H
3+#define ANSI_H
4+
5+enum ansi_kind {
6+ ANSI_NONE = 0,
7+ ANSI_SGR,
8+ ANSI_DISCARD,
9+};
10+
11+int ansi_escape(const char *s, const char **next, enum ansi_kind *kind);
12+
13+#endif
A
assert.h
+6,
-0
1@@ -0,0 +1,6 @@
2+#ifndef ASSERT_H
3+#define ASSERT_H
4+
5+#define assert(x) ((void)0)
6+
7+#endif
+49,
-0
1@@ -0,0 +1,49 @@
2+# i know this is a ninja file, but you're allowed to edit it.
3+# you can also pass things on the command line if you like, eg
4+#
5+# CC=clang ninja
6+
7+cc = $${CC:-cc}
8+cflags = $${CFLAGS:--O2 -std=c99}
9+ldflags = $${LDFLAGS:-}
10+libs = $${LIBS:--ltinfo}
11+prefix = $${PREFIX:-/usr/local}
12+destdir = $${DESTDIR:-}
13+bindir = $${BINDIR:-$${DESTDIR:-}$${PREFIX:-/usr/local}/bin}
14+
15+rule cc
16+ command = $cc $cflags -MMD -MF $out.d -c -o $out $in
17+ deps = gcc
18+ depfile = $out.d
19+ description = cc $out
20+
21+rule link
22+ command = $cc $ldflags -o $out $in $libs
23+ description = link $out
24+
25+rule install
26+ command = mkdir -p $bindir && cp yap $bindir/
27+ description = install yap
28+
29+build ansi.o: cc ansi.c
30+build commands.o: cc commands.c
31+build display.o: cc display.c
32+build getcomm.o: cc getcomm.c
33+build getline.o: cc getline.c
34+build help.o: cc help.c
35+build keys.o: cc keys.c
36+build machine.o: cc machine.c
37+build main.o: cc main.c
38+build options.o: cc options.c
39+build output.o: cc output.c
40+build pattern.o: cc pattern.c
41+build process.o: cc process.c
42+build prompt.o: cc prompt.c
43+build rune.o: cc rune.c
44+build term.o: cc term.c
45+
46+build yap: link ansi.o commands.o display.o getcomm.o getline.o help.o keys.o machine.o main.o options.o output.o pattern.o process.o prompt.o rune.o term.o
47+build all: phony yap
48+build install: install yap
49+
50+default all
+785,
-0
1@@ -0,0 +1,785 @@
2+/* Copyright (c) 1985 Ceriel J.H. Jacobs */
3+
4+#include "in_all.h"
5+#include "commands.h"
6+#include "output.h"
7+#include "process.h"
8+#include "help.h"
9+#include "term.h"
10+#include "prompt.h"
11+#include "getline.h"
12+#include "getcomm.h"
13+#include "pattern.h"
14+#include "display.h"
15+#include "options.h"
16+#include "machine.h"
17+#include "keys.h"
18+#include "main.h"
19+#include "assert.h"
20+
21+static long lastcount; /* Save last count for '.' command */
22+static int lastcomm; /* Save last command for '.' command */
23+static int searchdir; /* Direction of last search */
24+
25+static int do_nocomm(long cnt);
26+static void do_search(char *str, long cnt, int dir);
27+static int do_fsearch(long cnt);
28+static int do_bsearch(long cnt);
29+static int n_or_rn_search(long cnt, int dir);
30+static int do_nsearch(long cnt);
31+static int do_rnsearch(long cnt);
32+static int shell_command(int esc_ch, long cnt);
33+static int do_shell(long cnt);
34+static int do_pipe(long cnt);
35+static int do_writefile(long cnt);
36+static int do_absolute(long cnt);
37+static int do_visit(long cnt);
38+static int do_error(long cnt);
39+static int prev_screen(int sz, int really);
40+static int next_screen(int sz, int really);
41+static int do_redraw(long cnt);
42+static int page_size(unsigned cnt);
43+static int do_forward(long cnt);
44+static int do_backward(long cnt);
45+static int do_firstline(long cnt);
46+static int do_lline(long cnt);
47+static int do_lf(long cnt);
48+static int do_upline(long cnt);
49+static int do_skiplines(long cnt);
50+static int do_bskiplines(long cnt);
51+static int do_fscreens(long cnt);
52+static int do_bscreens(long cnt);
53+static int scro_size(unsigned cnt);
54+static int do_f_scroll(long cnt);
55+static int do_b_scroll(long cnt);
56+static int do_previousfile(long cnt);
57+static int do_nextfile(long cnt);
58+static int do_lcomm(long cnt);
59+static int do_quit(long cnt);
60+
61+static int
62+do_nocomm(long cnt)
63+{ /* Do nothing */
64+ (void)cnt;
65+ return 0;
66+}
67+
68+int
69+do_chkm(long cnt)
70+{ /* Change key map */
71+ struct keymap *p;
72+ (void)cnt;
73+
74+ if (!(p = othermap)) {
75+ error("No other keymap");
76+ return 0;
77+ }
78+ othermap = currmap;
79+ currmap = p;
80+ return 0;
81+}
82+
83+/*
84+ * Perform searches
85+ */
86+
87+static void
88+do_search(char *str, long cnt, int dir)
89+{
90+ char *p;
91+ long lineno;
92+
93+ if (str) {
94+ /*
95+ * We have to get a pattern, which we have to prompt for
96+ * with the string "str".
97+ */
98+ if ((p = readline(str)) == 0) {
99+ /*
100+ * User cancelled command
101+ */
102+ return;
103+ }
104+ if ((p = re_comp(p))) {
105+ /*
106+ * There was an error in the pattern
107+ */
108+ error(p);
109+ return;
110+ }
111+ searchdir = dir;
112+ }
113+ if (dir < 0)
114+ lineno = scr_info.firstline;
115+ else
116+ lineno = scr_info.lastline;
117+ for (;;) {
118+ p = 0;
119+ if ((lineno += dir) > 0)
120+ p = getline(lineno, 0);
121+ if (interrupt)
122+ return;
123+ if (!p) { /* End of file reached */
124+ error("pattern not found");
125+ return;
126+ }
127+ if (re_exec(p) && --cnt <= 0) {
128+ /*
129+ * We found the pattern, and we found it often enough.
130+ * Pity that we still don't know where the match is.
131+ * We only know the linenumber. So, we just hope the
132+ * following will at least bring it on the screen ...
133+ */
134+ (void)display(lineno, 0, pagesize, 0);
135+ (void)scrollb(2, 0);
136+ redraw(0);
137+ return;
138+ }
139+ }
140+ /* NOTREACHED */
141+}
142+
143+static int
144+do_fsearch(long cnt)
145+{ /* Forward search */
146+ do_search("/", cnt, 1);
147+ return 0;
148+}
149+
150+static int
151+do_bsearch(long cnt)
152+{ /* Backward search */
153+ do_search("?", cnt, -1);
154+ return 0;
155+}
156+
157+/*
158+ * Repeat last search in direction "dir"
159+ */
160+
161+static int
162+n_or_rn_search(long cnt, int dir)
163+{
164+ char *p;
165+
166+ if (dir == 1) {
167+ p = "/\r";
168+ } else if (dir == -1) {
169+ p = "?\r";
170+ } else {
171+ error("No previous pattern");
172+ return 0;
173+ }
174+ if (!stupid)
175+ clrbline();
176+ putline(p);
177+ flush();
178+ do_search((char *)0, cnt, dir);
179+ return 0;
180+}
181+
182+static int
183+do_nsearch(long cnt)
184+{ /* Repeat search in same direction */
185+ n_or_rn_search(cnt, searchdir);
186+ return 0;
187+}
188+
189+static int
190+do_rnsearch(long cnt)
191+{ /* Repeat search in opposite direction */
192+ n_or_rn_search(cnt, -searchdir);
193+ return 0;
194+}
195+
196+static int
197+shell_command(int esc_ch, long cnt)
198+{
199+ char *p;
200+ static char buf[2];
201+
202+ buf[0] = esc_ch;
203+ buf[1] = '\0';
204+ if ((p = readline(buf)) != 0) {
205+ shellescape(p, esc_ch);
206+ if (cnt >= 0 && !hardcopy) {
207+ p = startcomm;
208+ startcomm = 0;
209+ ret_to_continue();
210+ putline(TI);
211+ if (!p) {
212+ /*
213+ * Avoid double redraw.
214+ * After a "startcomm", a redraw will
215+ * take place anyway.
216+ */
217+ redraw(1);
218+ }
219+ }
220+ }
221+ return 0;
222+}
223+
224+static int
225+do_shell(long cnt)
226+{ /* Execute a shell escape */
227+ return shell_command('!', cnt);
228+}
229+
230+static int
231+do_pipe(long cnt)
232+{ /* Execute a shell escape */
233+ return shell_command('|', cnt);
234+}
235+
236+static int
237+do_writefile(long cnt)
238+{ /* Write input to a file */
239+ char *p;
240+ int fd;
241+ (void)cnt;
242+
243+ if ((p = readline("Filename: ")) == 0 || !*p) {
244+ /*
245+ * No file name given
246+ */
247+ return 0;
248+ }
249+ if ((fd = open(p, O_CREAT | O_EXCL | O_WRONLY, 0644)) < 0) {
250+ if (errno == EEXIST) {
251+ error("File exists");
252+ return 0;
253+ }
254+ error("Could not open file");
255+ return 0;
256+ }
257+ wrt_fd(fd);
258+ (void)close(fd);
259+ return 0;
260+}
261+
262+void
263+wrt_fd(int fd)
264+{
265+ long l = 1;
266+ char *p = getline(l, 0), *pbuf;
267+ char buf[1024];
268+
269+ while (p) {
270+ pbuf = buf;
271+ while (p && pbuf < &buf[1024]) {
272+ if (!*p) {
273+ *pbuf++ = '\n';
274+ p = getline(++l, 0);
275+ } else
276+ *pbuf++ = *p++;
277+ }
278+ if (write(fd, buf, pbuf - buf) < 0) {
279+ error("Write failed");
280+ break;
281+ }
282+ }
283+}
284+
285+static int
286+do_absolute(long cnt)
287+{ /* Go to linenumber "cnt" */
288+
289+ if (!getline(cnt, 0)) { /* Not there or interrupt */
290+ if (!interrupt) {
291+ /*
292+ * User did'nt give an interrupt, so the line number
293+ * was too high. Go to the last line.
294+ */
295+ do_lline(cnt);
296+ }
297+ return 0;
298+ }
299+ (void)display(cnt, 0, pagesize, 1);
300+ return 0;
301+}
302+
303+static int
304+do_visit(long cnt)
305+{ /* Visit a file */
306+ char *p;
307+ static char fn[128]; /* Keep file name */
308+ (void)cnt;
309+
310+ if ((p = readline("Filename: ")) == 0) {
311+ return 0;
312+ }
313+ if (*p) {
314+ (void)strcpy(fn, p);
315+ visitfile(fn);
316+ } else {
317+ /*
318+ * User typed a return. Visit the current file
319+ */
320+ if (!(p = filenames[filecount])) {
321+ error("No current file");
322+ return 0;
323+ }
324+ visitfile(p);
325+ }
326+ (void)display(1L, 0, pagesize, 1);
327+ return 0;
328+}
329+
330+static int
331+do_error(long cnt)
332+{ /* Called when user types wrong key sequence */
333+ (void)cnt;
334+ error(currmap->k_help);
335+ return 0;
336+}
337+
338+/*
339+ * Interface routine for displaying previous screen,
340+ * depending on cflag.
341+ */
342+
343+static int
344+prev_screen(int sz, int really)
345+{
346+ int retval;
347+
348+ retval = scrollb(sz - 1, really && cflag);
349+ if (really && !cflag) {
350+ /*
351+ * The previous call did not display anything, but at least we
352+ * know where to start
353+ */
354+ return display(scr_info.firstline, scr_info.nf, sz, 1);
355+ }
356+ return retval;
357+}
358+
359+/*
360+ * Interface routine for displaying the next screen,
361+ * dependent on cflag.
362+ */
363+
364+static int
365+next_screen(int sz, int really)
366+{
367+ int t;
368+ struct scr_info *p = &scr_info;
369+
370+ if (cflag) {
371+ return scrollf(sz - 1, really);
372+ }
373+ t = p->tail->cnt - 1;
374+ if (p->lastline == p->firstline) {
375+ t += p->nf;
376+ }
377+ return display(p->lastline, t, sz, really);
378+}
379+
380+static int
381+do_redraw(long cnt)
382+{
383+ (void)cnt;
384+ redraw(1);
385+ return 0;
386+}
387+
388+static int
389+page_size(unsigned cnt)
390+{
391+
392+ if (cnt) {
393+ if (cnt > (unsigned)maxpagesize)
394+ return maxpagesize;
395+ if (cnt < MINPAGESIZE)
396+ return MINPAGESIZE;
397+ return (int)cnt;
398+ }
399+ return pagesize;
400+}
401+
402+static int
403+do_forward(long cnt)
404+{ /* Display next page */
405+ int i;
406+
407+ i = page_size((unsigned)cnt);
408+ if (status & EOFILE) {
409+ /*
410+ * May seem strange, but actually a visit to the next file
411+ * has already been done here
412+ */
413+ (void)display(1L, 0, i, 1);
414+ return 0;
415+ }
416+ (void)next_screen(i, 1);
417+ return 0;
418+}
419+
420+static int
421+do_backward(long cnt)
422+{
423+ int i, temp;
424+
425+ i = page_size((unsigned)cnt);
426+ if (!(status & START)) {
427+ (void)prev_screen(i, 1);
428+ return 0;
429+ }
430+ if (stdf < 0) {
431+ (void)display(1L, 0, i, 1);
432+ return 0;
433+ }
434+ /*
435+ * The next part is a bit clumsy.
436+ * We want to display the last page of the previous file (for which
437+ * a visit has already been done), but the pagesize may temporarily
438+ * be different because the command had a count
439+ */
440+ temp = pagesize;
441+ pagesize = i;
442+ do_lline(cnt);
443+ pagesize = temp;
444+ return 0;
445+}
446+
447+static int
448+do_firstline(long cnt)
449+{ /* Go to start of input */
450+ (void)cnt;
451+ do_absolute(1L);
452+ return 0;
453+}
454+
455+static int
456+do_lline(long cnt)
457+{ /* Go to end of input */
458+ int i = 0;
459+ int j = pagesize - 1;
460+
461+ if ((cnt = to_lastline()) < 0) {
462+ /*
463+ * Interrupted by the user
464+ */
465+ return 0;
466+ }
467+ /*
468+ * Display the page such that only the last line of the page is
469+ * a "~", independant of the pagesize
470+ */
471+ while (!(display(cnt, i, j, 0) & EOFILE)) {
472+ /*
473+ * The last line could of course be very long ...
474+ */
475+ i += j;
476+ }
477+ (void)scrollb(j - scr_info.tail->cnt, 0);
478+ redraw(0);
479+ return 0;
480+}
481+
482+static int
483+do_lf(long cnt)
484+{ /* Display next line, or go to line */
485+
486+ if (cnt) { /* Go to line */
487+ do_absolute(cnt);
488+ return 0;
489+ }
490+ (void)scrollf(1, 1);
491+ return 0;
492+}
493+
494+static int
495+do_upline(long cnt)
496+{ /* Display previous line, or go to line */
497+
498+ if (cnt) { /* Go to line */
499+ do_absolute(cnt);
500+ return 0;
501+ }
502+ (void)scrollb(1, 1);
503+ return 0;
504+}
505+
506+static int
507+do_skiplines(long cnt)
508+{ /* Skip lines forwards */
509+
510+ /* Should be interruptable ... */
511+ (void)scrollf((int)(cnt + maxpagesize - 1), 0);
512+ redraw(0);
513+ return 0;
514+}
515+
516+static int
517+do_bskiplines(long cnt)
518+{ /* Skip lines backwards */
519+
520+ /* Should be interruptable ... */
521+ (void)scrollb((int)(cnt + pagesize - 1), 0);
522+ redraw(0);
523+ return 0;
524+}
525+
526+static int
527+do_fscreens(long cnt)
528+{ /* Skip screens forwards */
529+
530+ do {
531+ if ((next_screen(pagesize, 0) & EOFILE) || interrupt)
532+ break;
533+ } while (--cnt >= 0);
534+ redraw(0);
535+ return 0;
536+}
537+
538+static int
539+do_bscreens(long cnt)
540+{ /* Skip screens backwards */
541+
542+ do {
543+ if ((prev_screen(pagesize, 0) & START) || interrupt)
544+ break;
545+ } while (--cnt >= 0);
546+ redraw(0);
547+ return 0;
548+}
549+
550+static int
551+scro_size(unsigned cnt)
552+{
553+
554+ if (cnt >= (unsigned)maxpagesize)
555+ return maxpagesize;
556+ if (cnt)
557+ return (int)cnt;
558+ return scrollsize;
559+}
560+
561+static int
562+do_f_scroll(long cnt)
563+{ /* Scroll forwards */
564+
565+ (void)scrollf(scro_size((unsigned)cnt), 1);
566+ return 0;
567+}
568+
569+static int
570+do_b_scroll(long cnt)
571+{ /* Scroll backwards */
572+
573+ (void)scrollb(scro_size((unsigned)cnt), 1);
574+ return 0;
575+}
576+
577+static int
578+do_previousfile(long cnt)
579+{ /* Visit previous file */
580+
581+ if (nextfile(-(int)cnt)) {
582+ error("No (Nth) previous file");
583+ return 0;
584+ }
585+ redraw(0);
586+ return 0;
587+}
588+
589+static int
590+do_nextfile(long cnt)
591+{ /* Visit next file */
592+
593+ if (nextfile((int)cnt)) {
594+ error("No (Nth) next file");
595+ return 0;
596+ }
597+ redraw(0);
598+ return 0;
599+}
600+
601+static int
602+do_quit(long cnt)
603+{
604+ (void)cnt;
605+ return quit();
606+}
607+
608+/*
609+ * The next array is initialized, sorted on the first element of the structs,
610+ * so that we can perform binary search
611+ */
612+struct commands commands[] = {
613+ {"", 0, do_error, ""},
614+ {"", 0, do_nocomm, ""},
615+ {"bf", STICKY | NEEDS_COUNT,
616+ do_previousfile, "Visit previous file"},
617+ {"bl", NEEDS_SCREEN | STICKY,
618+ do_upline, "Scroll one line up, or go to line"},
619+ {"bot", STICKY,
620+ do_lline, "Go to last line of the input"},
621+ {"bp", BACK | NEEDS_SCREEN | TOPREVFILE | STICKY,
622+ do_backward, "display previous page"},
623+ {"bps", SCREENSIZE_ADAPT | BACK | NEEDS_SCREEN | TOPREVFILE | STICKY,
624+ do_backward, "Display previous page, set pagesize"},
625+ {"bs", BACK | NEEDS_SCREEN | STICKY,
626+ do_b_scroll, "Scroll backwards"},
627+ {"bse", 0, do_bsearch, "Search backwards for pattern"},
628+ {"bsl", BACK | NEEDS_SCREEN | STICKY | NEEDS_COUNT,
629+ do_bskiplines, "Skip lines backwards"},
630+ {"bsp", BACK | NEEDS_SCREEN | STICKY | NEEDS_COUNT,
631+ do_bscreens, "Skip screens backwards"},
632+ {"bss", SCROLLSIZE_ADAPT | BACK | NEEDS_SCREEN | STICKY,
633+ do_b_scroll, "Scroll backwards, set scrollsize"},
634+ {"chm", 0, do_chkm, "Switch to other keymap"},
635+ {"exg", STICKY, exgmark, "Exchange current page with mark"},
636+ {"ff", STICKY | NEEDS_COUNT,
637+ do_nextfile, "Visit next file"},
638+ {"fl", NEEDS_SCREEN | STICKY,
639+ do_lf, "Scroll one line down, or go to line"},
640+ {"fp", TONEXTFILE | AHEAD | STICKY,
641+ do_forward, "Display next page"},
642+ {"fps", SCREENSIZE_ADAPT | TONEXTFILE | AHEAD | STICKY,
643+ do_forward, "Display next page, set pagesize"},
644+ {"fs", AHEAD | NEEDS_SCREEN | STICKY,
645+ do_f_scroll, "Scroll forwards"},
646+ {"fse", 0, do_fsearch, "Search forwards for pattern"},
647+ {"fsl", AHEAD | NEEDS_SCREEN | STICKY | NEEDS_COUNT,
648+ do_skiplines, "Skip lines forwards"},
649+ {"fsp", AHEAD | NEEDS_SCREEN | STICKY | NEEDS_COUNT,
650+ do_fscreens, "Skip screens forwards"},
651+ {"fss", SCROLLSIZE_ADAPT | AHEAD | NEEDS_SCREEN | STICKY,
652+ do_f_scroll, "Scroll forwards, set scrollsize"},
653+ {"hlp", 0, do_help, "Give description of all commands"},
654+ {"mar", 0, setmark, "Set a mark on the current page"},
655+ {"nse", STICKY, do_nsearch, "Repeat the last search"},
656+ {"nsr", STICKY, do_rnsearch, "Repeat last search in other direction"},
657+ {"pip", ESC, do_pipe, "pipe input into shell command"},
658+ {"qui", 0, do_quit, "Exit from yap"},
659+ {"red", 0, do_redraw, "Redraw screen"},
660+ {"rep", 0, do_lcomm, "Repeat last command"},
661+ {"shl", ESC, do_shell, "Execute a shell escape"},
662+ {"tom", 0, tomark, "Go to mark"},
663+ {"top", STICKY, do_firstline, "Go to the first line of the input"},
664+ {"vis", 0, do_visit, "Visit a file"},
665+ {"wrf", 0, do_writefile, "Write input to a file"},
666+};
667+
668+/*
669+ * Lookup string "s" in the commands array, and return index.
670+ * return 0 if not found.
671+ */
672+
673+int
674+lookup(char *s)
675+{
676+ struct commands *l, *u, *m;
677+
678+ l = &commands[2];
679+ u = &commands[sizeof(commands) / sizeof(*u) - 1];
680+ do {
681+ /*
682+ * Perform binary search
683+ */
684+ m = l + (u - l) / 2;
685+ if (strcmp(s, m->c_cmd) > 0)
686+ l = m + 1;
687+ else
688+ u = m;
689+ } while (l < u);
690+ if (!strcmp(s, u->c_cmd))
691+ return u - commands;
692+ return 0;
693+}
694+
695+/*ARGSUSED*/
696+static int
697+do_lcomm(long cnt)
698+{ /* Repeat last command */
699+ (void)cnt;
700+
701+ if (!lastcomm) {
702+ error("No previous command");
703+ return 0;
704+ }
705+ do_comm(lastcomm, lastcount);
706+ return 0;
707+}
708+
709+/*
710+ * Execute a command, with optional count "count".
711+ */
712+
713+void
714+do_comm(int comm, long count)
715+{
716+ struct commands *pcomm;
717+ int temp;
718+ int flags;
719+
720+ pcomm = &commands[comm];
721+ flags = pcomm->c_flags;
722+
723+ /*
724+ * Check the command.
725+ * If the last line of the file is displayed and the command goes
726+ * forwards and does'nt have the ability to go to the next file, it
727+ * is an error.
728+ * If the first line of the file is displayed and the command goes
729+ * backwards and does'nt have the ability to go to the previous file,
730+ * it is an error.
731+ * Also check wether we need the next or previous file. If so, get it.
732+ */
733+ if ((status & EOFILE) && (flags & AHEAD)) {
734+ if (qflag || !(flags & TONEXTFILE))
735+ return;
736+ if (nextfile(1))
737+ quit();
738+ }
739+ if ((status & START) && (flags & BACK)) {
740+ if (qflag || !(flags & TOPREVFILE))
741+ return;
742+ if (nextfile(-1))
743+ quit();
744+ }
745+ /*
746+ * Does the command stick around for LASTCOMM?
747+ */
748+ if (flags & STICKY) {
749+ lastcomm = comm;
750+ lastcount = count;
751+ }
752+ if (!count) {
753+ if (flags & NEEDS_COUNT)
754+ count = 1;
755+ } else {
756+ /*
757+ * Does the command adapt the screensize?
758+ */
759+ if (flags & SCREENSIZE_ADAPT) {
760+ temp = maxpagesize;
761+ if ((unsigned)count < (unsigned)temp) {
762+ temp = (int)count;
763+ }
764+ if (temp < MINPAGESIZE) {
765+ temp = MINPAGESIZE;
766+ }
767+ count = 0;
768+ pagesize = temp;
769+ }
770+ /*
771+ * Does the command adapt the scrollsize?
772+ */
773+ if (flags & SCROLLSIZE_ADAPT) {
774+ temp = maxpagesize - 1;
775+ if ((unsigned)count < (unsigned)temp) {
776+ temp = (int)count;
777+ }
778+ scrollsize = temp;
779+ count = 0;
780+ }
781+ }
782+ /*
783+ * Now execute the command.
784+ */
785+ (*(pcomm->c_func))(count);
786+}
+27,
-0
1@@ -0,0 +1,27 @@
2+#ifndef COMMANDS_H
3+#define COMMANDS_H
4+
5+#define SCREENSIZE_ADAPT 01
6+#define SCROLLSIZE_ADAPT 02
7+#define TONEXTFILE 04
8+#define AHEAD 010
9+#define BACK 020
10+#define NEEDS_SCREEN 040
11+#define TOPREVFILE 0100
12+#define STICKY 0200
13+#define NEEDS_COUNT 0400
14+#define ESC 01000
15+
16+extern struct commands {
17+ char *c_cmd;
18+ int c_flags;
19+ int (*c_func)(long);
20+ char *c_descr;
21+} commands[];
22+
23+int do_chkm(long cnt);
24+void do_comm(int command, long count);
25+int lookup(char *str);
26+void wrt_fd(int fd);
27+
28+#endif
+692,
-0
1@@ -0,0 +1,692 @@
2+/* Copyright (c) 1985 Ceriel J.H. Jacobs */
3+
4+#include "in_all.h"
5+#include "display.h"
6+#include "assert.h"
7+#include "machine.h"
8+#include "term.h"
9+#include "output.h"
10+#include "options.h"
11+#include "process.h"
12+#include "getline.h"
13+#include "main.h"
14+#define getline yap_getline
15+#include "utf.h"
16+#undef getline
17+#include "ansi.h"
18+
19+int pagesize;
20+int maxpagesize;
21+int scrollsize;
22+struct scr_info scr_info;
23+int status;
24+
25+static char *do_line(char *str, int reallydispl);
26+static void flush_display_buffer(char *buf, char **p);
27+static int rune_width(Rune r);
28+static int decode_cell(const char *s, const char **next, int *width,
29+ int *is_underscore);
30+int wcwidth(wchar_t wc);
31+
32+/*
33+ * Fill n lines of the screen, each with "str".
34+ */
35+
36+static void
37+fillscr(char *str, int n)
38+{
39+
40+ while (n-- > 0) {
41+ putline(str);
42+ }
43+}
44+
45+/*
46+ * Skip "n" screenlines of line "p", and return what's left of it.
47+ */
48+
49+static char *
50+skiplines(char *p, int n)
51+{
52+
53+ while (n-- > 0) {
54+ p = do_line(p, 0);
55+ scr_info.currentpos--;
56+ }
57+ return p;
58+}
59+
60+/*
61+ * Redraw screen.
62+ * "n" = 1 if it is a real redraw, 0 if one page must be displayed.
63+ * It is also called when yap receives a stop signal.
64+ */
65+
66+void
67+redraw(int n)
68+{
69+ struct scr_info *p = &scr_info;
70+ int i;
71+
72+ i = pagesize;
73+ if (n && p->currentpos) {
74+ i = p->currentpos;
75+ }
76+ (void)display(p->firstline, p->nf, i, 1);
77+}
78+
79+/*
80+ * Compute return value for the routines "display" and "scrollf".
81+ * This return value indicates wether we are at the end of file
82+ * or at the start, or both.
83+ * "s" contains that part of the last line that was not displayed.
84+ */
85+
86+static int
87+compretval(const char *s)
88+{
89+ int i;
90+ struct scr_info *p = &scr_info;
91+
92+ i = 0;
93+ if (!s || (!*s && !getline(p->lastline + 1, 1))) {
94+ i = EOFILE;
95+ }
96+ if (p->firstline == 1 && !p->nf) {
97+ i |= START;
98+ }
99+ status = i;
100+ return i;
101+}
102+
103+/*
104+ * Display nlines, starting at line n, not displaying the first
105+ * nd screenlines of n.
106+ * If reallydispl = 0, the actual displaying is not performed,
107+ * only the computing associated with it is done.
108+ */
109+
110+int
111+display(long n, int nd, int nlines, int reallydispl)
112+{
113+
114+ struct scr_info *s = &scr_info;
115+ char *p; /* pointer to line to be displayed */
116+
117+ if (startcomm) { /* No displaying on a command from the
118+ * yap command line. In this case, displaying
119+ * will be done after executing the command,
120+ * by a redraw.
121+ */
122+ reallydispl = 0;
123+ }
124+ if (!n) {
125+ n = 1L;
126+ nd = 0;
127+ }
128+ if (reallydispl) { /* move cursor to starting point */
129+ if (stupid) {
130+ putline(currentfile);
131+ putline(", line ");
132+ prnum(n);
133+ nlines--;
134+ }
135+ if (cflag) {
136+ putline("\r\n");
137+ } else {
138+ home();
139+ clrscreen();
140+ }
141+ }
142+ /*
143+ * Now, do computations and display
144+ */
145+ s->currentpos = 0;
146+ s->nf = nd;
147+ s->head = s->tail;
148+ s->tail->cnt = 0;
149+ s->tail->line = n;
150+ p = skiplines(getline(n, 1), nd);
151+ while (nlines && p) {
152+ /*
153+ * While there is room,
154+ * and there is something left to display ...
155+ */
156+ (s->tail->cnt)++;
157+ nlines--;
158+ if (*(p = do_line(p, reallydispl)) == '\0') {
159+ /*
160+ * File-line finished, get next one ...
161+ */
162+ p = getline(++n, 1);
163+ if (nlines && p) {
164+ s->tail = s->tail->next;
165+ s->tail->cnt = 0;
166+ s->tail->line = n;
167+ }
168+ }
169+ }
170+ if (!stupid) {
171+ s->currentpos += nlines;
172+ if (reallydispl) {
173+ fillscr("~\r\n", nlines);
174+ fillscr("\r\n", maxpagesize - s->currentpos);
175+ }
176+ }
177+ return compretval(p);
178+}
179+
180+/*
181+ * Scroll forwards n lines.
182+ */
183+
184+int
185+scrollf(int n, int reallydispl)
186+{
187+
188+ struct scr_info *s = &scr_info;
189+ char *p;
190+ long ll;
191+ int i;
192+
193+ /*
194+ * First, find out how many screenlines of the last line were already
195+ * on the screen, and possibly above it.
196+ */
197+
198+ if (n <= 0 || (status & EOFILE))
199+ return status;
200+ if (startcomm)
201+ reallydispl = 0;
202+ /*
203+ * Find out where to begin displaying
204+ */
205+ i = s->tail->cnt;
206+ if ((ll = s->lastline) == s->firstline)
207+ i += s->nf;
208+ p = skiplines(getline(ll, 1), i);
209+ /*
210+ * Now, place the cursor at the first free line
211+ */
212+ if (reallydispl && !stupid) {
213+ clrbline();
214+ mgoto(s->currentpos);
215+ }
216+ /*
217+ * Now display lines, keeping track of which lines are on the screen.
218+ */
219+ while (n-- > 0) { /* There are still rows to be displayed */
220+ if (!*p) { /* End of line, get next one */
221+ if (!(p = getline(++ll, 1))) {
222+ /*
223+ * No lines left. At end of file
224+ */
225+ break;
226+ }
227+ s->tail = s->tail->next;
228+ s->tail->cnt = 0;
229+ s->tail->line = ll;
230+ }
231+ if (s->currentpos >= maxpagesize) {
232+ /*
233+ * No room, delete first screen-line
234+ */
235+ s->currentpos--;
236+ s->nf++;
237+ if (--(s->head->cnt) == 0) {
238+ /*
239+ * The first file-line on the screen is wiped
240+ * out completely; update administration
241+ * accordingly.
242+ */
243+ s->nf = 0;
244+ s->head = s->head->next;
245+ assert(s->head->cnt > 0);
246+ }
247+ }
248+ s->tail->cnt++;
249+ p = do_line(p, reallydispl);
250+ }
251+ return compretval(p);
252+}
253+
254+/*
255+ * Scroll back n lines
256+ */
257+
258+int
259+scrollb(int n, int reallydispl)
260+{
261+
262+ struct scr_info *s = &scr_info;
263+ char *p; /* Holds string to be displayed */
264+ int i;
265+ int count;
266+ long ln; /* a line number */
267+ int nodispl;
268+ int cannotscroll; /* stupid or no insert-line */
269+
270+ /*
271+ * First, find out where to start
272+ */
273+ if ((count = n) <= 0 || (status & START))
274+ return status;
275+ if (startcomm)
276+ reallydispl = 0;
277+ cannotscroll = stupid || (!*AL && !*SR);
278+ ln = s->firstline;
279+ nodispl = s->nf;
280+ while (count) { /* While scrolling back ... */
281+ i = nodispl;
282+ if (i) {
283+ /*
284+ * There were screen-lines of s->firstline that were not
285+ * displayed.
286+ * We can use them now, but only "count" of them.
287+ */
288+ if (i > count)
289+ i = count;
290+ s->currentpos += i;
291+ nodispl -= i;
292+ count -= i;
293+ } else { /* Get previous line */
294+ if (ln == 1)
295+ break; /* isn't there ... */
296+ p = getline(--ln, 1);
297+ /*
298+ * Make it the first line of the screen and compute
299+ * how many screenlines it takes. These lines are not
300+ * displayed, but nodispl is set to this count, so
301+ * that it will be nonzero next time around
302+ */
303+ nodispl = 0;
304+ do { /* Find out how many screenlines */
305+ nodispl++;
306+ p = skiplines(p, 1);
307+ } while (*p);
308+ }
309+ }
310+ n -= count;
311+ if ((i = s->currentpos) > maxpagesize)
312+ i = maxpagesize;
313+ if (reallydispl && hardcopy)
314+ i = n;
315+ /*
316+ * Now that we know where to start, we can use "display" to do the
317+ * rest of the computing for us, and maybe even the displaying ...
318+ */
319+ i = display(ln,
320+ nodispl,
321+ i,
322+ reallydispl && cannotscroll);
323+ if (cannotscroll || !reallydispl) {
324+ /*
325+ * Yes, "display" did the displaying, or we did'nt have to
326+ * display at all.
327+ * I like it, but the user obviously does not.
328+ * Let him buy another (smarter) terminal ...
329+ */
330+ return i;
331+ }
332+ /*
333+ * Now, all we have to do is the displaying. And we are dealing with
334+ * a smart terminal (it can insert lines or scroll back).
335+ */
336+ home();
337+ /*
338+ * Insert lines all at once
339+ */
340+ for (i = n; i; i--) {
341+ if (DB && *CE) {
342+ /*
343+ * Grumble..., terminal retains lines below, so we have
344+ * to clear the lines that we push off the screen
345+ */
346+ clrbline();
347+ home();
348+ }
349+ if (*SR) {
350+ scrollreverse();
351+ } else {
352+ insert_line(0);
353+ }
354+ }
355+ p = skiplines(getline(ln = s->firstline, 1), s->nf);
356+ for (i = 0; i < n; i++) {
357+ p = do_line(p, 1);
358+ s->currentpos--;
359+ if (!*p) {
360+ p = getline(++ln, 1);
361+ }
362+ }
363+ return count;
364+}
365+
366+/*
367+ * Process a line.
368+ * If reallydispl > 0 then display it.
369+ */
370+
371+static char *
372+do_line(char *str, int reallydispl)
373+{
374+ char buf[1024];
375+ char *p = buf;
376+ int pos = COLS;
377+ int do_ul = 0, do_hl = 0;
378+ int lastmode = 0, lasthlmode = 0;
379+ int c2;
380+ int cell_width;
381+ int tab_width;
382+ int is_underscore;
383+ int cell_len;
384+ int next_len;
385+ int next_is_underscore;
386+ unsigned char uc;
387+ const char *cell_start;
388+ const char *cursor;
389+ const char *next;
390+ enum ansi_kind ansi_kind;
391+
392+ while (*str && pos > 0) {
393+ uc = (unsigned char)*str;
394+ if (uc == 0x1b && ansi_escape(str, &next, &ansi_kind)) {
395+ if (ansi_kind == ANSI_SGR) {
396+ cell_len = next - str;
397+ if (reallydispl &&
398+ p + cell_len >= &buf[sizeof(buf) - 1]) {
399+ flush_display_buffer(buf, &p);
400+ }
401+ if (reallydispl) {
402+ (void)memcpy(p, str, (size_t)cell_len);
403+ p += cell_len;
404+ }
405+ }
406+ str = (char *)next;
407+ continue;
408+ }
409+ if (uc < ' ' && (cell_len = match(str, &c2, sppat)) > 0) {
410+ /*
411+ * We found a string that matches, and thus must be
412+ * echoed literally
413+ */
414+ if ((pos - c2) <= 0) {
415+ /*
416+ * It did not fit
417+ */
418+ break;
419+ }
420+ pos -= c2;
421+ if (reallydispl) {
422+ flush_display_buffer(buf, &p);
423+ cell_start = str;
424+ str += cell_len;
425+ uc = (unsigned char)*str;
426+ *str = '\0';
427+ putline((char *)cell_start);
428+ *str = (char)uc;
429+ } else {
430+ str += cell_len;
431+ }
432+ continue;
433+ }
434+
435+ cell_start = str;
436+ cell_len = decode_cell(str, &next, &cell_width, &is_underscore);
437+ cursor = next;
438+ do_hl = 0;
439+ if (*cursor == '\b' && *(cursor + 1) != '\0') {
440+ next_len = decode_cell(cursor + 1, &next, &tab_width,
441+ &next_is_underscore);
442+ if (!(is_underscore && *(cursor + 1 + next_len) != '\b')) {
443+ while (*cursor == '\b' && *(cursor + 1) != '\0') {
444+ cell_start = cursor + 1;
445+ cell_len = decode_cell(cell_start, &next, &cell_width,
446+ &is_underscore);
447+ cursor = next;
448+ do_hl = 1;
449+ }
450+ }
451+ }
452+ do_ul = 1;
453+ /*
454+ * Find underline sequences ...
455+ */
456+ if (is_underscore && *cursor == '\b' && *(cursor + 1) != '\0') {
457+ cell_start = cursor + 1;
458+ cell_len = decode_cell(cell_start, &next, &cell_width,
459+ &is_underscore);
460+ cursor = next;
461+ } else {
462+ if (*cursor == '\b' && *(cursor + 1) == '_') {
463+ cursor += 2;
464+ } else {
465+ do_ul = 0;
466+ }
467+ }
468+ if (cell_width == -1) {
469+ tab_width = 8 - ((COLS - pos) & 0x07);
470+ if (pos - tab_width < 0) {
471+ break;
472+ }
473+ } else if (cell_width == -2) {
474+ if (pos <= 1) {
475+ break;
476+ }
477+ } else if (cell_width > pos) {
478+ break;
479+ }
480+ if (reallydispl && do_hl != lasthlmode) {
481+ flush_display_buffer(buf, &p);
482+ if (do_hl) {
483+ bold();
484+ } else {
485+ end_bold();
486+ }
487+ }
488+ lasthlmode = do_hl;
489+ if (reallydispl && do_ul != lastmode) {
490+ flush_display_buffer(buf, &p);
491+ if (do_ul) {
492+ underline();
493+ } else {
494+ end_underline();
495+ }
496+ }
497+ lastmode = do_ul;
498+ if (cell_width == -1) {
499+ pos -= tab_width;
500+ if (reallydispl) {
501+ if (expandtabs) {
502+ while (tab_width-- > 0) {
503+ *p++ = ' ';
504+ }
505+ } else {
506+ flush_display_buffer(buf, &p);
507+ givetab();
508+ }
509+ }
510+ str = (char *)cursor;
511+ continue;
512+ }
513+ if (reallydispl && p + cell_len >= &buf[sizeof(buf) - 1]) {
514+ flush_display_buffer(buf, &p);
515+ }
516+ if (cell_width == -2) {
517+ if (reallydispl) {
518+ if (p + 2 >= &buf[sizeof(buf) - 1]) {
519+ flush_display_buffer(buf, &p);
520+ }
521+ *p++ = '^';
522+ *p++ = *cell_start ^ 0x40;
523+ }
524+ pos -= 2;
525+ str = (char *)cursor;
526+ continue;
527+ }
528+ if (reallydispl) {
529+ (void)memcpy(p, cell_start, (size_t)cell_len);
530+ p += cell_len;
531+ }
532+ if (cell_width >= 0) {
533+ pos -= cell_width;
534+ if (reallydispl && do_ul && *UC && cell_width == 1 && pos > 0) {
535+ /*
536+ * Underlining apparently is done one
537+ * character at a time.
538+ */
539+ flush_display_buffer(buf, &p);
540+ backspace();
541+ underchar();
542+ }
543+ str = (char *)cursor;
544+ continue;
545+ }
546+ str = (char *)cursor;
547+ }
548+ if (reallydispl) {
549+ flush_display_buffer(buf, &p);
550+ if (pos > 0 || (pos <= 0 && (!AM || XN))) {
551+ putline("\r\n");
552+ }
553+ /*
554+ * The next should be here! I.e. it may not be before printing
555+ * the newline. This has to do with XN. We don't know exactly
556+ * WHEN the terminal will stop ignoring the newline.
557+ * I have for example a terminal (Ampex a230) that will
558+ * continue to ignore the newline after a clear to end of line
559+ * sequence, but not after an end_underline sequence.
560+ */
561+ if (lastmode) {
562+ end_underline();
563+ }
564+ if (lasthlmode) {
565+ end_bold();
566+ }
567+ }
568+ scr_info.currentpos++;
569+ return str;
570+}
571+
572+static void
573+flush_display_buffer(char *buf, char **p)
574+{
575+ if (*p == buf) {
576+ return;
577+ }
578+ **p = '\0';
579+ putline(buf);
580+ *p = buf;
581+}
582+
583+static int
584+rune_width(Rune r)
585+{
586+ int width;
587+
588+ width = wcwidth((wchar_t)r);
589+ if (width < 0) {
590+ return 1;
591+ }
592+ return width;
593+}
594+
595+static int
596+decode_cell(const char *s, const char **next, int *width, int *is_underscore)
597+{
598+ const char *p;
599+ Rune r;
600+ Rune mark;
601+ int len;
602+ int mark_len;
603+ int mark_width;
604+
605+ len = chartorune(&r, s);
606+ if (len <= 0) {
607+ len = 1;
608+ r = Runeerror;
609+ }
610+ *is_underscore = (len == 1 && *s == '_');
611+ if (*s == '\t') {
612+ *width = -1;
613+ *next = s + 1;
614+ return 1;
615+ }
616+ if ((unsigned char)*s < ' ' || (unsigned char)*s == 0x7f) {
617+ *width = -2;
618+ *next = s + 1;
619+ return 1;
620+ }
621+ *width = rune_width(r);
622+ p = s + len;
623+ while (*p) {
624+ if (*p == '\b' || *p == '\t' || (unsigned char)*p < ' ' ||
625+ (unsigned char)*p == 0x7f) {
626+ break;
627+ }
628+ mark_len = chartorune(&mark, p);
629+ if (mark_len <= 0) {
630+ break;
631+ }
632+ mark_width = rune_width(mark);
633+ if (mark_width != 0) {
634+ break;
635+ }
636+ p += mark_len;
637+ len += mark_len;
638+ }
639+ *next = p;
640+ return len;
641+}
642+
643+/* ARGSUSED */
644+int
645+setmark(long cnt)
646+{ /* Set a mark on the current page */
647+ struct scr_info *p = &scr_info;
648+ (void)cnt;
649+
650+ p->savfirst = p->firstline;
651+ p->savnf = p->nf;
652+ return 0;
653+}
654+
655+/* ARGSUSED */
656+int
657+tomark(long cnt)
658+{ /* Go to the mark */
659+ struct scr_info *p = &scr_info;
660+ (void)cnt;
661+
662+ (void)display(p->savfirst, p->savnf, pagesize, 1);
663+ return 0;
664+}
665+
666+/* ARGSUSED */
667+int
668+exgmark(long cnt)
669+{ /* Exchange mark and current page */
670+ struct scr_info *p = &scr_info;
671+ long svfirst;
672+ int svnf;
673+ (void)cnt;
674+
675+ svfirst = p->firstline;
676+ svnf = p->nf;
677+ tomark(0L);
678+ p->savfirst = svfirst;
679+ p->savnf = svnf;
680+ return 0;
681+}
682+
683+void
684+d_clean()
685+{ /* Clean up */
686+ struct scr_info *p = &scr_info;
687+
688+ p->savnf = 0;
689+ p->savfirst = 0;
690+ p->head = p->tail;
691+ p->head->line = 0;
692+ p->currentpos = 0;
693+}
+41,
-0
1@@ -0,0 +1,41 @@
2+#ifndef DISPLAY_H
3+#define DISPLAY_H
4+
5+#define MINPAGESIZE 5
6+
7+extern int pagesize;
8+extern int maxpagesize;
9+extern int scrollsize;
10+
11+struct scr_info {
12+ struct linelist {
13+ int cnt;
14+ long line;
15+#define firstline head->line
16+#define lastline tail->line
17+ struct linelist *next;
18+ struct linelist *prev;
19+ } *tail, *head;
20+ int nf;
21+ int currentpos;
22+ struct linelist ssaavv;
23+#define savfirst ssaavv.line
24+#define savnf ssaavv.cnt
25+};
26+
27+extern struct scr_info scr_info;
28+extern int status;
29+
30+#define EOFILE 01
31+#define START 02
32+
33+void redraw(int flag);
34+int display(long first_line, int nodispl, int nlines, int really);
35+int scrollf(int nlines, int really);
36+int scrollb(int nlines, int really);
37+int tomark(long cnt);
38+int setmark(long cnt);
39+int exgmark(long cnt);
40+void d_clean(void);
41+
42+#endif
+303,
-0
1@@ -0,0 +1,303 @@
2+/* Copyright (c) 1985 Ceriel J.H. Jacobs */
3+
4+/*
5+ * Command reader, also executes shell escapes
6+ */
7+
8+#include <ctype.h>
9+#include "in_all.h"
10+#include "term.h"
11+#include "process.h"
12+#include "getcomm.h"
13+#include "commands.h"
14+#include "prompt.h"
15+#include "main.h"
16+#include "output.h"
17+#include "getline.h"
18+#include "machine.h"
19+#include "keys.h"
20+#include "display.h"
21+#include "assert.h"
22+
23+static int killchar(int c);
24+static void sigquit(int signo);
25+
26+/*
27+ * Read a line from the terminal, doing line editing.
28+ * The parameter s contains the prompt for the line.
29+ */
30+
31+char *
32+readline(char *s)
33+{
34+
35+ static char buf[80];
36+ char *p = buf;
37+ int ch;
38+ int pos;
39+
40+ clrbline();
41+ putline(s);
42+ pos = strlen(s);
43+ while ((ch = getch()) != '\n' && ch != '\r') {
44+ if (ch == -1) {
45+ /*
46+ * Can only occur because of an interrupted read.
47+ */
48+ ch = erasech;
49+ interrupt = 0;
50+ }
51+ if (ch == erasech) {
52+ /*
53+ * Erase last char
54+ */
55+ if (p == buf) {
56+ /*
57+ * There was none, so return
58+ */
59+ return (char *)0;
60+ }
61+ pos -= killchar(*--p);
62+ if (*p != '\\')
63+ continue;
64+ }
65+ if (ch == killch) {
66+ /*
67+ * Erase the whole line
68+ */
69+ if (!(p > buf && *(p - 1) == '\\')) {
70+ while (p > buf) {
71+ pos -= killchar(*--p);
72+ }
73+ continue;
74+ }
75+ pos -= killchar(*--p);
76+ }
77+ if (p > &buf[78] || pos >= COLS - 2) {
78+ /*
79+ * Line does not fit.
80+ * Simply refuse to make it any longer
81+ */
82+ pos -= killchar(*--p);
83+ }
84+ *p++ = ch;
85+ if (ch < ' ' || ch >= 0177) {
86+ fputch('^');
87+ pos++;
88+ ch ^= 0100;
89+ }
90+ fputch(ch);
91+ pos++;
92+ }
93+ fputch('\r');
94+ *p++ = '\0';
95+ flush();
96+ return buf;
97+}
98+
99+/*
100+ * Erase a character from the command line.
101+ */
102+
103+static int
104+killchar(int c)
105+{
106+
107+ backspace();
108+ putch(' ');
109+ backspace();
110+ if (c < ' ' || c >= 0177) {
111+ (void)killchar(' ');
112+ return 2;
113+ }
114+ return 1;
115+}
116+
117+/*
118+ * Do a shell escape, after expanding '%' and '!'.
119+ */
120+
121+void
122+shellescape(char *p, int esc_char)
123+{
124+ char *p2; /* walks through command */
125+ int id; /* procid of child */
126+ int cnt; /* prevent array bound errors */
127+ int lastc = 0; /* will contain the previous char */
128+#ifdef SIGTSTP
129+ void (*savetstp)(int);
130+#endif
131+ static char previous[256]; /* previous command */
132+ char comm[256]; /* space for command */
133+ int piped[2];
134+
135+ p2 = comm;
136+ *p2++ = esc_char;
137+ cnt = 253;
138+ while (*p) {
139+ /*
140+ * expand command
141+ */
142+ switch (*p++) {
143+ case '!':
144+ /*
145+ * An unescaped ! expands to the previous
146+ * command, but disappears if there is none
147+ */
148+ if (lastc != '\\') {
149+ if (*previous) {
150+ id = strlen(previous);
151+ if ((cnt -= id) <= 0)
152+ break;
153+ (void)strcpy(p2, previous);
154+ p2 += id;
155+ }
156+ } else {
157+ *(p2 - 1) = '!';
158+ }
159+ continue;
160+ case '%':
161+ /*
162+ * An unescaped % will expand to the current
163+ * filename, but disappears is there is none
164+ */
165+ if (lastc != '\\') {
166+ if (nopipe) {
167+ id = strlen(currentfile);
168+ if ((cnt -= id) <= 0)
169+ break;
170+ (void)strcpy(p2, currentfile);
171+ p2 += id;
172+ }
173+ } else {
174+ *(p2 - 1) = '%';
175+ }
176+ continue;
177+ default:
178+ lastc = *(p - 1);
179+ if (cnt-- <= 0)
180+ break;
181+ *p2++ = lastc;
182+ continue;
183+ }
184+ break;
185+ }
186+ clrbline();
187+ *p2 = '\0';
188+ if (!stupid) {
189+ /*
190+ * Display expanded command
191+ */
192+ cputline(comm);
193+ putline("\r\n");
194+ }
195+ flush();
196+ (void)strcpy(previous, comm + 1);
197+ resettty();
198+ if (esc_char == '|' && pipe(piped) < 0) {
199+ error("Cannot create pipe");
200+ return;
201+ }
202+ if ((id = fork()) < 0) {
203+ error("Cannot fork");
204+ return;
205+ }
206+ if (id == 0) {
207+ if (esc_char == '|') {
208+ close(piped[1]);
209+ close(0);
210+ fcntl(piped[0], F_DUPFD, 0);
211+ close(piped[0]);
212+ }
213+ execl("/bin/sh", "sh", "-c", comm + 1, (char *)0);
214+ exit(1);
215+ }
216+ (void)signal(SIGINT, SIG_IGN);
217+ (void)signal(SIGQUIT, SIG_IGN);
218+#ifdef SIGTSTP
219+ if ((savetstp = signal(SIGTSTP, SIG_IGN)) != SIG_IGN) {
220+ (void)signal(SIGTSTP, SIG_DFL);
221+ }
222+#endif
223+ if (esc_char == '|') {
224+ (void)close(piped[0]);
225+ (void)signal(SIGPIPE, SIG_IGN);
226+ wrt_fd(piped[1]);
227+ (void)close(piped[1]);
228+ }
229+ while ((lastc = wait((int *)0)) != id && lastc >= 0) {
230+ /*
231+ * Wait for child, making sure it is the one we expected ...
232+ */
233+ }
234+ (void)signal(SIGINT, catchdel);
235+ (void)signal(SIGQUIT, sigquit);
236+#ifdef SIGTSTP
237+ (void)signal(SIGTSTP, savetstp);
238+#endif
239+ inittty();
240+}
241+
242+static void
243+sigquit(int signo)
244+{
245+ (void)signo;
246+ quit();
247+}
248+
249+/*
250+ * Get all those commands ...
251+ */
252+
253+int
254+getcomm(long *plong)
255+{
256+ int c;
257+ long count;
258+ char *p;
259+ int i;
260+ int j;
261+ char buf[10];
262+
263+ for (;;) {
264+ count = 0;
265+ give_prompt();
266+ while (isdigit((c = getch()))) {
267+ count = count * 10 + (c - '0');
268+ }
269+ *plong = count;
270+ p = buf;
271+ for (;;) {
272+ if (c == -1) {
273+ /*
274+ * This should never happen, but it does,
275+ * when the user gives a TSTP signal (^Z) or
276+ * an interrupt while the program is trying
277+ * to read a character from the terminal.
278+ * In this case, the read is interrupted, so
279+ * we end up here.
280+ * Right, we will have to read again.
281+ */
282+ if (interrupt)
283+ return 1;
284+ break;
285+ }
286+ *p++ = c;
287+ *p = 0;
288+ if ((i = match(buf, &j, currmap->k_mach)) > 0) {
289+ /*
290+ * The key sequence matched. We have a command
291+ */
292+ return j;
293+ }
294+ if (i == 0)
295+ return 0;
296+ /*
297+ * We have a prefix of a command.
298+ */
299+ assert(i == FSM_ISPREFIX);
300+ c = getch();
301+ }
302+ }
303+ /* NOTREACHED */
304+}
+8,
-0
1@@ -0,0 +1,8 @@
2+#ifndef GETCOMM_H
3+#define GETCOMM_H
4+
5+int getcomm(long *arg);
6+void shellescape(char *command, int esc_char);
7+char *readline(char *prompt);
8+
9+#endif
+475,
-0
1@@ -0,0 +1,475 @@
2+/* Copyright (c) 1985 Ceriel J.H. Jacobs */
3+
4+#include "in_all.h"
5+#include "getline.h"
6+#include "options.h"
7+#include "process.h"
8+#include "term.h"
9+#include "main.h"
10+#include "display.h"
11+#include "output.h"
12+#include "prompt.h"
13+#include "assert.h"
14+
15+#define BLOCKSIZE 2048 /* size of blocks */
16+#define CHUNK 50 /* # of blockheaders allocated at a time */
17+
18+/*
19+ * Blocks are kept in an array in line-number order. Each block stores the raw
20+ * text and the offsets of the lines parsed from it.
21+ */
22+
23+struct block {
24+ int b_flags; /* Contains the following flags: */
25+#define PARTLY 02 /* block not filled completely (eof) */
26+ long b_end; /* line number of last line in block */
27+ char *b_info; /* the block */
28+ int *b_offs; /* line offsets within the block */
29+};
30+
31+static struct block *blocklist, /* beginning of the list of blocks */
32+ *maxblocklist, /* first free entry in the list */
33+ *topblocklist; /* end of allocated core for the list */
34+static long lastreadline; /* lineno of last line read */
35+static int ENDseen;
36+
37+static void nextblock(struct block *pblock);
38+static char *re_alloc(char *ptr, unsigned newsize);
39+static struct block *getblock(long n, int disable_interrupt);
40+
41+static struct block *
42+new_block()
43+{
44+ struct block *pblock = maxblocklist - 1;
45+
46+ if (!maxblocklist || !(pblock->b_flags & PARTLY)) {
47+ /*
48+ * There is no last block, or it was filled completely,
49+ * so allocate a new blockheader.
50+ */
51+ int siz;
52+
53+ pblock = blocklist;
54+ if (maxblocklist == topblocklist) {
55+ /*
56+ * No blockheaders left. Allocate new ones
57+ */
58+ siz = topblocklist - pblock;
59+ blocklist = pblock = (struct block *)
60+ re_alloc((char *)pblock,
61+ (unsigned)((siz + CHUNK) * sizeof(*pblock)));
62+ pblock += siz;
63+ topblocklist = pblock + CHUNK;
64+ maxblocklist = pblock;
65+ for (; pblock < topblocklist; pblock++) {
66+ pblock->b_end = 0;
67+ pblock->b_info = 0;
68+ pblock->b_flags = 0;
69+ }
70+ if (!siz) {
71+ /*
72+ * Create dummy header cell.
73+ */
74+ maxblocklist++;
75+ }
76+ }
77+ pblock = maxblocklist++;
78+ }
79+ nextblock(pblock);
80+ return pblock;
81+}
82+
83+/*
84+ * Return the block in which line 'n' of the current file can be found.
85+ * If "disable_interrupt" = 0, the call may be interrupted, in which
86+ * case it returns 0.
87+ */
88+
89+static struct block *
90+getblock(long n, int disable_interrupt)
91+{
92+ struct block *pblock;
93+
94+ if (stdf < 0) {
95+ /*
96+ * Not file descriptor, so return end of file
97+ */
98+ return 0;
99+ }
100+ pblock = maxblocklist - 1;
101+ if (n < lastreadline ||
102+ (n == lastreadline && !(pblock->b_flags & PARTLY))) {
103+ /*
104+ * The line asked for has been read already.
105+ * Perform binary search in the blocklist to find the block
106+ * where it's in.
107+ */
108+ struct block *min, *mid;
109+
110+ min = blocklist + 1;
111+ do {
112+ mid = min + (pblock - min) / 2;
113+ if (n > mid->b_end) {
114+ min = mid + 1;
115+ } else
116+ pblock = mid;
117+ } while (min < pblock);
118+ /* Found, pblock is now a reference to the block wanted */
119+ return pblock;
120+ }
121+
122+ /*
123+ * The line was'nt read yet, so read blocks until found
124+ */
125+ for (;;) {
126+ if (interrupt && !disable_interrupt)
127+ return 0;
128+ pblock = new_block();
129+ if (pblock->b_end >= n) {
130+ return pblock;
131+ }
132+ if (pblock->b_flags & PARTLY) {
133+ /*
134+ * We did not find it, and the last block could not be
135+ * read completely, so return 0;
136+ */
137+ return 0;
138+ }
139+ }
140+ /* NOTREACHED */
141+}
142+
143+char *
144+getline(long n, int disable_interrupt)
145+{
146+ struct block *pblock;
147+
148+ if (!(pblock = getblock(n, disable_interrupt))) {
149+ return (char *)0;
150+ }
151+ return pblock->b_info + pblock->b_offs[n - ((pblock - 1)->b_end + 1)];
152+}
153+
154+/*
155+ * Find the last line of the input, and return its number
156+ */
157+
158+long
159+to_lastline()
160+{
161+
162+ for (;;) {
163+ if (!getline(lastreadline + 1, 0)) {
164+ /*
165+ * "lastreadline" always contains the linenumber of
166+ * the last line read. So, if the call to getline
167+ * succeeds, "lastreadline" is affected
168+ */
169+ if (interrupt)
170+ return -1L;
171+ return lastreadline;
172+ }
173+ }
174+ /* NOTREACHED */
175+}
176+
177+char *
178+alloc(unsigned size)
179+{
180+ char *pmem;
181+
182+ pmem = malloc(size);
183+ if (!pmem && size != 0) {
184+ panic("No core");
185+ }
186+ return pmem;
187+}
188+
189+/*
190+ * Re-allocate the memorychunk pointed to by ptr, to let it
191+ * grow or shrink.
192+ */
193+
194+static char *
195+re_alloc(char *ptr, unsigned newsize)
196+{
197+ char *pmem;
198+
199+ pmem = realloc(ptr, newsize);
200+ if (!pmem && newsize != 0) {
201+ panic("No core");
202+ }
203+ return pmem;
204+}
205+
206+static char *saved;
207+static long filldegree;
208+
209+/*
210+ * Try to read the block indicated by pblock
211+ */
212+
213+static void
214+nextblock(struct block *pblock)
215+{
216+ char *c, /* Run through pblock->b_info */
217+ *c1; /* indicate end of pblock->b_info */
218+ int *poff; /* pointer in line-offset list */
219+ int cnt; /* # of characters read */
220+ unsigned siz; /* Size of allocated line-offset list */
221+ static unsigned savedsiz; /* saved "siz" */
222+ static int *savedpoff; /* saved "poff" */
223+ static char *savedc1; /* saved "c1" */
224+
225+ if (pblock->b_flags & PARTLY) {
226+ /*
227+ * The block was already partly filled. Initialize locals
228+ * accordingly
229+ */
230+ poff = savedpoff;
231+ siz = savedsiz;
232+ pblock->b_flags = 0;
233+ c1 = savedc1;
234+ if (c1 == pblock->b_info || *(c1 - 1)) {
235+ /*
236+ * We had incremented "lastreadline" temporarily,
237+ * because the last line could not be completely read
238+ * last time we tried. Undo this increment
239+ */
240+ poff--;
241+ --lastreadline;
242+ }
243+ } else {
244+ if (saved) {
245+ /*
246+ * There were leftovers from the previous block
247+ */
248+ pblock->b_info = saved;
249+ c1 = savedc1;
250+ saved = 0;
251+ } else { /* Allocate new block */
252+ pblock->b_info = c1 = alloc(BLOCKSIZE + 1);
253+ }
254+ /*
255+ * Allocate some space for line-offsets
256+ */
257+ pblock->b_offs = poff = (int *)
258+ alloc((unsigned)(100 * sizeof(int)));
259+ siz = 99;
260+ *poff++ = 0;
261+ }
262+ c = c1;
263+ for (;;) {
264+ /*
265+ * Read loop
266+ */
267+ cnt = read(stdf, c1, BLOCKSIZE - (c1 - pblock->b_info));
268+ if (cnt < 0) {
269+ /*
270+ * Interrupted read
271+ */
272+ if (errno == EINTR)
273+ continue;
274+ error("Could not read input file");
275+ cnt = 0;
276+ }
277+ c1 += cnt;
278+ if (c1 != pblock->b_info + BLOCKSIZE) {
279+ ENDseen = 1;
280+ pblock->b_flags |= PARTLY;
281+ }
282+ break;
283+ }
284+ assert(c <= c1);
285+ while (c < c1) {
286+ /*
287+ * Now process the block
288+ */
289+ if (*c == '\n') {
290+ /*
291+ * Newlines are replaced by '\0', so that "getline"
292+ * can deliver one line at a time
293+ */
294+ *c = 0;
295+ lastreadline++;
296+ /*
297+ * Remember the line-offset
298+ */
299+ if (poff == pblock->b_offs + siz) {
300+ /*
301+ * No space for it, allocate some more
302+ */
303+ pblock->b_offs = (int *)
304+ re_alloc((char *)pblock->b_offs,
305+ (unsigned)((siz + 51) * sizeof(int)));
306+ poff = pblock->b_offs + siz;
307+ siz += 50;
308+ }
309+ *poff++ = c - pblock->b_info + 1;
310+ }
311+ c++;
312+ }
313+ assert(c == c1);
314+ *c = 0;
315+ if (c != pblock->b_info && *(c - 1) != 0) {
316+ /*
317+ * The last line read does not end with a newline, so add one
318+ */
319+ lastreadline++;
320+ *poff++ = c - pblock->b_info + 1;
321+ if (!(pblock->b_flags & PARTLY) && *(poff - 2) != 0) {
322+ /*
323+ * Save the started line; it will be in the next block.
324+ * Remove the newline we added just now.
325+ */
326+ saved = c1 = alloc(BLOCKSIZE + 1);
327+ c = pblock->b_info + *(--poff - 1);
328+ while (*c)
329+ *c1++ = *c++;
330+ c = pblock->b_info + *(poff - 1);
331+ savedc1 = c1;
332+ --lastreadline;
333+ }
334+ }
335+ pblock->b_end = lastreadline;
336+ if (pblock->b_flags & PARTLY) {
337+ /*
338+ * Take care, that we can call "nextblock" again, to fill in
339+ * the rest of this block
340+ */
341+ savedsiz = siz;
342+ savedpoff = poff;
343+ savedc1 = c;
344+ if (c == pblock->b_info) {
345+ lastreadline++;
346+ pblock->b_end = 0;
347+ }
348+ } else {
349+ cnt = pblock - blocklist;
350+ filldegree = ((c - pblock->b_info) + (cnt - 1) * filldegree) / cnt;
351+ }
352+ assert(pblock->b_end - (pblock - 1)->b_end <= poff - pblock->b_offs);
353+}
354+
355+/*
356+ * Called after processing a file.
357+ * Free all core.
358+ */
359+
360+void
361+do_clean()
362+{
363+
364+ struct block *pblock;
365+ char *p;
366+
367+ for (pblock = blocklist; pblock < maxblocklist; pblock++) {
368+ if ((p = pblock->b_info) != 0) {
369+ free(p);
370+ free((char *)pblock->b_offs);
371+ }
372+ }
373+ if ((p = (char *)blocklist) != 0) {
374+ free(p);
375+ }
376+ blocklist = 0;
377+ maxblocklist = 0;
378+ topblocklist = 0;
379+ lastreadline = 0;
380+ filldegree = 0;
381+ ENDseen = 0;
382+ if ((p = saved) != 0)
383+ free(p);
384+ saved = 0;
385+}
386+
387+/*
388+ * Get a character. If possible, do some workahead.
389+ */
390+
391+int
392+getch()
393+{
394+ int flags, bytes_ready, bytes_read;
395+ struct stat buf;
396+ char c;
397+
398+ flush();
399+ if (startcomm) {
400+ /*
401+ * Command line option command
402+ */
403+ if (*startcomm)
404+ return *startcomm++;
405+ return '\n';
406+ }
407+ if (stdf >= 0) {
408+ /*
409+ * Make reads from the terminal non-blocking, so that
410+ * we can see if the user typed something
411+ */
412+ flags = fcntl(0, F_GETFL, 0);
413+ if (flags != -1 && fcntl(0, F_SETFL, flags | O_NONBLOCK) != -1) {
414+ bytes_read = 0;
415+ while (!ENDseen &&
416+ ((bytes_read = read(0, &c, 1)) == 0
417+#ifdef EWOULDBLOCK
418+ || (bytes_read < 0 && errno == EWOULDBLOCK)
419+#endif
420+#ifdef EAGAIN
421+ || (bytes_read < 0 && errno == EAGAIN)
422+#endif
423+ ) &&
424+ (nopipe ||
425+ (fstat(stdf, &buf) >= 0 && buf.st_size > 0))) {
426+ /*
427+ * Do some read ahead, after making sure there
428+ * is input and the user did not type a command
429+ */
430+ new_block();
431+ }
432+ (void)fcntl(0, F_SETFL, flags);
433+ if (bytes_read < 0) {
434+ /*
435+ * Could this have happened?
436+ * I'm not sure, because the read is
437+ * nonblocking. Can it be interrupted then?
438+ */
439+ return -1;
440+ }
441+ if (bytes_read > 0)
442+ return c & 0x7f;
443+ }
444+ }
445+ if (ioctl(0, FIONREAD, (char *)&bytes_ready) >= 0 && stdf >= 0) {
446+ while (!ENDseen &&
447+ bytes_ready == 0 &&
448+ (nopipe || (fstat(stdf, &buf) >= 0 && buf.st_size > 0))) {
449+ if (interrupt)
450+ return -1;
451+ new_block();
452+ if (ioctl(0, FIONREAD, (char *)&bytes_ready) < 0) {
453+ break;
454+ }
455+ }
456+ }
457+ if (read(0, &c, 1) <= 0)
458+ return -1;
459+ return c & 0x7f;
460+}
461+
462+/*
463+ * Get the position of line "ln" in the file.
464+ */
465+
466+long
467+getpos(long ln)
468+{
469+ struct block *pblock;
470+ long i;
471+
472+ pblock = getblock(ln, 1);
473+ assert(pblock != 0);
474+ i = filldegree * (pblock - blocklist);
475+ return i - (filldegree - pblock->b_offs[ln - (pblock - 1)->b_end]);
476+}
+11,
-0
1@@ -0,0 +1,11 @@
2+#ifndef GETLINE_H
3+#define GETLINE_H
4+
5+char *getline(long ln, int disable_interrupt);
6+char *alloc(unsigned size);
7+void do_clean(void);
8+int getch(void);
9+long to_lastline(void);
10+long getpos(long line);
11+
12+#endif
A
help.c
+112,
-0
1@@ -0,0 +1,112 @@
2+/* Copyright (c) 1985 Ceriel J.H. Jacobs */
3+
4+#include "in_all.h"
5+#include "help.h"
6+#include "machine.h"
7+#include "commands.h"
8+#include "keys.h"
9+#include "output.h"
10+#include "prompt.h"
11+#include "main.h"
12+#include "display.h"
13+#include "term.h"
14+#include "options.h"
15+
16+static int h_cnt; /* Count # of lines */
17+static struct state *origin; /* Keep track of startstate */
18+
19+/*
20+ * Print a key sequence.
21+ * We arrived at an endstate. The s_next link in the state structure now
22+ * leads us from "origin" to the current state, so that we can print the key
23+ * sequence easily.
24+ */
25+
26+static void
27+pr_comm()
28+{
29+ struct state *p = origin;
30+ char *pb;
31+ int c;
32+ char buf[30];
33+ int i = 0; /* How many characters printed? */
34+
35+ pb = buf;
36+ for (;;) {
37+ c = p->s_char & 0177;
38+ if (c < ' ' || c == 0177) {
39+ /*
40+ * Will take an extra position
41+ */
42+ i++;
43+ }
44+ *pb++ = c;
45+ i++;
46+ if (!p->s_match)
47+ break;
48+ p = p->s_next;
49+ }
50+ do {
51+ *pb++ = ' ';
52+ } while (++i < 12);
53+ *pb = 0;
54+ cputline(buf);
55+}
56+
57+/*
58+ * Print out a description of the keymap. This is done, by temporarily using
59+ * the s_next field in the state structure indicate the state matching the
60+ * next character, so that we can walk from "origin" to an endstate.
61+ */
62+
63+static void
64+pr_mach(struct state *currstate, struct state *back)
65+{
66+ struct state *save;
67+
68+ while (currstate) {
69+ if (interrupt)
70+ break;
71+ if (back) {
72+ save = back->s_next; /* Save original link */
73+ back->s_next = currstate;
74+ }
75+ if (!currstate->s_match) {
76+ /*
77+ * End state, print command
78+ */
79+ pr_comm();
80+ putline(commands[currstate->s_cnt].c_descr);
81+ putline("\r\n");
82+ if (++h_cnt >= maxpagesize) {
83+ ret_to_continue();
84+ h_cnt = 0;
85+ }
86+ } else
87+ pr_mach(currstate->s_match, currstate);
88+ currstate = currstate->s_next;
89+ if (back)
90+ back->s_next = save; /* restore */
91+ else
92+ origin = currstate;
93+ }
94+}
95+
96+/*ARGSUSED*/
97+int
98+do_help(long i)
99+{ /* The help command */
100+ (void)i;
101+
102+ startcomm = 0;
103+ h_cnt = 2;
104+ putline("\r\nSummary of yap commands:\r\n");
105+ origin = currmap->k_mach;
106+ pr_mach(currmap->k_mach, (struct state *)0);
107+ if (h_cnt) {
108+ ret_to_continue();
109+ }
110+ if (!hardcopy && scr_info.currentpos)
111+ redraw(1);
112+ return 0;
113+}
A
help.h
+6,
-0
1@@ -0,0 +1,6 @@
2+#ifndef HELP_H
3+#define HELP_H
4+
5+int do_help(long cnt);
6+
7+#endif
A
in_all.h
+23,
-0
1@@ -0,0 +1,23 @@
2+#ifndef IN_ALL_H
3+#define IN_ALL_H
4+
5+#define _DEFAULT_SOURCE
6+
7+#include <errno.h>
8+#include <fcntl.h>
9+#include <libgen.h>
10+#include <locale.h>
11+#include <regex.h>
12+#include <signal.h>
13+#include <stddef.h>
14+#include <stdlib.h>
15+#include <string.h>
16+#include <sys/ioctl.h>
17+#include <sys/stat.h>
18+#include <sys/types.h>
19+#include <sys/wait.h>
20+#include <termios.h>
21+#include <unistd.h>
22+#include <wchar.h>
23+
24+#endif
A
keys.c
+187,
-0
1@@ -0,0 +1,187 @@
2+/* Copyright (c) 1985 Ceriel J.H. Jacobs */
3+
4+#include <ctype.h>
5+#include "in_all.h"
6+#include "machine.h"
7+#include "keys.h"
8+#include "commands.h"
9+#include "prompt.h"
10+#include "assert.h"
11+
12+struct keymap *currmap, *othermap;
13+
14+char defaultmap[] = "\
15+bf=P:bl=k:bl=^K:bl=^[[A:bot=l:bot=$:bp=-:bs=^B:bse=?:bsl=S:bsp=F:chm=X:exg=x:\
16+ff=N:fl=^J:fl=^M:fl=j:fl=^[[B:fp= :fs=^D:fse=/:fsl=s:fsp=f:hlp=h:nse=n:nsr=r:\
17+red=^L:rep=.:bps=Z:bss=b:fps=z:fss=d:shl=!:tom=':top=\\^:vis=e:\
18+wrf=w:qui=q:qui=Q:mar=m:pip=|";
19+
20+/*
21+ * Construct an error message and return it
22+ */
23+
24+static char *
25+kerror(char *key, char *emess)
26+{
27+ static char ebuf[80]; /* Room for the error message */
28+
29+ (void)strcpy(ebuf, key);
30+ (void)strcat(ebuf, emess);
31+ return ebuf;
32+}
33+
34+/*
35+ * Compile a keymap into commtable. Returns an error message if there
36+ * is one
37+ */
38+
39+static char *
40+compile(char *map, struct keymap *commtable)
41+{
42+ char *mark; /* Indicates start of mnemonic */
43+ char *c; /* Runs through buf */
44+ int temp;
45+ char *escapes = commtable->k_esc;
46+ char buf[10]; /* Will hold key sequence */
47+
48+ (void)strcpy(commtable->k_help, "Illegal command");
49+ while (*map) {
50+ c = buf;
51+ mark = map; /* Start of mnemonic */
52+ while (*map && *map != '=') {
53+ map++;
54+ }
55+ if (!*map) {
56+ /*
57+ * Mnemonic should end with '='
58+ */
59+ return kerror(mark, ": Syntax error");
60+ }
61+ *map++ = 0;
62+ while (*map) {
63+ /*
64+ * Get key sequence
65+ */
66+ if (*map == ':') {
67+ /*
68+ * end of key sequence
69+ */
70+ map++;
71+ break;
72+ }
73+ *c = *map++ & 0x7f;
74+ if (*c == '^' || *c == '\\') {
75+ if (!(temp = *map++)) {
76+ /*
77+ * Escape not followed by a character
78+ */
79+ return kerror(mark, ": Syntax error");
80+ }
81+ if (*c == '^') {
82+ if (temp == '?')
83+ *c = 0x7f;
84+ else
85+ *c = temp & 0x1f;
86+ } else
87+ *c = temp & 0x7f;
88+ }
89+ setused(*c);
90+ c++;
91+ if (c >= &buf[9]) {
92+ return kerror(mark, ": Key sequence too long");
93+ }
94+ }
95+ *c = 0;
96+ if (!(temp = lookup(mark))) {
97+ return kerror(mark, ": Nonexistent function");
98+ }
99+ if (c == &buf[1] && (commands[temp].c_flags & ESC) &&
100+ escapes < &(commtable->k_esc[sizeof(commtable->k_esc) - 1])) {
101+ *escapes++ = buf[0] & 0x7f;
102+ }
103+ temp = addstring(buf, temp, &(commtable->k_mach));
104+ if (temp == FSM_ISPREFIX) {
105+ return kerror(mark, ": Prefix of other key sequence");
106+ }
107+ if (temp == FSM_HASPREFIX) {
108+ return kerror(mark, ": Other key sequence is prefix");
109+ }
110+ assert(temp == FSM_OKE);
111+ if (!strcmp(mark, "hlp")) {
112+ /*
113+ * Create an error message to be given when the user
114+ * types an illegal command
115+ */
116+ (void)strcpy(commtable->k_help, "Type ");
117+ (void)strcat(commtable->k_help, buf);
118+ (void)strcat(commtable->k_help, " for help");
119+ }
120+ }
121+ *escapes = 0;
122+ return (char *)0;
123+}
124+
125+/*
126+ * Initialize the keymaps
127+ */
128+
129+void
130+initkeys()
131+{
132+ char *p;
133+ static struct keymap xx[2];
134+
135+ currmap = &xx[0];
136+ othermap = &xx[1];
137+ p = compile(defaultmap, currmap); /* Compile default map */
138+ assert(p == (char *)0);
139+ p = getenv("YAPKEYS");
140+ if (p) {
141+ if (!(p = compile(p, othermap))) {
142+ /*
143+ * No errors in user defined keymap. So, use it
144+ */
145+ do_chkm(0L);
146+ return;
147+ }
148+ error(p);
149+ }
150+ othermap = 0; /* No other keymap */
151+}
152+
153+int
154+is_escape(int c)
155+{
156+ char *p = currmap->k_esc;
157+
158+ while (*p) {
159+ if (c == *p++)
160+ return 1;
161+ }
162+ return 0;
163+}
164+
165+static char keyset[16]; /* bitset indicating which keys are
166+ * used
167+ */
168+/*
169+ * Mark key "key" as used
170+ */
171+
172+void
173+setused(int key)
174+{
175+
176+ keyset[(key & 0x7f) >> 3] |= (1 << (key & 0x07));
177+}
178+
179+/*
180+ * return non-zero if key "key" is used in a keymap
181+ */
182+
183+int
184+isused(int key)
185+{
186+
187+ return keyset[(key & 0x7f) >> 3] & (1 << (key & 0x07));
188+}
A
keys.h
+15,
-0
1@@ -0,0 +1,15 @@
2+#ifndef KEYS_H
3+#define KEYS_H
4+
5+extern struct keymap {
6+ char k_help[80];
7+ struct state *k_mach;
8+ char k_esc[10];
9+} *currmap, *othermap;
10+
11+void initkeys(void);
12+void setused(int key);
13+int isused(int key);
14+int is_escape(int c);
15+
16+#endif
+134,
-0
1@@ -0,0 +1,134 @@
2+/* Copyright (c) 1985 Ceriel J.H. Jacobs */
3+
4+#include <ctype.h>
5+#include "in_all.h"
6+#include "machine.h"
7+#include "getline.h"
8+#include "assert.h"
9+
10+/*
11+ * Add part of finite state machine to recognize the string s.
12+ */
13+
14+static int
15+addtomach(char *s, int cnt, struct state **list)
16+{
17+
18+ struct state *l;
19+ int i = FSM_OKE; /* Return value */
20+ int j;
21+
22+ for (;;) {
23+ l = *list;
24+ if (!l) {
25+ /*
26+ * Create new list element
27+ */
28+ *list = l = (struct state *)alloc(sizeof(*l));
29+ l->s_char = *s;
30+ l->s_endstate = 0;
31+ l->s_match = 0;
32+ l->s_next = 0;
33+ }
34+ if (l->s_char == *s) {
35+ /*
36+ * Continue with next character
37+ */
38+ if (!*++s) {
39+ /*
40+ * No next character
41+ */
42+ j = l->s_endstate;
43+ l->s_endstate = 1;
44+ if (l->s_match || j) {
45+ /*
46+ * If the state already was an endstate,
47+ * or has a successor, the currently
48+ * added string is a prefix of an
49+ * already recognized string
50+ */
51+ return FSM_ISPREFIX;
52+ }
53+ l->s_cnt = cnt;
54+ return i;
55+ }
56+ if (l->s_endstate) {
57+ /*
58+ * In this case, the currently added string has
59+ * a prefix that is an already recognized
60+ * string.
61+ */
62+ i = FSM_HASPREFIX;
63+ }
64+ list = &(l->s_match);
65+ continue;
66+ }
67+ list = &(l->s_next);
68+ }
69+ /* NOTREACHED */
70+}
71+
72+/*
73+ * Add a string to the FSM.
74+ */
75+
76+int
77+addstring(char *s, int cnt, struct state **machine)
78+{
79+
80+ if (!s || !*s) {
81+ return FSM_ISPREFIX;
82+ }
83+ return addtomach(s, cnt, machine);
84+}
85+
86+/*
87+ * Match string s with the finite state machine.
88+ * If it matches, the number of characters actually matched is returned,
89+ * and the count is put in the word pointed to by i.
90+ * If the string is a prefix of a string that could be matched,
91+ * FSM_ISPREFIX is returned. Otherwise, 0 is returned.
92+ */
93+
94+int
95+match(char *s, int *i, struct state *mach)
96+{
97+
98+ char *s1 = s; /* Walk through string */
99+ struct state *mach1 = 0;
100+ /* Keep track of previous state */
101+
102+ while (mach && *s1) {
103+ if (mach->s_char == *s1) {
104+ /*
105+ * Current character matches. Carry on with next
106+ * character and next state
107+ */
108+ mach1 = mach;
109+ mach = mach->s_match;
110+ s1++;
111+ continue;
112+ }
113+ mach = mach->s_next;
114+ }
115+ if (!mach1) {
116+ /*
117+ * No characters matched
118+ */
119+ return 0;
120+ }
121+ if (mach1->s_endstate) {
122+ /*
123+ * The string matched
124+ */
125+ *i = mach1->s_cnt;
126+ return s1 - s;
127+ }
128+ if (!*s1) {
129+ /*
130+ * The string matched a prefix
131+ */
132+ return FSM_ISPREFIX;
133+ }
134+ return 0;
135+}
+19,
-0
1@@ -0,0 +1,19 @@
2+#ifndef MACHINE_H
3+#define MACHINE_H
4+
5+struct state {
6+ char s_char;
7+ char s_endstate;
8+ struct state *s_match;
9+ struct state *s_next;
10+ short s_cnt;
11+};
12+
13+#define FSM_OKE 0
14+#define FSM_ISPREFIX -1
15+#define FSM_HASPREFIX 1
16+
17+int addstring(char *str, int cnt, struct state **mach);
18+int match(char *str, int *p_int, struct state *mach);
19+
20+#endif
A
main.c
+195,
-0
1@@ -0,0 +1,195 @@
2+/* Copyright (c) 1985 Ceriel J.H. Jacobs */
3+
4+#include "in_all.h"
5+#include "main.h"
6+#include "term.h"
7+#include "options.h"
8+#include "output.h"
9+#include "process.h"
10+#include "commands.h"
11+#include "display.h"
12+#include "prompt.h"
13+
14+int nopipe;
15+char *progname;
16+int interrupt;
17+int no_tty;
18+
19+static int initialize(int x);
20+static void sigquit(int signo);
21+#ifdef SIGTSTP
22+static void suspsig(int signo);
23+#endif
24+
25+int
26+main(int argc, char **argv)
27+{
28+ char **av;
29+
30+ (void)setlocale(LC_CTYPE, "");
31+ if (!isatty(1)) {
32+ no_tty = 1;
33+ }
34+ argv[argc] = 0;
35+ progname = argv[0];
36+ if ((av = readoptions(argv)) == (char **)0 ||
37+ initialize(*av ? 1 : 0)) {
38+ if (no_tty) {
39+ close(1);
40+ (void)dup(2);
41+ }
42+ putline("Usage: ");
43+ putline(argv[0]);
44+ putline(
45+ " [-c] [-u] [-n] [-q] [-number] [+command] [file ... ]\n");
46+ flush();
47+ exit(1);
48+ }
49+ if (no_tty) {
50+ *--av = "cat";
51+ execve("/bin/cat", av, (char *const[]){NULL});
52+ } else
53+ processfiles(argc - (av - argv), av);
54+ (void)quit();
55+ /* NOTREACHED */
56+}
57+
58+/*
59+ * Open temporary file for reading and writing.
60+ * Panic if it fails
61+ */
62+
63+/*
64+ * Collect initializing stuff here.
65+ */
66+
67+static int
68+initialize(int x)
69+{
70+
71+ if (!(nopipe = x)) {
72+ /*
73+ * Reading from pipe
74+ */
75+ if (isatty(0)) {
76+ return 1;
77+ }
78+ stdf = dup(0); /* Duplicate file descriptor of input */
79+ if (no_tty)
80+ return 0;
81+ /*
82+ * Make sure standard input is from the terminal.
83+ */
84+ (void)close(0);
85+ if (open("/dev/tty", O_RDONLY, 0) != 0) {
86+ putline("Couldn't open terminal\n");
87+ flush();
88+ exit(1);
89+ }
90+ }
91+ if (no_tty)
92+ return 0;
93+ /*
94+ * Handle signals.
95+ * Catch QUIT, DELETE and ^Z
96+ */
97+ (void)signal(SIGQUIT, SIG_IGN);
98+ (void)signal(SIGINT, catchdel);
99+ ini_terminal();
100+#ifdef SIGTSTP
101+ if (signal(SIGTSTP, SIG_IGN) == SIG_DFL) {
102+ (void)signal(SIGTSTP, suspsig);
103+ }
104+#endif
105+ (void)signal(SIGQUIT, sigquit);
106+ return 0;
107+}
108+
109+void
110+catchdel(int signo)
111+{
112+ (void)signo;
113+ (void)signal(SIGINT, catchdel);
114+ interrupt = 1;
115+}
116+
117+static void
118+sigquit(int signo)
119+{
120+ (void)signo;
121+ quit();
122+}
123+
124+#ifdef SIGTSTP
125+
126+/*
127+ * We had a SIGTSTP signal.
128+ * Suspend, by a call to this routine.
129+ */
130+
131+void
132+suspend()
133+{
134+
135+ nflush();
136+ resettty();
137+ (void)signal(SIGTSTP, SIG_DFL);
138+ (void)kill(0, SIGTSTP);
139+ /*
140+ * We are not here anymore ...
141+ *
142+
143+ *
144+ * But we arive here ...
145+ */
146+ inittty();
147+ putline(TI);
148+ flush();
149+ (void)signal(SIGTSTP, suspsig);
150+}
151+
152+/*
153+ * SIGTSTP signal handler.
154+ * Just indicate that we had one, ignore further ones and return.
155+ */
156+
157+static void
158+suspsig(int signo)
159+{
160+ (void)signo;
161+
162+ suspend();
163+ if (DoneSetJmp)
164+ longjmp(SetJmpBuf, 1);
165+}
166+#endif
167+
168+/*
169+ * quit : called on exit.
170+ * I bet you guessed that much.
171+ */
172+
173+int
174+quit()
175+{
176+
177+ clrbline();
178+ resettty();
179+ flush();
180+ exit(0);
181+}
182+
183+/*
184+ * Exit, but nonvoluntarily.
185+ * At least tell the user why.
186+ */
187+
188+void
189+panic(char *s)
190+{
191+
192+ putline("\a\a\a\r\n");
193+ putline(s);
194+ putline("\r\n");
195+ quit();
196+}
A
main.h
+18,
-0
1@@ -0,0 +1,18 @@
2+#ifndef MAIN_H
3+#define MAIN_H
4+
5+extern int nopipe;
6+extern char *progname;
7+extern int interrupt;
8+extern int no_tty;
9+
10+int main(int argc, char **argv);
11+void catchdel(int signo);
12+int quit(void);
13+void panic(char *s);
14+
15+#ifdef SIGTSTP
16+void suspend(void);
17+#endif
18+
19+#endif
+91,
-0
1@@ -0,0 +1,91 @@
2+/* Copyright (c) 1985 Ceriel J.H. Jacobs */
3+
4+#include "in_all.h"
5+#include "options.h"
6+#include "output.h"
7+#include "display.h"
8+#include <ctype.h>
9+
10+int cflag;
11+int uflag;
12+int nflag;
13+int qflag;
14+char *startcomm;
15+
16+static int parsopt(char *s);
17+
18+/*
19+ * Read the options. Return the argv pointer following them if there were
20+ * no errors, otherwise return 0.
21+ */
22+
23+char **
24+readoptions(char **argv)
25+{
26+
27+ char **av = argv + 1;
28+ char *p;
29+
30+ if ((p = getenv("YAP")) != 0) {
31+ (void)parsopt(p);
32+ }
33+ while (*av && **av == '-') {
34+ if (parsopt(*av)) {
35+ /*
36+ * Error in option
37+ */
38+ putline(*av);
39+ putline(": illegal option\n");
40+ return (char **)0;
41+ }
42+ av++;
43+ }
44+ if (*av && **av == '+') {
45+ /*
46+ * Command in command line
47+ */
48+ startcomm = *av + 1;
49+ av++;
50+ }
51+ return av;
52+}
53+
54+static int
55+parsopt(char *s)
56+{
57+ int i;
58+
59+ if (*s == '-')
60+ s++;
61+ if (isdigit(*s)) {
62+ /*
63+ * pagesize option
64+ */
65+ i = 0;
66+ do {
67+ i = i * 10 + *s++ - '0';
68+ } while (isdigit(*s));
69+ if (i < MINPAGESIZE)
70+ i = MINPAGESIZE;
71+ pagesize = i;
72+ }
73+ while (*s) {
74+ switch (*s++) {
75+ case 'c':
76+ cflag++;
77+ break;
78+ case 'n':
79+ nflag++;
80+ break;
81+ case 'u':
82+ uflag++;
83+ break;
84+ case 'q':
85+ qflag++;
86+ break;
87+ default:
88+ return 1;
89+ }
90+ }
91+ return 0;
92+}
+12,
-0
1@@ -0,0 +1,12 @@
2+#ifndef OPTIONS_H
3+#define OPTIONS_H
4+
5+extern int cflag;
6+extern int uflag;
7+extern int nflag;
8+extern int qflag;
9+extern char *startcomm;
10+
11+char **readoptions(char **argv);
12+
13+#endif
A
output.c
+102,
-0
1@@ -0,0 +1,102 @@
2+/* Copyright (c) 1985 Ceriel J.H. Jacobs */
3+
4+/*
5+ * Handle output to screen
6+ */
7+
8+#include "in_all.h"
9+#include "output.h"
10+#include "main.h"
11+
12+int _ocnt;
13+char *_optr;
14+
15+#define OBUFSIZ 64 * 128
16+
17+static char _outbuf[OBUFSIZ];
18+
19+void
20+flush()
21+{ /* Flush output buffer, by writing it */
22+ char *p = _outbuf;
23+
24+ _ocnt = OBUFSIZ;
25+ if (_optr)
26+ (void)write(1, p, _optr - p);
27+ _optr = p;
28+}
29+
30+void
31+nflush()
32+{ /* Flush output buffer, ignoring it */
33+
34+ _ocnt = OBUFSIZ;
35+ _optr = _outbuf;
36+}
37+
38+int
39+fputch(int ch)
40+{ /* print a character */
41+ putch(ch);
42+ return ch;
43+}
44+
45+void
46+putline(char *s)
47+{ /* Print string s */
48+
49+ if (!s)
50+ return;
51+ while (*s) {
52+ putch(*s++);
53+ }
54+}
55+
56+/*
57+ * A safe version of putline. All control characters are echoed as ^X
58+ */
59+
60+void
61+cputline(char *s)
62+{
63+ int c;
64+
65+ while ((c = *s++) != 0) {
66+ if ((unsigned char)c < ' ' || (unsigned char)c == 0x7f) {
67+ putch('^');
68+ c ^= 0x40;
69+ }
70+ putch(c);
71+ }
72+}
73+
74+/*
75+ * Simple minded routine to print a number
76+ */
77+
78+void
79+prnum(long n)
80+{
81+
82+ putline(getnum(n));
83+}
84+
85+static char *
86+fillnum(long n, char *p)
87+{
88+ if (n >= 10) {
89+ p = fillnum(n / 10, p);
90+ }
91+ *p++ = (int)(n % 10) + '0';
92+ *p = '\0';
93+ return p;
94+}
95+
96+char *
97+getnum(long n)
98+{
99+ static char buf[20];
100+
101+ fillnum(n, buf);
102+ return buf;
103+}
A
output.h
+22,
-0
1@@ -0,0 +1,22 @@
2+#ifndef OUTPUT_H
3+#define OUTPUT_H
4+
5+extern int _ocnt;
6+extern char *_optr;
7+
8+#define putch(ch) \
9+ do { \
10+ if (--_ocnt <= 0) \
11+ flush(); \
12+ *_optr++ = (ch); \
13+ } while (0)
14+
15+void flush(void);
16+void nflush(void);
17+int fputch(int c);
18+void putline(char *s);
19+void cputline(char *s);
20+void prnum(long n);
21+char *getnum(long n);
22+
23+#endif
+34,
-0
1@@ -0,0 +1,34 @@
2+#include "in_all.h"
3+#include "pattern.h"
4+#include <regex.h>
5+
6+/*
7+ * Interface to POSIX regular expression routines.
8+ */
9+
10+static regex_t pattern;
11+static int pattern_valid;
12+
13+char *
14+re_comp(char *s)
15+{
16+
17+ if (!*s) {
18+ return (char *)0;
19+ }
20+ if (pattern_valid) {
21+ regfree(&pattern);
22+ pattern_valid = 0;
23+ }
24+ if (regcomp(&pattern, s, 0) == 0) {
25+ pattern_valid = 1;
26+ return (char *)0;
27+ }
28+ return "Error in pattern";
29+}
30+
31+int
32+re_exec(char *s)
33+{
34+ return pattern_valid && regexec(&pattern, s, 0, (regmatch_t *)0, 0) == 0;
35+}
+7,
-0
1@@ -0,0 +1,7 @@
2+#ifndef PATTERN_H
3+#define PATTERN_H
4+
5+char *re_comp(char *s);
6+int re_exec(char *s);
7+
8+#endif
+115,
-0
1@@ -0,0 +1,115 @@
2+/* Copyright (c) 1985 Ceriel J.H. Jacobs */
3+
4+#include "in_all.h"
5+#include "process.h"
6+#include "commands.h"
7+#include "display.h"
8+#include "prompt.h"
9+#include "getline.h"
10+#include "getcomm.h"
11+#include "main.h"
12+#include "options.h"
13+#include "output.h"
14+
15+jmp_buf SetJmpBuf;
16+int DoneSetJmp;
17+int stdf;
18+int filecount;
19+char **filenames;
20+char *currentfile;
21+long maxpos;
22+
23+static int nfiles; /* Number of filenames on command line */
24+
25+/*
26+ * Visit a file, file name is "fn".
27+ */
28+
29+void
30+visitfile(char *fn)
31+{
32+ struct stat statbuf;
33+
34+ if (stdf > 0) {
35+ /*
36+ * Close old input file
37+ */
38+ (void)close(stdf);
39+ }
40+ currentfile = fn;
41+ if ((stdf = open(fn, O_RDONLY, 0)) < 0) {
42+ error(": could not open");
43+ maxpos = 0;
44+ } else { /* Get size for percentage in prompt */
45+ (void)fstat(stdf, &statbuf);
46+ maxpos = statbuf.st_size;
47+ }
48+ do_clean();
49+ d_clean();
50+}
51+
52+/*
53+ * process the input files, one by one.
54+ * If there is none, input is from a pipe.
55+ */
56+
57+void
58+processfiles(int n, char **argv)
59+{
60+
61+ static char *dummies[3];
62+ long arg;
63+
64+ if (!(nfiles = n)) {
65+ /*
66+ * Input from pipe
67+ */
68+ currentfile = "standard-input";
69+ /*
70+ * Take care that *(filenames - 1) and *(filenames + 1) are 0
71+ */
72+ filenames = &dummies[1];
73+ d_clean();
74+ do_clean();
75+ } else {
76+ filenames = argv;
77+ (void)nextfile(0);
78+ }
79+ *--argv = 0;
80+ if (startcomm) {
81+ n = getcomm(&arg);
82+ if (commands[n].c_flags & NEEDS_SCREEN) {
83+ redraw(0);
84+ }
85+ do_comm(n, arg);
86+ startcomm = 0;
87+ }
88+ redraw(1);
89+ if (setjmp(SetJmpBuf)) {
90+ nflush();
91+ redraw(1);
92+ }
93+ DoneSetJmp = 1;
94+ for (;;) {
95+ interrupt = 0;
96+ n = getcomm(&arg);
97+ do_comm(n, arg);
98+ }
99+}
100+
101+/*
102+ * Get the next file the user asks for.
103+ */
104+
105+int
106+nextfile(int n)
107+{
108+ int i;
109+
110+ if ((i = filecount + n) >= nfiles || i < 0) {
111+ return 1;
112+ }
113+ filecount = i;
114+ visitfile(filenames[i]);
115+ return 0;
116+}
+19,
-0
1@@ -0,0 +1,19 @@
2+#ifndef PROCESS_H
3+#define PROCESS_H
4+
5+#include <setjmp.h>
6+
7+extern jmp_buf SetJmpBuf;
8+extern int DoneSetJmp;
9+
10+extern int stdf;
11+extern int filecount;
12+extern char **filenames;
13+extern char *currentfile;
14+extern long maxpos;
15+
16+void visitfile(char *fn);
17+void processfiles(int n, char **argv);
18+int nextfile(int n);
19+
20+#endif
A
prompt.c
+174,
-0
1@@ -0,0 +1,174 @@
2+/* Copyright (c) 1985 Ceriel J.H. Jacobs */
3+
4+#include "in_all.h"
5+#include "prompt.h"
6+#include "term.h"
7+#include "output.h"
8+#include "options.h"
9+#include "display.h"
10+#include "process.h"
11+#include "getline.h"
12+#include "main.h"
13+#include "getcomm.h"
14+#include "machine.h"
15+#include "keys.h"
16+#include "assert.h"
17+#include "commands.h"
18+
19+static char *errorgiven; /* Set to error message, if there is one */
20+
21+static char *display_basename(char *path, char *scratch, size_t scratch_size);
22+
23+char *
24+copy(char *p, const char *ep, char *s)
25+{
26+ while (p < ep && *s) {
27+ *p++ = *s++;
28+ }
29+ return p;
30+}
31+
32+/*
33+ * display the prompt and refresh the screen.
34+ */
35+
36+void
37+give_prompt()
38+{
39+
40+ char **name;
41+ struct scr_info *p = &scr_info;
42+ char buf[256];
43+ char filebuf[256];
44+ char *pb = buf;
45+
46+ if (startcomm)
47+ return;
48+ flush();
49+ if (window()) {
50+ redraw(0);
51+ flush();
52+ }
53+ if (!stupid) {
54+ /*
55+ * fancy prompt
56+ */
57+ clrbline();
58+ standout();
59+ pb = copy(pb, &buf[255],
60+ display_basename(currentfile, filebuf, sizeof(filebuf)));
61+ if (stdf >= 0) {
62+ pb = copy(pb, &buf[255], ", ");
63+ pb = copy(pb, &buf[255], getnum(p->firstline));
64+ pb = copy(pb, &buf[255], "-");
65+ pb = copy(pb, &buf[255], getnum(p->lastline));
66+ }
67+ } else {
68+ *pb++ = '\007'; /* Stupid terminal, stupid prompt */
69+ }
70+ if (errorgiven) {
71+ /*
72+ * display error message
73+ */
74+ pb = copy(pb, &buf[255], " ");
75+ pb = copy(pb, &buf[255], errorgiven);
76+ if (stupid) {
77+ pb = copy(pb, &buf[255], "\r\n");
78+ }
79+ errorgiven = 0;
80+ } else if (!stupid && (status || maxpos)) {
81+ pb = copy(pb, &buf[255], " (");
82+ name = &filenames[filecount];
83+ if (status) {
84+ /*
85+ * indicate top and/or bottom
86+ */
87+ if (status & START) {
88+ if (!*(name - 1)) {
89+ pb = copy(pb, &buf[255], "Top");
90+ } else {
91+ pb = copy(pb, &buf[255], "Previous: ");
92+ pb = copy(pb, &buf[255], display_basename(*(name - 1),
93+ filebuf,
94+ sizeof(filebuf)));
95+ }
96+ if (status & EOFILE) {
97+ pb = copy(pb, &buf[255], ", ");
98+ }
99+ }
100+ if (status & EOFILE) {
101+ if (!*(name + 1)) {
102+ pb = copy(pb, &buf[255], "Bottom");
103+ } else {
104+ pb = copy(pb, &buf[255], "Next: ");
105+ pb = copy(pb, &buf[255], display_basename(*(name + 1),
106+ filebuf,
107+ sizeof(filebuf)));
108+ }
109+ }
110+ } else { /* display percentage */
111+ pb = copy(pb, &buf[255], getnum((100 * getpos(p->lastline)) / maxpos));
112+ pb = copy(pb, &buf[255], "%");
113+ }
114+ pb = copy(pb, &buf[255], ")");
115+ }
116+ *pb = '\0';
117+ if (!stupid) {
118+ buf[COLS - 1] = 0;
119+ putline(buf);
120+ standend();
121+ } else
122+ putline(buf);
123+}
124+
125+static char *
126+display_basename(char *path, char *scratch, size_t scratch_size)
127+{
128+ char *base;
129+
130+ if (!path || scratch_size == 0) {
131+ return "";
132+ }
133+ (void)strncpy(scratch, path, scratch_size - 1);
134+ scratch[scratch_size - 1] = '\0';
135+ base = basename(scratch);
136+ return base ? base : scratch;
137+}
138+
139+/*
140+ * Remember error message
141+ */
142+
143+void
144+error(char *str)
145+{
146+
147+ errorgiven = str;
148+}
149+
150+void
151+ret_to_continue()
152+{ /* Obvious */
153+ int c;
154+ static char buf[2];
155+
156+ for (;;) {
157+ clrbline();
158+ standout();
159+ if (errorgiven) {
160+ putline(errorgiven);
161+ putline(" ");
162+ errorgiven = 0;
163+ }
164+ putline("[Type anything to continue]");
165+ standend();
166+ if (is_escape(c = getch())) {
167+ buf[0] = c;
168+ (void)match(buf, &c, currmap->k_mach);
169+ assert(c > 0);
170+ do_comm(c, -1L);
171+ } else
172+ break;
173+ }
174+ clrbline();
175+}
A
prompt.h
+8,
-0
1@@ -0,0 +1,8 @@
2+#ifndef PROMPT_H
3+#define PROMPT_H
4+
5+void give_prompt(void);
6+void error(char *s);
7+void ret_to_continue(void);
8+
9+#endif
A
rune.c
+148,
-0
1@@ -0,0 +1,148 @@
2+/* MIT/X Consortium Copyright (c) 2012 Connor Lane Smith <cls@lubutu.com>
3+ *
4+ * Permission is hereby granted, free of charge, to any person obtaining a
5+ * copy of this software and associated documentation files (the "Software"),
6+ * to deal in the Software without restriction, including without limitation
7+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8+ * and/or sell copies of the Software, and to permit persons to whom the
9+ * Software is furnished to do so, subject to the following conditions:
10+ *
11+ * The above copyright notice and this permission notice shall be included in
12+ * all copies or substantial portions of the Software.
13+ *
14+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20+ * DEALINGS IN THE SOFTWARE.
21+ */
22+#include "utf.h"
23+
24+#define MIN(x,y) ((x) < (y) ? (x) : (y))
25+
26+#define UTFSEQ(x) ((((x) & 0x80) == 0x00) ? 1 /* 0xxxxxxx */ \
27+ : (((x) & 0xC0) == 0x80) ? 0 /* 10xxxxxx */ \
28+ : (((x) & 0xE0) == 0xC0) ? 2 /* 110xxxxx */ \
29+ : (((x) & 0xF0) == 0xE0) ? 3 /* 1110xxxx */ \
30+ : (((x) & 0xF8) == 0xF0) ? 4 /* 11110xxx */ \
31+ : (((x) & 0xFC) == 0xF8) ? 5 /* 111110xx */ \
32+ : (((x) & 0xFE) == 0xFC) ? 6 /* 1111110x */ \
33+ : 0 )
34+
35+#define BADRUNE(x) ((x) < 0 || (x) > Runemax \
36+ || ((x) & 0xFFFE) == 0xFFFE \
37+ || ((x) >= 0xD800 && (x) <= 0xDFFF) \
38+ || ((x) >= 0xFDD0 && (x) <= 0xFDEF))
39+
40+int
41+runetochar(char *s, const Rune *p)
42+{
43+ Rune r = *p;
44+
45+ switch(runelen(r)) {
46+ case 1: /* 0aaaaaaa */
47+ s[0] = r;
48+ return 1;
49+ case 2: /* 00000aaa aabbbbbb */
50+ s[0] = 0xC0 | ((r & 0x0007C0) >> 6); /* 110aaaaa */
51+ s[1] = 0x80 | (r & 0x00003F); /* 10bbbbbb */
52+ return 2;
53+ case 3: /* aaaabbbb bbcccccc */
54+ s[0] = 0xE0 | ((r & 0x00F000) >> 12); /* 1110aaaa */
55+ s[1] = 0x80 | ((r & 0x000FC0) >> 6); /* 10bbbbbb */
56+ s[2] = 0x80 | (r & 0x00003F); /* 10cccccc */
57+ return 3;
58+ case 4: /* 000aaabb bbbbcccc ccdddddd */
59+ s[0] = 0xF0 | ((r & 0x1C0000) >> 18); /* 11110aaa */
60+ s[1] = 0x80 | ((r & 0x03F000) >> 12); /* 10bbbbbb */
61+ s[2] = 0x80 | ((r & 0x000FC0) >> 6); /* 10cccccc */
62+ s[3] = 0x80 | (r & 0x00003F); /* 10dddddd */
63+ return 4;
64+ default:
65+ return 0; /* error */
66+ }
67+}
68+
69+int
70+chartorune(Rune *p, const char *s)
71+{
72+ return charntorune(p, s, UTFmax);
73+}
74+
75+int
76+charntorune(Rune *p, const char *s, size_t len)
77+{
78+ unsigned int i, n;
79+ Rune r;
80+
81+ if(len == 0) /* can't even look at s[0] */
82+ return 0;
83+
84+ switch((n = UTFSEQ(s[0]))) {
85+ case 1: r = s[0]; break; /* 0xxxxxxx */
86+ case 2: r = s[0] & 0x1F; break; /* 110xxxxx */
87+ case 3: r = s[0] & 0x0F; break; /* 1110xxxx */
88+ case 4: r = s[0] & 0x07; break; /* 11110xxx */
89+ case 5: r = s[0] & 0x03; break; /* 111110xx */
90+ case 6: r = s[0] & 0x01; break; /* 1111110x */
91+ default: /* invalid sequence */
92+ *p = Runeerror;
93+ return 1;
94+ }
95+ /* add values from continuation bytes */
96+ for(i = 1; i < MIN(n, len); i++)
97+ if((s[i] & 0xC0) == 0x80) {
98+ /* add bits from continuation byte to rune value
99+ * cannot overflow: 6 byte sequences contain 31 bits */
100+ r = (r << 6) | (s[i] & 0x3F); /* 10xxxxxx */
101+ }
102+ else { /* expected continuation */
103+ *p = Runeerror;
104+ return i;
105+ }
106+
107+ if(i < n) /* must have reached len limit */
108+ return 0;
109+
110+ /* reject invalid or overlong sequences */
111+ if(BADRUNE(r) || runelen(r) < (int)n)
112+ r = Runeerror;
113+
114+ *p = r;
115+ return n;
116+}
117+
118+int
119+runelen(Rune r)
120+{
121+ if(BADRUNE(r))
122+ return 0; /* error */
123+ else if(r <= 0x7F)
124+ return 1;
125+ else if(r <= 0x07FF)
126+ return 2;
127+ else if(r <= 0xFFFF)
128+ return 3;
129+ else
130+ return 4;
131+}
132+
133+size_t
134+runenlen(const Rune *p, size_t len)
135+{
136+ size_t i, n = 0;
137+
138+ for(i = 0; i < len; i++)
139+ n += runelen(p[i]);
140+ return n;
141+}
142+
143+int
144+fullrune(const char *s, size_t len)
145+{
146+ Rune r;
147+
148+ return charntorune(&r, s, len) > 0;
149+}
A
term.c
+459,
-0
1@@ -0,0 +1,459 @@
2+/* Copyright (c) 1985 Ceriel J.H. Jacobs */
3+
4+/*
5+ * Terminal handling routines, mostly initializing.
6+ */
7+
8+#include "in_all.h"
9+#include "term.h"
10+#include "machine.h"
11+#include "output.h"
12+#include "display.h"
13+#include "options.h"
14+#include "getline.h"
15+#include "keys.h"
16+#include "main.h"
17+#define getline yap_getline
18+#define getch yap_getch
19+#include <term.h>
20+#undef getch
21+#undef getline
22+#undef insert_line
23+
24+int expandtabs;
25+int stupid;
26+int hardcopy;
27+char *CE, *CL, *SO, *SE, *US, *UE, *UC, *MD, *ME, *TI, *TE, *CM, *TA, *SR, *AL;
28+char *UP, *HO, *BO;
29+int LINES, COLS, AM, XN, DB;
30+int erasech, killch;
31+struct state *sppat;
32+char *BC;
33+
34+#ifdef TIOCGWINSZ
35+static struct winsize w;
36+#endif
37+
38+#ifdef TIOCSPGRP
39+static int proc_id, saved_pgrpid;
40+#endif
41+
42+static char *ll;
43+
44+struct linelist _X[100]; /* 100 is enough ? */
45+
46+static struct termios _tty, _svtty;
47+
48+static void
49+handle(cc_t *c)
50+{ /* if character *c is used, set it to undefined */
51+
52+ if (isused(*c))
53+ *c = 0xff;
54+}
55+
56+/*
57+ * Set terminal in cbreak mode.
58+ * Also check if tabs need expanding.
59+ */
60+
61+void
62+inittty()
63+{
64+ struct termios *p = &_tty;
65+
66+ tcgetattr(0, p);
67+ _svtty = *p;
68+ p->c_oflag &= ~OPOST;
69+ p->c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL | ICANON);
70+ if (isused('S' & 0x1f) || isused('Q' & 0x1f))
71+ p->c_iflag &= ~IXON;
72+ handle(&p->c_cc[VINTR]);
73+ handle(&p->c_cc[VQUIT]);
74+ erasech = p->c_cc[VERASE];
75+ killch = p->c_cc[VKILL];
76+ p->c_cc[VMIN] = 1; /* Just wait for one character */
77+ p->c_cc[VTIME] = 0;
78+ tcsetattr(0, TCSANOW, p);
79+}
80+
81+void
82+backspace()
83+{
84+ putline(BC);
85+}
86+
87+void
88+clrscreen()
89+{
90+ tputs(CL, LINES, fputch);
91+}
92+
93+void
94+clrtoeol()
95+{
96+ tputs(CE, 1, fputch);
97+}
98+
99+void
100+scrollreverse()
101+{
102+ tputs(SR, LINES, fputch);
103+}
104+
105+void
106+standout()
107+{
108+ tputs(SO, 1, fputch);
109+}
110+
111+void
112+standend()
113+{
114+ tputs(SE, 1, fputch);
115+}
116+
117+void
118+underline()
119+{
120+ tputs(US, 1, fputch);
121+}
122+
123+void
124+end_underline()
125+{
126+ tputs(UE, 1, fputch);
127+}
128+
129+void
130+bold()
131+{
132+ tputs(MD, 1, fputch);
133+}
134+
135+void
136+end_bold()
137+{
138+ tputs(ME, 1, fputch);
139+}
140+
141+void
142+underchar()
143+{
144+ tputs(UC, 1, fputch);
145+}
146+
147+void
148+givetab()
149+{
150+ tputs(TA, 1, fputch);
151+}
152+
153+/*
154+ * Reset the terminal to its original state
155+ */
156+
157+void
158+resettty()
159+{
160+ tcsetattr(0, TCSANOW, &_svtty);
161+ putline(TE);
162+ flush();
163+}
164+
165+/*
166+ * Get string terminal capability "cap".
167+ * If not present, return an empty string.
168+ */
169+
170+static char *
171+getcap(char *cap)
172+{
173+ char *s;
174+
175+ s = tigetstr(cap);
176+ if (!s || s == (char *)-1)
177+ return "";
178+ return s;
179+}
180+
181+static int
182+getflag(char *cap)
183+{
184+ int value;
185+
186+ value = tigetflag(cap);
187+ return value < 0 ? 0 : value;
188+}
189+
190+static int
191+getnumcap(char *cap)
192+{
193+ int value;
194+
195+ value = tigetnum(cap);
196+ return value < 0 ? -1 : value;
197+}
198+
199+/*
200+ * Initialize some terminal-dependent stuff.
201+ */
202+
203+void
204+ini_terminal()
205+{
206+
207+ char *s;
208+ struct linelist *lp, *lp1;
209+ int i;
210+ int UG, SG;
211+ char tempbuf[20];
212+ char *mb, *mh, *mr; /* attributes */
213+ int err;
214+
215+ initkeys();
216+#ifdef TIOCSPGRP
217+ proc_id = getpid();
218+ ioctl(0, TIOCGPGRP, (char *)&saved_pgrpid);
219+#endif
220+ inittty();
221+ stupid = 1;
222+ BC = "\b";
223+ TA = "\t";
224+ if (!(s = getenv("TERM")))
225+ s = "dumb";
226+ if (setupterm(s, 1, &err) != 0) {
227+ panic("No terminfo entry");
228+ }
229+ stupid = 0;
230+ hardcopy = getflag("hc"); /* Hard copy terminal?*/
231+ if (*(s = getcap("cub1"))) {
232+ /*
233+ * Backspace if not ^H
234+ */
235+ BC = s;
236+ }
237+ UP = getcap("cuu1"); /* move up a line */
238+ CE = getcap("el"); /* clear to end of line */
239+ CL = getcap("clear"); /* clear screen */
240+ if (!*CL)
241+ cflag = 1;
242+ TI = getcap("smcup"); /* Initialization for CM */
243+ TE = getcap("rmcup"); /* end for CM */
244+ CM = getcap("cup"); /* cursor addressing */
245+ SR = getcap("ri"); /* scroll reverse */
246+ AL = getcap("il"); /* Insert line */
247+ SO = getcap("smso"); /* standout */
248+ SE = getcap("rmso"); /* standend */
249+ SG = getnumcap("xmc"); /* blanks left by attributes */
250+ if (SG < 0)
251+ SG = 0;
252+ US = getcap("smul"); /* underline */
253+ UE = getcap("rmul"); /* end underline */
254+ UG = getnumcap("xmc"); /* blanks left by attributes */
255+ if (UG < 0)
256+ UG = 0;
257+ UC = getcap("uc"); /* underline a character */
258+ mb = getcap("blink"); /* blinking attribute */
259+ MD = getcap("bold"); /* bold attribute */
260+ ME = getcap("sgr0"); /* turn off attributes */
261+ mh = getcap("dim"); /* half bright attribute */
262+ mr = getcap("rev"); /* reversed video attribute */
263+ if (!nflag) {
264+ /*
265+ * Recognize special strings
266+ */
267+ (void)addstring(SO, SG, &sppat);
268+ (void)addstring(SE, SG, &sppat);
269+ (void)addstring(US, UG, &sppat);
270+ (void)addstring(UE, UG, &sppat);
271+ (void)addstring(mb, 0, &sppat);
272+ (void)addstring(MD, 0, &sppat);
273+ (void)addstring(ME, 0, &sppat);
274+ (void)addstring(mh, 0, &sppat);
275+ (void)addstring(mr, 0, &sppat);
276+ if (*UC) {
277+ (void)strcpy(tempbuf, BC);
278+ (void)strcat(tempbuf, UC);
279+ (void)addstring(tempbuf, 0, &sppat);
280+ }
281+ }
282+ if (UG > 0 || uflag) {
283+ US = "";
284+ UE = "";
285+ }
286+ if (*US || uflag)
287+ UC = "";
288+ COLS = getnumcap("cols"); /* columns on page */
289+ i = getnumcap("lines"); /* Lines on page */
290+ AM = getflag("am"); /* terminal wraps automatically? */
291+ XN = getflag("xenl"); /* and then ignores next newline? */
292+ DB = getflag("db"); /* terminal retains lines below */
293+ HO = getcap("home");
294+ if (!*HO && *CM) {
295+ HO = tiparm(CM, 0, 0); /* Another way of getting home */
296+ }
297+ if ((!*CE && !*AL) || !*HO || hardcopy) {
298+ cflag = stupid = 1;
299+ }
300+ if (*(s = getcap("ht"))) {
301+ /*
302+ * Tab (other than ^I or padding)
303+ */
304+ TA = s;
305+ }
306+ if (!*(ll = getcap("ll")) && *CM && i > 0) {
307+ /*
308+ * Lower left hand corner
309+ */
310+ BO = tiparm(CM, i - 1, 0);
311+ } else
312+ BO = ll;
313+ if (COLS <= 0 || COLS > 256) {
314+ if ((unsigned)COLS >= 65409) {
315+ /* SUN bug */
316+ COLS &= 0xffff;
317+ COLS -= (65409 - 128);
318+ }
319+ if (COLS <= 0 || COLS > 256)
320+ COLS = 80;
321+ }
322+ if (i <= 0) {
323+ i = 24;
324+ cflag = stupid = 1;
325+ }
326+ LINES = i;
327+ maxpagesize = i - 1;
328+ scrollsize = maxpagesize / 2;
329+ if (scrollsize <= 0)
330+ scrollsize = 1;
331+ if (!pagesize || pagesize >= i) {
332+ pagesize = maxpagesize;
333+ }
334+
335+ /*
336+ * The next part does not really belong here, but there it is ...
337+ * Initialize a circular list for the screenlines.
338+ */
339+
340+ scr_info.tail = lp = _X;
341+ lp1 = lp + (100 - 1);
342+ for (; lp <= lp1; lp++) {
343+ /*
344+ * Circular doubly linked list
345+ */
346+ lp->next = lp + 1;
347+ lp->prev = lp - 1;
348+ }
349+ lp1->next = scr_info.tail;
350+ lp1->next->prev = lp1;
351+ if (stupid) {
352+ BO = "\r\n";
353+ }
354+ putline(TI);
355+ window();
356+}
357+
358+/*
359+ * Place cursor at start of line n.
360+ */
361+
362+void
363+mgoto(int n)
364+{
365+
366+ if (n == 0)
367+ home();
368+ else if (n == maxpagesize && *BO)
369+ bottom();
370+ else if (*CM) {
371+ /*
372+ * Cursor addressing
373+ */
374+ tputs(tiparm(CM, n, 0), 1, fputch);
375+ } else if (*BO && *UP && n >= (maxpagesize >> 1)) {
376+ /*
377+ * Bottom and then up
378+ */
379+ bottom();
380+ while (n++ < maxpagesize)
381+ putline(UP);
382+ } else { /* Home, and then down */
383+ home();
384+ while (n--)
385+ putline("\r\n");
386+ }
387+}
388+
389+/*
390+ * Clear bottom line
391+ */
392+
393+void
394+clrbline()
395+{
396+
397+ if (stupid) {
398+ putline("\r\n");
399+ return;
400+ }
401+ bottom();
402+ if (*CE) {
403+ /*
404+ * We can clear to end of line
405+ */
406+ clrtoeol();
407+ return;
408+ }
409+ ins_line(maxpagesize);
410+}
411+
412+void
413+ins_line(int l)
414+{
415+ tputs(tiparm(AL, l), maxpagesize - l, fputch);
416+}
417+
418+void
419+home()
420+{
421+
422+ tputs(HO, 1, fputch);
423+}
424+
425+void
426+bottom()
427+{
428+
429+ tputs(BO, 1, fputch);
430+ if (!*BO)
431+ mgoto(maxpagesize);
432+}
433+
434+int
435+window()
436+{
437+#ifdef TIOCGWINSZ
438+ if (ioctl(1, TIOCGWINSZ, &w) < 0)
439+ return 0;
440+
441+ if (w.ws_col == 0)
442+ w.ws_col = COLS;
443+ if (w.ws_row == 0)
444+ w.ws_row = LINES;
445+ if (w.ws_col != COLS || w.ws_row != LINES) {
446+ COLS = w.ws_col;
447+ LINES = w.ws_row;
448+ maxpagesize = LINES - 1;
449+ pagesize = maxpagesize;
450+ if (!*ll)
451+ BO = tiparm(CM, maxpagesize, 0);
452+ scr_info.currentpos = 0;
453+ scrollsize = maxpagesize / 2;
454+ if (scrollsize <= 0)
455+ scrollsize = 1;
456+ return 1;
457+ }
458+#endif
459+ return 0;
460+}
A
term.h
+61,
-0
1@@ -0,0 +1,61 @@
2+#ifndef TERM_H
3+#define TERM_H
4+
5+extern int expandtabs;
6+extern int stupid;
7+extern int hardcopy;
8+
9+extern char *CE;
10+extern char *CL;
11+extern char *SO;
12+extern char *SE;
13+extern char *US;
14+extern char *UE;
15+extern char *UC;
16+extern char *MD;
17+extern char *ME;
18+extern char *TI;
19+extern char *TE;
20+extern char *CM;
21+extern char *TA;
22+extern char *SR;
23+extern char *AL;
24+extern char *UP;
25+extern char *HO;
26+extern char *BO;
27+
28+extern int LINES;
29+extern int COLS;
30+extern int AM;
31+extern int XN;
32+extern int DB;
33+
34+extern int erasech;
35+extern int killch;
36+extern struct state *sppat;
37+extern char *BC;
38+
39+void inittty(void);
40+void resettty(void);
41+void ini_terminal(void);
42+void backspace(void);
43+void clrscreen(void);
44+void clrtoeol(void);
45+void scrollreverse(void);
46+void standout(void);
47+void standend(void);
48+void underline(void);
49+void end_underline(void);
50+void bold(void);
51+void end_bold(void);
52+void underchar(void);
53+void givetab(void);
54+void mgoto(int n);
55+void clrbline(void);
56+void home(void);
57+void bottom(void);
58+int window(void);
59+void ins_line(int l);
60+#define insert_line(l) ins_line(l)
61+
62+#endif
A
utf.h
+69,
-0
1@@ -0,0 +1,69 @@
2+/* MIT/X Consortium Copyright (c) 2012 Connor Lane Smith <cls@lubutu.com>
3+ *
4+ * Permission is hereby granted, free of charge, to any person obtaining a
5+ * copy of this software and associated documentation files (the "Software"),
6+ * to deal in the Software without restriction, including without limitation
7+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8+ * and/or sell copies of the Software, and to permit persons to whom the
9+ * Software is furnished to do so, subject to the following conditions:
10+ *
11+ * The above copyright notice and this permission notice shall be included in
12+ * all copies or substantial portions of the Software.
13+ *
14+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20+ * DEALINGS IN THE SOFTWARE.
21+ */
22+#include <stdio.h>
23+
24+typedef int Rune;
25+
26+enum {
27+ UTFmax = 6, /* maximum bytes per rune */
28+ Runeself = 0x80, /* rune and utf are equal (<) */
29+ Runeerror = 0xFFFD, /* decoding error in utf */
30+ Runemax = 0x10FFFF /* maximum rune value */
31+};
32+
33+int runetochar(char *, const Rune *);
34+int chartorune(Rune *, const char *);
35+int charntorune(Rune *, const char *, size_t);
36+int runelen(Rune);
37+size_t runenlen(const Rune *, size_t);
38+int fullrune(const char *, size_t);
39+char *utfecpy(char *, char *, const char *);
40+size_t utflen(const char *);
41+size_t utfnlen(const char *, size_t);
42+size_t utfmemlen(const char *, size_t);
43+char *utfrune(const char *, Rune);
44+char *utfrrune(const char *, Rune);
45+char *utfutf(const char *, const char *);
46+
47+int isalnumrune(Rune);
48+int isalpharune(Rune);
49+int isblankrune(Rune);
50+int iscntrlrune(Rune);
51+int isdigitrune(Rune);
52+int isgraphrune(Rune);
53+int islowerrune(Rune);
54+int isprintrune(Rune);
55+int ispunctrune(Rune);
56+int isspacerune(Rune);
57+int istitlerune(Rune);
58+int isupperrune(Rune);
59+int isxdigitrune(Rune);
60+
61+Rune tolowerrune(Rune);
62+Rune toupperrune(Rune);
63+
64+size_t utftorunestr(const char *, Rune *);
65+size_t utfntorunestr(const char *, size_t, Rune *);
66+
67+int fgetrune(Rune *, FILE *);
68+int efgetrune(Rune *, FILE *, const char *);
69+int fputrune(const Rune *, FILE *);
70+int efputrune(const Rune *, FILE *, const char *);