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