Esempio n. 1
0
/* Get next line of input from G.input_file_list, flushing append buffer and
 * noting if we ran out of files without a newline on the last line we read.
 */
static char *get_next_line(char *gets_char, char *last_puts_char)
{
	char *temp = NULL;
	size_t len;
	char gc;

	flush_append(last_puts_char);

	/* will be returned if last line in the file
	 * doesn't end with either '\n' or '\0' */
	gc = NO_EOL_CHAR;
	for (; G.current_input_file <= G.last_input_file; G.current_input_file++) {
		FILE *fp = G.current_fp;
		if (!fp) {
			const char *path = G.input_file_list[G.current_input_file];
			fp = stdin;
			if (path != bb_msg_standard_input) {
				fp = fopen_or_warn(path, "r");
				if (!fp) {
					G.exitcode = EXIT_FAILURE;
					continue;
				}
			}
			G.current_fp = fp;
		}
		/* Read line up to a newline or NUL byte, inclusive,
		 * return malloc'ed char[]. length of the chunk read
		 * is stored in len. NULL if EOF/error */
		temp = bb_get_chunk_from_file(fp, &len);
		if (temp) {
			/* len > 0 here, it's ok to do temp[len-1] */
			char c = temp[len-1];
			if (c == '\n' || c == '\0') {
				temp[len-1] = '\0';
				gc = c;
				if (c == '\0') {
					int ch = fgetc(fp);
					if (ch != EOF)
						ungetc(ch, fp);
					else
						gc = LAST_IS_NUL;
				}
			}
			/* else we put NO_EOL_CHAR into *gets_char */
			break;

		/* NB: I had the idea of peeking next file(s) and returning
		 * NO_EOL_CHAR only if it is the *last* non-empty
		 * input file. But there is a case where this won't work:
		 * file1: "a woo\nb woo"
		 * file2: "c no\nd no"
		 * sed -ne 's/woo/bang/p' input1 input2 => "a bang\nb bang"
		 * (note: *no* newline after "b bang"!) */
		}
		/* Close this file and advance to next one */
		fclose_if_not_stdin(fp);
		G.current_fp = NULL;
	}
	*gets_char = gc;
	return temp;
}
Esempio n. 2
0
int expand_main(int argc UNUSED_PARAM, char **argv)
{
	/* Default 8 spaces for 1 tab */
	const char *opt_t = "8";
	FILE *file;
	unsigned tab_size;
	unsigned opt;
	int exit_status = EXIT_SUCCESS;

#if ENABLE_FEATURE_EXPAND_LONG_OPTIONS
	static const char expand_longopts[] ALIGN1 =
		/* name, has_arg, val */
		"initial\0"          No_argument       "i"
		"tabs\0"             Required_argument "t"
	;
#endif
#if ENABLE_FEATURE_UNEXPAND_LONG_OPTIONS
	static const char unexpand_longopts[] ALIGN1 =
		/* name, has_arg, val */
		"first-only\0"       No_argument       "i"
		"tabs\0"             Required_argument "t"
		"all\0"              No_argument       "a"
	;
#endif
	init_unicode();

	if (ENABLE_EXPAND && (!ENABLE_UNEXPAND || applet_name[0] == 'e')) {
		IF_FEATURE_EXPAND_LONG_OPTIONS(applet_long_options = expand_longopts);
		opt = getopt32(argv, "it:", &opt_t);
	} else {
		IF_FEATURE_UNEXPAND_LONG_OPTIONS(applet_long_options = unexpand_longopts);
		/* -t NUM sets also -a */
		opt_complementary = "ta";
		opt = getopt32(argv, "ft:a", &opt_t);
		/* -f --first-only is the default */
		if (!(opt & OPT_ALL)) opt |= OPT_INITIAL;
	}
	tab_size = xatou_range(opt_t, 1, UINT_MAX);

	argv += optind;

	if (!*argv) {
		*--argv = (char*)bb_msg_standard_input;
	}
	do {
		file = fopen_or_warn_stdin(*argv);
		if (!file) {
			exit_status = EXIT_FAILURE;
			continue;
		}

		if (ENABLE_EXPAND && (!ENABLE_UNEXPAND || applet_name[0] == 'e'))
			IF_EXPAND(expand(file, tab_size, opt));
		else
			IF_UNEXPAND(unexpand(file, tab_size, opt));

		/* Check and close the file */
		if (fclose_if_not_stdin(file)) {
			bb_simple_perror_msg(*argv);
			exit_status = EXIT_FAILURE;
		}
		/* If stdin also clear EOF */
		if (file == stdin)
			clearerr(file);
	} while (*++argv);

	/* Now close stdin also */
	/* (if we didn't read from it, it's a no-op) */
	if (fclose(stdin))
		bb_perror_msg_and_die(bb_msg_standard_input);

	fflush_stdout_and_exit(exit_status);
}
int strings_main(int argc UNUSED_PARAM, char **argv)
{
	int c, status = EXIT_SUCCESS;
	unsigned n, count;
	off_t offset;
	FILE *file;
	char *string;
	const char *fmt = "%s: ";
	const char *n_arg = "4";

	getopt32(argv, "afon:", &n_arg);
	/* -a is our default behaviour */
	/*argc -= optind;*/
	argv += optind;

	n = xatou_range(n_arg, 1, INT_MAX);
	string = xzalloc(n + 1);
	n--;

	if (!*argv) {
		fmt = "{%s}: ";
		*--argv = (char *)bb_msg_standard_input;
	}

	do {
		file = fopen_or_warn_stdin(*argv);
		if (!file) {
			status = EXIT_FAILURE;
			continue;
		}
		offset = 0;
		count = 0;
		do {
			c = fgetc(file);
			if (isprint_asciionly(c) || c == '\t') {
				if (count > n) {
					bb_putchar(c);
				} else {
					string[count] = c;
					if (count == n) {
						if (option_mask32 & PRINT_NAME) {
							printf(fmt, *argv);
						}
						if (option_mask32 & PRINT_OFFSET) {
							printf("%7"OFF_FMT"o ", offset - n);
						}
						fputs(string, stdout);
					}
					count++;
				}
			} else {
				if (count > n) {
					bb_putchar('\n');
				}
				count = 0;
			}
			offset++;
		} while (c != EOF);
		fclose_if_not_stdin(file);
	} while (*++argv);

	if (ENABLE_FEATURE_CLEAN_UP)
		free(string);

	fflush_stdout_and_exit(status);
}
Esempio n. 4
0
int sed_main(int argc UNUSED_PARAM, char **argv)
{
	unsigned opt;
	llist_t *opt_e, *opt_f;
	char *opt_i;

#if ENABLE_LONG_OPTS
	static const char sed_longopts[] ALIGN1 =
		/* name             has_arg             short */
		"in-place\0"        Optional_argument   "i"
		"regexp-extended\0" No_argument         "r"
		"quiet\0"           No_argument         "n"
		"silent\0"          No_argument         "n"
		"expression\0"      Required_argument   "e"
		"file\0"            Required_argument   "f";
#endif

	INIT_G();

	/* destroy command strings on exit */
	if (ENABLE_FEATURE_CLEAN_UP) atexit(sed_free_and_close_stuff);

	/* Lie to autoconf when it starts asking stupid questions. */
	if (argv[1] && strcmp(argv[1], "--version") == 0) {
		puts("This is not GNU sed version 4.0");
		return 0;
	}

	/* do normal option parsing */
	opt_e = opt_f = NULL;
	opt_i = NULL;
	/* -i must be first, to match OPT_in_place definition */
	/* -E is a synonym of -r:
	 * GNU sed 4.2.1 mentions it in neither --help
	 * nor manpage, but does recognize it.
	 */
	opt = getopt32long(argv, "^"
			"i::rEne:*f:*"
			"\0" "nn"/*count -n*/,
			sed_longopts,
			&opt_i, &opt_e, &opt_f,
			&G.be_quiet); /* counter for -n */
	//argc -= optind;
	argv += optind;
	if (opt & OPT_in_place) { // -i
		die_func = cleanup_outname;
	}
	if (opt & (2|4))
		G.regex_type |= REG_EXTENDED; // -r or -E
	//if (opt & 8)
	//	G.be_quiet++; // -n (implemented with a counter instead)
	while (opt_e) { // -e
		add_cmd_block(llist_pop(&opt_e));
	}
	while (opt_f) { // -f
		char *line;
		FILE *cmdfile;
		cmdfile = xfopen_stdin(llist_pop(&opt_f));
		while ((line = xmalloc_fgetline(cmdfile)) != NULL) {
			add_cmd(line);
			free(line);
		}
		fclose_if_not_stdin(cmdfile);
	}
	/* if we didn't get a pattern from -e or -f, use argv[0] */
	if (!(opt & 0x30)) {
		if (!*argv)
			bb_show_usage();
		add_cmd_block(*argv++);
	}
	/* Flush any unfinished commands. */
	add_cmd("");

	/* By default, we write to stdout */
	G.nonstdout = stdout;

	/* argv[0..(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. */
	G.input_file_list = argv;
	if (!argv[0]) {
		if (opt & OPT_in_place)
			bb_error_msg_and_die(bb_msg_requires_arg, "-i");
		argv[0] = (char*)bb_msg_standard_input;
		/* G.last_input_file = 0; - already is */
	} else {
		goto start;

		for (; *argv; argv++) {
			struct stat statbuf;
			int nonstdoutfd;
			sed_cmd_t *sed_cmd;

			G.last_input_file++;
 start:
			if (!(opt & OPT_in_place)) {
				if (LONE_DASH(*argv)) {
					*argv = (char*)bb_msg_standard_input;
					process_files();
				}
				continue;
			}

			/* -i: process each FILE separately: */

			if (stat(*argv, &statbuf) != 0) {
				bb_simple_perror_msg(*argv);
				G.exitcode = EXIT_FAILURE;
				G.current_input_file++;
				continue;
			}
			G.outname = xasprintf("%sXXXXXX", *argv);
			nonstdoutfd = xmkstemp(G.outname);
			G.nonstdout = xfdopen_for_write(nonstdoutfd);
			/* Set permissions/owner of output file */
			/* chmod'ing AFTER chown would preserve suid/sgid bits,
			 * but GNU sed 4.2.1 does not preserve them either */
			fchmod(nonstdoutfd, statbuf.st_mode);
			fchown(nonstdoutfd, statbuf.st_uid, statbuf.st_gid);

			process_files();
			fclose(G.nonstdout);
			G.nonstdout = stdout;

			if (opt_i) {
				char *backupname = xasprintf("%s%s", *argv, opt_i);
				xrename(*argv, backupname);
				free(backupname);
			}
			/* else unlink(*argv); - rename below does this */
			xrename(G.outname, *argv); //TODO: rollback backup on error?
			free(G.outname);
			G.outname = NULL;

			/* Fix disabled range matches and mangled ",+N" ranges */
			for (sed_cmd = G.sed_cmd_head; sed_cmd; sed_cmd = sed_cmd->next) {
				sed_cmd->beg_line = sed_cmd->beg_line_orig;
				sed_cmd->end_line = sed_cmd->end_line_orig;
			}
		}
		/* Here, to handle "sed 'cmds' nonexistent_file" case we did:
		 * if (G.current_input_file[G.current_input_file] == NULL)
		 *	return G.exitcode;
		 * but it's not needed since process_files() works correctly
		 * in this case too. */
	}

	process_files();

	return G.exitcode;
}
Esempio n. 5
0
int cut_main(int argc ATTRIBUTE_UNUSED, char **argv)
{
	char delim = '\t';	/* delimiter, default is tab */
	char *sopt, *ltok;

	opt_complementary = "b--bcf:c--bcf:f--bcf";
	getopt32(argv, optstring, &sopt, &sopt, &sopt, &ltok);
//	argc -= optind;
	argv += optind;
	if (!(option_mask32 & (CUT_OPT_BYTE_FLGS | CUT_OPT_CHAR_FLGS | CUT_OPT_FIELDS_FLGS)))
		bb_error_msg_and_die("expected a list of bytes, characters, or fields");

	if (option_mask32 & CUT_OPT_DELIM_FLGS) {
		if (ltok[0] && ltok[1]) { /* more than 1 char? */
			bb_error_msg_and_die("the delimiter must be a single character");
		}
		delim = ltok[0];
	}

	/*  non-field (char or byte) cutting has some special handling */
	if (!(option_mask32 & CUT_OPT_FIELDS_FLGS)) {
		static const char _op_on_field[] ALIGN1 = " only when operating on fields";

		if (option_mask32 & CUT_OPT_SUPPRESS_FLGS) {
			bb_error_msg_and_die
				("suppressing non-delimited lines makes sense%s",
				 _op_on_field);
		}
		if (delim != '\t') {
			bb_error_msg_and_die
				("a delimiter may be specified%s", _op_on_field);
		}
	}

	/*
	 * parse list and put values into startpos and endpos.
	 * valid list formats: N, N-, N-M, -M
	 * more than one list can be separated by commas
	 */
	{
		char *ntok;
		int s = 0, e = 0;

		/* take apart the lists, one by one (they are separated with commas) */
		while ((ltok = strsep(&sopt, ",")) != NULL) {

			/* it's actually legal to pass an empty list */
			if (!ltok[0])
				continue;

			/* get the start pos */
			ntok = strsep(&ltok, "-");
			if (!ntok[0]) {
				s = BOL;
			} else {
				s = xatoi_u(ntok);
				/* account for the fact that arrays are zero based, while
				 * the user expects the first char on the line to be char #1 */
				if (s != 0)
					s--;
			}

			/* get the end pos */
			if (ltok == NULL) {
				e = NON_RANGE;
			} else if (!ltok[0]) {
				e = EOL;
			} else {
				e = xatoi_u(ltok);
				/* if the user specified and end position of 0, that means "til the
				 * end of the line */
				if (e == 0)
					e = EOL;
				e--;	/* again, arrays are zero based, lines are 1 based */
				if (e == s)
					e = NON_RANGE;
			}

			/* add the new list */
			cut_lists = xrealloc(cut_lists, sizeof(struct cut_list) * (++nlists));
			cut_lists[nlists-1].startpos = s;
			cut_lists[nlists-1].endpos = e;
		}

		/* make sure we got some cut positions out of all that */
		if (nlists == 0)
			bb_error_msg_and_die("missing list of positions");

		/* now that the lists are parsed, we need to sort them to make life
		 * easier on us when it comes time to print the chars / fields / lines
		 */
		qsort(cut_lists, nlists, sizeof(struct cut_list), cmpfunc);
	}

	{
		int retval = EXIT_SUCCESS;

		if (!*argv)
			*--argv = (char *)"-";

		do {
			FILE *file = fopen_or_warn_stdin(*argv);
			if (!file) {
				retval = EXIT_FAILURE;
				continue;
			}
			cut_file(file, delim);
			fclose_if_not_stdin(file);
		} while (*++argv);

		if (ENABLE_FEATURE_CLEAN_UP)
			free(cut_lists);
		fflush_stdout_and_exit(retval);
	}
}
Esempio n. 6
0
int fold_main(int argc UNUSED_PARAM, char **argv)
{
	char *line_out = NULL;
	const char *w_opt = "80";
	unsigned width;
	smallint exitcode = EXIT_SUCCESS;

	init_unicode();

	if (ENABLE_INCLUDE_SUSv2) {
		/* Turn any numeric options into -w options.  */
		int i;
		for (i = 1; argv[i]; i++) {
			const char *a = argv[i];
			if (*a == '-') {
				a++;
				if (*a == '-' && !a[1]) /* "--" */
					break;
				if (isdigit(*a))
					argv[i] = xasprintf("-w%s", a);
			}
		}
	}

	getopt32(argv, "bsw:", &w_opt);
	width = xatou_range(w_opt, 1, 10000);

	argv += optind;
	if (!*argv)
		*--argv = (char*)"-";

	do {
		FILE *istream = fopen_or_warn_stdin(*argv);
		int c;
		unsigned column = 0;     /* Screen column where next char will go */
		unsigned offset_out = 0; /* Index in 'line_out' for next char */

		if (istream == NULL) {
			exitcode = EXIT_FAILURE;
			continue;
		}

		while ((c = getc(istream)) != EOF) {
			/* We grow line_out in chunks of 0x1000 bytes */
			if ((offset_out & 0xfff) == 0) {
				line_out = xrealloc(line_out, offset_out + 0x1000);
			}
 rescan:
			line_out[offset_out] = c;
			if (c == '\n') {
				write2stdout(line_out, offset_out + 1);
				column = offset_out = 0;
				continue;
			}
			column = adjust_column(column, c);
			if (column <= width || offset_out == 0) {
				/* offset_out == 0 case happens
				 * with small width (say, 1) and tabs.
				 * The very first tab already goes to column 8,
				 * but we must not wrap it */
				offset_out++;
				continue;
			}

			/* This character would make the line too long.
			 * Print the line plus a newline, and make this character
			 * start the next line */
			if (option_mask32 & FLAG_BREAK_SPACES) {
				unsigned i;
				unsigned logical_end;

				/* Look for the last blank. */
				for (logical_end = offset_out - 1; (int)logical_end >= 0; logical_end--) {
					if (!isblank(line_out[logical_end]))
						continue;

					/* Found a space or tab.
					 * Output up to and including it, and start a new line */
					logical_end++;
					/*line_out[logical_end] = '\n'; - NO! this nukes one buffered character */
					write2stdout(line_out, logical_end);
					putchar('\n');
					/* Move the remainder to the beginning of the next line.
					 * The areas being copied here might overlap. */
					memmove(line_out, line_out + logical_end, offset_out - logical_end);
					offset_out -= logical_end;
					for (column = i = 0; i < offset_out; i++) {
						column = adjust_column(column, line_out[i]);
					}
					goto rescan;
				}
				/* No blank found, wrap will split the overlong word */
			}
			/* Output what we accumulated up to now, and start a new line */
			line_out[offset_out] = '\n';
			write2stdout(line_out, offset_out + 1);
			column = offset_out = 0;
			goto rescan;
		} /* while (not EOF) */

		if (offset_out) {
			write2stdout(line_out, offset_out);
		}

		if (fclose_if_not_stdin(istream)) {
			bb_simple_perror_msg(*argv);
			exitcode = EXIT_FAILURE;
		}
	} while (*++argv);

	fflush_stdout_and_exit(exitcode);
}
Esempio n. 7
0
int head_main(int argc, char **argv)
{
	unsigned long count = 10;
	unsigned long i;
#if ENABLE_FEATURE_FANCY_HEAD
	int count_bytes = 0;
	int header_threshhold = 1;
#endif

	FILE *fp;
	const char *fmt;
	char *p;
	int opt;
	int c;
	int retval = EXIT_SUCCESS;

#if ENABLE_INCLUDE_SUSv2 || ENABLE_FEATURE_FANCY_HEAD
	/* Allow legacy syntax of an initial numeric option without -n. */
	if (argc > 1 && argv[1][0] == '-'
	 && isdigit(argv[1][1])
	) {
		--argc;
		++argv;
		p = (*argv) + 1;
		goto GET_COUNT;
	}
#endif

	/* No size benefit in converting this to getopt32 */
	while ((opt = getopt(argc, argv, head_opts)) > 0) {
		switch (opt) {
#if ENABLE_FEATURE_FANCY_HEAD
		case 'q':
			header_threshhold = INT_MAX;
			break;
		case 'v':
			header_threshhold = -1;
			break;
		case 'c':
			count_bytes = 1;
			/* fall through */
#endif
		case 'n':
			p = optarg;
#if ENABLE_INCLUDE_SUSv2 || ENABLE_FEATURE_FANCY_HEAD
 GET_COUNT:
#endif

#if !ENABLE_FEATURE_FANCY_HEAD
			count = xatoul(p);
#else
			count = xatoul_sfx(p, head_suffixes);
#endif
			break;
		default:
			bb_show_usage();
		}
	}

	argv += optind;
	if (!*argv) {
		*--argv = "-";
	}

	fmt = header_fmt_str + 1;
#if ENABLE_FEATURE_FANCY_HEAD
	if (argc - optind <= header_threshhold) {
		header_threshhold = 0;
	}
#else
	if (argc <= optind + 1) {
		fmt += 11;
	}
	/* Now define some things here to avoid #ifdefs in the code below.
	 * These should optimize out of the if conditions below. */
#define header_threshhold   1
#define count_bytes         0
#endif

	do {
		fp = fopen_or_warn_stdin(*argv);
		if (fp) {
			if (fp == stdin) {
				*argv = (char *) bb_msg_standard_input;
			}
			if (header_threshhold) {
				printf(fmt, *argv);
			}
			i = count;
			while (i && ((c = getc(fp)) != EOF)) {
				if (count_bytes || (c == '\n')) {
					--i;
				}
				putchar(c);
			}
			if (fclose_if_not_stdin(fp)) {
				bb_perror_msg("%s", *argv);	/* Avoid multibyte problems. */
				retval = EXIT_FAILURE;
			}
			die_if_ferror_stdout();
		}
		fmt = header_fmt_str;
	} while (*++argv);

	fflush_stdout_and_exit(retval);
}
Esempio n. 8
0
int grep_main(int argc, char **argv)
{
	FILE *file;
	int matched;
	llist_t *fopt = NULL;

	/* do normal option parsing */
#if ENABLE_FEATURE_GREP_CONTEXT
	char *slines_after;
	char *slines_before;
	char *Copt;

	opt_complementary = "H-h:e::f::C-AB";
	getopt32(argc, argv,
		GREP_OPTS GREP_OPT_CONTEXT OPT_EGREP,
		&pattern_head, &fopt,
		&slines_after, &slines_before, &Copt);

	if (option_mask32 & GREP_OPT_C) {
		/* -C unsets prev -A and -B, but following -A or -B
		   may override it */
		if (!(option_mask32 & GREP_OPT_A)) /* not overridden */
			slines_after = Copt;
		if (!(option_mask32 & GREP_OPT_B)) /* not overridden */
			slines_before = Copt;
		option_mask32 |= GREP_OPT_A|GREP_OPT_B; /* for parser */
	}
	if (option_mask32 & GREP_OPT_A) {
		lines_after = xatoi_u(slines_after);
	}
	if (option_mask32 & GREP_OPT_B) {
		lines_before = xatoi_u(slines_before);
	}
	/* sanity checks */
	if (option_mask32 & (GREP_OPT_c|GREP_OPT_q|GREP_OPT_l|GREP_OPT_L)) {
		option_mask32 &= ~GREP_OPT_n;
		lines_before = 0;
		lines_after = 0;
	} else if (lines_before > 0)
		before_buf = xzalloc(lines_before * sizeof(char *));
#else
	/* with auto sanity checks */
	opt_complementary = "H-h:e::f::c-n:q-n:l-n";
	getopt32(argc, argv, GREP_OPTS OPT_EGREP,
		&pattern_head, &fopt);
#endif
	invert_search = ((option_mask32 & GREP_OPT_v) != 0); /* 0 | 1 */

	if (pattern_head != NULL) {
		/* convert char *argv[] to grep_list_data_t */
		llist_t *cur;

		for (cur = pattern_head; cur; cur = cur->link)
			cur->data = new_grep_list_data(cur->data, 0);
	}
	if (option_mask32 & GREP_OPT_f)
		load_regexes_from_file(fopt);

	if (ENABLE_FEATURE_GREP_FGREP_ALIAS && applet_name[0] == 'f')
		option_mask32 |= GREP_OPT_F;

	if (!(option_mask32 & GREP_OPT_o))
		reflags = REG_NOSUB;

	if (ENABLE_FEATURE_GREP_EGREP_ALIAS &&
			(applet_name[0] == 'e' || (option_mask32 & GREP_OPT_E)))
		reflags |= REG_EXTENDED;

	if (option_mask32 & GREP_OPT_i)
		reflags |= REG_ICASE;

	argv += optind;
	argc -= optind;

	/* 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 (pattern_head == NULL) {
		if (*argv == NULL)
			bb_show_usage();
		else {
			char *pattern = new_grep_list_data(*argv++, 0);

			llist_add_to(&pattern_head, pattern);
			argc--;
		}
	}

	/* argv[(optind)..(argc-1)] should be names of file to grep through. If
	 * there is more than one file to grep, we will print the filenames. */
	if (argc > 1)
		print_filename = 1;
	/* -H / -h of course override */
	if (option_mask32 & GREP_OPT_H)
		print_filename = 1;
	if (option_mask32 & GREP_OPT_h)
		print_filename = 0;

	/* If no files were specified, or '-' was specified, take input from
	 * stdin. Otherwise, we grep through all the files specified. */
	if (argc == 0)
		argc++;
	matched = 0;
	while (argc--) {
		cur_file = *argv++;
		file = stdin;
		if (!cur_file || (*cur_file == '-' && !cur_file[1])) {
			cur_file = "(standard input)";
		} else {
			if (option_mask32 & GREP_OPT_r) {
				struct stat st;
				if (stat(cur_file, &st) == 0 && S_ISDIR(st.st_mode)) {
					if (!(option_mask32 & GREP_OPT_h))
						print_filename = 1;
					matched += grep_dir(cur_file);
					goto grep_done;
				}
			}
			/* else: fopen(dir) will succeed, but reading won't */
			file = fopen(cur_file, "r");
			if (file == NULL) {
				if (!SUPPRESS_ERR_MSGS)
					bb_perror_msg("%s", cur_file);
				open_errors = 1;
				continue;
			}
		}
		matched += grep_file(file);
		fclose_if_not_stdin(file);
 grep_done:
		if (matched < 0) {
			/* we found a match but were told to be quiet, stop here and
			* return success */
			break;
		}
	}

	/* destroy all the elments in the pattern list */
	if (ENABLE_FEATURE_CLEAN_UP) {
		while (pattern_head) {
			llist_t *pattern_head_ptr = pattern_head;
			grep_list_data_t *gl =
				(grep_list_data_t *)pattern_head_ptr->data;

			pattern_head = pattern_head->link;
			if ((gl->flg_mem_alocated_compiled & PATTERN_MEM_A))
				free(gl->pattern);
			if ((gl->flg_mem_alocated_compiled & COMPILED))
				regfree(&(gl->preg));
			free(pattern_head_ptr);
		}
	}
	/* 0 = success, 1 = failed, 2 = error */
	/* If the -q option is specified, the exit status shall be zero
	 * if an input line is selected, even if an error was detected.  */
	if (BE_QUIET && matched)
		return 0;
	if (open_errors)
		return 2;
	return !matched; /* invert return value 0 = success, 1 = failed */
}
Esempio n. 9
0
int wc_main(int argc ATTRIBUTE_UNUSED, char **argv)
{
	FILE *fp;
	const char *s, *arg;
	const char *start_fmt = " %9"COUNT_FMT + 1;
	const char *fname_fmt = " %s\n";
	COUNT_T *pcounts;
	COUNT_T counts[4];
	COUNT_T totals[4];
	unsigned linepos;
	unsigned u;
	int num_files = 0;
	int c;
	smallint status = EXIT_SUCCESS;
	smallint in_word;
	unsigned print_type;

	print_type = getopt32(argv, "lwcL");

	if (print_type == 0) {
		print_type = (1 << WC_LINES) | (1 << WC_WORDS) | (1 << WC_CHARS);
	}

	argv += optind;
	if (!argv[0]) {
		*--argv = (char *) bb_msg_standard_input;
		fname_fmt = "\n";
		if (!((print_type-1) & print_type)) /* exactly one option? */
			start_fmt = "%"COUNT_FMT;
	}

	memset(totals, 0, sizeof(totals));

	pcounts = counts;

	while ((arg = *argv++) != 0) {
		++num_files;
		fp = fopen_or_warn_stdin(arg);
		if (!fp) {
			status = EXIT_FAILURE;
			continue;
		}

		memset(counts, 0, sizeof(counts));
		linepos = 0;
		in_word = 0;

		do {
			/* Our -w doesn't match GNU wc exactly... oh well */

			++counts[WC_CHARS];
			c = getc(fp);
			if (isprint(c)) {
				++linepos;
				if (!isspace_given_isprint(c)) {
					in_word = 1;
					continue;
				}
			} else if (((unsigned int)(c - 9)) <= 4) {
				/* \t  9
				 * \n 10
				 * \v 11
				 * \f 12
				 * \r 13
				 */
				if (c == '\t') {
					linepos = (linepos | 7) + 1;
				} else {			/* '\n', '\r', '\f', or '\v' */
				DO_EOF:
					if (linepos > counts[WC_LENGTH]) {
						counts[WC_LENGTH] = linepos;
					}
					if (c == '\n') {
						++counts[WC_LINES];
					}
					if (c != '\v') {
						linepos = 0;
					}
				}
			} else if (c == EOF) {
				if (ferror(fp)) {
					bb_simple_perror_msg(arg);
					status = EXIT_FAILURE;
				}
				--counts[WC_CHARS];
				goto DO_EOF;		/* Treat an EOF as '\r'. */
			} else {
				continue;
			}

			counts[WC_WORDS] += in_word;
			in_word = 0;
			if (c == EOF) {
				break;
			}
		} while (1);

		if (totals[WC_LENGTH] < counts[WC_LENGTH]) {
			totals[WC_LENGTH] = counts[WC_LENGTH];
		}
		totals[WC_LENGTH] -= counts[WC_LENGTH];

		fclose_if_not_stdin(fp);

	OUTPUT:
		/* coreutils wc tries hard to print pretty columns
		 * (saves results for all files, find max col len etc...)
		 * we won't try that hard, it will bloat us too much */
		s = start_fmt;
		u = 0;
		do {
			if (print_type & (1 << u)) {
				printf(s, pcounts[u]);
				s = " %9"COUNT_FMT; /* Ok... restore the leading space. */
			}
			totals[u] += pcounts[u];
		} while (++u < 4);
		printf(fname_fmt, arg);
	}

	/* If more than one file was processed, we want the totals.  To save some
	 * space, we set the pcounts ptr to the totals array.  This has the side
	 * effect of trashing the totals array after outputting it, but that's
	 * irrelavent since we no longer need it. */
	if (num_files > 1) {
		num_files = 0;				/* Make sure we don't get here again. */
		arg = "total";
		pcounts = totals;
		--argv;
		goto OUTPUT;
	}

	fflush_stdout_and_exit(status);
}
Esempio n. 10
0
int sort_main(int argc UNUSED_PARAM, char **argv)
{
	FILE *fp, *outfile = stdout;
	char *line, **lines = NULL;
	char *str_ignored, *str_o, *str_t;
	llist_t *lst_k = NULL;
	int i, flag;
	int linecount = 0;

	xfunc_error_retval = 2;

	/* Parse command line options */
	/* -o and -t can be given at most once */
	opt_complementary = "o--o:t--t:" /* -t, -o: maximum one of each */
			"k::"; /* -k takes list */
	getopt32(argv, OPT_STR, &str_ignored, &str_ignored, &str_o, &lst_k, &str_t);
#if ENABLE_FEATURE_SORT_BIG
	if (option_mask32 & FLAG_o) outfile = xfopen_for_write(str_o);
	if (option_mask32 & FLAG_t) {
		if (!str_t[0] || str_t[1])
			bb_error_msg_and_die("bad -t parameter");
		key_separator = str_t[0];
	}
	/* parse sort key */
	while (lst_k) {
		enum {
			FLAG_allowed_for_k =
				FLAG_n | /* Numeric sort */
				FLAG_g | /* Sort using strtod() */
				FLAG_M | /* Sort date */
				FLAG_b | /* Ignore leading blanks */
				FLAG_r | /* Reverse */
				FLAG_d | /* Ignore !(isalnum()|isspace()) */
				FLAG_f | /* Force uppercase */
				FLAG_i | /* Ignore !isprint() */
			0
		};
		struct sort_key *key = add_key();
		char *str_k = llist_pop(&lst_k);
		const char *temp2;

		i = 0; /* i==0 before comma, 1 after (-k3,6) */
		while (*str_k) {
			/* Start of range */
			/* Cannot use bb_strtou - suffix can be a letter */
			key->range[2*i] = str2u(&str_k);
			if (*str_k == '.') {
				str_k++;
				key->range[2*i+1] = str2u(&str_k);
			}
			while (*str_k) {
				if (*str_k == ',' && !i++) {
					str_k++;
					break;
				} /* no else needed: fall through to syntax error
					 because comma isn't in OPT_STR */
				temp2 = strchr(OPT_STR, *str_k);
				if (!temp2)
					bb_error_msg_and_die("unknown key option");
				flag = 1 << (temp2 - OPT_STR);
				if (flag & ~FLAG_allowed_for_k)
					bb_error_msg_and_die("unknown sort type");
				/* b after ',' means strip _trailing_ space */
				if (i && flag == FLAG_b) flag = FLAG_bb;
				key->flags |= flag;
				str_k++;
			}
		}
	}
#endif
	/* global b strips leading and trailing spaces */
	if (option_mask32 & FLAG_b) option_mask32 |= FLAG_bb;

	/* Open input files and read data */
	argv += optind;
	if (!*argv)
		*--argv = (char*)"-";
	do {
		/* coreutils 6.9 compat: abort on first open error,
		 * do not continue to next file: */
		fp = xfopen_stdin(*argv);
		for (;;) {
			line = GET_LINE(fp);
			if (!line) break;
			lines = xrealloc_vector(lines, 6, linecount);
			lines[linecount++] = line;
		}
		fclose_if_not_stdin(fp);
	} while (*++argv);

#if ENABLE_FEATURE_SORT_BIG
	/* if no key, perform alphabetic sort */
	if (!key_list)
		add_key()->range[0] = 1;
	/* handle -c */
	if (option_mask32 & FLAG_c) {
		int j = (option_mask32 & FLAG_u) ? -1 : 0;
		for (i = 1; i < linecount; i++)
			if (compare_keys(&lines[i-1], &lines[i]) > j) {
				fprintf(stderr, "Check line %d\n", i);
				return EXIT_FAILURE;
			}
		return EXIT_SUCCESS;
	}
#endif
	/* Perform the actual sort */
	qsort(lines, linecount, sizeof(char *), compare_keys);
	/* handle -u */
	if (option_mask32 & FLAG_u) {
		flag = 0;
		/* coreutils 6.3 drop lines for which only key is the same */
		/* -- disabling last-resort compare... */
		option_mask32 |= FLAG_s;
		for (i = 1; i < linecount; i++) {
			if (!compare_keys(&lines[flag], &lines[i]))
				free(lines[i]);
			else
				lines[++flag] = lines[i];
		}
		if (linecount) linecount = flag+1;
	}
	/* Print it */
	flag = (option_mask32 & FLAG_z) ? '\0' : '\n';
	for (i = 0; i < linecount; i++)
		fprintf(outfile, "%s%c", lines[i], flag);

	fflush_stdout_and_exit(EXIT_SUCCESS);
}
Esempio n. 11
0
int sort_main(int argc UNUSED_PARAM, char **argv)
{
	char *line, **lines;
	char *str_ignored, *str_o, *str_t;
	llist_t *lst_k = NULL;
	int i;
	int linecount;
	unsigned opts;

	xfunc_error_retval = 2;

	/* Parse command line options */
	/* -o and -t can be given at most once */
	opt_complementary = "o--o:t--t"; /* -t, -o: at most one of each */
	opts = getopt32(argv, OPT_STR, &str_ignored, &str_ignored, &str_o, &lst_k, &str_t);
	/* global b strips leading and trailing spaces */
	if (opts & FLAG_b)
		option_mask32 |= FLAG_bb;
#if ENABLE_FEATURE_SORT_BIG
	if (opts & FLAG_t) {
		if (!str_t[0] || str_t[1])
			bb_error_msg_and_die("bad -t parameter");
		key_separator = str_t[0];
	}
	/* note: below this point we use option_mask32, not opts,
	 * since that reduces register pressure and makes code smaller */

	/* Parse sort key */
	while (lst_k) {
		enum {
			FLAG_allowed_for_k =
				FLAG_n | /* Numeric sort */
				FLAG_g | /* Sort using strtod() */
				FLAG_M | /* Sort date */
				FLAG_b | /* Ignore leading blanks */
				FLAG_r | /* Reverse */
				FLAG_d | /* Ignore !(isalnum()|isspace()) */
				FLAG_f | /* Force uppercase */
				FLAG_i | /* Ignore !isprint() */
			0
		};
		struct sort_key *key = add_key();
		char *str_k = llist_pop(&lst_k);

		i = 0; /* i==0 before comma, 1 after (-k3,6) */
		while (*str_k) {
			/* Start of range */
			/* Cannot use bb_strtou - suffix can be a letter */
			key->range[2*i] = str2u(&str_k);
			if (*str_k == '.') {
				str_k++;
				key->range[2*i+1] = str2u(&str_k);
			}
			while (*str_k) {
				int flag;
				const char *idx;

				if (*str_k == ',' && !i++) {
					str_k++;
					break;
				} /* no else needed: fall through to syntax error
					because comma isn't in OPT_STR */
				idx = strchr(OPT_STR, *str_k);
				if (!idx)
					bb_error_msg_and_die("unknown key option");
				flag = 1 << (idx - OPT_STR);
				if (flag & ~FLAG_allowed_for_k)
					bb_error_msg_and_die("unknown sort type");
				/* b after ',' means strip _trailing_ space */
				if (i && flag == FLAG_b)
					flag = FLAG_bb;
				key->flags |= flag;
				str_k++;
			}
		}
	}
#endif

	/* Open input files and read data */
	argv += optind;
	if (!*argv)
		*--argv = (char*)"-";
	linecount = 0;
	lines = NULL;
	do {
		/* coreutils 6.9 compat: abort on first open error,
		 * do not continue to next file: */
		FILE *fp = xfopen_stdin(*argv);
		for (;;) {
			line = GET_LINE(fp);
			if (!line)
				break;
			lines = xrealloc_vector(lines, 6, linecount);
			lines[linecount++] = line;
		}
		fclose_if_not_stdin(fp);
	} while (*++argv);

#if ENABLE_FEATURE_SORT_BIG
	/* If no key, perform alphabetic sort */
	if (!key_list)
		add_key()->range[0] = 1;
	/* Handle -c */
	if (option_mask32 & FLAG_c) {
		int j = (option_mask32 & FLAG_u) ? -1 : 0;
		for (i = 1; i < linecount; i++) {
			if (compare_keys(&lines[i-1], &lines[i]) > j) {
				fprintf(stderr, "Check line %u\n", i);
				return EXIT_FAILURE;
			}
		}
		return EXIT_SUCCESS;
	}
#endif
	/* Perform the actual sort */
	qsort(lines, linecount, sizeof(lines[0]), compare_keys);

	/* Handle -u */
	if (option_mask32 & FLAG_u) {
		int j = 0;
		/* coreutils 6.3 drop lines for which only key is the same */
		/* -- disabling last-resort compare... */
		option_mask32 |= FLAG_s;
		for (i = 1; i < linecount; i++) {
			if (compare_keys(&lines[j], &lines[i]) == 0)
				free(lines[i]);
			else
				lines[++j] = lines[i];
		}
		if (linecount)
			linecount = j+1;
	}

	/* Print it */
#if ENABLE_FEATURE_SORT_BIG
	/* Open output file _after_ we read all input ones */
	if (option_mask32 & FLAG_o)
		xmove_fd(xopen(str_o, O_WRONLY|O_CREAT|O_TRUNC), STDOUT_FILENO);
#endif
	{
		int ch = (option_mask32 & FLAG_z) ? '\0' : '\n';
		for (i = 0; i < linecount; i++)
			printf("%s%c", lines[i], ch);
	}

	fflush_stdout_and_exit(EXIT_SUCCESS);
}