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-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 * ========================================================================
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 "../c-client/utf8.h"
35 #include "../pith/osdep/collate.h"
36 #include "../pith/charconv/filesys.h"
37 #include "../pith/charconv/utf8.h"
38 #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
;
170 utf8_parameters(SET_UCS4WIDTH
, (void *) pith_ucs4width
);
171 #endif /* _WINDOWS */
173 set_input_timeout(600);
174 Pmaster
= NULL
; /* turn OFF composer functionality */
178 * Read command line flags before initializing, otherwise, we never
179 * know to init for f_keys...
181 file_to_edit
= pico_args(argc
, argv
, &starton
, &viewflag
, &setlocale_collate
);
183 set_collation(setlocale_collate
, 1);
185 #define cpstr(s) strcpy((char *)fs_get(1+strlen(s)), s)
188 init_utf8_display(1, NULL
);
192 if(display_character_set
)
193 display_charmap
= cpstr(display_character_set
);
194 #if HAVE_LANGINFO_H && defined(CODESET)
195 else if((dc
= nl_langinfo_codeset_wrapper()) != NULL
)
196 display_charmap
= cpstr(dc
);
200 display_charmap
= cpstr("US-ASCII");
202 if(keyboard_character_set
)
203 keyboard_charmap
= cpstr(keyboard_character_set
);
205 keyboard_charmap
= cpstr(display_charmap
);
208 if(use_system_translation
){
209 #if PREREQ_FOR_SYS_TRANSLATION
211 /* This modifies its arguments */
212 if(setup_for_input_output(use_system
, &display_charmap
, &keyboard_charmap
,
213 &input_cs
, &err
) == -1){
214 fprintf(stderr
, "%s\n", err
? err
: "trouble with character set");
218 fprintf(stderr
, "%s\n", err
);
219 fs_give((void **) &err
);
225 if(setup_for_input_output(use_system
, &display_charmap
, &keyboard_charmap
,
226 &input_cs
, &err
) == -1){
227 fprintf(stderr
, "%s\n", err
? err
: "trouble with character set");
231 fprintf(stderr
, "%s\n", err
);
232 fs_give((void **) &err
);
236 if(keyboard_charmap
){
237 set_locale_charmap(keyboard_charmap
);
238 free((void *) keyboard_charmap
);
242 free((void *) display_charmap
);
247 * There are a couple arguments that we need to be sure
248 * are converted for internal use.
251 alt_speller
= cpstr(fname_to_utf8(alt_speller
));
253 if(opertree
&& opertree
[0]){
254 strncpy(opertree
, fname_to_utf8(opertree
), sizeof(opertree
));
255 opertree
[sizeof(opertree
)-1] = '\0';
258 if(glo_quote_str_orig
)
259 glo_quote_str
= utf8_to_ucs4_cpystr(fname_to_utf8(glo_quote_str_orig
));
261 if(glo_wordseps_orig
)
262 glo_wordseps
= utf8_to_ucs4_cpystr(fname_to_utf8(glo_wordseps_orig
));
265 file_to_edit
= cpstr(fname_to_utf8(file_to_edit
));
269 #if defined(DOS) || defined(OS2)
270 if(file_to_edit
){ /* strip quotes? */
273 if(strchr("'\"", file_to_edit
[0])
274 && (l
= strlen(file_to_edit
)) > 1
275 && file_to_edit
[l
-1] == file_to_edit
[0]){
276 file_to_edit
[l
-1] = '\0'; /* blat trailing quote */
277 file_to_edit
++; /* advance past leading quote */
282 if(!vtinit()) /* Displays. */
285 strncpy(bname
, "main", sizeof(bname
)); /* default buffer name */
286 bname
[sizeof(bname
)-1] = '\0';
287 edinit(bname
); /* Buffers, windows. */
289 update(); /* let the user know we are here */
292 mswin_setwindow(NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
294 mswin_showcaret(1); /* turn on for main window */
295 mswin_allowpaste(MSWIN_PASTE_FULL
);
296 mswin_setclosetext("Use the ^X command to exit Pico.");
297 mswin_setscrollcallback (pico_scroll_callback
);
300 #if defined(USE_TERMCAP) || defined(USE_TERMINFO) || defined(VMS)
301 if(kbesc
== NULL
){ /* will arrow keys work ? */
302 (*term
.t_putchar
)('\007');
303 emlwrite("Warning: keypad keys may be non-functional", NULL
);
305 #endif /* USE_TERMCAP/USE_TERMINFO/VMS */
307 if(file_to_edit
){ /* Any file to edit? */
309 makename(bname
, file_to_edit
); /* set up a buffer for this file */
311 bp
= curbp
; /* read in first file */
312 makename(bname
, file_to_edit
);
313 strncpy(bp
->b_bname
, bname
, sizeof(bp
->b_bname
));
314 bp
->b_bname
[sizeof(bp
->b_bname
)-1] = '\0';
316 if(strlen(file_to_edit
) >= NFILEN
){
319 snprintf(buf
, sizeof(buf
), "Filename \"%.10s...\" too long", file_to_edit
);
324 strncpy(bp
->b_fname
, file_to_edit
, sizeof(bp
->b_fname
));
325 bp
->b_fname
[sizeof(bp
->b_fname
)-1] = '\0';
326 if (((gmode
&MDTREE
) && !in_oper_tree(file_to_edit
)) ||
327 readin(file_to_edit
, (viewflag
==FALSE
), TRUE
) == ABORT
) {
328 if ((gmode
&MDTREE
) && !in_oper_tree(file_to_edit
)){
331 emlwrite(_("Can't read file from outside of %s"), &eml
);
339 strncpy(bp
->b_bname
, "main", sizeof(bp
->b_bname
));
340 bp
->b_bname
[sizeof(bp
->b_bname
)-1] = '\0';
341 strncpy(bp
->b_fname
, "", sizeof(bp
->b_fname
));
342 bp
->b_fname
[sizeof(bp
->b_fname
)-1] = '\0';
345 bp
->b_dotp
= bp
->b_linep
;
348 if (viewflag
) /* set the view mode */
349 bp
->b_mode
|= MDVIEW
;
352 /* setup to process commands */
353 lastflag
= 0; /* Fake last flags. */
354 curbp
->b_mode
|= gmode
; /* and set default modes*/
356 curwp
->w_flag
|= WFMODE
; /* and force an update */
361 eml
.s
= comatose(get_input_timeout());
362 emlwrite(_("Checking for new mail every %s seconds"), &eml
);
366 forwline(0, starton
- 1); /* move dot to specified line */
372 if(km_popped
== 0) /* cause bottom three lines to be repainted */
373 curwp
->w_flag
|= WFHARD
;
376 if(km_popped
){ /* temporarily change to cause menu to be painted */
378 curwp
->w_ntrows
-= 2;
379 curwp
->w_flag
|= WFMODE
;
380 movecursor(term
.t_nrow
-2, 0); /* clear status line, too */
384 update(); /* Fix up the screen */
387 curwp
->w_ntrows
+= 2;
392 /* New mouse function for real mouse text seletion. */
393 register_mfunc(mouse_in_pico
, 2, 0, term
.t_nrow
- (term
.t_mrow
+ 1),
396 mouse_in_content(KEY_MOUSE
, -1, -1, 0, 0);
397 register_mfunc(mouse_in_content
, 2, 0, term
.t_nrow
- (term
.t_mrow
+ 1),
402 mswin_setdndcallback (pico_file_drop
);
403 mswin_mousetrackcallback(pico_cursor
);
408 clear_mfunc(mouse_in_pico
);
410 clear_mfunc(mouse_in_content
);
414 mswin_cleardndcallback ();
415 mswin_mousetrackcallback(NULL
);
418 if(timeoutset
&& (c
== NODATA
|| time_to_check())){
420 emlwrite(_("You may possibly have new mail."), NULL
);
431 /* clear bottom three lines */
439 if(mpresf
){ /* erase message line? */
440 if(mpresf
++ > MESSDELAY
)
448 clear_mfunc(mouse_in_content
);
451 execute(normalize_cmd(c
, fkm
, 1), f
, n
);
457 * Parse the command line args.
461 * starton -- place to return starton value
462 * viewflag -- place to return viewflag value
464 * Result: command arguments parsed
465 * possible printing of help for command line
466 * various global flags set
467 * returns the name of any file to open, else NULL
470 pico_args(int ac
, char **av
, int *starton
, int *viewflag
, int *setlocale_collate
)
474 char tmp_1k_buf
[1000]; /* tmp buf to contain err msgs */
477 /* while more arguments with leading - or + */
478 while(--ac
> 0 && (**++av
== '-' || **av
== '+')){
485 snprintf(tmp_1k_buf
, sizeof(tmp_1k_buf
), _(args_pico_missing_arg
), '+');
486 pico_display_args_err(tmp_1k_buf
, NULL
, 1);
491 if(!isdigit((unsigned char)str
[0])){
492 snprintf(tmp_1k_buf
, sizeof(tmp_1k_buf
), _(args_pico_missing_num
), '+');
493 pico_display_args_err(tmp_1k_buf
, NULL
, 1);
498 *starton
= atoi(str
);
503 /* while more chars in this argument */
506 if(strcmp(*av
, "version") == 0){
509 else if(strcmp(*av
, "no_setlocale_collate") == 0){
510 *setlocale_collate
= 0;
514 else if(strcmp(*av
, "syscs") == 0){
515 use_system_translation
= !use_system_translation
;
518 #endif /* ! _WINDOWS */
520 else if(strcmp(*av
, "cnf") == 0
521 || strcmp(*av
, "cnb") == 0
522 || strcmp(*av
, "crf") == 0
523 || strcmp(*av
, "crb") == 0){
525 char *cmd
= *av
; /* save it to use below */
532 else if(cmd
[2] == 'b')
535 else if(cmd
[1] == 'r'){
538 else if(cmd
[2] == 'b')
543 snprintf(tmp_1k_buf
, sizeof(tmp_1k_buf
), _(args_pico_missing_color
), cmd
);
544 pico_display_args_err(tmp_1k_buf
, NULL
, 1);
550 #endif /* _WINDOWS */
552 else if(strcmp(*av
, "dcs") == 0 || strcmp(*av
, "kcs") == 0){
556 if(strcmp(*av
, "dcs") == 0){
557 display_character_set
= *++av
;
558 if(!output_charset_is_supported(display_character_set
)){
559 snprintf(tmp_1k_buf
, sizeof(tmp_1k_buf
), _(args_pico_output_charset
), display_character_set
);
560 pico_display_args_err(tmp_1k_buf
, NULL
, 1);
565 keyboard_character_set
= *++av
;
566 if(!input_charset_is_supported(keyboard_character_set
)){
567 snprintf(tmp_1k_buf
, sizeof(tmp_1k_buf
), _(args_pico_input_charset
), keyboard_character_set
);
568 pico_display_args_err(tmp_1k_buf
, NULL
, 1);
574 snprintf(tmp_1k_buf
, sizeof(tmp_1k_buf
), _(args_pico_missing_charset
), cmd
);
575 pico_display_args_err(tmp_1k_buf
, NULL
, 1);
581 #endif /* ! _WINDOWS */
584 * Single char options.
588 * These don't take arguments.
591 gmode
^= MDDOTSOK
; /* show dot files */
596 * Make MDREPLACE always on instead
597 * Don't leave this to allow turning off of MDREPLACE because the
598 * polarity of -b will have changed. Don't think anybody wants to
601 gmode
^= MDREPLACE
; /* -b for replace string in where is command */
604 case 'd': /* -d for rebind delete key */
605 bindtokey(0x7f, forwdel
);
607 case 'e': /* file name completion */
610 case 'f': /* -f for function key use */
613 case 'g': /* show-cursor in file browser */
619 case 'j': /* allow "Goto" in file browser */
622 case 'k': /* kill from dot */
625 case 'm': /* turn on mouse support */
629 preserve_start_stop
= 1;
631 case 'q': /* -q for termcap takes precedence */
634 case 't': /* special shutdown mode */
636 rebindfunc(wquit
, quickexit
);
638 case 'v': /* -v for View File */
640 *viewflag
= !*viewflag
;
641 break; /* break back to inner-while */
642 case 'w': /* -w turn off word wrap */
645 case 'x': /* suppress keyhelp */
646 sup_keyhelp
= !sup_keyhelp
;
648 case 'z': /* -z to suspend */
653 * These do take arguments.
655 case 'r': /* set fill column */
656 case 'n': /* -n for new mail notification */
657 case 's' : /* speller */
658 case 'o' : /* operating tree */
659 case 'Q' : /* Quote string */
660 case 'W' : /* Word separators */
671 snprintf(tmp_1k_buf
, sizeof(tmp_1k_buf
), _(args_pico_missing_arg
), c
);
672 pico_display_args_err(tmp_1k_buf
, NULL
, 1);
683 strncpy(opertree
, str
, NLINE
);
687 glo_quote_str_orig
= str
;
690 glo_wordseps_orig
= str
;
696 if(!isdigit((unsigned char)str
[0])){
697 snprintf(tmp_1k_buf
, sizeof(tmp_1k_buf
), _(args_pico_missing_num
), c
);
698 pico_display_args_err(tmp_1k_buf
, NULL
, 1);
703 if((userfillcol
= atoi(str
)) < 1)
708 set_input_timeout(180);
709 if(set_input_timeout(atoi(str
)) < 30)
710 set_input_timeout(180);
719 snprintf(tmp_1k_buf
, sizeof(tmp_1k_buf
), _(args_pico_missing_flag
), c
);
720 pico_display_args_err(tmp_1k_buf
, NULL
, 1);
730 /* return the first filename for editing */
743 pico_file_drop(int x
, int y
, char *filename
)
746 * if current buffer is unchanged
747 * *or* "new buffer" and no current text
749 if(((curwp
->w_bufp
->b_flag
& BFCHG
) == 0)
750 || (curwp
->w_bufp
->b_fname
[0] == '\0'
751 && curwp
->w_bufp
->b_linep
== lforw(curwp
->w_bufp
->b_linep
)
752 && curwp
->w_doto
== 0)){
753 register BUFFER
*bp
= curwp
->w_bufp
;
756 makename(bname
, filename
);
757 strncpy(bp
->b_bname
, bname
, sizeof(bp
->b_bname
));
758 bp
->b_bname
[sizeof(bp
->b_bname
)-1] = '\0';
759 strncpy(bp
->b_fname
, filename
, sizeof(bp
->b_fname
));
760 bp
->b_fname
[sizeof(bp
->b_fname
)-1] = '\0';
761 bp
->b_flag
&= ~BFCHG
; /* turn off change bit */
762 if (readin(filename
, 1, 1) == ABORT
) {
763 strncpy(bp
->b_bname
, "", sizeof(bp
->b_bname
));
764 bp
->b_bname
[sizeof(bp
->b_bname
)-1] = '\0';
765 strncpy(bp
->b_fname
, "", sizeof(bp
->b_fname
));
766 bp
->b_fname
[sizeof(bp
->b_fname
)-1] = '\0';
769 bp
->b_dotp
= bp
->b_linep
;
776 curwp
->w_flag
|= WFHARD
;
779 emlwrite("Inserted dropped file \"%s\"", &eml
);
782 curwp
->w_flag
|= WFHARD
;
783 update(); /* restore cursor */
789 /*----------------------------------------------------------------------
790 print a few lines of help for command line arguments
794 Result: prints help messages
795 ----------------------------------------------------------------------*/
804 /** print out possible starting arguments... **/
806 for(a
=args_pico_args
; a
&& *a
; a
++){
808 pico_display_args_err(NULL
, pp
, 0);
821 snprintf(v0
, sizeof(v0
), "Pico %.50s", version
);
825 pico_display_args_err(NULL
, v
, 0);
830 /*----------------------------------------------------------------------
831 write argument error to the display...
835 Result: prints help messages
836 ----------------------------------------------------------------------*/
838 pico_display_args_err(char *s
, char **a
, int err
)
840 char errstr
[256], *errp
;
841 FILE *fp
= err
? stderr
: stdout
;
843 char tmp_20k_buf
[SIZEOF_20KBUF
];
848 snprintf(errp
= errstr
, sizeof(errstr
), _("Argument Error: %.200s"), s
);
854 mswin_messagebox(errp
, err
);
857 strncpy(tmp_20k_buf
, *a
++, SIZEOF_20KBUF
);
858 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
860 strncat(tmp_20k_buf
, "\n", SIZEOF_20KBUF
-strlen(tmp_20k_buf
)-1);
861 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
862 strncat(tmp_20k_buf
, *a
++, SIZEOF_20KBUF
-strlen(tmp_20k_buf
)-1);
863 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
866 mswin_messagebox(tmp_20k_buf
, err
);
870 fprintf(fp
, "%s\n", errp
);
873 fprintf(fp
, "%s\n", *a
++);