1 /* @(#)quitcmds.c	1.64 09/07/13 Copyright 1984-1989, 1994-2009 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static	UConst char sccsid[] =
5 	"@(#)quitcmds.c	1.64 09/07/13 Copyright 1984-1989, 1994-2009 J. Schilling";
6 #endif
7 /*
8  *	Commands that deal with exiting the editor in a clean state
9  *
10  *	Copyright (c) 1984-1989, 1994-2009 J. Schilling
11  */
12 /*
13  * The contents of this file are subject to the terms of the
14  * Common Development and Distribution License, Version 1.0 only
15  * (the "License").  You may not use this file except in compliance
16  * with the License.
17  *
18  * See the file CDDL.Schily.txt in this distribution for details.
19  * A copy of the CDDL is also available via the Internet at
20  * http://www.opensource.org/licenses/cddl1.txt
21  *
22  * When distributing Covered Code, include this CDDL HEADER in each
23  * file and include the License file CDDL.Schily.txt from this distribution.
24  */
25 
26 #include "ved.h"
27 #include <schily/unistd.h>
28 #include <schily/fcntl.h>
29 #include <schily/dirent.h>
30 #include <schily/signal.h>
31 #include <schily/errno.h>
32 
33 EXPORT	BOOL	bakbuf		__PR((ewin_t *wp, BOOL force));
34 EXPORT	BOOL	writebuf	__PR((ewin_t *wp, BOOL force));
35 EXPORT	void	vbackup		__PR((ewin_t *wp));
36 EXPORT	void	vquit		__PR((ewin_t *wp));
37 EXPORT	void	eexit		__PR((ewin_t *wp));
38 EXPORT	void	vsusp		__PR((ewin_t *wp));
39 LOCAL	void	suspendme	__PR((ewin_t *wp));
40 #ifndef	JOS
41 LOCAL	int	suspend		__PR((int p));
42 #endif
43 
44 
45 /*
46  * Write back the content of the current file buffer,
47  * create a backup file if 'nobak' is not set.
48  */
49 EXPORT BOOL
bakbuf(wp,force)50 bakbuf(wp, force)
51 	ewin_t	*wp;
52 	BOOL	force;
53 {
54 		Uchar	backup[FNAMESIZE+4];	/* += strlen(".bak");	*/
55 	register Uchar	*t;
56 	register Uchar	*s;
57 	int	 oldmodes;
58 	BOOL	 backpresent = TRUE;
59 
60 	if (wrtcheck(wp, TRUE) == FALSE) {
61 		if (!force)
62 			return (FALSE);
63 	}
64 	if (modcheck(wp) == FALSE) {
65 		if (!force)
66 			return (FALSE);
67 		sleep(1);
68 	}
69 
70 	oldmodes = getfmodes(wp->curfile);
71 	strcpy(C backup, C wp->curfile);
72 	s = t = backup;
73 	while (*t) {			/* find rightmost '/'		    */
74 		if (*t++ == '/')
75 			s = t;
76 	}
77 
78 #ifdef	FOUND_DIRSIZE
79 	if (t - s >= DIRSIZE)		/* If ".bak" would not fit, trucate */
80 		t = s + DIRSIZE - 4;
81 #endif
82 
83 	strcpy(C t, ".bak");		/* add the the ".bak" extension	    */
84 	if (rename(C wp->curfile, C backup) < 0) { /* rename old curfile to backup */
85 		backpresent = FALSE;
86 		if (geterrno() != ENOENT)
87 			writemsg(wp, "Can't make *.bak file");
88 	}
89 
90 	if (!writebuf(wp, force)) {	/* if writeback failed ... */
91 		if (backpresent)	/* rename backup to orig file name */
92 			rename(C backup, C wp->curfile);
93 		return (FALSE);
94 	}
95 	if (oldmodes >= 0)
96 		chmod(C wp->curfile, oldmodes);
97 	if (nobak)
98 		unlink(C backup);
99 	return (TRUE);
100 }
101 
102 /*
103  * Write back the content of the current file buffer,
104  * do not reate a backup file, write into the currently edited file.
105  */
106 EXPORT BOOL
writebuf(wp,force)107 writebuf(wp, force)
108 	ewin_t	*wp;
109 	BOOL	force;
110 {
111 	FILE	*outfile;
112 	BOOL	ret = TRUE;
113 #ifdef	HAVE_FSYNC
114 	int	err;
115 	int	cnt;
116 #endif
117 
118 	if ((!force || ReadOnly > 1) && wrtcheck(wp, TRUE) == FALSE)
119 		return (FALSE);
120 
121 	if (modcheck(wp) == FALSE) {
122 		if (!force)
123 			return (FALSE);
124 		sleep(1);
125 	}
126 	/*
127 	 * create outfile
128 	 */
129 	if ((outfile = opensyserr(wp, wp->curfile, "ctwub")) == NULL) {
130 		return (FALSE);
131 	}
132 	lockfd(fdown(outfile));
133 
134 	/*
135 	 * If writeback failed for some reason, return FALSE.
136 	 * Be very serious that the file could actually written back correctly.
137 	 */
138 	if (wp->eof != 0 && !savefile(wp, (epos_t)0, wp->eof, outfile, "FILE"))
139 		ret = FALSE;
140 	if (fflush(outfile) != 0)
141 		ret = FALSE;
142 #ifdef	HAVE_FSYNC
143 	err = 0;
144 	cnt = 0;
145 	do {
146 		if (fsync(fdown(outfile)) != 0)
147 			err = geterrno();
148 
149 		if (err == EINVAL)
150 			err = 0;
151 	} while (err == EINTR && ++cnt < 10);
152 	if (err != 0)
153 		ret = FALSE;
154 #endif
155 	if (fclose(outfile) != 0)
156 		ret = FALSE;
157 
158 	if (ret == FALSE)
159 		write_errno(wp, "CAN'T PUT %s", wp->curfile);
160 	return (ret);
161 }
162 
163 /*
164  * Do a backup write of the current file,
165  * create a backup file if required.
166  */
167 EXPORT void
vbackup(wp)168 vbackup(wp)
169 	ewin_t	*wp;
170 {
171 	int	c;
172 
173 	switch (c = getcmdchar(wp, NULL, "BACKUP?(Y/W/N/F/!) ")) {
174 
175 	default:
176 		abortmsg(wp);
177 		/* FALLTHROUGH */
178 	case 0:			/* aborted */
179 	case 'n':
180 	case 'N':
181 		return;
182 	case 'w':
183 	case 'W':
184 	case '!':
185 		if (!writebuf(wp, c == '!'))
186 			return;
187 		goto go_on;
188 	case 'y':
189 	case 'Y':
190 	case 'f':
191 	case 'F':
192 		if (!bakbuf(wp, c == 'f' || c == 'F'))
193 			return;
194 	go_on:
195 		newprot(wp);
196 		wp->modflg = 0;
197 		wp->curftime = gftime(C wp->curfile);
198 		defaultinfo(wp, UC NULL);
199 	}
200 }
201 
202 /*
203  * Quit the editor, ask if the current buffer should be saved.
204  */
205 EXPORT void
vquit(wp)206 vquit(wp)
207 	ewin_t	*wp;
208 {
209 	int	c;
210 
211 	vedstopstats();
212 
213 	if (wp->modflg)
214 		writeerr(wp, "FILE MODIFIED!");
215 
216 	switch (c = getcmdchar(wp, NULL, "QUITTING. PUT EDITS?(Y/W/N/F/!) ")) {
217 
218 	default:
219 		abortmsg(wp);
220 		/* FALLTHROUGH */
221 	case 0:
222 		return;			/* aborted */
223 	case 'w':
224 	case 'W':
225 	case '!':
226 		if (!writebuf(wp, c == '!'))
227 			return;
228 		goto ex_it;
229 	case 'y':
230 	case 'Y':
231 	case 'f':
232 	case 'F':
233 		if (!bakbuf(wp, c == 'f' || c == 'F'))
234 			return;
235 		/* FALLTHROUGH */
236 	case 'n':
237 	case 'N':
238 	ex_it:
239 		put_vedtmp(wp, TRUE);
240 		eexit(wp);
241 		exit(0);
242 	}
243 }
244 
245 /*
246  * Exit the editor, reset the terminal, the tty driver and
247  * delete temporary files.
248  */
249 EXPORT void
eexit(wp)250 eexit(wp)
251 	ewin_t	*wp;
252 {
253 	rsttmodes(wp);
254 	tmpcleanup(wp, TRUE);
255 	vedstatistics();
256 }
257 
258 /*
259  * Suspend the editor, ask if the current buffer should be saved.
260  */
261 EXPORT void
vsuspend(wp)262 vsuspend(wp)
263 	ewin_t	*wp;
264 {
265 #if	defined(SIGSTOP) || defined(JOS)
266 	int	c;
267 
268 	if (wp->modflg)
269 		writeerr(wp, "FILE MODIFIED!");
270 
271 	switch (c = getcmdchar(wp, NULL, "SUSPENDING. PUT EDITS?(Y/W/N/F/!) ")) {
272 
273 	default:
274 		abortmsg(wp);
275 		/* FALLTHROUGH */
276 	case 0:
277 		return;			/* aborted */
278 	case 'w':
279 	case 'W':
280 	case '!':
281 		if (!writebuf(wp, c == '!'))
282 			return;
283 		goto go_on;
284 	case 'y':
285 	case 'Y':
286 	case 'f':
287 	case 'F':
288 		if (!bakbuf(wp, c == 'f' || c == 'F'))
289 			return;
290 	go_on:
291 		wp->modflg = 0;
292 		wp->curftime = gftime(C wp->curfile);
293 		defaultinfo(wp, UC NULL);
294 		newprot(wp);
295 		/* FALLTHROUGH */
296 	case 'n':
297 	case 'N':
298 		suspendme(wp);
299 	}
300 #else
301 	writeerr(wp, "NOT IMPLEMENTED!");
302 #endif
303 }
304 
305 /*
306  * Suspend the editor, reset the terminal, the tty driver,
307  * do not delete temporary files.
308  * Reset terminal and tty state on continue.
309  */
310 #if	defined(SIGSTOP) || defined(JOS)
311 LOCAL void
suspendme(wp)312 suspendme(wp)
313 	ewin_t	*wp;
314 {
315 	rsttmodes(wp);
316 	suspend(0);
317 	settmodes(wp);
318 	vredisp(wp);
319 }
320 #endif
321 
322 /*
323  * Suspend a process
324  */
325 #ifndef	JOS
326 LOCAL int
suspend(p)327 suspend(p)
328 	int	p;
329 {
330 #ifdef	SIGSTOP
331 	return (kill(p, SIGSTOP));
332 #else
333 	raisecond("suspend not implemented", 0L);
334 #endif
335 }
336 #endif
337