* new version 2.19.9999
[alpine.git] / pico / file.c
blob47c55968331c3c171e1ed8284d3adb1b90e3ece8
1 #if !defined(lint) && !defined(DOS)
2 static char rcsid[] = "$Id: file.c 1082 2008-06-12 18:39:50Z hubert@u.washington.edu $";
3 #endif
5 /*
6 * ========================================================================
7 * Copyright 2006-2007 University of Washington
8 * Copyright 2013-2015 Eduardo Chappa
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
14 * http://www.apache.org/licenses/LICENSE-2.0
16 * ========================================================================
18 * Program: High level file input and output routines
23 * The routines in this file
24 * handle the reading and writing of
25 * disk files. All of details about the
26 * reading and writing of the disk are
27 * in "fileio.c".
29 #include "headers.h"
30 #include "../pith/charconv/filesys.h"
33 void init_insmsgchar_cbuf(void);
34 int insmsgchar(int);
35 char *file_split(char *, size_t, char *, int);
38 * Read a file into the current
39 * buffer. This is really easy; all you do it
40 * find the name of the file, and call the standard
41 * "read a file into the current buffer" code.
42 * Bound to "C-X C-R".
44 int
45 fileread(int f, int n)
47 register int s;
48 char fname[NFILEN];
49 EML eml;
51 if ((s=mlreply_utf8(_("Read file: "), fname, NFILEN, QNORML, NULL)) != TRUE)
52 return(s);
54 if(gmode&MDSCUR){
55 emlwrite(_("File reading disabled in secure mode"),NULL);
56 return(0);
59 if (strlen(fname) == 0) {
60 emlwrite(_("No file name entered"),NULL);
61 return(0);
64 if((gmode & MDTREE) && !in_oper_tree(fname)){
65 eml.s = opertree;
66 emlwrite(_("Can't read file from outside of %s"), &eml);
67 return(0);
70 return(readin(fname, TRUE, TRUE));
75 static char *inshelptext[] = {
76 /* TRANSLATORS: several lines of help text */
77 N_("Insert File Help Text"),
78 " ",
79 N_(" Type in a file name to have it inserted into your editing"),
80 N_(" buffer between the line that the cursor is currently on"),
81 N_(" and the line directly below it. You may abort this by "),
82 N_("~ typing the ~F~2 (~^~C) key after exiting help."),
83 " ",
84 N_("End of Insert File Help"),
85 " ",
86 NULL
89 static char *writehelp[] = {
90 /* TRANSLATORS: several lines of help text */
91 N_("Write File Help Text"),
92 " ",
93 N_(" Type in a file name to have it written out, thus saving"),
94 N_(" your buffer, to a file. You can abort this by typing "),
95 N_("~ the ~F~2 (~^~C) key after exiting help."),
96 " ",
97 N_("End of Write File Help"),
98 " ",
99 " ",
100 NULL
105 * Insert a file into the current
106 * buffer. This is really easy; all you do it
107 * find the name of the file, and call the standard
108 * "insert a file into the current buffer" code.
109 * Bound to "C-X C-I".
112 insfile(int f, int n)
114 register int s;
115 char fname[NLINE], dir[NLINE];
116 int retval, bye = 0, msg = 0;
117 char prompt[64], *infile;
118 EXTRAKEYS menu_ins[5];
119 EML eml;
121 if (curbp->b_mode&MDVIEW) /* don't allow this command if */
122 return(rdonly()); /* we are in read only mode */
124 fname[0] = dir[0] = '\0';
125 while(!bye){
126 /* set up keymenu stuff */
127 if(!msg){
128 int last_menu = 0;
130 menu_ins[last_menu].name = "^T";
131 menu_ins[last_menu].key = (CTRL|'T');
132 menu_ins[last_menu].label = N_("To Files");
133 KS_OSDATASET(&menu_ins[last_menu], KS_NONE);
135 if(Pmaster && Pmaster->msgntext){
136 menu_ins[++last_menu].name = "^W";
137 menu_ins[last_menu].key = (CTRL|'W');
138 /* TRANSLATORS: Insert File is a key label for a command
139 that inserts a file into a message being composed.
140 InsertMsg means Insert Message and it inserts a different
141 message into the message being composed. */
142 menu_ins[last_menu].label = msg ? N_("InsertFile") : N_("InsertMsg");
143 KS_OSDATASET(&menu_ins[last_menu], KS_NONE);
146 #if !defined(DOS) && !defined(MAC)
147 if(Pmaster && Pmaster->upload){
148 menu_ins[++last_menu].name = "^Y";
149 menu_ins[last_menu].key = (CTRL|'Y');
150 menu_ins[last_menu].label = "RcvUpload";
151 KS_OSDATASET(&menu_ins[last_menu], KS_NONE);
153 #endif /* !(DOS || MAC) */
155 if(gmode & MDCMPLT){
156 menu_ins[++last_menu].name = msg ? "" : "TAB";
157 menu_ins[last_menu].key = (CTRL|'I');
158 menu_ins[last_menu].label = msg ? "" : N_("Complete");
159 KS_OSDATASET(&menu_ins[last_menu], KS_NONE);
162 menu_ins[++last_menu].name = NULL;
165 snprintf(prompt, sizeof(prompt), "%s to insert from %s %s: ",
166 msg ? "Number of message" : "File",
167 (msg || (gmode&MDCURDIR))
168 ? "current"
169 : ((gmode & MDTREE) || opertree[0]) ? opertree : "home",
170 msg ? "folder" : "directory");
171 s = mlreplyd_utf8(prompt, fname, NLINE, QDEFLT, msg ? NULL : menu_ins);
172 /* something to read and it was edited or the default accepted */
173 if(fname[0] && (s == TRUE || s == FALSE)){
174 bye++;
175 if(msg){
176 init_insmsgchar_cbuf();
177 if((*Pmaster->msgntext)(atol(fname), insmsgchar)){
178 eml.s = fname;
179 emlwrite(_("Message %s included"), &eml);
182 else{
183 bye++;
184 if(gmode&MDSCUR){
185 emlwrite(_("Can't insert file in restricted mode"),NULL);
187 else{
188 if((gmode & MDTREE)
189 && !compresspath(opertree, fname, sizeof(fname))){
190 eml.s = opertree;
191 emlwrite(
192 _("Can't insert file from outside of %s: too many ..'s"), &eml);
194 else{
195 fixpath(fname, sizeof(fname));
197 if((gmode & MDTREE) && !in_oper_tree(fname)){
198 eml.s = opertree;
199 emlwrite(_("Can't insert file from outside of %s"), &eml);
201 else
202 retval = ifile(fname);
207 else{
208 switch(s){
209 case (CTRL|'I') :
211 char *fn;
213 dir[0] = '\0';
214 fn = file_split(dir, sizeof(dir), fname, 0);
216 if(!pico_fncomplete(dir, fn, sizeof(fname)-(fn-fname)))
217 (*term.t_beep)();
220 break;
221 case (CTRL|'W'):
222 msg = !msg; /* toggle what to insert */
223 break;
224 case (CTRL|'T'):
225 if(msg){
226 emlwrite(_("Can't select messages yet!"), NULL);
228 else{
229 char *fn;
231 fn = file_split(dir, sizeof(dir), fname, 1);
232 if(!isdir(dir, NULL, NULL)){
233 strncpy(dir, (gmode&MDCURDIR)
234 ? (browse_dir[0] ? browse_dir : ".")
235 : ((gmode & MDTREE) || opertree[0])
236 ? opertree
237 : (browse_dir[0] ? browse_dir
238 :gethomedir(NULL)), sizeof(dir));
239 dir[sizeof(dir)-1] = '\0';
241 else{
242 if(*fn){
243 int dirlen;
245 dirlen = strlen(dir);
246 if(dirlen && dir[dirlen - 1] != C_FILESEP){
247 strncat(dir, S_FILESEP, sizeof(dir)-strlen(dir)-1);
248 dir[sizeof(dir)-1] = '\0';
251 strncat(dir, fn, sizeof(dir)-strlen(dir)-1);
252 dir[sizeof(dir)-1] = '\0';
253 if(!isdir(dir, NULL, NULL))
254 dir[MIN(dirlen,sizeof(dir)-1)] = '\0';
258 fname[0] = '\0';
259 if((s = FileBrowse(dir, sizeof(dir), fname, sizeof(fname),
260 NULL, 0, FB_READ, NULL)) == 1){
261 if(gmode&MDSCUR){
262 emlwrite(_("Can't insert in restricted mode"),
263 NULL);
264 sleep(2);
266 else{
267 size_t len;
269 len = strlen(dir)+strlen(S_FILESEP)+strlen(fname);
270 if ((infile = (char *)malloc((len+1)*sizeof(char))) != NULL){
271 strncpy(infile, dir, len);
272 infile[len] = '\0';
273 strncat(infile, S_FILESEP, len+1-1-strlen(infile));
274 infile[len] = '\0';
275 strncat(infile, fname, len+1-1-strlen(infile));
276 infile[len] = '\0';
277 retval = ifile(infile);
278 free((char *) infile);
280 else {
281 emlwrite("Trouble allocating space for insert!"
282 ,NULL);
283 sleep(3);
286 bye++;
288 else
289 fname[0] = '\0';
291 pico_refresh(FALSE, 1);
292 if(s != 1){
293 update(); /* redraw on return */
294 continue;
298 break;
300 #if !defined(DOS) && !defined(MAC)
301 case (CTRL|'Y') :
302 if(Pmaster && Pmaster->upload){
303 char tfname[NLINE];
305 if(gmode&MDSCUR){
306 emlwrite(
307 _("\007Restricted mode disallows uploaded command"),
308 NULL);
309 return(0);
312 tfname[0] = '\0';
313 retval = (*Pmaster->upload)(tfname, sizeof(tfname), NULL);
315 pico_refresh(FALSE, 1);
316 update();
318 if(retval){
319 retval = ifile(tfname);
320 bye++;
322 else
323 sleep(3); /* problem, show error! */
325 if(tfname[0]) /* clean up temp file */
326 our_unlink(tfname);
328 else
329 (*term.t_beep)(); /* what? */
331 break;
332 #endif /* !(DOS || MAC) */
333 case HELPCH:
334 if(Pmaster){
335 VARS_TO_SAVE *saved_state;
337 saved_state = save_pico_state();
338 (*Pmaster->helper)(msg ? Pmaster->ins_m_help
339 : Pmaster->ins_help,
340 _("Help for Insert File"), 1);
341 if(saved_state){
342 restore_pico_state(saved_state);
343 free_pico_state(saved_state);
346 else
347 pico_help(inshelptext, _("Help for Insert File"), 1);
348 case (CTRL|'L'):
349 pico_refresh(FALSE, 1);
350 update();
351 continue;
352 default:
353 ctrlg(FALSE, 0);
354 retval = s;
355 bye++;
359 curwp->w_flag |= WFMODE|WFHARD;
361 return(retval);
365 * split out the file name from the path.
366 * Copy path into dirbuf, return filename,
367 * which is a pointer into orig_fname.
368 * is_for_browse - use browse dir if possible
369 * don't want to use it for TAB-completion
371 char *
372 file_split(char *dirbuf, size_t dirbuflen, char *orig_fname, int is_for_browse)
374 char *p, *fn;
375 size_t dirlen;
377 if(*orig_fname && (p = strrchr(orig_fname, C_FILESEP))){
378 fn = p + 1;
379 dirlen = p - orig_fname;
380 if(p == orig_fname){
381 strncpy(dirbuf, S_FILESEP, dirbuflen);
382 dirbuf[dirbuflen-1] = '\0';
384 #ifdef DOS
385 else if(orig_fname[0] == C_FILESEP
386 || (isalpha((unsigned char)orig_fname[0])
387 && orig_fname[1] == ':')){
388 if(orig_fname[1] == ':' && p == orig_fname+2)
389 dirlen = fn - orig_fname;
391 dirlen = MIN(dirlen, dirbuflen-1);
392 strncpy(dirbuf, orig_fname, dirlen);
393 dirbuf[dirlen] = '\0';
395 #else
396 else if (orig_fname[0] == C_FILESEP || orig_fname[0] == '~'){
397 dirlen = MIN(dirlen, dirbuflen-1);
398 strncpy(dirbuf, orig_fname, dirlen);
399 dirbuf[dirlen] = '\0';
401 #endif
402 else
403 snprintf(dirbuf, dirbuflen, "%s%c%.*s",
404 (gmode & MDCURDIR)
405 ? ((is_for_browse && browse_dir[0]) ? browse_dir : ".")
406 : ((gmode & MDTREE) || opertree[0])
407 ? opertree
408 : ((is_for_browse && browse_dir[0])
409 ? browse_dir : gethomedir(NULL)),
410 C_FILESEP, p - orig_fname, orig_fname);
412 else{
413 fn = orig_fname;
414 strncpy(dirbuf, (gmode & MDCURDIR)
415 ? ((is_for_browse && browse_dir[0]) ? browse_dir : ".")
416 : ((gmode & MDTREE) || opertree[0])
417 ? opertree
418 : ((is_for_browse && browse_dir[0])
419 ? browse_dir : gethomedir(NULL)), dirbuflen);
420 dirbuf[dirbuflen-1] = '\0';
423 return fn;
427 static CBUF_S insmsgchar_cb;
429 void
430 init_insmsgchar_cbuf(void)
432 insmsgchar_cb.cbuf[0] = '\0';
433 insmsgchar_cb.cbufp = insmsgchar_cb.cbuf;
434 insmsgchar_cb.cbufend = insmsgchar_cb.cbuf;
439 * This is called with a stream of UTF-8 characters.
440 * We change that stream into UCS characters and insert
441 * those characters.
444 insmsgchar(int c)
446 if(c == '\n'){
447 UCS *u;
449 lnewline();
450 for(u = glo_quote_str; u && *u; u++)
451 if(!linsert(1, *u))
452 return(0);
454 else if(c != '\r'){ /* ignore CR (likely CR of CRLF) */
455 int outchars;
456 UCS ucs;
458 if((outchars = utf8_to_ucs4_oneatatime(c, &insmsgchar_cb, &ucs, NULL)) != 0)
459 if(!linsert(1, ucs))
460 return(0);
463 return(1);
468 * Read file "fname" into the current
469 * buffer, blowing away any text found there. Called
470 * by both the read and find commands. Return the final
471 * status of the read. Also called by the mainline,
472 * to read in a file specified on the command line as
473 * an argument.
476 readin(char fname[], /* name of file to read */
477 int lockfl, /* check for file locks? */
478 int rename) /* don't rename if reading from, say, alt speller */
480 UCS line[NLINE], *linep;
481 long nline;
482 int s, done, newline;
484 curbp->b_linecnt = -1; /* Must be recalculated */
485 if ((s = bclear(curbp)) != TRUE) /* Might be old. */
486 return (s);
488 if(rename){
489 strncpy(curbp->b_fname, fname, sizeof(curbp->b_fname));
490 curbp->b_fname[sizeof(curbp->b_fname)-1] = '\0';
493 if ((s=ffropen(fname)) != FIOSUC){ /* Hard file open. */
494 if(s == FIOFNF) /* File not found. */
495 emlwrite(_("New file"), NULL);
496 else
497 fioperr(s, fname);
499 else{
500 size_t charsread = 0;
502 emlwrite(_("Reading file"), NULL);
503 nline = 0L;
504 done = newline = 0;
505 while(!done)
506 if((s = ffgetline(line, NLINE, &charsread, 1)) == FIOEOF){
507 char b[200];
509 curbp->b_flag &= ~(BFTEMP|BFCHG);
510 gotobob(FALSE, 1);
511 if(nline > 1)
512 snprintf(b, sizeof(b), _("Read %ld lines"), nline);
513 else
514 snprintf(b, sizeof(b), _("Read 1 line"));
516 emlwrite(b, NULL);
518 break;
520 else{
521 if(newline){
522 if(lnewline() == FALSE){
523 done++;
524 continue;
526 newline = 0;
529 switch(s){
530 case FIOSUC :
531 nline++;
532 newline = 1;
534 case FIOLNG :
535 for(linep = line; charsread-- > 0; linep++)
536 if(linsert(1, *linep) == FALSE) done++;
538 break;
540 default :
541 done++;
542 break;
546 ffclose(); /* Ignore errors. */
549 return(s != FIOERR && s != FIOFNF); /* true if success */
554 * Ask for a file name, and write the
555 * contents of the current buffer to that file.
556 * Update the remembered file name and clear the
557 * buffer changed flag. This handling of file names
558 * is different from the earlier versions, and
559 * is more compatable with Gosling EMACS than
560 * with ITS EMACS. Bound to "C-X C-W".
563 filewrite(int f, int n)
565 register WINDOW *wp;
566 register int s;
567 char fname[NFILEN];
568 char shows[NLINE], origshows[NLINE], *bufp;
569 EXTRAKEYS menu_write[3];
570 EML eml;
572 if(curbp->b_fname[0] != 0){
573 strncpy(fname, curbp->b_fname, sizeof(curbp->b_fname));
574 curbp->b_fname[sizeof(curbp->b_fname)-1] = '\0';
576 else
577 fname[0] = '\0';
579 menu_write[0].name = "^T";
580 menu_write[0].label = N_("To Files");
581 menu_write[0].key = (CTRL|'T');
582 menu_write[1].name = "TAB";
583 menu_write[1].label = N_("Complete");
584 menu_write[1].key = (CTRL|'I');
585 menu_write[2].name = NULL;
586 for(;!(gmode & MDTOOL);){
587 /* TRANSLATORS: Asking for name of file to write data into */
588 s = mlreplyd_utf8(_("File Name to write : "), fname, NFILEN,
589 QDEFLT|QFFILE, menu_write);
591 switch(s){
592 case FALSE:
593 if(!fname[0]){ /* no file name to write to */
594 ctrlg(FALSE, 0);
595 return(s);
597 case TRUE:
598 if((gmode & MDTREE) && !compresspath(opertree, fname, sizeof(fname))){
599 eml.s = opertree;
600 emlwrite(_("Can't write outside of %s: too many ..'s"), &eml);
601 sleep(2);
602 continue;
604 else{
605 fixpath(fname, sizeof(fname)); /* fixup ~ in file name */
606 if((gmode & MDTREE) && !in_oper_tree(fname)){
607 eml.s = opertree;
608 emlwrite(_("Can't write outside of %s"), &eml);
609 sleep(2);
610 continue;
614 break;
616 case (CTRL|'I'):
618 char *fn, *p, dir[NFILEN];
619 int l = NFILEN;
621 dir[0] = '\0';
622 if(*fname && (p = strrchr(fname, C_FILESEP))){
623 fn = p + 1;
624 l -= fn - fname;
625 if(p == fname){
626 strncpy(dir, S_FILESEP, sizeof(dir));
627 dir[sizeof(dir)-1] = '\0';
629 #ifdef DOS
630 else if(fname[0] == C_FILESEP
631 || (isalpha((unsigned char)fname[0])
632 && fname[1] == ':'))
633 #else
634 else if (fname[0] == C_FILESEP || fname[0] == '~')
635 #endif
637 strncpy(dir, fname, MIN(p - fname, sizeof(dir)-1));
638 dir[MIN(p-fname, sizeof(dir)-1)] = '\0';
640 else
641 snprintf(dir, sizeof(dir), "%s%c%.*s",
642 (gmode & MDCURDIR)
643 ? "."
644 : ((gmode & MDTREE) || opertree[0])
645 ? opertree : gethomedir(NULL),
646 C_FILESEP, p - fname, fname);
648 else{
649 fn = fname;
650 strncpy(dir, (gmode & MDCURDIR)
651 ? "."
652 : ((gmode & MDTREE) || opertree[0])
653 ? opertree : gethomedir(NULL), sizeof(dir));
654 dir[sizeof(dir)-1] = '\0';
657 if(!pico_fncomplete(dir, fn, sizeof(fname)-(fn-fname)))
658 (*term.t_beep)();
661 continue;
663 case (CTRL|'T'):
664 /* If we have a file name, break up into path and file name.*/
665 *shows = 0;
666 if(*fname) {
667 if(isdir(fname, NULL, NULL)) {
668 /* fname is a directory. */
669 strncpy(shows, fname, sizeof(shows));
670 shows[sizeof(shows)-1] = '\0';
671 *fname = '\0';
673 else {
674 /* Find right most separator. */
675 bufp = strrchr (fname, C_FILESEP);
676 if (bufp != NULL) {
677 /* Copy directory part to 'shows', and file
678 * name part to front of 'fname'. */
679 *bufp = '\0';
680 strncpy(shows, fname, sizeof(shows));
681 shows[sizeof(shows)-1] = '\0';
682 strncpy(fname, bufp+1, MIN(strlen(bufp+1)+1, sizeof(fname)));
683 fname[sizeof(fname)-1] = '\0';
688 /* If we did not end up with a valid directory, use home. */
689 if (!*shows || !isdir (shows, NULL, NULL)){
690 strncpy(shows, ((gmode & MDTREE) || opertree[0])
691 ? opertree
692 : (browse_dir[0] ? browse_dir
693 : gethomedir(NULL)), sizeof(shows));
694 shows[sizeof(shows)-1] = '\0';
697 strncpy(origshows, shows, sizeof(origshows));
698 origshows[sizeof(origshows)-1] = '\0';
699 if ((s = FileBrowse(shows, sizeof(shows), fname, sizeof(fname), NULL, 0,
700 FB_SAVE, NULL)) == 1) {
701 if (strlen(shows)+strlen(S_FILESEP)+strlen(fname) < NLINE){
702 strncat(shows, S_FILESEP, sizeof(shows)-strlen(shows)-1);
703 shows[sizeof(shows)-1] = '\0';
704 strncat(shows, fname, sizeof(shows)-strlen(shows)-1);
705 shows[sizeof(shows)-1] = '\0';
706 strncpy(fname, shows, sizeof(fname));
707 fname[sizeof(fname)-1] = '\0';
709 else {
710 emlwrite("Cannot write. File name too long!!",NULL);
711 sleep(3);
714 else if (s == 0 && strcmp(shows, origshows)){
715 strncat(shows, S_FILESEP, sizeof(shows)-strlen(shows)-1);
716 shows[sizeof(shows)-1] = '\0';
717 strncat(shows, fname, sizeof(shows)-strlen(shows)-1);
718 shows[sizeof(shows)-1] = '\0';
719 strncpy(fname, shows, sizeof(fname));
720 fname[sizeof(fname)-1] = '\0';
722 else if (s == -1){
723 emlwrite("Cannot write. File name too long!!",NULL);
724 sleep(3);
727 pico_refresh(FALSE, 1);
728 update();
729 if(s == 1)
730 break;
731 else
732 continue;
734 case HELPCH:
735 pico_help(writehelp, "", 1);
736 case (CTRL|'L'):
737 pico_refresh(FALSE, 1);
738 update();
739 continue;
741 default:
742 return(s);
743 break;
746 if(strcmp(fname, curbp->b_fname) == 0)
747 break;
749 if((s=fexist(fname, "w", (off_t *)NULL)) == FIOSUC){
750 /*exists overwrite? */
752 snprintf(shows, sizeof(shows), _("File \"%s\" exists, OVERWRITE"), fname);
753 if((s=mlyesno_utf8(shows, FALSE)) == TRUE)
754 break;
756 else if(s == FIOFNF){
757 break; /* go write it */
759 else{ /* some error, can't write */
760 fioperr(s, fname);
761 return(ABORT);
765 emlwrite("Writing...", NULL);
767 if ((s=writeout(fname, 0)) != -1) {
768 if(!(gmode&MDTOOL)){
769 strncpy(curbp->b_fname, fname, sizeof(curbp->b_fname));
770 curbp->b_fname[sizeof(curbp->b_fname)-1] = '\0';
771 curbp->b_flag &= ~BFCHG;
773 wp = wheadp; /* Update mode lines. */
774 while (wp != NULL) {
775 if (wp->w_bufp == curbp)
776 if((Pmaster && s == TRUE) || Pmaster == NULL)
777 wp->w_flag |= WFMODE;
778 wp = wp->w_wndp;
782 if(s > 1){
783 eml.s = comatose(s);
784 emlwrite(_("Wrote %s lines"), &eml);
786 else
787 emlwrite(_("Wrote 1 line"), NULL);
790 return ((s == -1) ? FALSE : TRUE);
795 * Save the contents of the current
796 * buffer in its associatd file. No nothing
797 * if nothing has changed (this may be a bug, not a
798 * feature). Error if there is no remembered file
799 * name for the buffer. Bound to "C-X C-S". May
800 * get called by "C-Z".
803 filesave(int f, int n)
805 register WINDOW *wp;
806 register int s;
807 EML eml;
809 if (curbp->b_mode&MDVIEW) /* don't allow this command if */
810 return(rdonly()); /* we are in read only mode */
811 if ((curbp->b_flag&BFCHG) == 0) /* Return, no changes. */
812 return (TRUE);
813 if (curbp->b_fname[0] == 0) { /* Must have a name. */
814 emlwrite(_("No file name"), NULL);
815 sleep(2);
816 return (FALSE);
819 emlwrite("Writing...", NULL);
820 if ((s=writeout(curbp->b_fname, 0)) != -1) {
821 curbp->b_flag &= ~BFCHG;
822 wp = wheadp; /* Update mode lines. */
823 while (wp != NULL) {
824 if (wp->w_bufp == curbp)
825 if(Pmaster == NULL)
826 wp->w_flag |= WFMODE;
827 wp = wp->w_wndp;
829 if(s > 1){
830 eml.s = comatose(s);
831 emlwrite(_("Wrote %s lines"), &eml);
833 else
834 emlwrite(_("Wrote 1 line"), NULL);
836 return (s);
841 * This function performs the details of file
842 * writing. Uses the file management routines in the
843 * "fileio.c" package. The number of lines written is
844 * displayed. Sadly, it looks inside a LINE; provide
845 * a macro for this. Most of the grief is error
846 * checking of some sort.
848 * If the argument readonly is set, the file is created with user read
849 * and write permission only if it doesn't already exist. Note that the
850 * word readonly is misleading. It is user r/w permission only.
852 * CHANGES: 1 Aug 91: returns number of lines written or -1 on error, MSS
855 writeout(char *fn, int readonly)
857 register int s;
858 register int t;
859 register LINE *lp;
860 register int nline;
862 if (!((s = ffwopen(fn, readonly)) == FIOSUC && ffelbowroom()))
863 return (-1); /* Open writes message. */
865 lp = lforw(curbp->b_linep); /* First line. */
866 nline = 0; /* Number of lines. */
867 while (lp != curbp->b_linep) {
868 if ((s=ffputline(&lp->l_text[0], llength(lp))) != FIOSUC)
869 break;
870 ++nline;
871 lp = lforw(lp);
874 t = ffclose(); /* ffclose complains if error */
876 if(s == FIOSUC)
877 s = t; /* report worst case */
879 return ((s == FIOSUC) ? nline : -1);
884 * writetmp - write a temporary file for message text, mindful of
885 * access restrictions and included text. If n is true, include
886 * lines that indicated included message text, otw forget them
887 * If dir is non-null, put the temp file in that directory.
889 char *
890 writetmp(int n, char *dir)
892 static char fn[NFILEN];
893 register int s;
894 register int t;
895 register LINE *lp;
896 register int nline;
898 tmpname(dir, fn);
900 /* Open writes message */
901 if (!fn[0] || (s=ffwopen(fn, TRUE)) != FIOSUC){
902 if(fn[0])
903 our_unlink(fn);
905 return(NULL);
908 lp = lforw(curbp->b_linep); /* First line. */
909 nline = 0; /* Number of lines. */
910 while (lp != curbp->b_linep) {
911 if(n || (!n && lp->l_text[0].c != '>'))
912 if ((s=ffputline(&lp->l_text[0], llength(lp))) != FIOSUC)
913 break;
915 ++nline;
916 lp = lforw(lp);
919 t = ffclose(); /* ffclose complains if error */
921 if(s == FIOSUC)
922 s = t; /* remember worst case */
924 if (s != FIOSUC){ /* Some sort of error. */
925 our_unlink(fn);
926 return(NULL);
929 return(fn);
934 * Insert file "fname" into the current
935 * buffer, Called by insert file command. Return the final
936 * status of the read.
939 ifile(char fname[])
941 UCS line[NLINE], *linep;
942 long nline;
943 int s, done, newline;
944 size_t charsread = 0;
945 EML eml;
947 if ((s=ffropen(fname)) != FIOSUC){ /* Hard file open. */
948 fioperr(s, fname);
949 return(FALSE);
952 gotobol(FALSE, 1);
954 curbp->b_flag |= BFCHG; /* we have changed */
955 curbp->b_flag &= ~BFTEMP; /* and are not temporary*/
956 curbp->b_linecnt = -1; /* must be recalculated */
958 eml.s = fname;
959 emlwrite(_("Inserting %s."), &eml);
960 done = newline = 0;
961 nline = 0L;
962 while(!done)
963 if((s = ffgetline(line, NLINE, &charsread, 1)) == FIOEOF){
964 char b[200];
966 if(llength(curwp->w_dotp) > curwp->w_doto)
967 lnewline();
968 else
969 forwchar(FALSE, 1);
971 if(nline > 1)
972 snprintf(b, sizeof(b), _("Inserted %ld lines"), nline);
973 else
974 snprintf(b, sizeof(b), _("Inserted 1 line"));
976 emlwrite(b, NULL);
977 break;
979 else{
980 if(newline){
981 if(lnewline() == FALSE){
982 done++;
983 continue;
985 newline = 0;
988 switch(s){
989 case FIOSUC : /* copy line into buf */
990 nline++;
991 newline = 1;
993 case FIOLNG :
994 for(linep = line; charsread-- > 0; linep++)
995 if(linsert(1, *linep) == FALSE) done++;
997 break;
999 default :
1000 done++;
1004 ffclose(); /* Ignore errors. */
1006 return(s != FIOERR);
1011 * pico_fncomplete - pico's function to complete the given file name
1014 pico_fncomplete(char *dirarg, char *fn, size_t fnlen)
1016 char *p, *dlist, tmp[NLINE], dir[NLINE];
1017 int n, i, match = -1;
1018 #ifdef DOS
1019 #define FILECMP(x, y) (toupper((unsigned char)(x))\
1020 == toupper((unsigned char)(y)))
1021 #else
1022 #define FILECMP(x, y) ((x) == (y))
1023 #endif
1025 strncpy(dir, dirarg, sizeof(dir));
1026 dir[sizeof(dir)-1] = '\0';
1027 pfnexpand(dir, sizeof(dir));
1028 if(*fn && (dlist = p = getfnames(dir, fn, &n, NULL, 0))){
1029 memset(tmp, 0, sizeof(tmp));
1030 while(n--){ /* any names in it */
1031 for(i = 0; i < sizeof(tmp)-1 && fn[i] && FILECMP(p[i], fn[i]); i++)
1034 if(!fn[i]){ /* match or more? */
1035 if(tmp[0]){
1036 for(; p[i] && FILECMP(p[i], tmp[i]); i++)
1039 match = !p[i] && !tmp[i];
1040 tmp[i] = '\0'; /* longest common string */
1042 else{
1043 match = 1; /* may be it!?! */
1044 strncpy(tmp, p, sizeof(tmp));
1045 tmp[sizeof(tmp)-1] = '\0';
1049 p += strlen(p) + 1;
1052 free(dlist);
1055 if(match >= 0){
1056 strncpy(fn, tmp, fnlen);
1057 fn[fnlen-1] = '\0';
1058 if(match == 1){
1059 if ((strlen(dir)+strlen(S_FILESEP)+strlen(fn)) < sizeof(dir)){
1060 strncat(dir, S_FILESEP, sizeof(dir)-strlen(dir)-1);
1061 dir[sizeof(dir)-1] = '\0';
1062 strncat(dir, fn, sizeof(dir)-strlen(dir)-1);
1063 dir[sizeof(dir)-1] = '\0';
1064 if(isdir(dir, NULL, NULL)){
1065 strncat(fn, S_FILESEP, fnlen-strlen(fn)-1);
1066 fn[fnlen-1] = '\0';
1069 else{
1070 emlwrite("File name too BIG!!",0);
1071 sleep(3);
1072 *fn = '\0';
1078 return(match == 1);
1083 * in_oper_tree - returns true if file "f" does reside in opertree
1086 in_oper_tree(char *f)
1088 int end = strlen(opertree);
1090 return(!strncmp(opertree, f, end)
1091 && (opertree[end-1] == '/'
1092 || opertree[end-1] == '\\'
1093 || f[end] == '\0'
1094 || f[end] == '/'
1095 || f[end] == '\\'));