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

📄 sed.c

📁 手机嵌入式Linux下可用的busybox源码
💻 C
📖 第 1 页 / 共 2 页
字号:
	/* if it was a single-letter command that takes no arguments (such as 'p'	 * or 'd') all we need to do is increment the index past that command */	if (strchr("pd", cmdstr[idx])) {		idx++;	}	/* handle (s)ubstitution command */	else if (sed_cmd->cmd == 's') {		idx += parse_subst_cmd(sed_cmd, &cmdstr[idx]);	}	/* handle edit cmds: (a)ppend, (i)nsert, and (c)hange */	else if (strchr("aic", sed_cmd->cmd)) {		if ((sed_cmd->end_line || sed_cmd->end_match) && sed_cmd->cmd != 'c')			error_msg_and_die("only a beginning address can be specified for edit commands");		idx += parse_edit_cmd(sed_cmd, &cmdstr[idx]);	}	/* handle file cmds: (r)ead */	else if (sed_cmd->cmd == 'r') {		if (sed_cmd->end_line || sed_cmd->end_match)			error_msg_and_die("Command only uses one address");		idx += parse_file_cmd(sed_cmd, &cmdstr[idx]);	}	else {		error_msg_and_die("invalid command");	}	/* give back whatever's left over */	return (char *)&cmdstr[idx];}static void add_cmd_str(const char *cmdstr){	char *mystr = (char *)cmdstr;	do {		/* trim leading whitespace and semicolons */		memmove(mystr, &mystr[strspn(mystr, "; \n\r\t\v")], strlen(mystr));		/* if we ate the whole thing, that means there was just trailing		 * whitespace or a final / no-op semicolon. either way, get out */		if (strlen(mystr) == 0)			return;		/* if this is a comment, jump past it and keep going */		if (mystr[0] == '#') {			mystr = strpbrk(mystr, ";\n\r");			continue;		}		/* grow the array */		sed_cmds = xrealloc(sed_cmds, sizeof(struct sed_cmd) * (++ncmds));		/* zero new element */		memset(&sed_cmds[ncmds-1], 0, sizeof(struct sed_cmd));		/* load command string into new array element, get remainder */		mystr = parse_cmd_str(&sed_cmds[ncmds-1], mystr);	} while (mystr && strlen(mystr));}static void load_cmd_file(char *filename){	FILE *cmdfile;	char *line;	char *nextline;	cmdfile = xfopen(filename, "r");	while ((line = get_line_from_file(cmdfile)) != NULL) {		/* if a line ends with '\' it needs the next line appended to it */		while (line[strlen(line)-2] == '\\' &&				(nextline = get_line_from_file(cmdfile)) != NULL) {			line = xrealloc(line, strlen(line) + strlen(nextline) + 1);			strcat(line, nextline);			free(nextline);		}		/* eat trailing newline (if any) --if I don't do this, edit commands		 * (aic) will print an extra newline */		chomp(line);		add_cmd_str(line);		free(line);	}}#define PIPE_MAGIC 0x7f#define PIPE_GROW 64  #define pipeputc(c) \{ if (pipeline[pipeline_idx] == PIPE_MAGIC) { \	pipeline = xrealloc(pipeline, pipeline_len+PIPE_GROW); \	memset(pipeline+pipeline_len, 0, PIPE_GROW); \	pipeline_len += PIPE_GROW; \	pipeline[pipeline_len-1] = PIPE_MAGIC; } \	pipeline[pipeline_idx++] = (c); }static void print_subst_w_backrefs(const char *line, const char *replace, 	regmatch_t *regmatch, char **pipeline_p, int *pipeline_idx_p, 	int *pipeline_len_p, int matches){	char *pipeline = *pipeline_p;	int pipeline_idx = *pipeline_idx_p;	int pipeline_len = *pipeline_len_p;	int i;	/* go through the replacement string */	for (i = 0; replace[i]; i++) {		/* if we find a backreference (\1, \2, etc.) print the backref'ed * text */		if (replace[i] == '\\' && isdigit(replace[i+1])) {			int j;			char tmpstr[2];			int backref;			++i; /* i now indexes the backref number, instead of the leading slash */			tmpstr[0] = replace[i];			tmpstr[1] = 0;			backref = atoi(tmpstr);			/* print out the text held in regmatch[backref] */			if (backref <= matches && regmatch[backref].rm_so != -1)				for (j = regmatch[backref].rm_so; j < regmatch[backref].rm_eo; j++)					pipeputc(line[j]);		}		/* if we find a backslash escaped character, print the character */		else if (replace[i] == '\\') {			++i;			pipeputc(replace[i]);		}		/* if we find an unescaped '&' print out the whole matched text.		 * fortunately, regmatch[0] contains the indicies to the whole matched		 * expression (kinda seems like it was designed for just such a		 * purpose...) */		else if (replace[i] == '&' && replace[i-1] != '\\') {			int j;			for (j = regmatch[0].rm_so; j < regmatch[0].rm_eo; j++)				pipeputc(line[j]);		}		/* nothing special, just print this char of the replacement string to stdout */		else			pipeputc(replace[i]);	}	*pipeline_p = pipeline;	*pipeline_idx_p = pipeline_idx;	*pipeline_len_p = pipeline_len;}static int do_subst_command(const struct sed_cmd *sed_cmd, char **line){	char *hackline = *line;	char *pipeline = 0;	int pipeline_idx = 0;	int pipeline_len = 0;	int altered = 0;	regmatch_t *regmatch = NULL;	/* we only proceed if the substitution 'search' expression matches */	if (regexec(sed_cmd->sub_match, hackline, 0, NULL, 0) == REG_NOMATCH)		return 0;	/* whaddaya know, it matched. get the number of back references */	regmatch = xmalloc(sizeof(regmatch_t) * (sed_cmd->num_backrefs+1));	/* allocate more PIPE_GROW bytes	   if replaced string is larger than original */	pipeline_len = strlen(hackline)+PIPE_GROW;	pipeline = xmalloc(pipeline_len);	memset(pipeline, 0, pipeline_len);	/* buffer magic */	pipeline[pipeline_len-1] = PIPE_MAGIC;	/* and now, as long as we've got a line to try matching and if we can match	 * the search string, we make substitutions */	while ((*hackline || !altered) && (regexec(sed_cmd->sub_match, hackline,					sed_cmd->num_backrefs+1, regmatch, 0) != REG_NOMATCH) ) {		int i;		/* print everything before the match */		for (i = 0; i < regmatch[0].rm_so; i++)			pipeputc(hackline[i]);		/* then print the substitution string */		print_subst_w_backrefs(hackline, sed_cmd->replace, regmatch, 				&pipeline, &pipeline_idx, &pipeline_len,				sed_cmd->num_backrefs);		/* advance past the match */		hackline += regmatch[0].rm_eo;		/* flag that something has changed */		altered++;		/* if we're not doing this globally, get out now */		if (!sed_cmd->sub_g)			break;	}	for (; *hackline; hackline++) pipeputc(*hackline);	if (pipeline[pipeline_idx] == PIPE_MAGIC) pipeline[pipeline_idx] = 0;	/* cleanup */	free(regmatch);	free(*line);	*line = pipeline;	return altered;}static void process_file(FILE *file){	char *line = NULL;	static int linenum = 0; /* GNU sed does not restart counting lines at EOF */	unsigned int still_in_range = 0;	int altered;	int i;	/* go through every line in the file */	while ((line = get_line_from_file(file)) != NULL) {		chomp(line);		linenum++;		altered = 0;		/* for every line, go through all the commands */		for (i = 0; i < ncmds; i++) {			/*			 * entry point into sedding...			 */			if (					/* no range necessary */					(sed_cmds[i].beg_line == 0 && sed_cmds[i].end_line == 0 &&					 sed_cmds[i].beg_match == NULL &&					 sed_cmds[i].end_match == NULL) ||					/* this line number is the first address we're looking for */					(sed_cmds[i].beg_line && (sed_cmds[i].beg_line == linenum)) ||					/* this line matches our first address regex */					(sed_cmds[i].beg_match && (regexec(sed_cmds[i].beg_match, line, 0, NULL, 0) == 0)) ||					/* we are currently within the beginning & ending address range */					still_in_range			   ) {				int deleted = 0;				/*				 * actual sedding				 */				switch (sed_cmds[i].cmd) {					case 'p':						puts(line);						break;					case 'd':						altered++;						deleted = 1;						break;					case 's':						/*						 * Some special cases for 's' printing to make it compliant with						 * GNU sed printing behavior (aka "The -n | s///p Matrix"):						 *						 *    -n ONLY = never print anything regardless of any successful						 *    substitution						 *						 *    s///p ONLY = always print successful substitutions, even if						 *    the line is going to be printed anyway (line will be printed						 *    twice).						 *						 *    -n AND s///p = print ONLY a successful substitution ONE TIME;						 *    no other lines are printed - this is the reason why the 'p'						 *    flag exists in the first place.						 */						/* if the user specified that they didn't want anything printed (i.e., a -n						 * flag and no 'p' flag after the s///), then there's really no point doing						 * anything here. */						if (be_quiet && !sed_cmds[i].sub_p)							break;						/* we print the line once, unless we were told to be quiet */						if (!be_quiet)							altered |= do_subst_command(&sed_cmds[i], &line);						/* we also print the line if we were given the 'p' flag						 * (this is quite possibly the second printing) */						if (sed_cmds[i].sub_p)							altered |= do_subst_command(&sed_cmds[i], &line);						if (altered && (i+1 >= ncmds || sed_cmds[i+1].cmd != 's'))							puts(line);						break;					case 'a':						puts(line);						fputs(sed_cmds[i].editline, stdout);						altered++;						break;					case 'i':						fputs(sed_cmds[i].editline, stdout);						break;					case 'c':						/* single-address case */						if (sed_cmds[i].end_match == NULL && sed_cmds[i].end_line == 0) {							fputs(sed_cmds[i].editline, stdout);						}						/* multi-address case */						else {							/* matching text */							if (sed_cmds[i].end_match && (regexec(sed_cmds[i].end_match, line, 0, NULL, 0) == 0))								fputs(sed_cmds[i].editline, stdout);							/* matching line numbers */							if (sed_cmds[i].end_line > 0 && sed_cmds[i].end_line == linenum)								fputs(sed_cmds[i].editline, stdout);						}						altered++;						break;					case 'r': {								  FILE *outfile;								  puts(line);								  outfile = fopen(sed_cmds[i].filename, "r");								  if (outfile)									  print_file(outfile);								  /* else if we couldn't open the output file,								   * no biggie, just don't print anything */								  altered++;							  }							  break;				}				/*				 * exit point from sedding...				 */				if (					/* this is a single-address command or... */					(sed_cmds[i].end_line == 0 && sed_cmds[i].end_match == NULL) || (						/* we were in the middle of our address range (this						 * isn't the first time through) and.. */						(still_in_range == 1) && (							/* this line number is the last address we're looking for or... */							(sed_cmds[i].end_line && (sed_cmds[i].end_line == linenum)) ||							/* this line matches our last address regex */							(sed_cmds[i].end_match && (regexec(sed_cmds[i].end_match, line, 0, NULL, 0) == 0))						)					)				) {					/* we're out of our address range */					still_in_range = 0;				}				/* didn't hit the exit? then we're still in the middle of an address range */				else {					still_in_range = 1;				}				if (deleted)					break;			}		}		/* we will print the line unless we were told to be quiet or if the		 * line was altered (via a 'd'elete or 's'ubstitution), in which case		 * the altered line was already printed */		if (!be_quiet && !altered)			puts(line);		free(line);	}}extern int sed_main(int argc, char **argv){	int opt;#ifdef BB_FEATURE_CLEAN_UP	/* destroy command strings on exit */	if (atexit(destroy_cmd_strs) == -1)		perror_msg_and_die("atexit");#endif	/* do normal option parsing */	while ((opt = getopt(argc, argv, "ne:f:")) > 0) {		switch (opt) {			case 'n':				be_quiet++;				break;			case 'e':				add_cmd_str(optarg);				break;			case 'f': 				load_cmd_file(optarg);				break;			default:				show_usage();		}	}	/* if we didn't get a pattern from a -e and no command file was specified,	 * argv[optind] should be the pattern. no pattern, no worky */	if (ncmds == 0) {		if (argv[optind] == NULL)			show_usage();		else {			add_cmd_str(argv[optind]);			optind++;		}	}	/* argv[(optind)..(argc-1)] should be names of file to process. If no	 * files were specified or '-' was specified, take input from stdin.	 * Otherwise, we process all the files specified. */	if (argv[optind] == NULL || (strcmp(argv[optind], "-") == 0)) {		process_file(stdin);	}	else {		int i;		FILE *file;		for (i = optind; i < argc; i++) {			file = fopen(argv[i], "r");			if (file == NULL) {				perror_msg("%s", argv[i]);			} else {				process_file(file);				fclose(file);			}		}	}		return 0;}

⌨️ 快捷键说明

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