1 /* @(#)filecmds.c	1.54 09/07/09 Copyright 1984-1986, 1989-2009 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static	UConst char sccsid[] =
5 	"@(#)filecmds.c	1.54 09/07/09 Copyright 1984-1986, 1989-2009 J. Schilling";
6 #endif
7 /*
8  *	Commands that deal with filenames and read/write of files
9  *
10  *	Copyright (c) 1984-1986, 1989-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 "buffer.h"
28 #include "terminal.h"
29 #include <schily/wait.h>
30 
31 EXPORT	void	vread		__PR((ewin_t *wp));
32 EXPORT	void	vwrite		__PR((ewin_t *wp));
33 LOCAL	BOOL	shellspecial	__PR((Uchar *pattern, int length));
34 LOCAL	int	glob		__PR((ewin_t *wp, Uchar* buf));
35 EXPORT	void	vchange		__PR((ewin_t *wp));
36 EXPORT	BOOL	change_file	__PR((ewin_t *wp, Uchar* file));
37 EXPORT	void	fchange		__PR((ewin_t *wp, Uchar* file));
38 EXPORT	void	vswrite		__PR((ewin_t *wp));
39 
40 /*
41  * Read a file into the current buffer
42  */
43 EXPORT void
vread(wp)44 vread(wp)
45 	ewin_t	*wp;
46 {
47 	register epos_t	savedot = wp->dot;
48 	int	len;
49 	Uchar	name[FNAMESIZE];
50 
51 	if (! (len = getcmdline(wp, name, sizeof (name), "Get from: ")))
52 		return;
53 	if (!issimple(name, len) || shellspecial(name, len))
54 		if (!glob(wp, name))
55 			return;
56 	loadfile(wp, name, FALSE);
57 	if (wp->dot == savedot)		/*  Did not load anything.  */
58 		return;
59 	dispup(wp, wp->dot, savedot);
60 	wp->dot = savedot;
61 	modified(wp);
62 }
63 
64 /*
65  * Write current buffer to a file.
66  */
67 EXPORT void
vwrite(wp)68 vwrite(wp)
69 	ewin_t	*wp;
70 {
71 	FILE	*f;
72 	int	len;
73 	Uchar	name[FNAMESIZE];
74 
75 	if (! (len = getcmdline(wp, name, sizeof (name), "Write to: ")))
76 		return;
77 	if (!issimple(name, len) || shellspecial(name, len))
78 		if (!glob(wp, name))
79 			return;
80 	if ((f = opensyserr(wp, name, "ctwub")) == (FILE *) NULL)
81 		return;
82 	lockfd(fdown(f));
83 	if (savefile(wp, (epos_t)0, wp->eof, f, "FILE")) {
84 		wp->modflg = 0;
85 		defaultinfo(wp, UC NULL);
86 	}
87 	fclose(f);
88 }
89 
90 /*
91  * Check if the pattern  contains shell special characters
92  * that (in addition to patthern matching characters) will
93  * expand filenames.
94  */
95 LOCAL BOOL
shellspecial(pattern,length)96 shellspecial(pattern, length)
97 	register Uchar *pattern;
98 	register int length;
99 {
100 	while (length-- > 0) {
101 		switch (*pattern++) {
102 
103 		case '~':
104 			return (TRUE);
105 		}
106 	}
107 	return (FALSE);
108 }
109 
110 /*
111  * Let shell do filename globbing - pipe buffer through shell.
112  */
113 LOCAL int
glob(wp,buf)114 glob(wp, buf)
115 	ewin_t	*wp;
116 	Uchar	*buf;
117 {
118 #ifdef	HAVE_FORK
119 	FILE	*pp[2];
120 	int	mypid;
121 	char	*sh;
122 	char	cmd[FNAMESIZE+5];	/* + strlen ("echo ") */
123 	char	tmp[FNAMESIZE];
124 
125 	if ((sh = getenv("SHELL")) == NULL)
126 		sh = "/bin/sh";
127 
128 	strcatl(cmd, "echo ", buf, (char *)NULL);
129 /*	cdbg("cmd: %s\n", cmd);*/
130 	if (fpipe(pp) == 0) {
131 		write_errno(wp, "Glob pipe failed");
132 		return (0);
133 	}
134 	mypid = fork();
135 	if (mypid < 0) {
136 		write_errno(wp, "Glob fork failed");
137 		return (0);
138 	}
139 	if (mypid == 0) {
140 		FILE	*null;
141 
142 		fclose(pp[0]);
143 
144 		/* We don't want to see errors */
145 		null = fileopen("/dev/null", "rwb");
146 
147 		fexecl(sh, null, pp[1], null, "sh", "-c", cmd, (char *)NULL);
148 		write_errno(wp, "Glob exec failed");
149 		_exit(-1);
150 	}
151 	fclose(pp[1]);
152 	tmp[0] = '\0';
153 	fgetline(pp[0], tmp, sizeof (tmp));
154 	fclose(pp[0]);
155 	wait(0);
156 /*	cdbg("line: '%s'\n", tmp);*/
157 	if (strchr(tmp, ' ')) {
158 		writeerr(wp, "Ambiguous");
159 		return (0);
160 	}
161 	strcpy(C buf, tmp);
162 	return (1);
163 #else
164 	writeerr(wp, "Glob not available");
165 	return (0);
166 #endif
167 }
168 
169 /*
170  * Replace the current file in current buffer
171  */
172 EXPORT void
vchange(wp)173 vchange(wp)
174 	ewin_t	*wp;
175 {
176 	int	len;
177 	Uchar	name[FNAMESIZE];
178 
179 	/*
180 	 * Get the new filename, abort on empty input.
181 	 */
182 	if (! (len = getcmdline(wp, name, sizeof (name), "Change to: ")))
183 		return;
184 	if (!issimple(name, len) || shellspecial(name, len))
185 		if (!glob(wp, name))
186 			return;
187 
188 	if (!change_file(wp, name))
189 		return;
190 
191 	newwindow(wp);
192 }
193 
194 /*
195  * Ask the user if and how the old file should be written back.
196  */
197 EXPORT BOOL
change_file(wp,file)198 change_file(wp, file)
199 	ewin_t	*wp;
200 	Uchar	*file;
201 {
202 	int	c;
203 
204 	if (wp->modflg)
205 		writeerr(wp, "FILE MODIFIED!");
206 	if (wp->modflg || mflag) {
207 
208 		switch (c = getcmdchar(wp, NULL,
209 			"CHANGING TO: %s. PUT EDITS?(Y/W/N/F/!) ", file)) {
210 
211 		default:
212 			abortmsg(wp);
213 			/* FALLTHROUGH */
214 		case 0:
215 			return (FALSE);
216 		case 'n':
217 		case 'N':
218 			break;
219 		case 'w':
220 		case 'W':
221 		case '!':
222 			if (!writebuf(wp, c == '!'))
223 				return (FALSE);
224 			break;
225 		case 'y':
226 		case 'Y':
227 		case 'f':
228 		case 'F':
229 			if (!bakbuf(wp, c == 'f' || c == 'F'))
230 				return (FALSE);
231 		}
232 	}
233 	flush();
234 
235 	fchange(wp, file);
236 	return (TRUE);
237 }
238 
239 /*
240  * Replace the content of the buffer with new file and put new file on screen.
241  */
242 EXPORT void
fchange(wp,file)243 fchange(wp, file)
244 	ewin_t	*wp;
245 	Uchar *file;
246 {
247 	/*
248 	 * Delete the old file.
249 	 */
250 	wp->dot = 0;
251 	wp->markvalid = 0;
252 	delete(wp, wp->eof);
253 	bufdebug(wp);
254 	/*
255 	 * Load the new file.
256 	 */
257 	defaulterr(wp, UC NULL);
258 	wp->curftime = gftime(C file);
259 	loadfile(wp, file, TRUE);
260 	wp->dot = 0;
261 
262 	if (autodos)
263 		wp->dosmode = isdos(wp);
264 
265 	namemsg(file);
266 	strncpy(C curfname, C file, sizeof (curfname));
267 	curfname[sizeof (curfname)-1] = '\0';
268 	wp->curfile = curfname;
269 
270 	put_vedtmp(wp, TRUE);	/* save new filename */
271 	newprot(wp);		/* change Prot file */
272 
273 	wp->modflg = 0;
274 
275 	/*
276 	 * Put the new file on screen.
277 	 */
278 	CLEAR_SCREEN(wp);
279 	defaultinfo(wp, UC NULL);
280 	refreshmsg(wp);
281 	if (wp->dosmode)
282 		writemsg(wp, "DOS MODE");
283 	(void) wrtcheck(wp, FALSE);
284 	writelockmsg(wp);
285 }
286 
287 /*
288  * Save the content of the current selection (between cursor and mark) to file.
289  */
290 EXPORT void
vswrite(wp)291 vswrite(wp)
292 	ewin_t	*wp;
293 {
294 	FILE	*f;
295 	int	len;
296 	Uchar	name[FNAMESIZE];
297 	epos_t	begin = min(wp->dot, wp->mark);
298 	epos_t	end   = max(wp->dot, wp->mark);
299 
300 	/*
301 	 * Ask the user for the filename, abort on empty input.
302 	 */
303 	if (! (len = getcmdline(wp, name, sizeof (name), "Sel to: ")))
304 		return;
305 	if (!issimple(name, len) || shellspecial(name, len))
306 		if (!glob(wp, name))
307 			return;
308 	if ((f = opensyserr(wp, name, "ctwub")) == (FILE *) NULL)
309 		return;
310 	lockfd(fdown(f));
311 	savefile(wp, begin, end, f, "FILE");
312 	fclose(f);
313 }
314