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