1 /*- 2 * Copyright (c) 1992 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Rodney Ruddock of the University of Guelph. 7 * 8 * %sccs.include.redist.c% 9 */ 10 11 #ifndef lint 12 static char sccsid[] = "@(#)main.c 5.2 (Berkeley) 01/23/93"; 13 #endif /* not lint */ 14 15 #include <sys/types.h> 16 17 #include <db.h> 18 #include <regex.h> 19 #include <setjmp.h> 20 #include <signal.h> 21 #include <stdio.h> 22 #include <stdlib.h> 23 #include <string.h> 24 25 #include "ed.h" 26 #include "extern.h" 27 28 /* 29 * This is where all of the "global" variables are declared. They are 30 * set for extern in the ed.h header file (so everyone can get them). 31 */ 32 33 int nn_max, nn_max_flag, start_default, End_default, address_flag; 34 int zsnum, filename_flag, add_flag=0; 35 int help_flag=0; 36 37 DB *dbhtmp; 38 39 LINE *nn_max_start, *nn_max_end; 40 41 struct MARK mark_matrix[26]; /* in init set all to null */ 42 43 char *text; 44 char *filename_current, *prompt_string=NULL, help_msg[130]; 45 char *template=NULL; 46 int prompt_str_flg=0, start_up_flag=0, name_set=0; 47 48 LINE *top, *current, *bottom, *start, *End; 49 struct u_layer *u_stk; 50 struct d_layer *d_stk; 51 LINE *u_current, *u_top, *u_bottom; 52 int u_set; 53 regex_t RE_comp; 54 regmatch_t RE_match[RE_SEC]; 55 int RE_sol=0, RE_flag=0; 56 char *RE_patt=NULL; 57 58 int ss; /* for the getc() */ 59 int explain_flag=1, g_flag=0, GV_flag=0, printsfx=0; 60 long change_flag=0L; 61 int line_length; 62 jmp_buf ctrl_position; /* For SIGnal handling. */ 63 int sigint_flag, sighup_flag, sigspecial; 64 65 static void sigint_handler __P((int)); 66 static void sighup_handler __P((int)); 67 68 /* 69 * Starts the whole show going. Set things up as the arguments spec 70 * in the shell and set a couple of the global variables. 71 * 72 * Note naming viol'n with errnum for consistancy. 73 */ 74 int 75 main(argc, argv) 76 int argc; 77 char *argv[]; 78 { 79 int l_num, l_ret, errnum = 0, l_err = 0; 80 char *l_fnametmp, l_bp[1024], *l_term; 81 82 l_term = getenv("TERM"); 83 l_ret = tgetent(l_bp, l_term); 84 if (l_ret < 1) 85 line_length = 78; /* Reasonable number for all term's. */ 86 else 87 if ((line_length = tgetnum("co") - 1) < 2) 88 line_length = 78; 89 90 start = End = NULL; 91 top = bottom = NULL; 92 current = NULL; 93 nn_max_flag = 0; 94 nn_max_start = nn_max_end = NULL; 95 l_fnametmp = calloc(FILENAME_LEN, sizeof(char)); 96 if (l_fnametmp == NULL) 97 ed_exit(4); 98 text = calloc(NN_MAX_START + 2, sizeof(char)); 99 if (text == NULL) 100 ed_exit(4); 101 start_default = End_default = 0; 102 zsnum = 22; /* for the 'z' command */ 103 u_stk = NULL; 104 d_stk = NULL; 105 u_current = u_top = u_bottom = NULL; 106 u_set = 0; /* for in d after a j */ 107 filename_flag = 0; 108 filename_current = NULL; 109 110 l_num = 1; 111 for (;;) { 112 /* Process the command line options */ 113 if (l_num >= argc) 114 break; 115 switch (argv[l_num][0]) { 116 case '-': 117 switch (argv[l_num][1]) { 118 case '\0': /* this is why 'getopt' not used */ 119 case 's': 120 explain_flag = 0; 121 break; 122 case 'p': 123 if (++l_num < argc) { 124 prompt_string = 125 calloc(strlen(argv[l_num]), 126 sizeof(char)); 127 if (prompt_string == NULL) 128 ed_exit(4); 129 strcpy(prompt_string, argv[l_num]); 130 prompt_str_flg = 1; 131 break; 132 } 133 l_err = 1; 134 default: 135 l_err++; 136 ed_exit(l_err); 137 } 138 break; 139 default: 140 if (name_set) 141 ed_exit(3); 142 strcpy(l_fnametmp, argv[l_num]); 143 filename_current = l_fnametmp; 144 name_set = 1; 145 if (prompt_str_flg) 146 break; 147 /* default ed prompt */ 148 prompt_string = (char *) calloc(3, sizeof(char)); 149 strcpy(prompt_string, "*"); 150 break; 151 } 152 l_num++; 153 } 154 155 start_up_flag = 1; 156 cmd_loop(stdin, &errnum); 157 /* NOTREACHED */ 158 } 159 160 /* 161 * The command loop. What the command is that the user has specified 162 * is determined here. This is not just for commands coming from 163 * the terminal but any standard i/o stream; see the global commands. 164 * Some of the commands are handled within here (i.e. 'H') while most 165 * are handled in their own functions (as called). 166 */ 167 void 168 cmd_loop(inputt, errnum) 169 FILE *inputt; 170 int *errnum; 171 { 172 LINE *l_tempp; 173 int l_last, l_jmp_flag; 174 175 l_last = 0; 176 177 if (g_flag == 0) { /* big, BIG trouble if we don't check! think. */ 178 /* set the jump point for the signals */ 179 l_jmp_flag = setjmp(ctrl_position); 180 signal(SIGINT, sigint_handler); 181 signal(SIGHUP, sighup_handler); 182 switch (l_jmp_flag) { 183 case JMP_SET: 184 break; 185 /* Some general cleanup not specific to the jmp pt. */ 186 case INTERUPT: 187 sigint_flag = 0; 188 GV_flag = 0; /* safest place to do these flags */ 189 g_flag = 0; 190 printf("?\n"); 191 break; 192 case HANGUP: /* shouldn't get here. */ 193 break; 194 default: 195 (void)fprintf(stderr, "Signal jump problem\n"); 196 } 197 /* Only do this once! */ 198 if (start_up_flag) { 199 start_up_flag = 0; 200 /* simulate the 'e' at startup */ 201 e2(inputt, errnum); 202 } 203 } 204 for (;;) { 205 if (prompt_str_flg == 1) 206 (void)printf("%s", prompt_string); 207 sigspecial = 1; /* see the SIGINT function above */ 208 ss = getc(inputt); 209 sigspecial = 0; 210 *errnum = 0; 211 l_tempp = start = End = NULL; 212 start_default = End_default = 1; 213 214 /* 215 * This isn't nice and alphabetical mainly because of 216 * restrictions with 'G' and 'V' (see ed(1)). 217 */ 218 for (;;) { 219 switch (ss) { 220 case 'd': 221 d(inputt, errnum); 222 break; 223 case 'e': 224 case 'E': 225 e(inputt, errnum); 226 break; 227 case 'f': 228 f(inputt, errnum); 229 break; 230 case 'a': 231 case 'c': 232 case 'i': 233 case 'g': 234 case 'G': 235 case 'v': 236 case 'V': 237 if (GV_flag == 1) { 238 (void)sprintf(help_msg, 239 "command `%c' illegal in G/V", ss); 240 *errnum = -1; 241 break; 242 } 243 switch (ss) { 244 case 'a': 245 a(inputt, errnum); 246 break; 247 case 'c': 248 c(inputt, errnum); 249 break; 250 case 'i': 251 i(inputt, errnum); 252 break; 253 default: 254 g(inputt, errnum); 255 } 256 break; 257 case 'h': 258 if (rol(inputt, errnum)) 259 break; 260 (void)printf("%s\n", help_msg); 261 *errnum = 1; 262 break; 263 case 'H': 264 if (rol(inputt, errnum)) 265 break; 266 if (help_flag == 0) { 267 help_flag = 1; 268 printf("%?: %s\n", help_msg); 269 } else 270 help_flag = 0; 271 *errnum = 1; 272 break; 273 case 'j': 274 j(inputt, errnum); 275 break; 276 case 'k': 277 set_mark(inputt, errnum); 278 break; 279 case 'l': 280 l(inputt, errnum); 281 break; 282 case 'm': 283 m(inputt, errnum); 284 break; 285 #ifdef POSIX 286 /* In POSIX-land 'P' toggles the prompt. */ 287 case 'P': 288 if (rol(inputt, errnum)) 289 break; 290 prompt_str_flg = prompt_str_flg ? 0 : 1; 291 *errnum = 1; 292 break; 293 #endif 294 case '\n': 295 if (GV_flag == 1) 296 return; 297 /* For 'p' to consume. */ 298 ungetc(ss, inputt); 299 if ((current == bottom) && (End == NULL)) { 300 strcpy(help_msg, "at end of buffer"); 301 *errnum = -1; 302 break; 303 } 304 current = current->below; 305 #ifdef BSD 306 /* In BSD 'P'=='p'. */ 307 case 'P': 308 #endif 309 case 'p': 310 p(inputt, errnum, 0); 311 break; 312 case 'n': 313 p(inputt, errnum, 1); 314 break; 315 /* 316 * An EOF means 'q' unless we're still in the middle 317 * of a global command, in which case it was just the 318 * end of the command list found. 319 */ 320 case EOF: 321 clearerr(inputt); 322 if (g_flag > 0) 323 return; 324 ss = 'q'; 325 case 'q': 326 case 'Q': 327 q(inputt, errnum); 328 break; 329 case 'r': 330 r(inputt, errnum); 331 break; 332 case 's': 333 s(inputt, errnum); 334 break; 335 case 't': 336 t(inputt, errnum); 337 break; 338 case 'u': 339 u(inputt, errnum); 340 break; 341 case 'w': 342 case 'W': 343 w(inputt, errnum); 344 break; 345 case 'z': 346 z(inputt, errnum); 347 break; 348 case '!': 349 bang(inputt, errnum); 350 break; 351 case '=': 352 equal(inputt, errnum); 353 break; 354 /* 355 * Control of address forms from here down. 356 * 357 * It's a head-game to understand why ";" and "," look 358 * as they do below, but a lot of it has to do with ";" 359 * and "," being special address pair forms themselves 360 * and the compatibility for address "chains". 361 */ 362 case ';': 363 if (End_default == 1 && start_default == 1) { 364 start = current; 365 End = bottom; 366 start_default = End_default = 0; 367 } else { 368 start = current = End; 369 start_default = 0; 370 End_default = 1; 371 } 372 l_tempp = NULL; 373 break; 374 /* 375 * Note address ".,x" where x is a cmd is legal; not a 376 * bug - for backward compatability. 377 */ 378 case ',': 379 if (End_default == 1 && start_default == 1) { 380 start = top; 381 End = bottom; 382 start_default = End_default = 0; 383 } else { 384 start = End; 385 start_default = 0; 386 End_default = 1; 387 } 388 l_tempp = NULL; 389 break; 390 case '%': 391 if (End_default == 0) { 392 strcpy(help_msg, 393 "'%' is an address pair"); 394 *errnum = -1; 395 break; 396 } 397 start = top; 398 End = bottom; 399 start_default = End_default = 0; 400 l_tempp = NULL; 401 break; 402 /* 403 * Within address_conv => l_last = '+', foobar, but 404 * historical and now POSIX... 405 */ 406 case ' ': 407 break; 408 case '0': 409 case '1': 410 case '2': 411 case '3': 412 case '4': 413 case '5': 414 case '6': 415 case '7': 416 case '8': 417 case '9': 418 case '-': 419 case '^': 420 case '+': 421 case '\'': 422 case '$': 423 case '?': 424 case '/': 425 case '.': 426 ungetc(ss, inputt); 427 if (start_default == 0 && End_default == 0) { 428 strcpy(help_msg, 429 "badly formed address"); 430 *errnum = -1; 431 break; 432 } 433 ss = l_last; 434 l_tempp = address_conv(l_tempp, inputt, errnum); 435 if (*errnum < 0) 436 break; 437 End = l_tempp; 438 End_default = 0; 439 if (start_default == 0) 440 *errnum = address_check(start, End); 441 break; 442 default: 443 *errnum = -1; 444 strcpy(help_msg, "unknown command"); 445 break; 446 } /* end-switch(ss) */ 447 448 /* Things came out okay with the last command. */ 449 if (*errnum > 0) { 450 if (GV_flag == 1) 451 return; 452 /* Do the suffixes if there were any. */ 453 if (printsfx > 0) { 454 start = End = current; 455 ungetc(ss, inputt); 456 if (printsfx == 1) 457 p(inputt, errnum, 0); 458 else 459 if (printsfx == 2) 460 p(inputt, errnum, 1); 461 else if (printsfx == 4) 462 l(inputt, errnum); 463 /* Unlikely it's needed, but... */ 464 if (*errnum < 0) 465 goto errmsg; 466 } 467 break; 468 } 469 /* There was a problem with the last command. */ 470 else if (*errnum < 0) { 471 errmsg: while (((ss = getc(inputt)) != '\n') && 472 (ss != EOF)); 473 if (help_flag == 1) 474 printf("%?: %s\n", help_msg); 475 else 476 printf("?\n"); 477 if (g_flag > 0) 478 return; 479 break; 480 } 481 l_last = ss; 482 ss = getc(inputt); 483 } 484 } 485 } 486 487 /* 488 * Exits ed and prints an appropriate message about the command line 489 * being malformed (see below). 490 */ 491 void 492 ed_exit(err) 493 int err; 494 { 495 switch (err) { 496 case 1: 497 (void)fprintf(stderr, "ed: illegal option\n"); 498 break; 499 case 2: 500 (void)fprintf(stderr, "ed: missing promptstring\n"); 501 break; 502 case 3: 503 (void)fprintf(stderr, "ed: too many filenames\n"); 504 break; 505 case 4: 506 (void)fprintf(stderr, "ed: out of memory error\n"); 507 break; 508 default: 509 (void)fprintf(stderr, "ed: command line error\n"); 510 break; 511 } 512 (void)fprintf(stderr, 513 "ed: ed [ -s ] [ -p promptstring ] [ filename ]\n"); 514 exit(1); 515 } 516 517 /* 518 * SIGINT is never turned off. We flag it happened and then pay attention 519 * to it at certain logical locations in the code we don't do more here 520 * cause some of our buffer pointer's may be in an inbetween state at the 521 * time of the SIGINT. So we flag it happened, let the local fn handle it 522 * and do a jump back to the cmd_loop 523 */ 524 static void 525 sigint_handler(signo) 526 int signo; 527 { 528 sigint_flag = 1; 529 if (sigspecial) /* Unstick when SIGINT on read(stdin). */ 530 SIGINT_ACTION; 531 } 532 533 static void 534 sighup_handler(signo) 535 int signo; 536 { 537 (void)fprintf(stderr,"\n SIGHUP \n"); 538 sighup_flag = 1; 539 undo(); 540 do_hup(); 541 /* NOTREACHED */ 542 543 SIGHUP_ACTION; 544 } 545