Commit | Line | Data |
---|---|---|
1850e72c WJ |
1 | /* main.c */ |
2 | ||
3 | /* Author: | |
4 | * Steve Kirkendall | |
5 | * 14407 SW Teal Blvd. #C | |
6 | * Beaverton, OR 97005 | |
7 | * kirkenda@cs.pdx.edu | |
8 | */ | |
9 | ||
10 | ||
11 | /* This file contains the main() function of vi */ | |
12 | ||
13 | /* HACK! bcc needs to disable use of precompiled headers for this file, | |
14 | or else command line args will not be passed to elvis */ | |
15 | #if __BORLANDC__ | |
16 | #include "borland.h" | |
17 | #endif | |
18 | ||
19 | #include "config.h" | |
20 | #include <setjmp.h> | |
21 | #include "vi.h" | |
22 | ||
23 | extern trapint(); /* defined below */ | |
24 | extern char *getenv(); | |
25 | jmp_buf jmpenv; | |
26 | ||
27 | #ifndef NO_DIGRAPH | |
28 | static init_digraphs(); | |
29 | #endif | |
30 | ||
31 | /*---------------------------------------------------------------------*/ | |
32 | ||
33 | #if AMIGA | |
34 | # include "amiwild.c" | |
35 | main (argc, argv) | |
36 | #else | |
37 | # if VMS | |
38 | # include "vmswild.c" | |
39 | main (argc, argv) | |
40 | # else | |
41 | void main(argc, argv) | |
42 | # endif | |
43 | #endif | |
44 | int argc; | |
45 | char *argv[]; | |
46 | { | |
47 | int i; | |
48 | char *cmd = (char *)0; | |
49 | char *err = (char *)0; | |
50 | char *str; | |
51 | char *tag = (char *)0; | |
52 | ||
53 | /* set mode to MODE_VI or MODE_EX depending on program name */ | |
54 | switch (argv[0][strlen(argv[0]) - 1]) | |
55 | { | |
56 | case 'x': /* "ex" */ | |
57 | mode = MODE_EX; | |
58 | break; | |
59 | ||
60 | case 'w': /* "view" */ | |
61 | mode = MODE_VI; | |
62 | *o_readonly = TRUE; | |
63 | break; | |
64 | #ifndef NO_EXTENSIONS | |
65 | case 't': /* "edit" or "input" */ | |
66 | mode = MODE_VI; | |
67 | *o_inputmode = TRUE; | |
68 | break; | |
69 | #endif | |
70 | default: /* "vi" or "elvis" */ | |
71 | mode = MODE_VI; | |
72 | } | |
73 | ||
74 | #ifndef DEBUG | |
75 | # ifdef SIGQUIT | |
76 | /* normally, we ignore SIGQUIT. SIGINT is trapped later */ | |
77 | signal(SIGQUIT, SIG_IGN); | |
78 | # endif | |
79 | #endif | |
80 | ||
81 | /* temporarily ignore SIGINT */ | |
82 | signal(SIGINT, SIG_IGN); | |
83 | ||
84 | /* start curses */ | |
85 | initscr(); | |
86 | cbreak(); | |
87 | noecho(); | |
88 | scrollok(stdscr, TRUE); | |
89 | ||
90 | /* arrange for deadly signals to be caught */ | |
91 | # ifdef SIGHUP | |
92 | signal(SIGHUP, (void(*)()) deathtrap); | |
93 | # endif | |
94 | # ifndef DEBUG | |
95 | # ifdef SIGILL | |
96 | signal(SIGILL, (void(*)()) deathtrap); | |
97 | # endif | |
98 | # ifdef SIGBUS | |
99 | signal(SIGBUS, (void(*)()) deathtrap); | |
100 | # endif | |
101 | # ifdef SIGSEGV | |
102 | signal(SIGSEGV, (void(*)()) deathtrap); | |
103 | # endif | |
104 | # ifdef SIGSYS | |
105 | signal(SIGSYS, (void(*)()) deathtrap); | |
106 | # endif | |
107 | # endif /* !DEBUG */ | |
108 | # ifdef SIGPIPE | |
109 | signal(SIGPIPE, (void(*)()) deathtrap); | |
110 | # endif | |
111 | # ifdef SIGTERM | |
112 | signal(SIGTERM, (void(*)()) deathtrap); | |
113 | # endif | |
114 | # ifdef SIGUSR1 | |
115 | signal(SIGUSR1, (void(*)()) deathtrap); | |
116 | # endif | |
117 | # ifdef SIGUSR2 | |
118 | signal(SIGUSR2, (void(*)()) deathtrap); | |
119 | # endif | |
120 | ||
121 | /* initialize the options - must be done after initscr(), so that | |
122 | * we can alter LINES and COLS if necessary. | |
123 | */ | |
124 | initopts(); | |
125 | ||
126 | /* map the arrow keys. The KU,KD,KL,and KR variables correspond to | |
127 | * the :ku=: (etc.) termcap capabilities. The variables are defined | |
128 | * as part of the curses package. | |
129 | */ | |
130 | if (has_KU) mapkey(has_KU, "k", WHEN_VICMD|WHEN_INMV, "<Up>"); | |
131 | if (has_KD) mapkey(has_KD, "j", WHEN_VICMD|WHEN_INMV, "<Down>"); | |
132 | if (has_KL) mapkey(has_KL, "h", WHEN_VICMD|WHEN_INMV, "<Left>"); | |
133 | if (has_KR) mapkey(has_KR, "l", WHEN_VICMD|WHEN_INMV, "<Right>"); | |
134 | if (has_HM) mapkey(has_HM, "^", WHEN_VICMD|WHEN_INMV, "<Home>"); | |
135 | if (has_EN) mapkey(has_EN, "$", WHEN_VICMD|WHEN_INMV, "<End>"); | |
136 | if (has_PU) mapkey(has_PU, "\002", WHEN_VICMD|WHEN_INMV, "<PageUp>"); | |
137 | if (has_PD) mapkey(has_PD, "\006", WHEN_VICMD|WHEN_INMV, "<PageDn>"); | |
138 | if (has_KI) mapkey(has_KI, "i", WHEN_VICMD|WHEN_INMV, "<Insert>"); | |
139 | #if MSDOS | |
140 | # if RAINBOW | |
141 | if (!strcmp("rainbow", o_term)) | |
142 | { | |
143 | mapkey("\033[1~", "/", WHEN_VICMD, "<Find>"); | |
144 | mapkey("\033[3~", "x", WHEN_VICMD|WHEN_INMV, "<Remove>"); | |
145 | mapkey("\033[4~", "v", WHEN_VICMD|WHEN_INMV, "<Select>"); | |
146 | mapkey("\033[17~", ":sh\n", WHEN_VICMD, "<Intrpt>"); | |
147 | mapkey("\033[19~", ":q\n", WHEN_VICMD, "<Cancel>"); | |
148 | mapkey("\033[21~", "ZZ", WHEN_VICMD, "<Exit>"); | |
149 | mapkey("\033[26~", "V", WHEN_VICMD|WHEN_INMV, "<AddlOp>"); | |
150 | mapkey("\033[28~", "\\", WHEN_VICMD|WHEN_INMV, "<Help>"); | |
151 | mapkey("\033[29~", "K", WHEN_VICMD|WHEN_INMV, "<Do>"); | |
152 | } | |
153 | else | |
154 | # endif /* RAINBOW */ | |
155 | { | |
156 | mapkey("#S", "x", WHEN_VICMD|WHEN_INMV, "<Delete>"); | |
157 | mapkey("#s", "B", WHEN_VICMD|WHEN_INMV, "^<Left>"); | |
158 | mapkey("#t", "W", WHEN_VICMD|WHEN_INMV, "^<Right>"); | |
159 | } | |
160 | #else /* not MSDOS */ | |
161 | # if COHERENT | |
162 | mapkey("\033[P", "x", WHEN_VICMD|WHEN_INMV, "<Del>"); | |
163 | # else | |
164 | #if AMIGA | |
165 | mapkey("\233?~", "\\", WHEN_VICMD|WHEN_INMV, "<Help>"); | |
166 | #endif | |
167 | ||
168 | if (ERASEKEY != '\177') | |
169 | { | |
170 | mapkey("\177", "x", WHEN_VICMD|WHEN_INMV, "<Del>"); | |
171 | } | |
172 | # endif | |
173 | #endif | |
174 | ||
175 | #ifndef NO_DIGRAPH | |
176 | init_digraphs(); | |
177 | #endif /* NO_DIGRAPH */ | |
178 | ||
179 | /* process any flags */ | |
180 | for (i = 1; i < argc && *argv[i] == '-'; i++) | |
181 | { | |
182 | switch (argv[i][1]) | |
183 | { | |
184 | case 'R': /* readonly */ | |
185 | *o_readonly = TRUE; | |
186 | break; | |
187 | ||
188 | case 'L': | |
189 | case 'r': /* recover */ | |
190 | msg("Use the `elvisrecover` program to recover lost files"); | |
191 | endmsgs(); | |
192 | refresh(); | |
193 | endwin(); | |
194 | exit(0); | |
195 | break; | |
196 | ||
197 | case 't': /* tag */ | |
198 | if (argv[i][2]) | |
199 | { | |
200 | tag = argv[i] + 2; | |
201 | } | |
202 | else | |
203 | { | |
204 | tag = argv[++i]; | |
205 | } | |
206 | break; | |
207 | ||
208 | case 'v': /* vi mode */ | |
209 | mode = MODE_VI; | |
210 | break; | |
211 | ||
212 | case 'e': /* ex mode */ | |
213 | mode = MODE_EX; | |
214 | break; | |
215 | #ifndef NO_EXTENSIONS | |
216 | case 'i': /* input mode */ | |
217 | *o_inputmode = TRUE; | |
218 | break; | |
219 | #endif | |
220 | #ifndef NO_ERRLIST | |
221 | case 'm': /* use "errlist" as the errlist */ | |
222 | if (argv[i][2]) | |
223 | { | |
224 | err = argv[i] + 2; | |
225 | } | |
226 | else if (i + 1 < argc) | |
227 | { | |
228 | err = argv[++i]; | |
229 | } | |
230 | else | |
231 | { | |
232 | err = ""; | |
233 | } | |
234 | break; | |
235 | #endif | |
236 | #ifndef CRUNCH | |
237 | case 'c': /* run the following command, later */ | |
238 | if (argv[i][2]) | |
239 | { | |
240 | cmd = argv[i] + 2; | |
241 | } | |
242 | else | |
243 | { | |
244 | cmd = argv[++i]; | |
245 | } | |
246 | break; | |
247 | ||
248 | case 'w': /* set the window size */ | |
249 | if (argv[i][2]) | |
250 | { | |
251 | *o_window = atoi(argv[i] + 2); | |
252 | wset = TRUE; | |
253 | } | |
254 | else | |
255 | { | |
256 | *o_window = atoi(argv[++i]); | |
257 | wset = TRUE; | |
258 | } | |
259 | break; | |
260 | #endif | |
261 | default: | |
262 | msg("Ignoring unknown flag \"%s\"", argv[i]); | |
263 | } | |
264 | } | |
265 | ||
266 | /* if we were given an initial ex command, save it... */ | |
267 | if (i < argc && *argv[i] == '+') | |
268 | { | |
269 | if (argv[i][1]) | |
270 | { | |
271 | cmd = argv[i++] + 1; | |
272 | } | |
273 | else | |
274 | { | |
275 | cmd = "$"; /* "vi + file" means start at EOF */ | |
276 | i++; | |
277 | } | |
278 | } | |
279 | ||
280 | /* the remaining args are file names. */ | |
281 | if (i < argc) | |
282 | { | |
283 | strcpy(args, argv[i]); | |
284 | while (++i < argc && strlen(args) + 1 + strlen(argv[i]) < sizeof args) | |
285 | { | |
286 | strcat(args, " "); | |
287 | strcat(args, argv[i]); | |
288 | } | |
289 | #if MSDOS || TOS | |
290 | /* expand wildcard characters, if necessary */ | |
291 | if (strchr(args, '*') || strchr(args, '?')) | |
292 | { | |
293 | strcpy(args, wildcard(args)); | |
294 | } | |
295 | #endif | |
296 | strcpy(tmpblk.c, args); | |
297 | cmd_args(MARK_UNSET, MARK_UNSET, CMD_ARGS, TRUE, tmpblk.c); | |
298 | } | |
299 | else | |
300 | { | |
301 | /* empty args list */ | |
302 | args[0] = '\0'; | |
303 | nargs = 1; | |
304 | argno = -1; | |
305 | } | |
306 | ||
307 | /* perform the .exrc files and EXINIT environment variable */ | |
308 | #ifdef SYSEXRC | |
309 | doexrc(SYSEXRC); | |
310 | #endif | |
311 | #ifdef HMEXRC | |
312 | str = getenv("HOME"); | |
313 | if (str && *str) | |
314 | { | |
315 | strcpy(tmpblk.c, str); | |
316 | str = tmpblk.c + strlen(tmpblk.c); | |
317 | #if !VMS | |
318 | # if AMIGA /* Don't SLASH a device. "Elvis:.exrc" */ | |
319 | if (str[-1] != COLON && str[-1] != SLASH) | |
320 | # else | |
321 | if (str[-1] != SLASH) | |
322 | # endif | |
323 | { | |
324 | *str++ = SLASH; | |
325 | } | |
326 | #endif | |
327 | strcpy(str, HMEXRC); | |
328 | doexrc(tmpblk.c); | |
329 | } | |
330 | #endif | |
331 | #ifndef CRUNCH | |
332 | if (*o_exrc) | |
333 | #endif | |
334 | { | |
335 | doexrc(EXRC); | |
336 | } | |
337 | #ifdef EXINIT | |
338 | str = getenv(EXINIT); | |
339 | if (str) | |
340 | { | |
341 | exstring(str, strlen(str), ctrl('V')); | |
342 | } | |
343 | #endif | |
344 | ||
345 | /* search for a tag (or an error) now, if desired */ | |
346 | blkinit(); | |
347 | if (tag) | |
348 | { | |
349 | cmd_tag(MARK_FIRST, MARK_FIRST, CMD_TAG, 0, tag); | |
350 | } | |
351 | #ifndef NO_ERRLIST | |
352 | else if (err) | |
353 | { | |
354 | cmd_errlist(MARK_FIRST, MARK_FIRST, CMD_ERRLIST, 0, err); | |
355 | } | |
356 | #endif | |
357 | ||
358 | /* if no tag/err, or tag failed, then start with first arg */ | |
359 | if (tmpfd < 0) | |
360 | { | |
361 | /* start with first arg */ | |
362 | cmd_next(MARK_UNSET, MARK_UNSET, CMD_NEXT, FALSE, ""); | |
363 | ||
364 | /* pretend to do something, just to force a recoverable | |
365 | * version of the file out to disk | |
366 | */ | |
367 | ChangeText | |
368 | { | |
369 | } | |
370 | clrflag(file, MODIFIED); | |
371 | } | |
372 | ||
373 | /* now we do the immediate ex command that we noticed before */ | |
374 | if (cmd) | |
375 | { | |
376 | doexcmd(cmd); | |
377 | } | |
378 | ||
379 | /* repeatedly call ex() or vi() (depending on the mode) until the | |
380 | * mode is set to MODE_QUIT | |
381 | */ | |
382 | while (mode != MODE_QUIT) | |
383 | { | |
384 | if (setjmp(jmpenv)) | |
385 | { | |
386 | /* Maybe we just aborted a change? */ | |
387 | abortdo(); | |
388 | } | |
389 | signal(SIGINT, (void(*)()) trapint); | |
390 | ||
391 | switch (mode) | |
392 | { | |
393 | case MODE_VI: | |
394 | vi(); | |
395 | break; | |
396 | ||
397 | case MODE_EX: | |
398 | ex(); | |
399 | break; | |
400 | #ifdef DEBUG | |
401 | default: | |
402 | msg("mode = %d?", mode); | |
403 | mode = MODE_QUIT; | |
404 | #endif | |
405 | } | |
406 | } | |
407 | ||
408 | /* free up the cut buffers */ | |
409 | cutend(); | |
410 | ||
411 | /* end curses */ | |
412 | #ifndef NO_CURSORSHAPE | |
413 | if (has_CQ) | |
414 | do_CQ(); | |
415 | #endif | |
416 | endmsgs(); | |
417 | move(LINES - 1, 0); | |
418 | clrtoeol(); | |
419 | refresh(); | |
420 | endwin(); | |
421 | ||
422 | exit(0); | |
423 | /*NOTREACHED*/ | |
424 | } | |
425 | ||
426 | ||
427 | /*ARGSUSED*/ | |
428 | int trapint(signo) | |
429 | int signo; | |
430 | { | |
431 | beep(); | |
432 | resume_curses(FALSE); | |
433 | abortdo(); | |
434 | #if OSK | |
435 | sigmask(-1); | |
436 | #endif | |
437 | #if TURBOC || __GNUC__ | |
438 | signal(signo, (void (*)())trapint); | |
439 | #else | |
440 | signal(signo, trapint); | |
441 | #endif | |
442 | doingglobal = FALSE; | |
443 | ||
444 | longjmp(jmpenv, 1); | |
445 | ||
446 | return 0; | |
447 | } | |
448 | ||
449 | ||
450 | ||
451 | #ifndef NO_DIGRAPH | |
452 | ||
453 | /* This stuff us used to build the default digraphs table. */ | |
454 | static char digtable[][4] = | |
455 | { | |
456 | # ifdef CS_IBMPC | |
457 | "C,\200", "u\"\1", "e'\2", "a^\3", | |
458 | "a\"\4", "a`\5", "a@\6", "c,\7", | |
459 | "e^\10", "e\"\211", "e`\12", "i\"\13", | |
460 | "i^\14", "i`\15", "A\"\16", "A@\17", | |
461 | "E'\20", "ae\21", "AE\22", "o^\23", | |
462 | "o\"\24", "o`\25", "u^\26", "u`\27", | |
463 | "y\"\30", "O\"\31", "U\"\32", "a'\240", | |
464 | "i'!", "o'\"", "u'#", "n~$", | |
465 | "N~%", "a-&", "o-'", "~?(", | |
466 | "~!-", "\"<.", "\">/", | |
467 | # ifdef CS_SPECIAL | |
468 | "2/+", "4/,", "^+;", "^q<", | |
469 | "^c=", "^r>", "^t?", "pp]", | |
470 | "^^^", "oo_", "*a`", "*ba", | |
471 | "*pc", "*Sd", "*se", "*uf", | |
472 | "*tg", "*Ph", "*Ti", "*Oj", | |
473 | "*dk", "*Hl", "*hm", "*En", | |
474 | "*No", "eqp", "pmq", "ger", | |
475 | "les", "*It", "*iu", "*/v", | |
476 | "*=w", "sq{", "^n|", "^2}", | |
477 | "^3~", "^_\377", | |
478 | # endif /* CS_SPECIAL */ | |
479 | # endif /* CS_IBMPC */ | |
480 | # ifdef CS_LATIN1 | |
481 | "~!!", "a-*", "\">+", "o-:", | |
482 | "\"<>", "~??", | |
483 | ||
484 | "A`@", "A'A", "A^B", "A~C", | |
485 | "A\"D", "A@E", "AEF", "C,G", | |
486 | "E`H", "E'I", "E^J", "E\"K", | |
487 | "I`L", "I'M", "I^N", "I\"O", | |
488 | "-DP", "N~Q", "O`R", "O'S", | |
489 | "O^T", "O~U", "O\"V", "O/X", | |
490 | "U`Y", "U'Z", "U^[", "U\"\\", | |
491 | "Y'_", | |
492 | ||
493 | "a``", "a'a", "a^b", "a~c", | |
494 | "a\"d", "a@e", "aef", "c,g", | |
495 | "e`h", "e'i", "e^j", "e\"k", | |
496 | "i`l", "i'm", "i^n", "i\"o", | |
497 | "-dp", "n~q", "o`r", "o's", | |
498 | "o^t", "o~u", "o\"v", "o/x", | |
499 | "u`y", "u'z", "u^{", "u\"|", | |
500 | "y'~", | |
501 | # endif /* CS_LATIN1 */ | |
502 | "" | |
503 | }; | |
504 | ||
505 | static init_digraphs() | |
506 | { | |
507 | int i; | |
508 | ||
509 | for (i = 0; *digtable[i]; i++) | |
510 | { | |
511 | do_digraph(FALSE, digtable[i]); | |
512 | } | |
513 | do_digraph(FALSE, (char *)0); | |
514 | return 0; | |
515 | } | |
516 | #endif /* NO_DIGRAPH */ |