⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 main.c

📁 早期freebsd实现
💻 C
字号:
/*- * Copyright (c) 1992, 1993 *	The Regents of the University of California.  All rights reserved. * * This code is derived from software contributed to Berkeley by * Rodney Ruddock of the University of Guelph. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software *    must display the following acknowledgement: *	This product includes software developed by the University of *	California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors *    may be used to endorse or promote products derived from this software *    without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#ifndef lintstatic char copyright[] ="@(#) Copyright (c) 1992, 1993\n\	The Regents of the University of California.  All rights reserved.\n";#endif /* not lint */#ifndef lintstatic char sccsid[] = "@(#)main.c	8.1 (Berkeley) 5/31/93";#endif /* not lint */#include <sys/types.h>#include <sys/ioctl.h>#include <limits.h>#include <regex.h>#include <setjmp.h>#include <signal.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#ifdef DBI#include <db.h>#endif#include "ed.h"#include "extern.h"/* * This is where all of the "global" variables are declared. They are * set for extern in the ed.h header file (so everyone can get them). */int nn_max, nn_max_flag, Start_default, End_default, address_flag;int zsnum, filename_flag, add_flag=0, join_flag=0;int help_flag=0, gut_num=-1;#ifdef STDIOFILE *fhtmp;int file_seek;#endif#ifdef DBIDB *dbhtmp;#endifLINE *nn_max_start, *nn_max_end;struct MARK mark_matrix[26]; /* in init set all to null */ char *text;LINE **gut=NULL;char *filename_current, *prompt_string=NULL, help_msg[130];char *template=NULL;int prompt_str_flg=0, start_up_flag=0, name_set=0;LINE *top, *current, *bottom, *Start, *End; struct u_layer *u_stk;struct d_layer *d_stk;LINE *u_current, *u_top, *u_bottom;int u_set;regex_t RE_comp;regmatch_t RE_match[RE_SEC];int RE_sol=0, RE_flag=0;char *RE_patt=NULL;int ss; /* for the getc() */int explain_flag=1, g_flag=0, GV_flag=0, printsfx=0, exit_code=0;long change_flag=0L;int line_length;jmp_buf ctrl_position, ctrl_position2, ctrl_position3; /* For SIGnal handling. */int sigint_flag, sighup_flag, sigspecial=0, sigspecial2=0, sigspecial3=0;static void sigint_handler __P((int));static void sighup_handler __P((int));/* * Starts the whole show going. Set things up as the arguments spec * in the shell and set a couple of the global variables. * * Note naming viol'n with errnum for consistancy. */intmain(argc, argv)	int argc;	char *argv[];{	int l_num, errnum=0, l_err=0;	char *l_fnametmp, *l_col, buf[2];	struct winsize win;	setbuffer(stdin, buf, 1);	line_length = ((l_col = getenv("COLUMNS")) == NULL ? 0 : atoi(l_col));	if ((line_length == 0 && isatty(STDOUT_FILENO) &&		ioctl(STDOUT_FILENO, TIOCGWINSZ, &win) != -1))		line_length = win.ws_col;	if (line_length == 0)		line_length = 78;	line_length -= 3;	/* for the octal to break properly in 'l' */	Start = End = NULL;	top = bottom = NULL;	current = NULL;	nn_max_flag = 0;	nn_max_start = nn_max_end = NULL;	l_fnametmp = calloc(FILENAME_LEN, sizeof(char));	if (l_fnametmp == NULL)		ed_exit(4);	text = calloc(NN_MAX_START + 2, sizeof(char));	if (text == NULL)		ed_exit(4);	Start_default = End_default = 0;	zsnum = 22;		/* for the 'z' command */	help_msg[0] = '\0';	u_stk = NULL;	d_stk = NULL;	u_current = u_top = u_bottom = NULL;	u_set = 0;		/* for in d after a j */	filename_flag = 0;	filename_current = NULL;	l_num = 1;	for (;;) {		/* Process the command line options */		if (l_num >= argc)			break;		switch (argv[l_num][0]) {		case '-':			switch (argv[l_num][1]) {			case '\0':	/* this is why 'getopt' not used */			case 's':				explain_flag = 0;				break;			case 'p':				if (++l_num < argc) {					prompt_string =					    calloc(strlen(argv[l_num]),					    sizeof(char));					if (prompt_string == NULL)						ed_exit(4);					strcpy(prompt_string, argv[l_num]);					prompt_str_flg = 1;					break;				}				l_err = 1;			case 'v':#ifdef BSD				(void)printf("ed: in BSD mode:\n");#endif#ifdef POSIX				(void)printf("ed: in POSIX mode:\n");#endif				break;			default:				l_err++;				ed_exit(l_err);			}			break;		default:			if (name_set)				ed_exit(3);			strcpy(l_fnametmp, argv[l_num]);			filename_current = l_fnametmp;			name_set = 1;			if (prompt_str_flg)				break;			/* default ed prompt */			prompt_string = (char *) calloc(3, sizeof(char));			strcpy(prompt_string, "*");			break;		}		l_num++;	}	start_up_flag = 1;	cmd_loop(stdin, &errnum);	/* NOTREACHED */}/* * The command loop. What the command is that the user has specified * is determined here. This is not just for commands coming from * the terminal but any standard i/o stream; see the global commands. * Some of the commands are handled within here (i.e. 'H') while most * are handled in their own functions (as called). */voidcmd_loop(inputt, errnum)	FILE *inputt;	int *errnum;{	LINE *l_tempp;	int l_last, l_jmp_flag;	l_last = 0; /* value in l_last may be clobbered (reset to = 0) by longjump, but that's okay */	if (g_flag == 0) {	/* big, BIG trouble if we don't check! think. */		/* set the jump point for the signals */		l_jmp_flag = setjmp(ctrl_position);		signal(SIGINT, sigint_handler);		signal(SIGHUP, sighup_handler);		switch (l_jmp_flag) {		case JMP_SET:			break;		/* Some general cleanup not specific to the jmp pt. */		case INTERUPT:			sigint_flag = 0;			GV_flag = 0;	/* safest place to do these flags */			g_flag = 0;			(void)printf("\n?\n");			break;		case HANGUP:		/* shouldn't get here. */			break;		default:			(void)fprintf(stderr, "Signal jump problem\n");		}		/* Only do this once! */		if (start_up_flag) {			start_up_flag = 0;			/* simulate the 'e' at startup */			e2(inputt, errnum);			if (*errnum == 0)				goto errmsg2;		}	}	for (;;) {		if (prompt_str_flg == 1)			(void)printf("%s", prompt_string);		ss = getc(inputt);		*errnum = 0;		l_tempp = Start = End = NULL;		Start_default = End_default = 1;		/*		 * This isn't nice and alphabetical mainly because of		 * restrictions with 'G' and 'V' (see ed(1)).		 */		for (;;) {			switch (ss) {			case 'd':				d(inputt, errnum);				break;			case 'e':			case 'E':				e(inputt, errnum);				if (*errnum == 0)					goto errmsg2;				break;			case 'f':				f(inputt, errnum);				break;			case 'a':			case 'c':			case 'i':			case 'g':			case 'G':			case 'v':			case 'V':				if (GV_flag == 1) {					(void)sprintf(help_msg,					    "command `%c' illegal in G/V", ss);					*errnum = -1;					break;				}				switch (ss) {				case 'a':					a(inputt, errnum);					break;				case 'c':					c(inputt, errnum);					break;				case 'i':					i(inputt, errnum);					break;				default:					g(inputt, errnum);				}				break;			case 'h':				if (rol(inputt, errnum))					break;				if (help_msg[0])					(void)printf("%s\n", help_msg);				*errnum = 1;				break;			case 'H':				if (rol(inputt, errnum))					break;				if (help_flag == 0) {					help_flag = 1;					if (help_msg[0])						(void)printf("%s\n",						    help_msg);				} else					help_flag = 0;				*errnum = 1;				break;			case 'j':				j(inputt, errnum);				break;			case 'k':				set_mark(inputt, errnum);				break;			case 'l':				l(inputt, errnum);				break;			case 'm':				m(inputt, errnum);				break;#ifdef POSIX				/* In POSIX-land 'P' toggles the prompt. */			case 'P':				if (rol(inputt, errnum))					break;				prompt_str_flg = prompt_str_flg ? 0 : 1;				*errnum = 1;				break;#endif			case '\n':				if (GV_flag == 1)					return;				/* For 'p' to consume. */				ungetc(ss, inputt);				if ((current == bottom) && (End == NULL)) {					strcpy(help_msg, "at end of buffer");					*errnum = -1;					break;				}				current = current->below;#ifdef BSD				/* In BSD 'P'=='p'. */			case 'P':#endif			case 'p':				p(inputt, errnum, 0);				break;			case 'n':				p(inputt, errnum, 1);				break;			/*			 * An EOF means 'q' unless we're still in the middle			 * of a global command, in which case it was just the			 * end of the command list found.			 */			case EOF:				clearerr(inputt);				if (g_flag > 0)					return;				/*ss = 'q';*/			case 'q':			case 'Q':				if ((!isatty(STDIN_FILENO)) && (ss == 'q'))					ss = 'Q';				q(inputt, errnum);				break;			case 'r':				r(inputt, errnum);				if (*errnum == 0)					goto errmsg2;				break;			case 's':				s(inputt, errnum);				break;			case 't':				t(inputt, errnum);				break;			case 'u':				u(inputt, errnum);				break;			case 'w':			case 'W':				w(inputt, errnum);				break;			case 'z':				z(inputt, errnum);				break;			case '!':				bang(inputt, errnum);				break;			case '=':				equal(inputt, errnum);				break;			/*			 * Control of address forms from here down.			 *			 * It's a head-game to understand why ";" and "," look			 * as they do below, but a lot of it has to do with ";"			 * and "," being special address pair forms themselves			 * and the compatibility for address "chains".			 */			case ';':				if (End_default == 1 && Start_default == 1) {					Start = current;					End = bottom;					Start_default = End_default = 0;				} else {					Start = current = End;					Start_default = 0;					End_default = 1;				}				l_tempp = NULL;				break;			/*			 * Note address ".,x" where x is a cmd is legal; not a			 * bug - for backward compatability.			 */			case ',':				if (End_default == 1 && Start_default == 1) {					Start = top;					End = bottom;					Start_default = End_default = 0;				} else {					Start = End;					Start_default = 0;					End_default = 1;				}				l_tempp = NULL;				break;			case '%':				if (End_default == 0) {					strcpy(help_msg,					    "'%' is an address pair");					*errnum = -1;					break;				}				Start = top;				End = bottom;				Start_default = End_default = 0;				l_tempp = NULL;				break;			/*			 * Within address_conv => l_last = '+', foobar, but			 * historical and now POSIX...			 */			case ' ':				break;			case '0':			case '1':			case '2':			case '3':			case '4':			case '5':			case '6':			case '7':			case '8':			case '9':			case '-':			case '^':			case '+':			case '\'':			case '$':			case '?':			case '/':			case '.':				ungetc(ss, inputt);				if (Start_default == 0 && End_default == 0) {					strcpy(help_msg,					    "badly formed address");					*errnum = -1;					break;				}				ss = l_last;				l_tempp = address_conv(l_tempp, inputt, errnum);				if (*errnum < 0)					break;				End = l_tempp;				End_default = 0;				if (Start_default == 0)					*errnum = address_check(Start, End);				break;			default:				*errnum = -1;				strcpy(help_msg, "unknown command");				break;			}	/* end-switch(ss) */			/* Things came out okay with the last command. */			if (*errnum > 0) {				if (GV_flag == 1)					return;				/* Do the suffixes if there were any. */				if (printsfx > 0) {					Start = End = current;					ungetc(ss, inputt);					if (printsfx == 1)						p(inputt, errnum, 0);					else						if (printsfx == 2)							p(inputt, errnum, 1);						else if (printsfx == 4)							l(inputt, errnum);					/* Unlikely it's needed, but... */					if (*errnum < 0)						goto errmsg;				}				break;			}			/* There was a problem with the last command. */			else if (*errnum < 0) {errmsg:				while (((ss = getc(inputt)) != '\n') &&				    (ss != EOF));				(void)printf("?\n");errmsg2:			if (help_flag)					(void)printf("%s\n", help_msg);				exit_code = 4;/* for people wanting scripts to carry on after a cmd error, then * define NOENDONSCRIPT on the compile line. */#ifndef NOENDONSCRIPT				if (!isatty(STDIN_FILENO)) {					ss = 'Q';					ungetc('\n', inputt);					q(inputt, errnum);				}#endif				break;			}			l_last = ss;			ss = getc(inputt);		}	}}/* * Exits ed and prints an appropriate message about the command line * being malformed (see below). */voided_exit(err)	int err;{	switch (err) {          case 1:		(void)fprintf(stderr, "ed: illegal option\n");		break;          case 2:		(void)fprintf(stderr, "ed: missing promptstring\n");		break;          case 3:		(void)fprintf(stderr, "ed: too many filenames\n");		break;          case 4:		(void)fprintf(stderr, "ed: out of memory error\n");		break;	  case 5:		(void)fprintf(stderr, "ed: unable to create buffer\n");		break;          default:		(void)fprintf(stderr, "ed: command line error\n");		break;        }	(void)fprintf(stderr,	    "ed: ed [ -s ] [ -p promptstring ] [ filename ]\n");	exit(1);}/* * SIGINT is never turned off. We flag it happened and then pay attention * to it at certain logical locations in the code we don't do more here * cause some of our buffer pointer's may be in an inbetween state at the * time of the SIGINT. So we flag it happened, let the local fn handle it * and do a jump back to the cmd_loop */static voidsigint_handler(signo)	int signo;{	sigint_flag = 1;	if (sigspecial3) {		sigspecial3 = 0;		SIGINT_ILACTION;	}	else		if (sigspecial);		else			SIGINT_ACTION;}static voidsighup_handler(signo)	int signo;{	sighup_flag = 1;	undo();	do_hup();	/* NOTREACHED */	SIGHUP_ACTION;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -