* When a filename is attached and its name is encoded, the save attachment
[alpine.git] / pico / file.c
blob149971f0f6644b78d75d301f89175e2b93d5c9a0
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-2016 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[10];
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 memset(&menu_ins, 0, 10*sizeof(EXTRAKEYS));
125 fname[0] = dir[0] = '\0';
126 while(!bye){
127 /* set up keymenu stuff */
128 if(!msg){
129 int last_menu = 0;
131 menu_ins[last_menu].name = "^T";
132 menu_ins[last_menu].key = (CTRL|'T');
133 menu_ins[last_menu].label = N_("To Files");
134 KS_OSDATASET(&menu_ins[last_menu], KS_NONE);
136 if(Pmaster && Pmaster->msgntext){
137 menu_ins[++last_menu].name = "^W";
138 menu_ins[last_menu].key = (CTRL|'W');
139 /* TRANSLATORS: Insert File is a key label for a command
140 that inserts a file into a message being composed.
141 InsertMsg means Insert Message and it inserts a different
142 message into the message being composed. */
143 menu_ins[last_menu].label = msg ? N_("InsertFile") : N_("InsertMsg");
144 KS_OSDATASET(&menu_ins[last_menu], KS_NONE);
147 #if !defined(DOS) && !defined(MAC)
148 if(Pmaster && Pmaster->upload){
149 menu_ins[++last_menu].name = "^Y";
150 menu_ins[last_menu].key = (CTRL|'Y');
151 menu_ins[last_menu].label = "RcvUpload";
152 KS_OSDATASET(&menu_ins[last_menu], KS_NONE);
154 #endif /* !(DOS || MAC) */
156 if(gmode & MDCMPLT){
157 menu_ins[++last_menu].name = msg ? "" : "TAB";
158 menu_ins[last_menu].key = (CTRL|'I');
159 menu_ins[last_menu].label = msg ? "" : N_("Complete");
160 KS_OSDATASET(&menu_ins[last_menu], KS_NONE);
163 menu_ins[++last_menu].name = NULL;
166 snprintf(prompt, sizeof(prompt), "%s to insert from %s %s: ",
167 msg ? "Number of message" : "File",
168 (msg || (gmode&MDCURDIR))
169 ? "current"
170 : ((gmode & MDTREE) || opertree[0]) ? opertree : "home",
171 msg ? "folder" : "directory");
172 s = mlreplyd_utf8(prompt, fname, NLINE, QDEFLT, msg ? NULL : menu_ins);
173 /* something to read and it was edited or the default accepted */
174 if(fname[0] && (s == TRUE || s == FALSE)){
175 bye++;
176 if(msg){
177 init_insmsgchar_cbuf();
178 if((*Pmaster->msgntext)(atol(fname), insmsgchar)){
179 eml.s = fname;
180 emlwrite(_("Message %s included"), &eml);
183 else{
184 bye++;
185 if(gmode&MDSCUR){
186 emlwrite(_("Can't insert file in restricted mode"),NULL);
188 else{
189 if((gmode & MDTREE)
190 && !compresspath(opertree, fname, sizeof(fname))){
191 eml.s = opertree;
192 emlwrite(
193 _("Can't insert file from outside of %s: too many ..'s"), &eml);
195 else{
196 fixpath(fname, sizeof(fname));
198 if((gmode & MDTREE) && !in_oper_tree(fname)){
199 eml.s = opertree;
200 emlwrite(_("Can't insert file from outside of %s"), &eml);
202 else
203 retval = ifile(fname);
208 else{
209 switch(s){
210 case (CTRL|'I') :
212 char *fn;
214 dir[0] = '\0';
215 fn = file_split(dir, sizeof(dir), fname, 0);
217 if(!pico_fncomplete(dir, fn, sizeof(fname)-(fn-fname)))
218 (*term.t_beep)();
221 break;
222 case (CTRL|'W'):
223 msg = !msg; /* toggle what to insert */
224 break;
225 case (CTRL|'T'):
226 if(msg){
227 emlwrite(_("Can't select messages yet!"), NULL);
229 else{
230 char *fn;
232 fn = file_split(dir, sizeof(dir), fname, 1);
233 if(!isdir(dir, NULL, NULL)){
234 strncpy(dir, (gmode&MDCURDIR)
235 ? (browse_dir[0] ? browse_dir : ".")
236 : ((gmode & MDTREE) || opertree[0])
237 ? opertree
238 : (browse_dir[0] ? browse_dir
239 :gethomedir(NULL)), sizeof(dir));
240 dir[sizeof(dir)-1] = '\0';
242 else{
243 if(*fn){
244 int dirlen;
246 dirlen = strlen(dir);
247 if(dirlen && dir[dirlen - 1] != C_FILESEP){
248 strncat(dir, S_FILESEP, sizeof(dir)-strlen(dir)-1);
249 dir[sizeof(dir)-1] = '\0';
252 strncat(dir, fn, sizeof(dir)-strlen(dir)-1);
253 dir[sizeof(dir)-1] = '\0';
254 if(!isdir(dir, NULL, NULL))
255 dir[MIN(dirlen,sizeof(dir)-1)] = '\0';
259 fname[0] = '\0';
260 if((s = FileBrowse(dir, sizeof(dir), fname, sizeof(fname),
261 NULL, 0, FB_READ, NULL)) == 1){
262 if(gmode&MDSCUR){
263 emlwrite(_("Can't insert in restricted mode"),
264 NULL);
265 sleep(2);
267 else{
268 size_t len;
270 len = strlen(dir)+strlen(S_FILESEP)+strlen(fname);
271 if ((infile = (char *)malloc((len+1)*sizeof(char))) != NULL){
272 strncpy(infile, dir, len);
273 infile[len] = '\0';
274 strncat(infile, S_FILESEP, len+1-1-strlen(infile));
275 infile[len] = '\0';
276 strncat(infile, fname, len+1-1-strlen(infile));
277 infile[len] = '\0';
278 retval = ifile(infile);
279 free((char *) infile);
281 else {
282 emlwrite("Trouble allocating space for insert!"
283 ,NULL);
284 sleep(3);
287 bye++;
289 else
290 fname[0] = '\0';
292 pico_refresh(FALSE, 1);
293 if(s != 1){
294 update(); /* redraw on return */
295 continue;
299 break;
301 #if !defined(DOS) && !defined(MAC)
302 case (CTRL|'Y') :
303 if(Pmaster && Pmaster->upload){
304 char tfname[NLINE];
306 if(gmode&MDSCUR){
307 emlwrite(
308 _("\007Restricted mode disallows uploaded command"),
309 NULL);
310 return(0);
313 tfname[0] = '\0';
314 retval = (*Pmaster->upload)(tfname, sizeof(tfname), NULL);
316 pico_refresh(FALSE, 1);
317 update();
319 if(retval){
320 retval = ifile(tfname);
321 bye++;
323 else
324 sleep(3); /* problem, show error! */
326 if(tfname[0]) /* clean up temp file */
327 our_unlink(tfname);
329 else
330 (*term.t_beep)(); /* what? */
332 break;
333 #endif /* !(DOS || MAC) */
334 case HELPCH:
335 if(Pmaster){
336 VARS_TO_SAVE *saved_state;
338 saved_state = save_pico_state();
339 (*Pmaster->helper)(msg ? Pmaster->ins_m_help
340 : Pmaster->ins_help,
341 _("Help for Insert File"), 1);
342 if(saved_state){
343 restore_pico_state(saved_state);
344 free_pico_state(saved_state);
347 else
348 pico_help(inshelptext, _("Help for Insert File"), 1);
349 case (CTRL|'L'):
350 pico_refresh(FALSE, 1);
351 update();
352 continue;
353 default:
354 ctrlg(FALSE, 0);
355 retval = s;
356 bye++;
360 curwp->w_flag |= WFMODE|WFHARD;
362 return(retval);
366 * split out the file name from the path.
367 * Copy path into dirbuf, return filename,
368 * which is a pointer into orig_fname.
369 * is_for_browse - use browse dir if possible
370 * don't want to use it for TAB-completion
372 char *
373 file_split(char *dirbuf, size_t dirbuflen, char *orig_fname, int is_for_browse)
375 char *p, *fn;
376 size_t dirlen;
378 if(*orig_fname && (p = strrchr(orig_fname, C_FILESEP))){
379 fn = p + 1;
380 dirlen = p - orig_fname;
381 if(p == orig_fname){
382 strncpy(dirbuf, S_FILESEP, dirbuflen);
383 dirbuf[dirbuflen-1] = '\0';
385 #ifdef DOS
386 else if(orig_fname[0] == C_FILESEP
387 || (isalpha((unsigned char)orig_fname[0])
388 && orig_fname[1] == ':')){
389 if(orig_fname[1] == ':' && p == orig_fname+2)
390 dirlen = fn - orig_fname;
392 dirlen = MIN(dirlen, dirbuflen-1);
393 strncpy(dirbuf, orig_fname, dirlen);
394 dirbuf[dirlen] = '\0';
396 #else
397 else if (orig_fname[0] == C_FILESEP || orig_fname[0] == '~'){
398 dirlen = MIN(dirlen, dirbuflen-1);
399 strncpy(dirbuf, orig_fname, dirlen);
400 dirbuf[dirlen] = '\0';
402 #endif
403 else
404 snprintf(dirbuf, dirbuflen, "%s%c%.*s",
405 (gmode & MDCURDIR)
406 ? ((is_for_browse && browse_dir[0]) ? browse_dir : ".")
407 : ((gmode & MDTREE) || opertree[0])
408 ? opertree
409 : ((is_for_browse && browse_dir[0])
410 ? browse_dir : gethomedir(NULL)),
411 C_FILESEP, (int) (p - orig_fname), orig_fname);
413 else{
414 fn = orig_fname;
415 strncpy(dirbuf, (gmode & MDCURDIR)
416 ? ((is_for_browse && browse_dir[0]) ? browse_dir : ".")
417 : ((gmode & MDTREE) || opertree[0])
418 ? opertree
419 : ((is_for_browse && browse_dir[0])
420 ? browse_dir : gethomedir(NULL)), dirbuflen);
421 dirbuf[dirbuflen-1] = '\0';
424 return fn;
428 static CBUF_S insmsgchar_cb;
430 void
431 init_insmsgchar_cbuf(void)
433 insmsgchar_cb.cbuf[0] = '\0';
434 insmsgchar_cb.cbufp = insmsgchar_cb.cbuf;
435 insmsgchar_cb.cbufend = insmsgchar_cb.cbuf;
440 * This is called with a stream of UTF-8 characters.
441 * We change that stream into UCS characters and insert
442 * those characters.
445 insmsgchar(int c)
447 if(c == '\n'){
448 UCS *u;
450 lnewline();
451 for(u = glo_quote_str; u && *u; u++)
452 if(!linsert(1, *u))
453 return(0);
455 else if(c != '\r'){ /* ignore CR (likely CR of CRLF) */
456 int outchars;
457 UCS ucs;
459 if((outchars = utf8_to_ucs4_oneatatime(c, &insmsgchar_cb, &ucs, NULL)) != 0)
460 if(!linsert(1, ucs))
461 return(0);
464 return(1);
469 * Read file "fname" into the current
470 * buffer, blowing away any text found there. Called
471 * by both the read and find commands. Return the final
472 * status of the read. Also called by the mainline,
473 * to read in a file specified on the command line as
474 * an argument.
477 readin(char fname[], /* name of file to read */
478 int lockfl, /* check for file locks? */
479 int rename) /* don't rename if reading from, say, alt speller */
481 UCS line[NLINE], *linep;
482 long nline;
483 int s, done, newline;
485 curbp->b_linecnt = -1; /* Must be recalculated */
486 if ((s = bclear(curbp)) != TRUE) /* Might be old. */
487 return (s);
489 if(rename){
490 strncpy(curbp->b_fname, fname, sizeof(curbp->b_fname));
491 curbp->b_fname[sizeof(curbp->b_fname)-1] = '\0';
494 if ((s=ffropen(fname)) != FIOSUC){ /* Hard file open. */
495 if(s == FIOFNF) /* File not found. */
496 emlwrite(_("New file"), NULL);
497 else
498 fioperr(s, fname);
500 else{
501 size_t charsread = 0;
503 emlwrite(_("Reading file"), NULL);
504 nline = 0L;
505 done = newline = 0;
506 while(!done)
507 if((s = ffgetline(line, NLINE, &charsread, 1)) == FIOEOF){
508 char b[200];
510 curbp->b_flag &= ~(BFTEMP|BFCHG);
511 gotobob(FALSE, 1);
512 if(nline > 1)
513 snprintf(b, sizeof(b), _("Read %ld lines"), nline);
514 else
515 snprintf(b, sizeof(b), _("Read 1 line"));
517 emlwrite(b, NULL);
519 break;
521 else{
522 if(newline){
523 if(lnewline() == FALSE){
524 done++;
525 continue;
527 newline = 0;
530 switch(s){
531 case FIOSUC :
532 nline++;
533 newline = 1;
535 case FIOLNG :
536 for(linep = line; charsread-- > 0; linep++)
537 if(linsert(1, *linep) == FALSE) done++;
539 break;
541 default :
542 done++;
543 break;
547 ffclose(); /* Ignore errors. */
550 return(s != FIOERR && s != FIOFNF); /* true if success */
555 * Ask for a file name, and write the
556 * contents of the current buffer to that file.
557 * Update the remembered file name and clear the
558 * buffer changed flag. This handling of file names
559 * is different from the earlier versions, and
560 * is more compatable with Gosling EMACS than
561 * with ITS EMACS. Bound to "C-X C-W".
564 filewrite(int f, int n)
566 register WINDOW *wp;
567 register int s;
568 char fname[NFILEN];
569 char shows[NLINE], origshows[NLINE], *bufp;
570 EXTRAKEYS menu_write[10];
571 EML eml;
573 memset(&menu_write, 0, 10*sizeof(EXTRAKEYS));
574 if(curbp->b_fname[0] != 0){
575 strncpy(fname, curbp->b_fname, sizeof(curbp->b_fname));
576 curbp->b_fname[sizeof(curbp->b_fname)-1] = '\0';
578 else
579 fname[0] = '\0';
581 menu_write[0].name = "^T";
582 menu_write[0].label = N_("To Files");
583 menu_write[0].key = (CTRL|'T');
584 menu_write[1].name = "TAB";
585 menu_write[1].label = N_("Complete");
586 menu_write[1].key = (CTRL|'I');
587 menu_write[2].name = NULL;
588 for(;!(gmode & MDTOOL);){
589 /* TRANSLATORS: Asking for name of file to write data into */
590 s = mlreplyd_utf8(_("File Name to write : "), fname, NFILEN,
591 QDEFLT|QFFILE, menu_write);
593 switch(s){
594 case FALSE:
595 if(!fname[0]){ /* no file name to write to */
596 ctrlg(FALSE, 0);
597 return(s);
599 case TRUE:
600 if((gmode & MDTREE) && !compresspath(opertree, fname, sizeof(fname))){
601 eml.s = opertree;
602 emlwrite(_("Can't write outside of %s: too many ..'s"), &eml);
603 sleep(2);
604 continue;
606 else{
607 fixpath(fname, sizeof(fname)); /* fixup ~ in file name */
608 if((gmode & MDTREE) && !in_oper_tree(fname)){
609 eml.s = opertree;
610 emlwrite(_("Can't write outside of %s"), &eml);
611 sleep(2);
612 continue;
616 break;
618 case (CTRL|'I'):
620 char *fn, *p, dir[NFILEN];
621 int l = NFILEN;
623 dir[0] = '\0';
624 if(*fname && (p = strrchr(fname, C_FILESEP))){
625 fn = p + 1;
626 l -= fn - fname;
627 if(p == fname){
628 strncpy(dir, S_FILESEP, sizeof(dir));
629 dir[sizeof(dir)-1] = '\0';
631 #ifdef DOS
632 else if(fname[0] == C_FILESEP
633 || (isalpha((unsigned char)fname[0])
634 && fname[1] == ':'))
635 #else
636 else if (fname[0] == C_FILESEP || fname[0] == '~')
637 #endif
639 strncpy(dir, fname, MIN(p - fname, sizeof(dir)-1));
640 dir[MIN(p-fname, sizeof(dir)-1)] = '\0';
642 else
643 snprintf(dir, sizeof(dir), "%s%c%.*s",
644 (gmode & MDCURDIR)
645 ? "."
646 : ((gmode & MDTREE) || opertree[0])
647 ? opertree : gethomedir(NULL),
648 C_FILESEP, (int) (p - fname), fname);
650 else{
651 fn = fname;
652 strncpy(dir, (gmode & MDCURDIR)
653 ? "."
654 : ((gmode & MDTREE) || opertree[0])
655 ? opertree : gethomedir(NULL), sizeof(dir));
656 dir[sizeof(dir)-1] = '\0';
659 if(!pico_fncomplete(dir, fn, sizeof(fname)-(fn-fname)))
660 (*term.t_beep)();
663 continue;
665 case (CTRL|'T'):
666 /* If we have a file name, break up into path and file name.*/
667 *shows = 0;
668 if(*fname) {
669 if(isdir(fname, NULL, NULL)) {
670 /* fname is a directory. */
671 strncpy(shows, fname, sizeof(shows));
672 shows[sizeof(shows)-1] = '\0';
673 *fname = '\0';
675 else {
676 /* Find right most separator. */
677 bufp = strrchr (fname, C_FILESEP);
678 if (bufp != NULL) {
679 /* Copy directory part to 'shows', and file
680 * name part to front of 'fname'. */
681 *bufp = '\0';
682 strncpy(shows, fname, sizeof(shows));
683 shows[sizeof(shows)-1] = '\0';
684 strncpy(fname, bufp+1, MIN(strlen(bufp+1)+1, sizeof(fname)));
685 fname[sizeof(fname)-1] = '\0';
690 /* If we did not end up with a valid directory, use home. */
691 if (!*shows || !isdir (shows, NULL, NULL)){
692 strncpy(shows, ((gmode & MDTREE) || opertree[0])
693 ? opertree
694 : (browse_dir[0] ? browse_dir
695 : gethomedir(NULL)), sizeof(shows));
696 shows[sizeof(shows)-1] = '\0';
699 strncpy(origshows, shows, sizeof(origshows));
700 origshows[sizeof(origshows)-1] = '\0';
701 if ((s = FileBrowse(shows, sizeof(shows), fname, sizeof(fname), NULL, 0,
702 FB_SAVE, NULL)) == 1) {
703 if (strlen(shows)+strlen(S_FILESEP)+strlen(fname) < NLINE){
704 strncat(shows, S_FILESEP, sizeof(shows)-strlen(shows)-1);
705 shows[sizeof(shows)-1] = '\0';
706 strncat(shows, fname, sizeof(shows)-strlen(shows)-1);
707 shows[sizeof(shows)-1] = '\0';
708 strncpy(fname, shows, sizeof(fname));
709 fname[sizeof(fname)-1] = '\0';
711 else {
712 emlwrite("Cannot write. File name too long!!",NULL);
713 sleep(3);
716 else if (s == 0 && strcmp(shows, origshows)){
717 strncat(shows, S_FILESEP, sizeof(shows)-strlen(shows)-1);
718 shows[sizeof(shows)-1] = '\0';
719 strncat(shows, fname, sizeof(shows)-strlen(shows)-1);
720 shows[sizeof(shows)-1] = '\0';
721 strncpy(fname, shows, sizeof(fname));
722 fname[sizeof(fname)-1] = '\0';
724 else if (s == -1){
725 emlwrite("Cannot write. File name too long!!",NULL);
726 sleep(3);
729 pico_refresh(FALSE, 1);
730 update();
731 if(s == 1)
732 break;
733 else
734 continue;
736 case HELPCH:
737 pico_help(writehelp, "", 1);
738 case (CTRL|'L'):
739 pico_refresh(FALSE, 1);
740 update();
741 continue;
743 default:
744 return(s);
745 break;
748 if(strcmp(fname, curbp->b_fname) == 0)
749 break;
751 if((s=fexist(fname, "w", (off_t *)NULL)) == FIOSUC){
752 /*exists overwrite? */
754 snprintf(shows, sizeof(shows), _("File \"%s\" exists, OVERWRITE"), fname);
755 if((s=mlyesno_utf8(shows, FALSE)) == TRUE)
756 break;
758 else if(s == FIOFNF){
759 break; /* go write it */
761 else{ /* some error, can't write */
762 fioperr(s, fname);
763 return(ABORT);
767 emlwrite("Writing...", NULL);
769 if ((s=writeout(fname, 0)) != -1) {
770 if(!(gmode&MDTOOL)){
771 strncpy(curbp->b_fname, fname, sizeof(curbp->b_fname));
772 curbp->b_fname[sizeof(curbp->b_fname)-1] = '\0';
773 curbp->b_flag &= ~BFCHG;
775 wp = wheadp; /* Update mode lines. */
776 while (wp != NULL) {
777 if (wp->w_bufp == curbp)
778 if((Pmaster && s == TRUE) || Pmaster == NULL)
779 wp->w_flag |= WFMODE;
780 wp = wp->w_wndp;
784 if(s > 1){
785 eml.s = comatose(s);
786 emlwrite(_("Wrote %s lines"), &eml);
788 else
789 emlwrite(_("Wrote 1 line"), NULL);
792 return ((s == -1) ? FALSE : TRUE);
797 * Save the contents of the current
798 * buffer in its associatd file. No nothing
799 * if nothing has changed (this may be a bug, not a
800 * feature). Error if there is no remembered file
801 * name for the buffer. Bound to "C-X C-S". May
802 * get called by "C-Z".
805 filesave(int f, int n)
807 register WINDOW *wp;
808 register int s;
809 EML eml;
811 if (curbp->b_mode&MDVIEW) /* don't allow this command if */
812 return(rdonly()); /* we are in read only mode */
813 if ((curbp->b_flag&BFCHG) == 0) /* Return, no changes. */
814 return (TRUE);
815 if (curbp->b_fname[0] == 0) { /* Must have a name. */
816 emlwrite(_("No file name"), NULL);
817 sleep(2);
818 return (FALSE);
821 emlwrite("Writing...", NULL);
822 if ((s=writeout(curbp->b_fname, 0)) != -1) {
823 curbp->b_flag &= ~BFCHG;
824 wp = wheadp; /* Update mode lines. */
825 while (wp != NULL) {
826 if (wp->w_bufp == curbp)
827 if(Pmaster == NULL)
828 wp->w_flag |= WFMODE;
829 wp = wp->w_wndp;
831 if(s > 1){
832 eml.s = comatose(s);
833 emlwrite(_("Wrote %s lines"), &eml);
835 else
836 emlwrite(_("Wrote 1 line"), NULL);
838 return (s);
843 * This function performs the details of file
844 * writing. Uses the file management routines in the
845 * "fileio.c" package. The number of lines written is
846 * displayed. Sadly, it looks inside a LINE; provide
847 * a macro for this. Most of the grief is error
848 * checking of some sort.
850 * If the argument readonly is set, the file is created with user read
851 * and write permission only if it doesn't already exist. Note that the
852 * word readonly is misleading. It is user r/w permission only.
854 * CHANGES: 1 Aug 91: returns number of lines written or -1 on error, MSS
857 writeout(char *fn, int readonly)
859 register int s;
860 register int t;
861 register LINE *lp;
862 register int nline;
864 if (!((s = ffwopen(fn, readonly)) == FIOSUC && ffelbowroom()))
865 return (-1); /* Open writes message. */
867 lp = lforw(curbp->b_linep); /* First line. */
868 nline = 0; /* Number of lines. */
869 while (lp != curbp->b_linep) {
870 if ((s=ffputline(&lp->l_text[0], llength(lp))) != FIOSUC)
871 break;
872 ++nline;
873 lp = lforw(lp);
876 t = ffclose(); /* ffclose complains if error */
878 if(s == FIOSUC)
879 s = t; /* report worst case */
881 return ((s == FIOSUC) ? nline : -1);
886 * writetmp - write a temporary file for message text, mindful of
887 * access restrictions and included text. If n is true, include
888 * lines that indicated included message text, otw forget them
889 * If dir is non-null, put the temp file in that directory.
891 char *
892 writetmp(int n, char *dir)
894 static char fn[NFILEN];
895 register int s;
896 register int t;
897 register LINE *lp;
898 register int nline;
900 tmpname(dir, fn);
902 /* Open writes message */
903 if (!fn[0] || (s=ffwopen(fn, TRUE)) != FIOSUC){
904 if(fn[0])
905 our_unlink(fn);
907 return(NULL);
910 lp = lforw(curbp->b_linep); /* First line. */
911 nline = 0; /* Number of lines. */
912 while (lp != curbp->b_linep) {
913 if(n || (!n && lp->l_text[0].c != '>'))
914 if ((s=ffputline(&lp->l_text[0], llength(lp))) != FIOSUC)
915 break;
917 ++nline;
918 lp = lforw(lp);
921 t = ffclose(); /* ffclose complains if error */
923 if(s == FIOSUC)
924 s = t; /* remember worst case */
926 if (s != FIOSUC){ /* Some sort of error. */
927 our_unlink(fn);
928 return(NULL);
931 return(fn);
936 * Insert file "fname" into the current
937 * buffer, Called by insert file command. Return the final
938 * status of the read.
941 ifile(char fname[])
943 UCS line[NLINE], *linep;
944 long nline;
945 int s, done, newline;
946 size_t charsread = 0;
947 EML eml;
949 if ((s=ffropen(fname)) != FIOSUC){ /* Hard file open. */
950 fioperr(s, fname);
951 return(FALSE);
954 gotobol(FALSE, 1);
956 curbp->b_flag |= BFCHG; /* we have changed */
957 curbp->b_flag &= ~BFTEMP; /* and are not temporary*/
958 curbp->b_linecnt = -1; /* must be recalculated */
960 eml.s = fname;
961 emlwrite(_("Inserting %s."), &eml);
962 done = newline = 0;
963 nline = 0L;
964 while(!done)
965 if((s = ffgetline(line, NLINE, &charsread, 1)) == FIOEOF){
966 char b[200];
968 if(llength(curwp->w_dotp) > curwp->w_doto)
969 lnewline();
970 else
971 forwchar(FALSE, 1);
973 if(nline > 1)
974 snprintf(b, sizeof(b), _("Inserted %ld lines"), nline);
975 else
976 snprintf(b, sizeof(b), _("Inserted 1 line"));
978 emlwrite(b, NULL);
979 break;
981 else{
982 if(newline){
983 if(lnewline() == FALSE){
984 done++;
985 continue;
987 newline = 0;
990 switch(s){
991 case FIOSUC : /* copy line into buf */
992 nline++;
993 newline = 1;
995 case FIOLNG :
996 for(linep = line; charsread-- > 0; linep++)
997 if(linsert(1, *linep) == FALSE) done++;
999 break;
1001 default :
1002 done++;
1006 ffclose(); /* Ignore errors. */
1008 return(s != FIOERR);
1013 * pico_fncomplete - pico's function to complete the given file name
1016 pico_fncomplete(char *dirarg, char *fn, size_t fnlen)
1018 char *p, *dlist, tmp[NLINE], dir[NLINE];
1019 int n, i, match = -1;
1020 #ifdef DOS
1021 #define FILECMP(x, y) (toupper((unsigned char)(x))\
1022 == toupper((unsigned char)(y)))
1023 #else
1024 #define FILECMP(x, y) ((x) == (y))
1025 #endif
1027 strncpy(dir, dirarg, sizeof(dir));
1028 dir[sizeof(dir)-1] = '\0';
1029 pfnexpand(dir, sizeof(dir));
1030 if(*fn && (dlist = p = getfnames(dir, fn, &n, NULL, 0))){
1031 memset(tmp, 0, sizeof(tmp));
1032 while(n--){ /* any names in it */
1033 for(i = 0; i < sizeof(tmp)-1 && fn[i] && FILECMP(p[i], fn[i]); i++)
1036 if(!fn[i]){ /* match or more? */
1037 if(tmp[0]){
1038 for(; p[i] && FILECMP(p[i], tmp[i]); i++)
1041 match = !p[i] && !tmp[i];
1042 tmp[i] = '\0'; /* longest common string */
1044 else{
1045 match = 1; /* may be it!?! */
1046 strncpy(tmp, p, sizeof(tmp));
1047 tmp[sizeof(tmp)-1] = '\0';
1051 p += strlen(p) + 1;
1054 free(dlist);
1057 if(match >= 0){
1058 strncpy(fn, tmp, fnlen);
1059 fn[fnlen-1] = '\0';
1060 if(match == 1){
1061 if ((strlen(dir)+strlen(S_FILESEP)+strlen(fn)) < sizeof(dir)){
1062 strncat(dir, S_FILESEP, sizeof(dir)-strlen(dir)-1);
1063 dir[sizeof(dir)-1] = '\0';
1064 strncat(dir, fn, sizeof(dir)-strlen(dir)-1);
1065 dir[sizeof(dir)-1] = '\0';
1066 if(isdir(dir, NULL, NULL)){
1067 strncat(fn, S_FILESEP, fnlen-strlen(fn)-1);
1068 fn[fnlen-1] = '\0';
1071 else{
1072 emlwrite("File name too BIG!!",0);
1073 sleep(3);
1074 *fn = '\0';
1080 return(match == 1);
1085 * in_oper_tree - returns true if file "f" does reside in opertree
1088 in_oper_tree(char *f)
1090 int end = strlen(opertree);
1092 return(!strncmp(opertree, f, end)
1093 && (opertree[end-1] == '/'
1094 || opertree[end-1] == '\\'
1095 || f[end] == '\0'
1096 || f[end] == '/'
1097 || f[end] == '\\'));