xref: /netbsd/external/bsd/nvi/dist/common/screen.c (revision cc73507a)
1 /*	$NetBSD: screen.c,v 1.8 2014/01/26 21:43:45 christos Exp $	*/
2 /*-
3  * Copyright (c) 1993, 1994
4  *	The Regents of the University of California.  All rights reserved.
5  * Copyright (c) 1993, 1994, 1995, 1996
6  *	Keith Bostic.  All rights reserved.
7  *
8  * See the LICENSE file for redistribution information.
9  */
10 
11 #include "config.h"
12 
13 #include <sys/cdefs.h>
14 #if 0
15 #ifndef lint
16 static const char sccsid[] = "Id: screen.c,v 10.22 2001/06/25 15:19:12 skimo Exp  (Berkeley) Date: 2001/06/25 15:19:12 ";
17 #endif /* not lint */
18 #else
19 __RCSID("$NetBSD: screen.c,v 1.8 2014/01/26 21:43:45 christos Exp $");
20 #endif
21 
22 #include <sys/types.h>
23 #include <sys/queue.h>
24 #include <sys/time.h>
25 
26 #include <bitstring.h>
27 #include <errno.h>
28 #include <limits.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <unistd.h>
33 
34 #include "common.h"
35 #include "../vi/vi.h"
36 
37 static int screen_end1(SCR *, int);
38 /*
39  * screen_init --
40  *	Do the default initialization of an SCR structure.
41  *
42  * PUBLIC: int screen_init __P((GS *, SCR *, SCR **));
43  */
44 int
screen_init(GS * gp,SCR * orig,SCR ** spp)45 screen_init(GS *gp, SCR *orig, SCR **spp)
46 {
47 	SCR *sp;
48 	size_t len;
49 
50 	*spp = NULL;
51 	CALLOC_RET(orig, sp, SCR *, 1, sizeof(SCR));
52 	*spp = sp;
53 
54 /* INITIALIZED AT SCREEN CREATE. */
55 	sp->id = ++gp->id;
56 	sp->refcnt = 1;
57 
58 	sp->gp = gp;			/* All ref the GS structure. */
59 
60 	sp->ccnt = 2;			/* Anything > 1 */
61 
62 	/*
63 	 * XXX
64 	 * sp->defscroll is initialized by the opts_init() code because
65 	 * we don't have the option information yet.
66 	 */
67 
68 	TAILQ_INIT(&sp->tiq);
69 
70 /* PARTIALLY OR COMPLETELY COPIED FROM PREVIOUS SCREEN. */
71 	if (orig == NULL) {
72 		sp->searchdir = NOTSET;
73 	} else {
74 		sp->wp = orig->wp;
75 
76 		/* Alternate file name. */
77 		if (orig->alt_name != NULL &&
78 		    (sp->alt_name = strdup(orig->alt_name)) == NULL)
79 			goto mem;
80 
81 		/* Last executed at buffer. */
82 		if (F_ISSET(orig, SC_AT_SET)) {
83 			F_SET(sp, SC_AT_SET);
84 			sp->at_lbuf = orig->at_lbuf;
85 		}
86 
87 		/* Retain searching/substitution information. */
88 		sp->searchdir = orig->searchdir == NOTSET ? NOTSET : FORWARD;
89 		if (orig->re != NULL && (sp->re =
90 		    v_wstrdup(sp, orig->re, orig->re_len)) == NULL)
91 			goto mem;
92 		sp->re_len = orig->re_len;
93 		if (orig->subre != NULL && (sp->subre =
94 		    v_wstrdup(sp, orig->subre, orig->subre_len)) == NULL)
95 			goto mem;
96 		sp->subre_len = orig->subre_len;
97 		if (orig->repl != NULL && (sp->repl =
98 		    v_wstrdup(sp, orig->repl, orig->repl_len)) == NULL)
99 			goto mem;
100 		sp->repl_len = orig->repl_len;
101 		if (orig->newl_len) {
102 			len = orig->newl_len * sizeof(size_t);
103 			MALLOC(sp, sp->newl, size_t *, len);
104 			if (sp->newl == NULL) {
105 mem:				msgq(orig, M_SYSERR, NULL);
106 				goto err;
107 			}
108 			sp->newl_len = orig->newl_len;
109 			sp->newl_cnt = orig->newl_cnt;
110 			memcpy(sp->newl, orig->newl, len);
111 		}
112 
113 		if (opts_copy(orig, sp))
114 			goto err;
115 
116 		F_SET(sp, F_ISSET(orig, SC_EX | SC_VI));
117 	}
118 
119 	if (ex_screen_copy(orig, sp))		/* Ex. */
120 		goto err;
121 	if (v_screen_copy(orig, sp))		/* Vi. */
122 		goto err;
123 	sp->cl_private = 0;			/* XXX */
124 	conv_init(orig, sp);			/* XXX */
125 
126 	*spp = sp;
127 	return (0);
128 
129 err:	screen_fini(sp);
130 	return (1);
131 }
132 
133 static int
screen_end1(SCR * sp,int init)134 screen_end1(SCR *sp, int init)
135 {
136 	int rval;
137 
138 	/* If multiply referenced, just decrement the count and return. */
139 	if (--sp->refcnt != 0)
140 		return (0);
141 
142 	/*
143 	 * Remove the screen from the displayed queue.
144 	 *
145 	 * If a created screen failed during initialization, it may not
146 	 * be linked into the chain.
147 	 *
148 	 * XXX screen_end can be called multiple times, abuse the tqe_prev pointer
149 	 * to signal wether the tailq node is on-list.
150 	 */
151 	if (init && sp->q.tqe_prev) {
152 		TAILQ_REMOVE(&sp->wp->scrq, sp, q);
153 		sp->q.tqe_prev = NULL;
154 	}
155 
156 	/* The screen is no longer real. */
157 	F_CLR(sp, SC_SCR_EX | SC_SCR_VI);
158 
159 	rval = 0;
160 #ifdef HAVE_PERL_INTERP
161 	if (perl_screen_end(sp))		/* End perl. */
162 		rval = 1;
163 #endif
164 	if (v_screen_end(sp))			/* End vi. */
165 		rval = 1;
166 	if (ex_screen_end(sp))			/* End ex. */
167 		rval = 1;
168 
169 	/* Free file names. */
170 	{ char **ap;
171 		if (!F_ISSET(sp, SC_ARGNOFREE) && sp->argv != NULL) {
172 			for (ap = sp->argv; *ap != NULL; ++ap)
173 				free(*ap);
174 			free(sp->argv);
175 		}
176 	}
177 
178 	/* Free any text input. */
179 	if (!TAILQ_EMPTY(&sp->tiq))
180 		text_lfree(&sp->tiq);
181 
182 	/* Free alternate file name. */
183 	if (sp->alt_name != NULL)
184 		free(sp->alt_name);
185 
186 	/* Free up search information. */
187 	if (sp->re != NULL)
188 		free(sp->re);
189 	if (F_ISSET(sp, SC_RE_SEARCH))
190 		regfree(&sp->re_c);
191 	if (sp->subre != NULL)
192 		free(sp->subre);
193 	if (F_ISSET(sp, SC_RE_SUBST))
194 		regfree(&sp->subre_c);
195 	if (sp->repl != NULL)
196 		free(sp->repl);
197 	if (sp->newl != NULL)
198 		free(sp->newl);
199 
200 	/* Free all the options */
201 	opts_free(sp);
202 
203 	/* Free the screen itself. */
204 	free(sp);
205 
206 	return (rval);
207 }
208 
209 /*
210  * screen_fini --
211  *	Release a screen, that has not been chained to the screen queues.
212  *
213  * PUBLIC: int screen_fini __P((SCR *));
214  */
215 int
screen_fini(SCR * sp)216 screen_fini(SCR *sp)
217 {
218 	return screen_end1(sp, 0);
219 }
220 
221 /*
222  * screen_end --
223  *	Release a screen, that has been chained to the screen queues.
224  *
225  * PUBLIC: int screen_end __P((SCR *));
226  */
227 int
screen_end(SCR * sp)228 screen_end(SCR *sp)
229 {
230 	return screen_end1(sp, 1);
231 }
232 /*
233  * screen_next --
234  *	Return the next screen in the queue.
235  *
236  * PUBLIC: SCR *screen_next __P((SCR *));
237  */
238 SCR *
screen_next(SCR * sp)239 screen_next(SCR *sp)
240 {
241 	GS *gp;
242 	WIN *wp;
243 	SCR *next;
244 
245 	/* Try the display queue, without returning the current screen. */
246 	gp = sp->gp;
247 	wp = sp->wp;
248 	TAILQ_FOREACH(next, &wp->scrq, q)
249 		if (next != sp)
250 			break;
251 	if (next != NULL)
252 		return (next);
253 
254 	/* Try the hidden queue; if found, move screen to the display queue. */
255 	if ((next = TAILQ_FIRST(&gp->hq)) != NULL) {
256 		TAILQ_REMOVE(&gp->hq, next, q);
257 		TAILQ_INSERT_HEAD(&wp->scrq, next, q);
258 		next->wp = sp->wp;
259 		return (next);
260 	}
261 	return (NULL);
262 }
263