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