1 #if !defined(lint) && !defined(DOS)
2 static char rcsid
[] = "$Id: main.c 1184 2008-12-16 23:52:15Z hubert@u.washington.edu $";
6 * ========================================================================
7 * Copyright 2006-2008 University of Washington
8 * Copyright 2013-2014 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 * ========================================================================
20 * Program: Main stand-alone Pine Composer routines
25 * 08 Jan 92 - removed PINE defines to simplify compiling
27 * 08 Apr 92 - removed PINE stub calls
32 #include "../c-client/mail.h"
33 #include "../c-client/rfc822.h"
34 #include "../pith/osdep/collate.h"
35 #include "../pith/charconv/filesys.h"
36 #include "../pith/charconv/utf8.h"
37 #include "../pith/conf.h"
41 * Useful internal prototypes
44 int pico_file_drop(int, int, char *);
48 * this isn't defined in the library, because it's a pine global
49 * which we use for GetKey's timeout
54 int my_timer_period
= (300 * 1000);
57 * function key mappings
59 static UCS fkm
[12][2] = {
78 char *pico_args(int, char **, int *, int *, int *);
79 void pico_args_help(void);
80 void pico_vers_help(void);
81 void pico_display_args_err(char *, char **, int);
83 /* TRANSLATORS: An error message about an unknown flag (option)
84 on the command line */
85 char args_pico_missing_flag
[] = N_("unknown flag \"%c\"");
86 /* TRANSLATORS: error message about command line */
87 char args_pico_missing_arg
[] = N_("missing or empty argument to \"%c\" flag");
88 char args_pico_missing_num
[] = N_("non numeric argument for \"%c\" flag");
89 char args_pico_missing_color
[] = N_("missing color for \"%s\" flag");
90 char args_pico_missing_charset
[] = N_("missing character set for \"%s\" flag");
91 char args_pico_input_charset
[] = N_("input character set \"%s\" is unsupported");
92 char args_pico_output_charset
[] = N_("output character set \"%s\" is unsupported");
94 char *args_pico_args
[] = {
95 /* TRANSLATORS: little help printed out when incorrect arguments
96 are given to pico program. */
97 N_("Possible Starting Arguments for Pico editor:"),
99 N_("\tArgument\t\tMeaning"),
100 N_("\t -e \t\tComplete - allow file name completion"),
101 N_("\t -k \t\tCut - let ^K cut from cursor position to end of line"),
102 N_("\t -a \t\tShowDot - show dot files in file browser"),
103 N_("\t -j \t\tGoto - allow 'Goto' command in file browser"),
104 N_("\t -g \t\tShow - show cursor in file browser"),
105 N_("\t -m \t\tMouse - turn on mouse support"),
106 N_("\t -x \t\tNoKeyhelp - suppress keyhelp"),
107 N_("\t -p \t\tPreserveStartStop - preserve \"start\"(^Q) and \"stop\"(^S) characters"),
108 N_("\t -q \t\tTermdefWins - termcap or terminfo takes precedence over defaults"),
109 N_("\t -Q <quotestr> \tSet quote string (eg. \"> \") esp. for composing email"),
110 N_("\t -d \t\tRebind - let delete key delete current character"),
111 N_("\t -f \t\tKeys - force use of function keys"),
112 N_("\t -b \t\tReplace - allow search and replace"),
113 N_("\t -h \t\tHelp - give this list of options"),
114 N_("\t -r[#cols] \tFill - set fill column to #cols columns, default=72"),
115 N_("\t -n[#s] \tMail - notify about new mail every #s seconds, default=180"),
116 N_("\t -s <speller> \tSpeller - specify alternative speller"),
117 N_("\t -t \t\tShutdown - enable special shutdown mode"),
118 N_("\t -o <dir>\tOperation - specify the operating directory"),
119 N_("\t -z \t\tSuspend - allow use of ^Z suspension"),
120 N_("\t -w \t\tNoWrap - turn off word wrap"),
121 N_("\t -W <wordseps> \tSet word separators other than whitespace"),
123 N_("\t -dcs <display_character_set> \tdefault uses LANG or LC_CTYPE from environment"),
124 N_("\t -kcs <keyboard_character_set> \tdefaults to display_character_set"),
125 N_("\t -syscs\t\tuse system-supplied translation routines"),
126 #endif /* ! _WINDOWS */
128 N_("\t -cnf color \tforeground color"),
129 N_("\t -cnb color \tbackground color"),
130 N_("\t -crf color \treverse foreground color"),
131 N_("\t -crb color \treverse background color"),
132 #endif /* _WINDOWS */
133 N_("\t +[line#] \tLine - start on line# line, default=1"),
134 N_("\t -v \t\tView - view file"),
135 N_("\t -no_setlocale_collate\tdo not do setlocale(LC_COLLATE)"),
136 N_("\t -version\tPico version number"),
138 N_("\t All arguments may be followed by a file name to display."),
145 * main standalone pico routine
149 app_main (int argc
, char *argv
[])
152 main(int argc
, char *argv
[])
159 int viewflag
= FALSE
; /* are we starting in view mode?*/
160 int starton
= 0; /* where's dot to begin with? */
161 int setlocale_collate
= 1;
162 char bname
[NBUFN
]; /* buffer name of file to read */
163 char *file_to_edit
= NULL
;
164 char *display_charmap
= NULL
, *dc
;
165 char *keyboard_charmap
= NULL
;
169 set_input_timeout(600);
170 Pmaster
= NULL
; /* turn OFF composer functionality */
174 * Read command line flags before initializing, otherwise, we never
175 * know to init for f_keys...
177 file_to_edit
= pico_args(argc
, argv
, &starton
, &viewflag
, &setlocale_collate
);
179 set_collation(setlocale_collate
, 1);
181 #define cpstr(s) strcpy((char *)fs_get(1+strlen(s)), s)
184 init_utf8_display(1, NULL
);
188 if(display_character_set
)
189 display_charmap
= cpstr(display_character_set
);
190 #if HAVE_LANGINFO_H && defined(CODESET)
191 else if((dc
= nl_langinfo_codeset_wrapper()) != NULL
)
192 display_charmap
= cpstr(dc
);
196 display_charmap
= cpstr("US-ASCII");
198 if(keyboard_character_set
)
199 keyboard_charmap
= cpstr(keyboard_character_set
);
201 keyboard_charmap
= cpstr(display_charmap
);
204 if(use_system_translation
){
205 #if PREREQ_FOR_SYS_TRANSLATION
207 /* This modifies its arguments */
208 if(setup_for_input_output(use_system
, &display_charmap
, &keyboard_charmap
,
209 &input_cs
, &err
) == -1){
210 fprintf(stderr
, "%s\n", err
? err
: "trouble with character set");
214 fprintf(stderr
, "%s\n", err
);
215 fs_give((void **) &err
);
221 if(setup_for_input_output(use_system
, &display_charmap
, &keyboard_charmap
,
222 &input_cs
, &err
) == -1){
223 fprintf(stderr
, "%s\n", err
? err
: "trouble with character set");
227 fprintf(stderr
, "%s\n", err
);
228 fs_give((void **) &err
);
232 if(keyboard_charmap
){
233 set_locale_charmap(keyboard_charmap
);
234 free((void *) keyboard_charmap
);
238 free((void *) display_charmap
);
243 * There are a couple arguments that we need to be sure
244 * are converted for internal use.
247 alt_speller
= cpstr(fname_to_utf8(alt_speller
));
249 if(opertree
&& opertree
[0]){
250 strncpy(opertree
, fname_to_utf8(opertree
), sizeof(opertree
));
251 opertree
[sizeof(opertree
)-1] = '\0';
254 if(glo_quote_str_orig
)
255 glo_quote_str
= utf8_to_ucs4_cpystr(fname_to_utf8(glo_quote_str_orig
));
257 if(glo_wordseps_orig
)
258 glo_wordseps
= utf8_to_ucs4_cpystr(fname_to_utf8(glo_wordseps_orig
));
261 file_to_edit
= cpstr(fname_to_utf8(file_to_edit
));
265 #if defined(DOS) || defined(OS2)
266 if(file_to_edit
){ /* strip quotes? */
269 if(strchr("'\"", file_to_edit
[0])
270 && (l
= strlen(file_to_edit
)) > 1
271 && file_to_edit
[l
-1] == file_to_edit
[0]){
272 file_to_edit
[l
-1] = '\0'; /* blat trailing quote */
273 file_to_edit
++; /* advance past leading quote */
278 if(!vtinit()) /* Displays. */
281 strncpy(bname
, "main", sizeof(bname
)); /* default buffer name */
282 bname
[sizeof(bname
)-1] = '\0';
283 edinit(bname
); /* Buffers, windows. */
285 update(); /* let the user know we are here */
288 mswin_setwindow(NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
290 mswin_showcaret(1); /* turn on for main window */
291 mswin_allowpaste(MSWIN_PASTE_FULL
);
292 mswin_setclosetext("Use the ^X command to exit Pico.");
293 mswin_setscrollcallback (pico_scroll_callback
);
296 #if defined(USE_TERMCAP) || defined(USE_TERMINFO) || defined(VMS)
297 if(kbesc
== NULL
){ /* will arrow keys work ? */
298 (*term
.t_putchar
)('\007');
299 emlwrite("Warning: keypad keys may be non-functional", NULL
);
301 #endif /* USE_TERMCAP/USE_TERMINFO/VMS */
303 if(file_to_edit
){ /* Any file to edit? */
305 makename(bname
, file_to_edit
); /* set up a buffer for this file */
307 bp
= curbp
; /* read in first file */
308 makename(bname
, file_to_edit
);
309 strncpy(bp
->b_bname
, bname
, sizeof(bp
->b_bname
));
310 bp
->b_bname
[sizeof(bp
->b_bname
)-1] = '\0';
312 if(strlen(file_to_edit
) >= NFILEN
){
315 snprintf(buf
, sizeof(buf
), "Filename \"%.10s...\" too long", file_to_edit
);
320 strncpy(bp
->b_fname
, file_to_edit
, sizeof(bp
->b_fname
));
321 bp
->b_fname
[sizeof(bp
->b_fname
)-1] = '\0';
322 if (((gmode
&MDTREE
) && !in_oper_tree(file_to_edit
)) ||
323 readin(file_to_edit
, (viewflag
==FALSE
), TRUE
) == ABORT
) {
324 if ((gmode
&MDTREE
) && !in_oper_tree(file_to_edit
)){
327 emlwrite(_("Can't read file from outside of %s"), &eml
);
335 strncpy(bp
->b_bname
, "main", sizeof(bp
->b_bname
));
336 bp
->b_bname
[sizeof(bp
->b_bname
)-1] = '\0';
337 strncpy(bp
->b_fname
, "", sizeof(bp
->b_fname
));
338 bp
->b_fname
[sizeof(bp
->b_fname
)-1] = '\0';
341 bp
->b_dotp
= bp
->b_linep
;
344 if (viewflag
) /* set the view mode */
345 bp
->b_mode
|= MDVIEW
;
348 /* setup to process commands */
349 lastflag
= 0; /* Fake last flags. */
350 curbp
->b_mode
|= gmode
; /* and set default modes*/
352 curwp
->w_flag
|= WFMODE
; /* and force an update */
357 eml
.s
= comatose(get_input_timeout());
358 emlwrite(_("Checking for new mail every %s seconds"), &eml
);
362 forwline(0, starton
- 1); /* move dot to specified line */
368 if(km_popped
== 0) /* cause bottom three lines to be repainted */
369 curwp
->w_flag
|= WFHARD
;
372 if(km_popped
){ /* temporarily change to cause menu to be painted */
374 curwp
->w_ntrows
-= 2;
375 curwp
->w_flag
|= WFMODE
;
376 movecursor(term
.t_nrow
-2, 0); /* clear status line, too */
380 update(); /* Fix up the screen */
383 curwp
->w_ntrows
+= 2;
388 /* New mouse function for real mouse text seletion. */
389 register_mfunc(mouse_in_pico
, 2, 0, term
.t_nrow
- (term
.t_mrow
+ 1),
392 mouse_in_content(KEY_MOUSE
, -1, -1, 0, 0);
393 register_mfunc(mouse_in_content
, 2, 0, term
.t_nrow
- (term
.t_mrow
+ 1),
398 mswin_setdndcallback (pico_file_drop
);
399 mswin_mousetrackcallback(pico_cursor
);
404 clear_mfunc(mouse_in_pico
);
406 clear_mfunc(mouse_in_content
);
410 mswin_cleardndcallback ();
411 mswin_mousetrackcallback(NULL
);
414 if(timeoutset
&& (c
== NODATA
|| time_to_check())){
416 emlwrite(_("You may possibly have new mail."), NULL
);
427 /* clear bottom three lines */
435 if(mpresf
){ /* erase message line? */
436 if(mpresf
++ > MESSDELAY
)
444 clear_mfunc(mouse_in_content
);
447 execute(normalize_cmd(c
, fkm
, 1), f
, n
);
453 * Parse the command line args.
457 * starton -- place to return starton value
458 * viewflag -- place to return viewflag value
460 * Result: command arguments parsed
461 * possible printing of help for command line
462 * various global flags set
463 * returns the name of any file to open, else NULL
466 pico_args(int ac
, char **av
, int *starton
, int *viewflag
, int *setlocale_collate
)
470 char tmp_1k_buf
[1000]; /* tmp buf to contain err msgs */
473 /* while more arguments with leading - or + */
474 while(--ac
> 0 && (**++av
== '-' || **av
== '+')){
481 snprintf(tmp_1k_buf
, sizeof(tmp_1k_buf
), _(args_pico_missing_arg
), '+');
482 pico_display_args_err(tmp_1k_buf
, NULL
, 1);
487 if(!isdigit((unsigned char)str
[0])){
488 snprintf(tmp_1k_buf
, sizeof(tmp_1k_buf
), _(args_pico_missing_num
), '+');
489 pico_display_args_err(tmp_1k_buf
, NULL
, 1);
494 *starton
= atoi(str
);
499 /* while more chars in this argument */
502 if(strcmp(*av
, "version") == 0){
505 else if(strcmp(*av
, "no_setlocale_collate") == 0){
506 *setlocale_collate
= 0;
510 else if(strcmp(*av
, "syscs") == 0){
511 use_system_translation
= !use_system_translation
;
514 #endif /* ! _WINDOWS */
516 else if(strcmp(*av
, "cnf") == 0
517 || strcmp(*av
, "cnb") == 0
518 || strcmp(*av
, "crf") == 0
519 || strcmp(*av
, "crb") == 0){
521 char *cmd
= *av
; /* save it to use below */
528 else if(cmd
[2] == 'b')
531 else if(cmd
[1] == 'r'){
534 else if(cmd
[2] == 'b')
539 snprintf(tmp_1k_buf
, sizeof(tmp_1k_buf
), _(args_pico_missing_color
), cmd
);
540 pico_display_args_err(tmp_1k_buf
, NULL
, 1);
546 #endif /* _WINDOWS */
548 else if(strcmp(*av
, "dcs") == 0 || strcmp(*av
, "kcs") == 0){
552 if(strcmp(*av
, "dcs") == 0){
553 display_character_set
= *++av
;
554 if(!output_charset_is_supported(display_character_set
)){
555 snprintf(tmp_1k_buf
, sizeof(tmp_1k_buf
), _(args_pico_output_charset
), display_character_set
);
556 pico_display_args_err(tmp_1k_buf
, NULL
, 1);
561 keyboard_character_set
= *++av
;
562 if(!input_charset_is_supported(keyboard_character_set
)){
563 snprintf(tmp_1k_buf
, sizeof(tmp_1k_buf
), _(args_pico_input_charset
), keyboard_character_set
);
564 pico_display_args_err(tmp_1k_buf
, NULL
, 1);
570 snprintf(tmp_1k_buf
, sizeof(tmp_1k_buf
), _(args_pico_missing_charset
), cmd
);
571 pico_display_args_err(tmp_1k_buf
, NULL
, 1);
577 #endif /* ! _WINDOWS */
580 * Single char options.
584 * These don't take arguments.
587 gmode
^= MDDOTSOK
; /* show dot files */
592 * Make MDREPLACE always on instead
593 * Don't leave this to allow turning off of MDREPLACE because the
594 * polarity of -b will have changed. Don't think anybody wants to
597 gmode
^= MDREPLACE
; /* -b for replace string in where is command */
600 case 'd': /* -d for rebind delete key */
601 bindtokey(0x7f, forwdel
);
603 case 'e': /* file name completion */
606 case 'f': /* -f for function key use */
609 case 'g': /* show-cursor in file browser */
615 case 'j': /* allow "Goto" in file browser */
618 case 'k': /* kill from dot */
621 case 'm': /* turn on mouse support */
625 preserve_start_stop
= 1;
627 case 'q': /* -q for termcap takes precedence */
630 case 't': /* special shutdown mode */
632 rebindfunc(wquit
, quickexit
);
634 case 'v': /* -v for View File */
636 *viewflag
= !*viewflag
;
637 break; /* break back to inner-while */
638 case 'w': /* -w turn off word wrap */
641 case 'x': /* suppress keyhelp */
642 sup_keyhelp
= !sup_keyhelp
;
644 case 'z': /* -z to suspend */
649 * These do take arguments.
651 case 'r': /* set fill column */
652 case 'n': /* -n for new mail notification */
653 case 's' : /* speller */
654 case 'o' : /* operating tree */
655 case 'Q' : /* Quote string */
656 case 'W' : /* Word separators */
667 snprintf(tmp_1k_buf
, sizeof(tmp_1k_buf
), _(args_pico_missing_arg
), c
);
668 pico_display_args_err(tmp_1k_buf
, NULL
, 1);
679 strncpy(opertree
, str
, NLINE
);
683 glo_quote_str_orig
= str
;
686 glo_wordseps_orig
= str
;
692 if(!isdigit((unsigned char)str
[0])){
693 snprintf(tmp_1k_buf
, sizeof(tmp_1k_buf
), _(args_pico_missing_num
), c
);
694 pico_display_args_err(tmp_1k_buf
, NULL
, 1);
699 if((userfillcol
= atoi(str
)) < 1)
704 set_input_timeout(180);
705 if(set_input_timeout(atoi(str
)) < 30)
706 set_input_timeout(180);
715 snprintf(tmp_1k_buf
, sizeof(tmp_1k_buf
), _(args_pico_missing_flag
), c
);
716 pico_display_args_err(tmp_1k_buf
, NULL
, 1);
726 /* return the first filename for editing */
739 pico_file_drop(int x
, int y
, char *filename
)
742 * if current buffer is unchanged
743 * *or* "new buffer" and no current text
745 if(((curwp
->w_bufp
->b_flag
& BFCHG
) == 0)
746 || (curwp
->w_bufp
->b_fname
[0] == '\0'
747 && curwp
->w_bufp
->b_linep
== lforw(curwp
->w_bufp
->b_linep
)
748 && curwp
->w_doto
== 0)){
749 register BUFFER
*bp
= curwp
->w_bufp
;
752 makename(bname
, filename
);
753 strncpy(bp
->b_bname
, bname
, sizeof(bp
->b_bname
));
754 bp
->b_bname
[sizeof(bp
->b_bname
)-1] = '\0';
755 strncpy(bp
->b_fname
, filename
, sizeof(bp
->b_fname
));
756 bp
->b_fname
[sizeof(bp
->b_fname
)-1] = '\0';
757 bp
->b_flag
&= ~BFCHG
; /* turn off change bit */
758 if (readin(filename
, 1, 1) == ABORT
) {
759 strncpy(bp
->b_bname
, "", sizeof(bp
->b_bname
));
760 bp
->b_bname
[sizeof(bp
->b_bname
)-1] = '\0';
761 strncpy(bp
->b_fname
, "", sizeof(bp
->b_fname
));
762 bp
->b_fname
[sizeof(bp
->b_fname
)-1] = '\0';
765 bp
->b_dotp
= bp
->b_linep
;
772 curwp
->w_flag
|= WFHARD
;
775 emlwrite("Inserted dropped file \"%s\"", &eml
);
778 curwp
->w_flag
|= WFHARD
;
779 update(); /* restore cursor */
785 /*----------------------------------------------------------------------
786 print a few lines of help for command line arguments
790 Result: prints help messages
791 ----------------------------------------------------------------------*/
800 /** print out possible starting arguments... **/
802 for(a
=args_pico_args
; a
&& *a
; a
++){
804 pico_display_args_err(NULL
, pp
, 0);
817 snprintf(v0
, sizeof(v0
), "Pico %.50s", version
);
821 pico_display_args_err(NULL
, v
, 0);
826 /*----------------------------------------------------------------------
827 write argument error to the display...
831 Result: prints help messages
832 ----------------------------------------------------------------------*/
834 pico_display_args_err(char *s
, char **a
, int err
)
836 char errstr
[256], *errp
;
837 FILE *fp
= err
? stderr
: stdout
;
839 char tmp_20k_buf
[SIZEOF_20KBUF
];
844 snprintf(errp
= errstr
, sizeof(errstr
), _("Argument Error: %.200s"), s
);
850 mswin_messagebox(errp
, err
);
853 strncpy(tmp_20k_buf
, *a
++, SIZEOF_20KBUF
);
854 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
856 strncat(tmp_20k_buf
, "\n", SIZEOF_20KBUF
-strlen(tmp_20k_buf
)-1);
857 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
858 strncat(tmp_20k_buf
, *a
++, SIZEOF_20KBUF
-strlen(tmp_20k_buf
)-1);
859 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
862 mswin_messagebox(tmp_20k_buf
, err
);
866 fprintf(fp
, "%s\n", errp
);
869 fprintf(fp
, "%s\n", *a
++);