157694Sbostic /*- 257694Sbostic * Copyright (c) 1992 The Regents of the University of California. 357694Sbostic * All rights reserved. 457694Sbostic * 557694Sbostic * This code is derived from software contributed to Berkeley by 657694Sbostic * Rodney Ruddock of the University of Guelph. 757694Sbostic * 857694Sbostic * %sccs.include.redist.c% 957694Sbostic */ 1057694Sbostic 1157694Sbostic #ifndef lint 12*58315Sbostic static char sccsid[] = "@(#)main.c 5.3 (Berkeley) 02/28/93"; 1357694Sbostic #endif /* not lint */ 1457694Sbostic 1557710Sbostic #include <sys/types.h> 16*58315Sbostic #include <sys/ioctl.h> 1757710Sbostic 18*58315Sbostic #include <limits.h> 1957710Sbostic #include <regex.h> 2057710Sbostic #include <setjmp.h> 2157710Sbostic #include <signal.h> 2257710Sbostic #include <stdio.h> 2357710Sbostic #include <stdlib.h> 2457710Sbostic #include <string.h> 2557710Sbostic 26*58315Sbostic #ifdef DBI 27*58315Sbostic #include <db.h> 28*58315Sbostic #endif 29*58315Sbostic 3057694Sbostic #include "ed.h" 3157710Sbostic #include "extern.h" 3257694Sbostic 3357694Sbostic /* 3457694Sbostic * This is where all of the "global" variables are declared. They are 3557694Sbostic * set for extern in the ed.h header file (so everyone can get them). 3657694Sbostic */ 3757694Sbostic 3857694Sbostic int nn_max, nn_max_flag, start_default, End_default, address_flag; 39*58315Sbostic int zsnum, filename_flag, add_flag=0, join_flag=0; 4057694Sbostic int help_flag=0; 41*58315Sbostic #ifdef STDIO 42*58315Sbostic FILE *fhtmp; 43*58315Sbostic int file_seek; 44*58315Sbostic #endif 4557694Sbostic 46*58315Sbostic #ifdef DBI 4757694Sbostic DB *dbhtmp; 48*58315Sbostic #endif 4957694Sbostic 5057694Sbostic LINE *nn_max_start, *nn_max_end; 5157694Sbostic 5257694Sbostic struct MARK mark_matrix[26]; /* in init set all to null */ 5357694Sbostic 5457694Sbostic char *text; 5557694Sbostic char *filename_current, *prompt_string=NULL, help_msg[130]; 5657694Sbostic char *template=NULL; 5757694Sbostic int prompt_str_flg=0, start_up_flag=0, name_set=0; 5857694Sbostic 5957694Sbostic LINE *top, *current, *bottom, *start, *End; 6057694Sbostic struct u_layer *u_stk; 6157694Sbostic struct d_layer *d_stk; 6257694Sbostic LINE *u_current, *u_top, *u_bottom; 6357694Sbostic int u_set; 6457694Sbostic regex_t RE_comp; 6557694Sbostic regmatch_t RE_match[RE_SEC]; 6657694Sbostic int RE_sol=0, RE_flag=0; 6757694Sbostic char *RE_patt=NULL; 6857694Sbostic 6957694Sbostic int ss; /* for the getc() */ 7057694Sbostic int explain_flag=1, g_flag=0, GV_flag=0, printsfx=0; 7157694Sbostic long change_flag=0L; 7257694Sbostic int line_length; 73*58315Sbostic jmp_buf ctrl_position, ctrl_position2; /* For SIGnal handling. */ 74*58315Sbostic int sigint_flag, sighup_flag, sigspecial=0, sigspecial2=0; 7557694Sbostic 7657710Sbostic static void sigint_handler __P((int)); 7757710Sbostic static void sighup_handler __P((int)); 7857710Sbostic 7957710Sbostic /* 8057710Sbostic * Starts the whole show going. Set things up as the arguments spec 8157710Sbostic * in the shell and set a couple of the global variables. 8257710Sbostic * 8357710Sbostic * Note naming viol'n with errnum for consistancy. 8457694Sbostic */ 8557710Sbostic int 8657710Sbostic main(argc, argv) 8757710Sbostic int argc; 8857710Sbostic char *argv[]; 8957694Sbostic { 90*58315Sbostic int l_num, errnum = 0, l_err = 0; 91*58315Sbostic char *l_fnametmp, *l_col; 92*58315Sbostic struct winsize win; 9357694Sbostic 94*58315Sbostic line_length = ((l_col = getenv("COLUMNS")) == NULL ? 0 : atoi(l_col)); 95*58315Sbostic if (line_length == 0 && isatty(STDOUT_FILENO) && 96*58315Sbostic ioctl(STDOUT_FILENO, TIOCGWINSZ, &win) != -1) 97*58315Sbostic line_length = win.ws_col; 98*58315Sbostic if (line_length == 0) 99*58315Sbostic line_length = 78; 10057694Sbostic 10157710Sbostic start = End = NULL; 10257710Sbostic top = bottom = NULL; 10357710Sbostic current = NULL; 10457710Sbostic nn_max_flag = 0; 10557710Sbostic nn_max_start = nn_max_end = NULL; 10657710Sbostic l_fnametmp = calloc(FILENAME_LEN, sizeof(char)); 10757710Sbostic if (l_fnametmp == NULL) 10857710Sbostic ed_exit(4); 10957710Sbostic text = calloc(NN_MAX_START + 2, sizeof(char)); 11057710Sbostic if (text == NULL) 11157710Sbostic ed_exit(4); 11257710Sbostic start_default = End_default = 0; 11357710Sbostic zsnum = 22; /* for the 'z' command */ 11457710Sbostic u_stk = NULL; 11557710Sbostic d_stk = NULL; 11657710Sbostic u_current = u_top = u_bottom = NULL; 11757710Sbostic u_set = 0; /* for in d after a j */ 11857710Sbostic filename_flag = 0; 11957710Sbostic filename_current = NULL; 12057694Sbostic 12157710Sbostic l_num = 1; 12257710Sbostic for (;;) { 12357710Sbostic /* Process the command line options */ 12457710Sbostic if (l_num >= argc) 12557710Sbostic break; 12657710Sbostic switch (argv[l_num][0]) { 12757710Sbostic case '-': 12857710Sbostic switch (argv[l_num][1]) { 12957710Sbostic case '\0': /* this is why 'getopt' not used */ 13057710Sbostic case 's': 13157710Sbostic explain_flag = 0; 13257710Sbostic break; 13357710Sbostic case 'p': 13457710Sbostic if (++l_num < argc) { 13557710Sbostic prompt_string = 13657710Sbostic calloc(strlen(argv[l_num]), 13757710Sbostic sizeof(char)); 13857710Sbostic if (prompt_string == NULL) 13957710Sbostic ed_exit(4); 14057710Sbostic strcpy(prompt_string, argv[l_num]); 14157710Sbostic prompt_str_flg = 1; 14257710Sbostic break; 14357710Sbostic } 14457710Sbostic l_err = 1; 14557710Sbostic default: 14657710Sbostic l_err++; 14757710Sbostic ed_exit(l_err); 14857710Sbostic } 14957710Sbostic break; 15057710Sbostic default: 15157710Sbostic if (name_set) 15257710Sbostic ed_exit(3); 15357710Sbostic strcpy(l_fnametmp, argv[l_num]); 15457710Sbostic filename_current = l_fnametmp; 15557710Sbostic name_set = 1; 15657710Sbostic if (prompt_str_flg) 15757710Sbostic break; 15857710Sbostic /* default ed prompt */ 15957710Sbostic prompt_string = (char *) calloc(3, sizeof(char)); 16057710Sbostic strcpy(prompt_string, "*"); 16157710Sbostic break; 16257710Sbostic } 16357710Sbostic l_num++; 16457710Sbostic } 16557710Sbostic 16657710Sbostic start_up_flag = 1; 16757710Sbostic cmd_loop(stdin, &errnum); 16857710Sbostic /* NOTREACHED */ 16957710Sbostic } 17057710Sbostic 17157694Sbostic /* 17257710Sbostic * The command loop. What the command is that the user has specified 17357694Sbostic * is determined here. This is not just for commands coming from 17457694Sbostic * the terminal but any standard i/o stream; see the global commands. 17557694Sbostic * Some of the commands are handled within here (i.e. 'H') while most 17657694Sbostic * are handled in their own functions (as called). 17757694Sbostic */ 17857694Sbostic void 17957694Sbostic cmd_loop(inputt, errnum) 18057710Sbostic FILE *inputt; 18157710Sbostic int *errnum; 18257694Sbostic { 18357710Sbostic LINE *l_tempp; 18457710Sbostic int l_last, l_jmp_flag; 18557694Sbostic 186*58315Sbostic l_last = 0; /* value in l_last may be clobbered (reset to = 0) by longjump, but that's okay */ 18757694Sbostic 18857710Sbostic if (g_flag == 0) { /* big, BIG trouble if we don't check! think. */ 18957710Sbostic /* set the jump point for the signals */ 19057710Sbostic l_jmp_flag = setjmp(ctrl_position); 19157710Sbostic signal(SIGINT, sigint_handler); 19257710Sbostic signal(SIGHUP, sighup_handler); 19357710Sbostic switch (l_jmp_flag) { 19457710Sbostic case JMP_SET: 19557710Sbostic break; 19657710Sbostic /* Some general cleanup not specific to the jmp pt. */ 19757710Sbostic case INTERUPT: 19857710Sbostic sigint_flag = 0; 19957710Sbostic GV_flag = 0; /* safest place to do these flags */ 20057710Sbostic g_flag = 0; 201*58315Sbostic printf("\n?\n"); 20257710Sbostic break; 20357710Sbostic case HANGUP: /* shouldn't get here. */ 20457710Sbostic break; 20557710Sbostic default: 20657710Sbostic (void)fprintf(stderr, "Signal jump problem\n"); 20757710Sbostic } 20857710Sbostic /* Only do this once! */ 20957710Sbostic if (start_up_flag) { 21057710Sbostic start_up_flag = 0; 21157710Sbostic /* simulate the 'e' at startup */ 21257710Sbostic e2(inputt, errnum); 21357710Sbostic } 21457710Sbostic } 21557710Sbostic for (;;) { 21657710Sbostic if (prompt_str_flg == 1) 21757710Sbostic (void)printf("%s", prompt_string); 21857710Sbostic ss = getc(inputt); 21957710Sbostic *errnum = 0; 22057710Sbostic l_tempp = start = End = NULL; 22157710Sbostic start_default = End_default = 1; 22257694Sbostic 22357710Sbostic /* 22457710Sbostic * This isn't nice and alphabetical mainly because of 22557710Sbostic * restrictions with 'G' and 'V' (see ed(1)). 22657710Sbostic */ 22757710Sbostic for (;;) { 22857710Sbostic switch (ss) { 22957710Sbostic case 'd': 23057710Sbostic d(inputt, errnum); 23157710Sbostic break; 23257710Sbostic case 'e': 23357710Sbostic case 'E': 23457710Sbostic e(inputt, errnum); 23557710Sbostic break; 23657710Sbostic case 'f': 23757710Sbostic f(inputt, errnum); 23857710Sbostic break; 23957710Sbostic case 'a': 24057710Sbostic case 'c': 24157710Sbostic case 'i': 24257710Sbostic case 'g': 24357710Sbostic case 'G': 24457710Sbostic case 'v': 24557710Sbostic case 'V': 24657710Sbostic if (GV_flag == 1) { 24757710Sbostic (void)sprintf(help_msg, 24857710Sbostic "command `%c' illegal in G/V", ss); 24957710Sbostic *errnum = -1; 25057710Sbostic break; 25157710Sbostic } 25257710Sbostic switch (ss) { 25357710Sbostic case 'a': 25457710Sbostic a(inputt, errnum); 25557710Sbostic break; 25657710Sbostic case 'c': 25757710Sbostic c(inputt, errnum); 25857710Sbostic break; 25957710Sbostic case 'i': 26057710Sbostic i(inputt, errnum); 26157710Sbostic break; 26257710Sbostic default: 26357710Sbostic g(inputt, errnum); 26457710Sbostic } 26557710Sbostic break; 26657710Sbostic case 'h': 26757710Sbostic if (rol(inputt, errnum)) 26857710Sbostic break; 26957710Sbostic (void)printf("%s\n", help_msg); 27057710Sbostic *errnum = 1; 27157710Sbostic break; 27257710Sbostic case 'H': 27357710Sbostic if (rol(inputt, errnum)) 27457710Sbostic break; 27557710Sbostic if (help_flag == 0) { 27657710Sbostic help_flag = 1; 27757710Sbostic printf("%?: %s\n", help_msg); 27857710Sbostic } else 27957710Sbostic help_flag = 0; 28057710Sbostic *errnum = 1; 28157710Sbostic break; 28257710Sbostic case 'j': 28357710Sbostic j(inputt, errnum); 28457710Sbostic break; 28557710Sbostic case 'k': 28657710Sbostic set_mark(inputt, errnum); 28757710Sbostic break; 28857710Sbostic case 'l': 28957710Sbostic l(inputt, errnum); 29057710Sbostic break; 29157710Sbostic case 'm': 29257710Sbostic m(inputt, errnum); 29357710Sbostic break; 29457694Sbostic #ifdef POSIX 29557710Sbostic /* In POSIX-land 'P' toggles the prompt. */ 29657710Sbostic case 'P': 29757710Sbostic if (rol(inputt, errnum)) 29857710Sbostic break; 29957710Sbostic prompt_str_flg = prompt_str_flg ? 0 : 1; 30057710Sbostic *errnum = 1; 30157710Sbostic break; 30257694Sbostic #endif 30357710Sbostic case '\n': 30457710Sbostic if (GV_flag == 1) 30557710Sbostic return; 30657710Sbostic /* For 'p' to consume. */ 30757710Sbostic ungetc(ss, inputt); 30857710Sbostic if ((current == bottom) && (End == NULL)) { 30957710Sbostic strcpy(help_msg, "at end of buffer"); 31057710Sbostic *errnum = -1; 31157710Sbostic break; 31257710Sbostic } 31357710Sbostic current = current->below; 31457694Sbostic #ifdef BSD 31557710Sbostic /* In BSD 'P'=='p'. */ 31657710Sbostic case 'P': 31757694Sbostic #endif 31857710Sbostic case 'p': 31957710Sbostic p(inputt, errnum, 0); 32057710Sbostic break; 32157710Sbostic case 'n': 32257710Sbostic p(inputt, errnum, 1); 32357710Sbostic break; 32457710Sbostic /* 32557710Sbostic * An EOF means 'q' unless we're still in the middle 32657710Sbostic * of a global command, in which case it was just the 32757710Sbostic * end of the command list found. 32857710Sbostic */ 32957710Sbostic case EOF: 33057710Sbostic clearerr(inputt); 33157710Sbostic if (g_flag > 0) 33257710Sbostic return; 33357710Sbostic ss = 'q'; 33457710Sbostic case 'q': 33557710Sbostic case 'Q': 33657710Sbostic q(inputt, errnum); 33757710Sbostic break; 33857710Sbostic case 'r': 33957710Sbostic r(inputt, errnum); 34057710Sbostic break; 34157710Sbostic case 's': 34257710Sbostic s(inputt, errnum); 34357710Sbostic break; 34457710Sbostic case 't': 34557710Sbostic t(inputt, errnum); 34657710Sbostic break; 34757710Sbostic case 'u': 34857710Sbostic u(inputt, errnum); 34957710Sbostic break; 35057710Sbostic case 'w': 35157710Sbostic case 'W': 35257710Sbostic w(inputt, errnum); 35357710Sbostic break; 35457710Sbostic case 'z': 35557710Sbostic z(inputt, errnum); 35657710Sbostic break; 35757710Sbostic case '!': 35857710Sbostic bang(inputt, errnum); 35957710Sbostic break; 36057710Sbostic case '=': 36157710Sbostic equal(inputt, errnum); 36257710Sbostic break; 36357710Sbostic /* 36457710Sbostic * Control of address forms from here down. 36557710Sbostic * 36657710Sbostic * It's a head-game to understand why ";" and "," look 36757710Sbostic * as they do below, but a lot of it has to do with ";" 36857710Sbostic * and "," being special address pair forms themselves 36957710Sbostic * and the compatibility for address "chains". 37057710Sbostic */ 37157710Sbostic case ';': 37257710Sbostic if (End_default == 1 && start_default == 1) { 37357710Sbostic start = current; 37457710Sbostic End = bottom; 37557710Sbostic start_default = End_default = 0; 37657710Sbostic } else { 37757710Sbostic start = current = End; 37857710Sbostic start_default = 0; 37957710Sbostic End_default = 1; 38057710Sbostic } 38157710Sbostic l_tempp = NULL; 38257710Sbostic break; 38357710Sbostic /* 38457710Sbostic * Note address ".,x" where x is a cmd is legal; not a 38557710Sbostic * bug - for backward compatability. 38657710Sbostic */ 38757710Sbostic case ',': 38857710Sbostic if (End_default == 1 && start_default == 1) { 38957710Sbostic start = top; 39057710Sbostic End = bottom; 39157710Sbostic start_default = End_default = 0; 39257710Sbostic } else { 39357710Sbostic start = End; 39457710Sbostic start_default = 0; 39557710Sbostic End_default = 1; 39657710Sbostic } 39757710Sbostic l_tempp = NULL; 39857710Sbostic break; 39957710Sbostic case '%': 40057710Sbostic if (End_default == 0) { 40157710Sbostic strcpy(help_msg, 40257710Sbostic "'%' is an address pair"); 40357710Sbostic *errnum = -1; 40457710Sbostic break; 40557710Sbostic } 40657710Sbostic start = top; 40757710Sbostic End = bottom; 40857710Sbostic start_default = End_default = 0; 40957710Sbostic l_tempp = NULL; 41057710Sbostic break; 41157710Sbostic /* 41257710Sbostic * Within address_conv => l_last = '+', foobar, but 41357710Sbostic * historical and now POSIX... 41457710Sbostic */ 41557710Sbostic case ' ': 41657710Sbostic break; 41757710Sbostic case '0': 41857710Sbostic case '1': 41957710Sbostic case '2': 42057710Sbostic case '3': 42157710Sbostic case '4': 42257710Sbostic case '5': 42357710Sbostic case '6': 42457710Sbostic case '7': 42557710Sbostic case '8': 42657710Sbostic case '9': 42757710Sbostic case '-': 42857710Sbostic case '^': 42957710Sbostic case '+': 43057710Sbostic case '\'': 43157710Sbostic case '$': 43257710Sbostic case '?': 43357710Sbostic case '/': 43457710Sbostic case '.': 43557710Sbostic ungetc(ss, inputt); 43657710Sbostic if (start_default == 0 && End_default == 0) { 43757710Sbostic strcpy(help_msg, 43857710Sbostic "badly formed address"); 43957710Sbostic *errnum = -1; 44057710Sbostic break; 44157710Sbostic } 44257710Sbostic ss = l_last; 44357710Sbostic l_tempp = address_conv(l_tempp, inputt, errnum); 44457710Sbostic if (*errnum < 0) 44557710Sbostic break; 44657710Sbostic End = l_tempp; 44757710Sbostic End_default = 0; 44857710Sbostic if (start_default == 0) 44957710Sbostic *errnum = address_check(start, End); 45057710Sbostic break; 45157710Sbostic default: 45257710Sbostic *errnum = -1; 45357710Sbostic strcpy(help_msg, "unknown command"); 45457710Sbostic break; 45557710Sbostic } /* end-switch(ss) */ 45657694Sbostic 45757710Sbostic /* Things came out okay with the last command. */ 45857710Sbostic if (*errnum > 0) { 45957710Sbostic if (GV_flag == 1) 46057710Sbostic return; 46157710Sbostic /* Do the suffixes if there were any. */ 46257710Sbostic if (printsfx > 0) { 46357710Sbostic start = End = current; 46457710Sbostic ungetc(ss, inputt); 46557710Sbostic if (printsfx == 1) 46657710Sbostic p(inputt, errnum, 0); 46757710Sbostic else 46857710Sbostic if (printsfx == 2) 46957710Sbostic p(inputt, errnum, 1); 47057710Sbostic else if (printsfx == 4) 47157710Sbostic l(inputt, errnum); 47257710Sbostic /* Unlikely it's needed, but... */ 47357710Sbostic if (*errnum < 0) 47457710Sbostic goto errmsg; 47557710Sbostic } 47657710Sbostic break; 47757710Sbostic } 47857710Sbostic /* There was a problem with the last command. */ 47957710Sbostic else if (*errnum < 0) { 48057710Sbostic errmsg: while (((ss = getc(inputt)) != '\n') && 48157710Sbostic (ss != EOF)); 482*58315Sbostic if (help_flag == 1) 483*58315Sbostic printf("%?: %s\n", help_msg); 484*58315Sbostic else 485*58315Sbostic printf("?\n"); 486*58315Sbostic if (g_flag > 0) 487*58315Sbostic return; 488*58315Sbostic break; 48957710Sbostic } 49057710Sbostic l_last = ss; 49157710Sbostic ss = getc(inputt); 49257710Sbostic } 49357710Sbostic } 49457710Sbostic } 49557694Sbostic 49657710Sbostic /* 49757710Sbostic * Exits ed and prints an appropriate message about the command line 49857694Sbostic * being malformed (see below). 49957694Sbostic */ 50057694Sbostic void 50157694Sbostic ed_exit(err) 50257710Sbostic int err; 50357694Sbostic { 50457710Sbostic switch (err) { 50557710Sbostic case 1: 50657710Sbostic (void)fprintf(stderr, "ed: illegal option\n"); 50757710Sbostic break; 50857710Sbostic case 2: 50957710Sbostic (void)fprintf(stderr, "ed: missing promptstring\n"); 51057710Sbostic break; 51157710Sbostic case 3: 51257710Sbostic (void)fprintf(stderr, "ed: too many filenames\n"); 51357710Sbostic break; 51457710Sbostic case 4: 51557710Sbostic (void)fprintf(stderr, "ed: out of memory error\n"); 51657710Sbostic break; 517*58315Sbostic case 5: 518*58315Sbostic (void)fprintf(stderr, "ed: unable to create buffer\n"); 519*58315Sbostic break; 52057710Sbostic default: 52157710Sbostic (void)fprintf(stderr, "ed: command line error\n"); 52257710Sbostic break; 52357710Sbostic } 52457710Sbostic (void)fprintf(stderr, 52557710Sbostic "ed: ed [ -s ] [ -p promptstring ] [ filename ]\n"); 52657710Sbostic exit(1); 52757710Sbostic } 52857694Sbostic 52957694Sbostic /* 53057710Sbostic * SIGINT is never turned off. We flag it happened and then pay attention 53157710Sbostic * to it at certain logical locations in the code we don't do more here 53257710Sbostic * cause some of our buffer pointer's may be in an inbetween state at the 53357710Sbostic * time of the SIGINT. So we flag it happened, let the local fn handle it 53457710Sbostic * and do a jump back to the cmd_loop 53557694Sbostic */ 53657710Sbostic static void 53757710Sbostic sigint_handler(signo) 53857710Sbostic int signo; 53957710Sbostic { 54057710Sbostic sigint_flag = 1; 541*58315Sbostic if (sigspecial2) { 542*58315Sbostic sigspecial2 = 0; 543*58315Sbostic SIGINT_ILACTION; 544*58315Sbostic } 545*58315Sbostic else 546*58315Sbostic if (sigspecial); 547*58315Sbostic else 548*58315Sbostic SIGINT_ACTION; 54957710Sbostic } 55057694Sbostic 55157710Sbostic static void 55257710Sbostic sighup_handler(signo) 55357710Sbostic int signo; 55457694Sbostic { 55557710Sbostic (void)fprintf(stderr,"\n SIGHUP \n"); 55657710Sbostic sighup_flag = 1; 55757710Sbostic undo(); 55857710Sbostic do_hup(); 55957710Sbostic /* NOTREACHED */ 56057694Sbostic 56157710Sbostic SIGHUP_ACTION; 56257710Sbostic } 563