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