1 /* io.c - file in/out and alloc subroutines for BVI
2  *
3  * 1996-02-28 V 1.0.0
4  * 1999-01-20 V 1.1.0
5  * 1999-04-27 V 1.1.1
6  * 1999-07-02 V 1.2.0 beta
7  * 1999-10-15 V 1.2.0 final
8  * 2000-03-23 V 1.3.0 beta
9  * 2000-08-17 V 1.3.0 final
10  * 2004-01-04 V 1.3.2
11  * 2010-06-02 V 1.3.4
12  * 2014-05-03 V 1.4.0
13  *
14  * NOTE: Edit this file with tabstop=4 !
15  *
16  * Copyright 1996-2014 by Gerhard Buergmann
17  * gerhard@puon.at
18  *
19  * This program is free software; you can redistribute it and/or modify it
20  * under the terms of the GNU General Public License as published by the
21  * Free Software Foundation; either version 2, or (at your option) any
22  * later version.
23  *
24  * This program is distributed in the hope that it will be useful, but
25  * WITHOUT ANY WARRANTY; without even the implied warranty of
26  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
27  * General Public License for more details.
28  *
29  * See file COPYING for information on distribution conditions.
30  */
31 
32 #include "bvi.h"
33 #include "set.h"
34 
35 #if 0
36 /* nowadays (2009) we should make sure that bvi is compiled with LFS support: */
37 /* defines _LARGEFILE_SOURCE _FILE_OFFSET_BITS=64 */
38 /* if compiled without LFS support, stat() open() lseek() will fail with */
39 /* EOVERFLOW(75)   Value too large for defined data type  */
40 /* see README for configure arguments to enable lfs support in 32-bit executables */
41 /* cygwin enables lfs by default */
42 #endif
43 
44 #include <limits.h>
45 #	ifndef OFF_T_MAX
46 #  		define OFF_T_MAX    ULONG_LONG_MAX
47 #	endif
48 
49 #ifdef HAVE_UNISTD_H
50 #	include <unistd.h>
51 #endif
52 
53 #ifdef HAVE_FCNTL_H
54 #	include <fcntl.h>
55 #endif
56 
57 int		filemode;
58 static	struct	stat	buf;
59 static	off_t	block_read;
60 char	*terminal;
61 
62 
63 /*********** Save the patched file ********************/
64 int
save(fname,start,end,flags)65 save(fname, start, end, flags)
66 	char	*fname;
67 	char	*start;
68 	char	*end;
69 	int		flags;
70 {
71 	int		fd;
72 	char	*string;
73 	char	*newstr;
74 	off_t	filesize;
75 
76 	if (!fname) {
77 		emsg("No file|No current filename");
78 		return 0;
79 	}
80 	string = malloc((size_t)strlen(fname) + MAXCMD);
81 	if (string == NULL) {
82 		emsg("Out of memory");
83 		return 0;
84 	}
85 	if (stat(fname, &buf) == -1) {
86 		newstr = "[New file] ";
87 	} else {
88 		if (S_ISDIR(buf.st_mode)) {
89 			sprintf(string, "\"%s\" Is a directory", fname);
90 			msg(string);
91 			free(string);
92 			return 0;
93 		} else if (S_ISCHR(buf.st_mode)) {
94 			sprintf(string, "\"%s\" Character special file", fname);
95 			msg(string);
96 			free(string);
97 			return 0;
98 		} else if (S_ISBLK(buf.st_mode)) {
99 			/*
100 			sprintf(string, "\"%s\" Block special file", fname);
101 			msg(string);
102 			return 0;
103 			*/
104 		}
105 		newstr = "";
106 	}
107 
108 	if (filemode == PARTIAL) flags = O_RDWR;
109 	if ((fd = open(fname, flags, 0666)) < 0) {
110         sysemsg(fname);
111 		free(string);
112 		return 0;
113 	}
114 	if (filemode == PARTIAL) {
115 		if (block_read) {
116 			filesize = block_read;
117 			sprintf(string, "\"%s\" range %llu-%llu", fname,
118 				(unsigned long long)block_begin,
119 				(unsigned long long)(block_begin - 1 + filesize));
120 			if (lseek(fd, block_begin, SEEK_SET) < 0) {
121 				sysemsg(fname);
122 				free(string);
123 				return 0;
124 			}
125 		} else {
126 			msg("Null range");
127 			free(string);
128 			return 0;
129         }
130 	} else {
131 		filesize = end - start + 1L;
132 
133 		sprintf(string, "\"%s\" %s%llu bytes", fname, newstr,
134 			(unsigned long long)filesize);
135 	}
136 
137 	if (write(fd, start, filesize) != filesize) {
138 		sysemsg(fname);
139 		free(string);
140 		close(fd);
141 		return 0;
142 	}
143 	close(fd);
144 	edits = 0;
145 	msg(string);
146 	free(string);
147 	return 1;
148 }
149 
150 
151 /* loads a file, returns the filesize */
152 off_t
load(fname)153 load(fname)
154 	char	*fname;
155 {
156 	int		fd = -1;
157 	char	*string;
158 
159 	buf.st_size = 0L;
160 	if (fname != NULL) {
161 		/*
162 		sprintf(string, "\"%s\"", fname);
163 		msg(string);
164 		refresh();
165 		*/
166 		if (stat(fname, &buf) == -1) {
167 		/* check for EOVERFLOW       75              */
168 		/* Value too large for defined data type     */
169 		/* means bvi is compiled without lfs support */
170 			if (errno == ENOENT) {
171 				filemode = NEW;
172 			} else {
173 				move(maxy, 0);
174 				endwin();
175 				perror(fname);
176 				exit(0);
177 			}
178 		/*
179 		} else if (S_ISDIR(buf.st_mode)) {
180 			filemode = DIRECTORY;
181 		*/
182 		} else if (S_ISCHR(buf.st_mode)) {
183 			filemode = CHARACTER_SPECIAL;
184 		} else if (S_ISBLK(buf.st_mode)) {
185 			filemode = BLOCK_SPECIAL;
186 			if (!block_flag) {
187 				block_flag = 1;
188 				block_begin = 0;
189 				block_size = 1024;
190 				block_end = block_begin + block_size - 1;
191 			}
192 			if ((fd = open(fname, O_RDONLY)) > 0) {
193 				P(P_RO) = TRUE;
194 				params[P_RO].flags |= P_CHANGED;
195 			} else {
196 				sysemsg(fname);
197 				filemode = ERROR;
198 			}
199 		} else if (S_ISREG(buf.st_mode) || S_ISDIR(buf.st_mode)) {
200 #if 0
201            /* stat() call above will fail if file is too large */
202            /* this size check will never fail                  */
203            if ((unsigned long long)buf.st_size > (unsigned long long)OFF_T_MAX) {
204 				move(maxy, 0);
205 				endwin();
206 				printf("File too large\n");
207 				exit(0);
208 			}
209 #endif
210 			if ((fd = open(fname, O_RDONLY)) > 0) {
211 				if (S_ISREG(buf.st_mode)) {
212 					filemode = REGULAR;
213 				} else {
214 					filemode = DIRECTORY;
215 				}
216 				if (access(fname, W_OK)) {
217 					P(P_RO) = TRUE;
218 					params[P_RO].flags |= P_CHANGED;
219 				}
220 			} else {
221 	            sysemsg(fname);
222 				filemode = ERROR;
223 			}
224 		}
225 	} else {
226 		filemode = NEW;
227 	}
228 	if (mem != NULL) free(mem);
229 	memsize = 1024;
230 	if (block_flag) {
231 		if (block_flag == BLOCK_BEGIN) {
232 			block_size = buf.st_size - block_begin;
233 		}
234 		memsize += block_size;
235 	} else if (filemode == REGULAR) {
236 		memsize += buf.st_size;
237 	}
238 	if ((mem = (char *)malloc(memsize)) == NULL) {
239 		move(maxy, 0);
240 		endwin();
241 		printf("Out of memory\n");
242 		exit(0);
243 	}
244 	clear_marks();
245 
246 	if (fname != NULL) {
247 		string = malloc((size_t)strlen(fname) + MAXCMD);
248 	} else {
249 		string = malloc(MAXCMD);
250 	}
251 	if (string == NULL) {
252 		emsg("Out of memory");
253 		return 0;
254 	}
255 
256 	if (block_flag && ((filemode == REGULAR) || (filemode == BLOCK_SPECIAL))) {
257 		if (lseek(fd, block_begin, SEEK_SET) < 0) {
258 			sysemsg(fname);
259 			filemode = ERROR;
260 		} else {
261 			if ((filesize = read(fd, mem, block_size)) == 0) {
262 				sprintf(string, "\"%s\" Empty file", fname);
263 				filemode = ERROR;
264 			} else {
265 				sprintf(string, "\"%s\" range %llu-%llu", fname,
266 					(unsigned long long)block_begin,
267 					(unsigned long long)(block_begin + filesize - 1));
268 				filemode = PARTIAL;
269 				block_read = filesize;
270 				P(P_OF) = block_begin;
271 				params[P_OF].flags |= P_CHANGED;
272 			}
273 			msg(string);
274 			refresh();
275 		}
276 	} else if ((filemode == REGULAR) || (filemode == DIRECTORY)) {
277 		filesize = buf.st_size;
278 		if (read(fd, mem, filesize) != filesize) {
279             sysemsg(fname);
280 			filemode = ERROR;
281 		}
282 	} else {
283 		filesize = 0L;
284 	}
285 	if (fd > 0) close(fd);
286 	if (fname != NULL) {
287 		switch (filemode) {
288 		case NEW:
289 			sprintf(string, "\"%s\" [New File]", fname);
290 			break;
291 		case REGULAR:
292 			sprintf(string, "\"%s\" %s%llu bytes", fname,
293 				P(P_RO) ? "[Read only] " : "",
294 				(unsigned long long)filesize);
295 			break;
296 		case DIRECTORY:
297 			sprintf(string, "\"%s\" Directory", fname);
298 			break;
299 		case CHARACTER_SPECIAL:
300 			sprintf(string, "\"%s\" Character special file", fname);
301 			break;
302 		case BLOCK_SPECIAL:
303 			sprintf(string, "\"%s\" Block special file", fname);
304 			break;
305 		}
306 		if (filemode != ERROR) msg(string);
307 	}
308 	pagepos = mem;
309 	maxpos = mem + filesize;
310 	loc = HEX;
311 	x = AnzAdd; y = 0;
312 	repaint();
313 	free(string);
314 	return(filesize);
315 }
316 
317 
318 /* argument "dir" not used!
319  * Needed for DOS version only
320  */
321 void
bvi_init(dir)322 bvi_init(dir)
323 	char *dir;
324 {
325 	char    *initstr;
326 	char    rcpath[MAXCMD];
327 
328 	terminal = getenv("TERM");
329 	shell = getenv("SHELL");
330 	if (shell == NULL || *shell == '\0')
331 		shell = "/bin/sh";
332 
333 	if ((initstr = getenv("BVIINIT")) != NULL) {
334 		docmdline(initstr);
335 		return;
336 	}
337 
338 #ifdef DJGPP
339 	strcpy(rcpath, "c:");
340 	strcpy(rcpath, dir);
341 	poi = strrchr(rcpath, '\\');
342 	*poi = '\0';
343 	strcat(rcpath, "\\BVI.RC");
344 	read_rc(rcpath);
345 	read_rc("BVI.RC");
346 #else
347 	strncpy(rcpath, getenv("HOME"), MAXCMD - 8);
348 	rcpath[MAXCMD - 8] = '\0';
349 	strcat(rcpath, "/.bvirc");
350 	if (stat(rcpath, &buf) == 0) {
351 		if (buf.st_uid == getuid()) read_rc(rcpath);
352 	}
353 
354 	strcpy(rcpath, ".bvirc");
355 	if (stat(rcpath, &buf) == 0) {
356 		if (buf.st_uid == getuid())	read_rc(rcpath);
357 	}
358 #endif
359 }
360 
361 
362 int
enlarge(add)363 enlarge(add)
364 	off_t	add;
365 {
366 	char	*newmem;
367 	off_t	savecur, savepag, savemax, saveundo;
368 
369 	savecur = curpos - mem;
370 	savepag = pagepos - mem;
371 	savemax = maxpos - mem;
372 	saveundo = undo_start - mem;
373 
374 	if (mem == NULL) {
375 		newmem = malloc(memsize + add);
376 	} else {
377 		newmem = realloc(mem, memsize + add);
378 	}
379 	if (newmem == NULL) {
380 		emsg("Out of memory");
381 		return 1;
382 	}
383 
384 	mem = newmem;
385 	memsize += add;
386 	curpos = mem + savecur;
387 	pagepos = mem + savepag;
388 	maxpos = mem + savemax;
389 	undo_start = mem + saveundo;
390 	current = curpos + 1L;
391 	return 0;
392 }
393 
394 
395 void
do_shell()396 do_shell()
397 {
398 	int ret;
399 
400 	addch('\n');
401 	savetty();
402 #ifdef DJGPP
403 	ret = system("");
404 #else
405 	ret = system(shell);
406 #endif
407 	resetty();
408 }
409 
410 
411 #ifndef HAVE_STRDUP
412 char *
strdup(s)413 strdup(s)
414 	char	*s;
415 {
416 	char    *p;
417 	size_t	 n;
418 
419 	n = strlen(s) + 1;
420 	if ((p = (char *)malloc(n)) != NULL)
421 		memcpy(p, s, n);
422 	return (p);
423 }
424 #endif
425 
426 
427 #ifndef HAVE_MEMMOVE
428 /*
429  * Copy contents of memory (with possible overlapping).
430  */
431 char *
memmove(s1,s2,n)432 memmove(s1, s2, n)
433 	char	*s1;
434 	char	*s2;
435 	size_t	n;
436 {
437 	bcopy(s2, s1, n);
438 	return(s1);
439 }
440 #endif
441 
442 
443 off_t
alloc_buf(n,buffer)444 alloc_buf(n, buffer)
445 	off_t	n;
446 	char	**buffer;
447 {
448 	if (*buffer == NULL) {
449 		*buffer = (char *)malloc(n);
450 	} else {
451 		*buffer = (char *)realloc(*buffer, n);
452 	}
453 	if (*buffer == NULL) {
454 		emsg("No buffer space available");
455 		return 0L;
456 	}
457 	return n;
458 }
459 
460 
461 int
addfile(fname)462 addfile(fname)
463 	char	*fname;
464 {
465 	int		fd;
466 	off_t	oldsize;
467 
468 	if (stat(fname, &buf)) {
469 		sysemsg(fname);
470 		return 1;
471 	}
472 	if ((fd = open(fname, O_RDONLY)) == -1) {
473 		sysemsg(fname);
474 		return 1;
475 	}
476 	oldsize = filesize;
477 	if (enlarge(buf.st_size)) return 1;
478 	if (read(fd, mem + filesize, buf.st_size) == -1) {
479 		sysemsg(fname);
480 		return 1;
481 	}
482 	filesize += buf.st_size;
483 	maxpos = mem + filesize;
484 	close(fd);
485 	setpage(mem + oldsize);
486 	return 0;
487 }
488