Compare commits

...

166 Commits

Author SHA1 Message Date
Jim Meyering
c4176dd559 . 1995-11-03 20:03:44 +00:00
Jim Meyering
47d5042d1e . 1995-11-03 20:03:18 +00:00
Jim Meyering
6df632b672 New version from glibc. 1995-11-03 20:02:00 +00:00
Jim Meyering
6875b205d6 (remove_file, remove_dir): Use euidaccess instead of euidaccess_stat.Likewise. 1995-11-03 20:01:13 +00:00
Jim Meyering
47306242ec (do_move): Use euidaccess instead of euidaccess_stat.Likewise. 1995-11-03 20:00:24 +00:00
Jim Meyering
83780d95f0 (copy): Use euidaccess instead of euidaccess_stat. 1995-11-03 19:59:44 +00:00
Jim Meyering
5b804afa6a New version from glibc. 1995-11-03 19:56:08 +00:00
Jim Meyering
83b9d5e9ef Add `const' attribute to some parameters. 1995-11-02 17:11:51 +00:00
Jim Meyering
a2b0b9846d . 1995-11-02 17:11:17 +00:00
Jim Meyering
a0ad16498b . 1995-11-02 17:11:04 +00:00
Jim Meyering
aa084c8407 Protoize. 1995-11-02 17:08:24 +00:00
Jim Meyering
ac821ab1ef Reorder functions to obviate forward dcls.
Remove forward dcls.
1995-11-02 17:06:52 +00:00
Jim Meyering
6e146d4216 (isdigits, convint): Remove these.
(main): Use xstrtol instead.
1995-10-31 12:52:29 +00:00
Jim Meyering
e4a96fff58 . 1995-10-31 12:52:14 +00:00
Jim Meyering
aa6cde5ca1 Add `const' attribute to some parameters. 1995-10-31 12:39:18 +00:00
Jim Meyering
05a5e42609 protoize. 1995-10-31 12:36:43 +00:00
Jim Meyering
11a013bf87 Reorder functions to obviate forward dcls.
Remove forward dcls.
1995-10-31 12:34:48 +00:00
Jim Meyering
de4de17bc5 (usage, next_line_num, main): Protoize. 1995-10-31 02:22:23 +00:00
Jim Meyering
b0302bb3a6 Add `const' attribute to some parameters. 1995-10-31 02:21:37 +00:00
Jim Meyering
334f8dcbb7 Add `const' attribute to some parameters. 1995-10-31 02:21:13 +00:00
Jim Meyering
47eaf4a1e8 Protoize. 1995-10-30 21:01:35 +00:00
Jim Meyering
1e30b2f8c4 Reorder functions to obviate forward dcls.
Remove forward dcls.
1995-10-30 21:00:36 +00:00
Jim Meyering
84df8be864 (eaccess_stat): Make static. 1995-10-30 18:00:05 +00:00
Jim Meyering
f05befc26c (copy): Update one of the calls to eaccess_stat to use 3 arguments. Ugh! 1995-10-30 17:53:48 +00:00
Jim Meyering
96e22ecc78 . 1995-10-29 20:44:54 +00:00
Jim Meyering
9eb195d6a5 . 1995-10-29 20:44:14 +00:00
Jim Meyering
40f0f4d2e8 (xwrite): Give output buffer parameter const attribute.
(output): Likewise for both parameters.
(tac): Likewise for file name parameter.
(tac_file): Likewise.
1995-10-29 20:38:01 +00:00
Jim Meyering
4fa07774d6 protoize. 1995-10-29 20:35:11 +00:00
Jim Meyering
7567c84e76 Reorder functions to obviate forward dcls.
Remove forward dcls.
1995-10-29 20:33:04 +00:00
Jim Meyering
a87c771012 (bsd_sum_file): Give file name parameter const attribute.
(sysv_sum_file): Likewise.
1995-10-29 20:24:53 +00:00
Jim Meyering
a2535fc95f Protoize. 1995-10-29 20:20:08 +00:00
Jim Meyering
d2aaf842b4 (main): Move function body to end of file.
Remove forward dcls.
1995-10-29 20:19:26 +00:00
Jim Meyering
13e93efe91 (nl_file): Give parameter const attribute.
Protoize.
1995-10-29 20:15:54 +00:00
Jim Meyering
af1033c63c Reorder functions to obviate forward dcls.
Remove forward dcls.
1995-10-29 20:12:32 +00:00
Jim Meyering
768f92072f (main): Move function body to end of file.
Remove forward dcls and protoize.
1995-10-29 20:05:29 +00:00
Jim Meyering
8b92864e1d Rename --file to --reference.
Leave --file as an alias, for now.  It will be removed later.
(usage): Update, but don't mention --file.
1995-10-29 19:29:19 +00:00
Jim Meyering
d97d668b69 . 1995-10-29 19:28:59 +00:00
Jim Meyering
5d1c0a2af5 . 1995-10-29 19:21:08 +00:00
Jim Meyering
b1c9ce6621 [TEST_STANDALONE]: Define. 1995-10-29 19:20:36 +00:00
Jim Meyering
aec547d764 . 1995-10-29 19:20:12 +00:00
Jim Meyering
185c59d3bd (mostlyclean): Remove *.info. 1995-10-29 14:26:48 +00:00
Jim Meyering
f1c5cfd5f2 (distclean): Remove .deps. 1995-10-29 14:23:11 +00:00
Jim Meyering
c848009e29 . 1995-10-29 14:22:15 +00:00
Jim Meyering
a0d766c204 . 1995-10-29 14:20:13 +00:00
Jim Meyering
c1f248d670 (INCLUDE, COMPILE): New variables.
(.c.o): Rewrite to be more like src/Makefile.in.
Add line that (--with-autodeps) will include mkdep-Makefile.
1995-10-29 12:14:37 +00:00
Jim Meyering
9b1d63b4a3 . 1995-10-28 21:07:18 +00:00
Jim Meyering
c7262bbe86 *** empty log message *** 1995-10-28 21:04:08 +00:00
Jim Meyering
008028896b . 1995-10-28 21:02:57 +00:00
Jim Meyering
c5716550a6 (md5_check): Use the same message format when the single file has a
read error or checksum mismatch as when there are more.
Write diagnostic to stderr, not stdout.
1995-10-28 21:01:01 +00:00
Jim Meyering
b43f5fb25b . 1995-10-28 05:55:34 +00:00
Jim Meyering
013277d331 New option --reference=FILE (-r FILE) analogous to the
like-named touch option.
(main): Recognize it and give diagnostic for misuse.
(usage): Describe briefly.
From Franc,ois Pinard.

(batch_convert): Close input stream also when it's not stdin.
(main): Reorganize to do option-consistency checks before all else.
1995-10-28 05:52:24 +00:00
Jim Meyering
09eedba01f . 1995-10-28 05:51:44 +00:00
Jim Meyering
ca59b76b50 (batch_convert): Close input stream also when it's not stdin. 1995-10-27 15:12:31 +00:00
Jim Meyering
b9485b8d52 (main): Use xfopen, not xtmpopen to open final output file. 1995-10-26 13:20:25 +00:00
Jim Meyering
66b9285a6f (xtmpfopen): New function -- for opening temp files.
Use it instead of xfopen.
1995-10-26 13:19:10 +00:00
Jim Meyering
470e773e76 . 1995-10-26 05:14:53 +00:00
Jim Meyering
039942bfc1 (xfopen): Rewrite using open/fdopen in order to set
proper permissions on temporary files.  Reported by Erik Corry
(erik@kroete2.freinet.de).
1995-10-26 05:14:41 +00:00
Jim Meyering
a94e341d85 . 1995-10-24 04:24:06 +00:00
Jim Meyering
db98ca11cf . 1995-10-24 04:17:33 +00:00
Jim Meyering
22a5274de9 . 1995-10-21 12:52:05 +00:00
Jim Meyering
2ee6cf8ea0 . 1995-10-21 12:50:56 +00:00
Jim Meyering
baf81e4974 . 1995-10-20 04:29:00 +00:00
Jim Meyering
bda4a5e5b7 (BEGIN_STATE): Use INT_MAX - 1 so as not to interfere with large repeat counts.
(struct E_string): New struct.

(find_closing_delim): Take E_string arg rather than char* and length.
(find_bracketed_repeat): Likewise.
(star_digits_closebracket): New function.

(append_char_class): No longer give diagnostic.
(append_equiv_class): No longer give diagnostic.
(build_spec_list): Give them here instead, allowing things like [:*][:upper:]
that got errors before.
Take E_string arg rather than char*.
Convert switch stmts into if-then so as to use ES_MATCH.
1995-10-20 04:26:56 +00:00
Jim Meyering
0598102472 . 1995-10-19 22:40:10 +00:00
Jim Meyering
4aba8a55f2 . 1995-10-19 22:39:16 +00:00
Jim Meyering
6f6a35a9a1 Indent cpp directives. 1995-10-19 22:38:39 +00:00
Jim Meyering
d691ea7ebc (build_spec_list): Propagate interface change.
(parse_str): Likewise.
1995-10-19 15:42:45 +00:00
Jim Meyering
ca63ca90ab (struct E_string): Define.
(unquote): Convert string to E_string instead of overwriting input.
Backslash-escaped non-special characters are marked as quoted in E_string.
(build_spec_list): Convert outer switch stmt to an if-stmt.
(parse_str): Update sole caller of unquote.
1995-10-19 15:33:33 +00:00
Jim Meyering
43dd57eba9 New version from FSF. 1995-10-19 14:21:35 +00:00
Jim Meyering
6dd358e12d Break lines longer than 79-80 chars. 1995-10-19 13:29:34 +00:00
Jim Meyering
c73aa6b629 . 1995-10-19 04:10:45 +00:00
Jim Meyering
63b348b3a9 Use HAVE_SYS_WAIT_H, not _POSIX_VERSION in conditional
inclusion of sys/wait.h.
[endgrent]: Test !HAVE_ENDGRENT rather than _POSIX_SOURCE.
[endpwent]: Test !HAVE_ENDPWENT rather than _POSIX_SOURCE.
1995-10-18 22:05:29 +00:00
Jim Meyering
6181f175e3 Use HAVE_SYS_IOCTL_H, rather than !_POSIX_SOURCE || _AIX. 1995-10-18 22:05:06 +00:00
Jim Meyering
5a52e61271 (duplicate_entry): Always return 0 if !D_INO_IN_DIRENT, rather than
if _POSIX_SOURCE
1995-10-18 17:02:07 +00:00
Jim Meyering
e74c290ac7 . 1995-10-18 16:33:52 +00:00
Jim Meyering
5ea57c875d . 1995-10-18 16:28:14 +00:00
Jim Meyering
492b177ca5 (main): Fail if the same file system type was both selected and excluded. 1995-10-18 16:11:58 +00:00
Jim Meyering
daa976fff6 [endgrent]: Test !HAVE_ENDGRENT rather than _POSIX_SOURCE. 1995-10-18 16:08:13 +00:00
Jim Meyering
871d176f15 [endpwent]: Test !HAVE_ENDPWENT rather than _POSIX_SOURCE.
[endgrent]: Remove unused definition.
1995-10-18 16:07:44 +00:00
Jim Meyering
fc2e23b1ad [HAVE_ENDGRENT]: Define away endgrent.
[HAVE_ENDPWENT]: Define away endpwent.
1995-10-18 15:59:12 +00:00
Jim Meyering
1cde2ceb5c Use _POSIX_VERSION, not _POSIX_SOURCE. 1995-10-18 15:57:50 +00:00
Jim Meyering
539457f1ae Merge latest change from FSF. 1995-10-18 14:31:14 +00:00
Jim Meyering
b6ff24fb7f Get latest from FSF. 1995-10-18 14:29:16 +00:00
Jim Meyering
da20dc044a . 1995-10-18 03:48:29 +00:00
Jim Meyering
a42c7fe2d1 Prootize. 1995-10-18 03:45:44 +00:00
Jim Meyering
b792f7aa0e Add `const' attribute to dcls of lots of formals. 1995-10-17 14:01:00 +00:00
Jim Meyering
9242af95a3 Protoize. 1995-10-17 13:49:32 +00:00
Jim Meyering
9583179c1b Protoize. 1995-10-17 13:47:48 +00:00
Jim Meyering
d9dee002e6 Reorder functions to obviate forward dcls. Remove forward dcls. 1995-10-17 13:43:00 +00:00
Jim Meyering
434b809272 Reorder functions to obviate forward dcls. Remove forward dcls. 1995-10-17 13:39:44 +00:00
Jim Meyering
4feb3b1e06 Protoize. Reorder functions to obviate forward dcls. Remove forward dcls. 1995-10-17 13:35:26 +00:00
Jim Meyering
14390d1fed Protoize. Reorder functions to obviate forward dcls.
Remove forward dcls.
1995-10-17 13:13:19 +00:00
Jim Meyering
8831ffbec4 Protoize.
Reorder functions to obviate forward dcls.
Remove forward dcls.
1995-10-16 21:30:25 +00:00
Jim Meyering
45d4def5e4 Move struct dcls to precede dcls of file-scope variables.
(monthtab, keyhead): Separate variable dcls from type dcls.
1995-10-16 14:45:09 +00:00
Jim Meyering
b9c1393e5f (usage): Move function definition to precede uses and
remove remove forward dcl.
Protoize and add `const' attribute to dcls of lots of formals.
1995-10-16 14:38:11 +00:00
Jim Meyering
c5bf4b6c9c . 1995-10-14 01:39:01 +00:00
Jim Meyering
3ac64eda17 (prjoin): Handle case in which file spec is 0.
(add_field): Update assertions.
(decode_field_spec): For S == "0", set file spec to zero and don't modify
*FIELD_INDEX.  Otherwise, *FIELD_INDEX gets the zero-based index.
1995-10-13 17:22:58 +00:00
Jim Meyering
148f37c34e Add tests to exercize -o 0. 1995-10-13 17:16:48 +00:00
Jim Meyering
9845d179b3 (prjoin): Rewrite loop that iterates over field specs. 1995-10-13 13:16:34 +00:00
Jim Meyering
11b87d29cc (add_field_list): Allow SPACE and TAB as well as `,' as list item separators. 1995-10-12 21:42:52 +00:00
Jim Meyering
bc7210e563 Remove bogus FIXME. 1995-10-12 04:08:35 +00:00
Jim Meyering
e1ab53f969 . 1995-10-09 13:59:55 +00:00
Jim Meyering
790196a645 . 1995-10-09 13:59:25 +00:00
Jim Meyering
b5c8c81d4d Indent cpp directives to reflect nesting. 1995-10-09 03:48:08 +00:00
Jim Meyering
91a709b210 Modified from glibc copy. 1995-10-09 03:46:41 +00:00
Jim Meyering
5e25ee19e4 (SOURCES): Add strpbrk.c..
Remove bcopy.c.
1995-10-09 03:42:21 +00:00
Jim Meyering
70390f60ec . 1995-10-09 03:42:11 +00:00
Jim Meyering
c22889019c . 1995-10-08 04:02:09 +00:00
Jim Meyering
06ea91f2f3 (main): Close input files. 1995-10-08 04:02:00 +00:00
Jim Meyering
3c7699600f Add alloca junk. 1995-10-08 03:38:09 +00:00
Jim Meyering
c8c90bb532 . 1995-10-08 03:30:22 +00:00
Jim Meyering
6f63d53e1b (add_field): No longer return a value.
(decode_field_spec): New function.
(add_field_list): Rewrite to be more strict about what is accepted.
Before, `,1.2' was accepted as valid.
(main): Use xstrtol instead atoi.
Combine nearly identical -a and -v cases.
1995-10-08 03:28:21 +00:00
Jim Meyering
cd1dbbcfc1 . 1995-10-06 19:23:31 +00:00
Jim Meyering
4bbadbb14a . 1995-10-06 02:55:44 +00:00
Jim Meyering
cc61df7131 Include limits.h.
[!INT_MAX]: Define it.
1995-10-06 02:55:14 +00:00
Jim Meyering
965c0bf39d [!HAVE_UTIME_H]: Don't declare struct utimbuf here.
[!HAVE_STRUCT_UTIMBUF]: Declare struct utimbuf here instead.
1995-10-06 02:53:42 +00:00
Jim Meyering
6fc3c211ec . 1995-10-06 02:51:04 +00:00
Jim Meyering
c25dcdd843 (read_filesystem_list): Cast -1 to dev_t before assignment. 1995-10-05 14:14:45 +00:00
Jim Meyering
e387fd1471 (show_point): Cast -2 to dev_t before assignment. 1995-10-05 14:12:29 +00:00
Jim Meyering
1c7bc6028a protoize 1995-10-04 21:21:23 +00:00
Jim Meyering
74f061de82 Remove forward dcl of usage. 1995-10-04 21:20:40 +00:00
Jim Meyering
47b91b8948 (usage): Move to precede all other functions. 1995-10-04 21:19:28 +00:00
Jim Meyering
2d73c959cc (main): Report `too few/many non-option arguments' then print --help
output rather than just the latter.
Properly interpret obsolescent usage like `join -o 2.1 2.1 2.2'.
(usage): Describe POSIX -1, -2 options and deprecate -j* ones
1995-10-04 21:17:43 +00:00
Jim Meyering
9a17340b10 . 1995-10-04 03:46:43 +00:00
Jim Meyering
a9de4d485a Test SA_INTERRUPT, not _POSIX_VERSION,
to determine whether `sigaction' functions are available.
Reported by Paul Nevai <nevai@ops.mps.ohio-state.edu>.
Fix suggested by Karl Berry.
1995-10-04 03:46:35 +00:00
Jim Meyering
111cb717e8 (set_fields): Use memset (not open coded loop) to initialize array. 1995-10-03 20:28:44 +00:00
Jim Meyering
6a45f61547 Convert a lot of int' types to unsigned int' to avoid warnings from
`gcc -Wall' about comparing signed and unsigned types.
1995-10-03 20:21:32 +00:00
Jim Meyering
026d10d369 (main): Declare counter, N_STRINGS, to be an integral type, not `char'. 1995-10-03 20:18:39 +00:00
Jim Meyering
d832bf77eb Correct typos, mostly from Jens Schweikhardt. 1995-10-03 19:05:47 +00:00
Jim Meyering
de97a7099c .c 1995-10-01 22:50:25 +00:00
Jim Meyering
1d15980fb6 Remove trailing whitespace. 1995-10-01 22:49:07 +00:00
Jim Meyering
b3303ba072 Declare stat, xstat. 1995-10-01 22:40:11 +00:00
Jim Meyering
eddb25aa26 Declare stat, xstat. 1995-10-01 20:17:25 +00:00
Jim Meyering
40c6966137 (SOURCES): Add strtoul. 1995-10-01 19:02:29 +00:00
Jim Meyering
4de6eab547 (get_fs_usage) [STATFS_TRUNCATES_BLOCK_COUNTS]: Copy untruncated block
counts from f_spare array into proper members of struct statfs.
From Eirik Fuller (eirik@netapp.com);
1995-10-01 18:23:29 +00:00
Jim Meyering
caa2df2274 . 1995-09-29 04:50:31 +00:00
Jim Meyering
4c8c0b69ba . 1995-09-29 04:49:08 +00:00
Jim Meyering
527d04d44b (dired_dump_obstack): Don't generate any output if the obstack is empty.
(main): Always initialize and dump subdired_obstack, not just if -R.
`ls -lDR dir dir2' was using uninitialized subdired_obstack.
Reported by Samuli K{rkk{inen <hskarkka@snakemail.hut.fi>.
1995-09-29 04:09:22 +00:00
Jim Meyering
9a12d05216 (decode_one_format): Remove spurious semicolon. 1995-09-27 15:58:18 +00:00
Jim Meyering
77c46a6b42 . 1995-09-27 04:06:28 +00:00
Jim Meyering
744393f0f4 (show_point): Ignore mtab entries with either
nonexistent mount points or with inconsistent device number.
From Eirik Fuller <eirik@synopsys.com>.
1995-09-26 04:18:55 +00:00
Jim Meyering
6f200d7982 . 1995-09-25 04:14:36 +00:00
Jim Meyering
12e85d31e2 Protoize. 1995-09-24 13:36:13 +00:00
Jim Meyering
17821cc15e [REL_ALLOC]: #ifdef-out dcls of unused variables. 1995-09-23 20:55:02 +00:00
Jim Meyering
0bcd6e68a9 . 1995-09-23 20:46:22 +00:00
Jim Meyering
528390fa58 (print_kth): Change order of args in compare, and reverse sense of comparison
(Hence, no semantic change).
1995-09-23 20:42:52 +00:00
Jim Meyering
a719a87508 Merge in changes for ConvexOS 11.0. 1995-09-23 20:28:39 +00:00
Jim Meyering
a1fa4eff25 New version from FSF. 1995-09-23 20:28:10 +00:00
Jim Meyering
f344b7fab6 (md5_check): Distinguish between open/read failure and checksum mismatch. 1995-09-23 20:22:05 +00:00
Jim Meyering
eca98f76ac . 1995-09-23 20:21:22 +00:00
Jim Meyering
f30618bac7 . 1995-09-23 20:09:52 +00:00
Jim Meyering
dc4a18b537 . 1995-09-23 19:56:32 +00:00
Jim Meyering
9801e9cde1 Update to reflect changes in md5sum.c.
Add FIXME with Karl's comm suggestion.
1995-09-21 18:17:14 +00:00
Jim Meyering
1b16c152bd (main): Reverse order of check' and compute sums' blocks in if-else
chain to make it a little more readable.
1995-09-20 12:47:37 +00:00
Jim Meyering
3ed71a2fdd . 1995-09-19 14:30:59 +00:00
Jim Meyering
0e15d57a89 Rewrite confusing comment. 1995-09-19 12:59:49 +00:00
Jim Meyering
c253d247ca (checkfp): Rearrange loop to avoid duplicate test.
Move a couple dcls from function scope into inner block.
1995-09-19 12:50:34 +00:00
Jim Meyering
656fac3d80 . 1995-09-19 12:48:46 +00:00
Jim Meyering
dde2c138e9 Protoize. 1995-09-18 12:44:47 +00:00
Jim Meyering
7823351d6b (main, usage): Remove -h, -s, -v short options.
Rename --verbose to --warn, --quiet to --status.
(main): Handle --help and --version using parse_long_options.
(md5_check): Check ferror.
1995-09-18 12:36:12 +00:00
Jim Meyering
b23b6bbcf7 (tempname): Replace `16' with a more readable expansion.
Make sure that SEQ never exceeds 99999.
1995-09-14 13:31:52 +00:00
Jim Meyering
800e219a2d (sort): Rename local: ntemp -> n_temp_files, to avoid confusion
with another local, ntmp.
1995-09-14 13:09:27 +00:00
Jim Meyering
ecf0d31b72 Fix typo in comment. 1995-09-13 13:15:35 +00:00
Jim Meyering
c3f476d467 . 1995-08-11 06:26:39 +00:00
Jim Meyering
7f3e86b27b . 1995-08-11 06:26:12 +00:00
Jim Meyering
b0453a43c0 (main) [handling --string option]: Don't output nonstandard `b' binary flag. 1995-08-10 21:11:24 +00:00
61 changed files with 5134 additions and 4682 deletions

View File

@@ -12,8 +12,8 @@
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
# along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
SHELL = /bin/sh
@@ -73,6 +73,7 @@ texclean:
*.fl *.cm *.op *.cps
mostlyclean: texclean
rm -f *.info
clean: mostlyclean

View File

@@ -2320,6 +2320,15 @@ current time and date. @var{datestr} can be in almost any common
format. It can contain month names, timezones, @samp{am} and @samp{pm},
@samp{yesterday}, @samp{ago}, @samp{next}, etc. @xref{Date input formats}.
@item -r @var{file}
@itemx --reference=@var{file}
@opindex -r
@opindex --reference
Display the time and date as obtained from a reference @var{file},
instead of the current time and date. Each file has a few timestamps
associated with it. In this context, the time and date of the last
modification are used.
@item -f @var{datefile}
@itemx --file=@var{datefile}
@opindex -f

View File

@@ -1054,7 +1054,7 @@ head [@var{option}]@dots{} [@var{file}]@dots{}
head -@var{number} [@var{option}]@dots{} [@var{file}]@dots{}
@end example
If more than one @var{file} is specicified, @code{head} prints a
If more than one @var{file} is specified, @code{head} prints a
one-line header consisting of
@example
==> @var{file name} <==
@@ -1312,7 +1312,7 @@ file, so that section of the input file is effectively ignored.
Repeat the previous pattern @var{repeat-count} additional
times. @var{repeat-count} can either be a positive integer or an
asterisk, meaning repeat as many times as necessary until the input is
exausted.
exhausted.
@end table
@@ -1603,10 +1603,23 @@ For each such line, @code{md5sum} reads the named file and computes its
MD5 checksum. Then, if the computed message digest does not match the
one on the line with the filename, the file is noted as having
failed the test. Otherwise, the file passes the test.
By default, for each valid line, one line is written to standard
output indicating whether the named file passed the test.
Use the @samp{--status} option to inhibit that output.
If any listed file cannot be opened or read, if any valid line has
a MD5 checksum inconsistent with the associated file, or if no valid
line is found, exit with a non-zero status. Otherwise, exit successfully.
@itemx --status
@opindex --status
@cindex verifying MD5 checksums
When verifying checksums, don't generate any output.
If all listed files are readable and are consistent with the associated
MD5 checksums, exit successfully. Otherwise exit with a status code
indicating there was a failure. Failures to open or read a file still
evoke diagnostics to standard error.
@item -s
@itemx --string=@var{string}
@opindex -s
@opindex --string
Compute the message digest for @var{string}, instead of for a file. The
result is the same as for a file that contains exactly @var{string}.
@@ -1619,11 +1632,14 @@ result is the same as for a file that contains exactly @var{string}.
Treat all input files as text files. This is the reverse of
@samp{--binary}.
@item -v
@itemx --verbose
@opindex -v
@opindex --verbose
Print progress information.
@item -w
@itemx --warn
@opindex -w
@opindex --warn
@cindex verifying MD5 checksums
When verifying checksums, warn about improperly formated MD5 checksum lines.
This option is useful only if all but a few lines in the checked input
are valid.
@end table
@@ -2021,6 +2037,9 @@ The input files must be sorted before @code{comm} can be used.
With no options, @code{comm} produces three column output. Column one
contains lines unique to @var{file1}, column two contains lines unique
to @var{file2}, and column three contains lines common to both files.
Columns are separated by @key{TAB}.
@c FIXME: when there's an option to supply an alternative separator
@c string, append `by default' to the above sentence.
@opindex -1
@opindex -2
@@ -2095,7 +2114,7 @@ For @samp{-f}, fields are separated by the first character in @var{delim}
@item -n
@opindex -n
Do not split multibyte characters (no-op for now).
Do not split multi-byte characters (no-op for now).
@item -s
@itemx --only-delimited
@@ -2207,6 +2226,8 @@ Each element in @var{field-list} consists of a file number (either 1 or
the list are separated by commas or blanks. Multiple @var{field-list}
arguments can be given after a single @samp{-o} option; the values
of all lists given with @samp{-o} are concatenated together.
All output lines -- including those printed because of any -a or -v
option -- are subject to the specified @var{field-list}.
@item -t @var{char}
Use character @var{char} as the input and output field separator.
@@ -3199,7 +3220,7 @@ much more efficient and do more than these programs do. Nevertheless, as
exposition of good programming style, and evangelism for a still-valuable
philosophy, these books are unparalleled, and I recommend them highly.
Acknowledgement: I would like to express my gratitude to Brian Kernighan
Acknowledgment: I would like to express my gratitude to Brian Kernighan
of Bell Labs, the original Software Toolsmith, for reviewing this column.

View File

@@ -5,3 +5,4 @@ safe-stat.h
safe-stat.c
safe-lstat.c
safe-lstat.h
getdate.tab.c

View File

@@ -38,7 +38,7 @@ modechange.c mountlist.c obstack.c safe-read.c savedir.c \
stripslash.c xgetcwd.c xmalloc.c xstrdup.c userspec.c yesno.c \
fileblocks.c fnmatch.c ftruncate.c mkdir.c mktime.c rename.c rmdir.c \
save-cwd.c stpcpy.c \
strdup.c strstr.c strtol.c alloca.c long-options.c \
strdup.c strstr.c strtol.c strtoul.c alloca.c long-options.c \
memcmp.c memcpy.c memset.c xstrtol.c xstrtoul.c
OBJECTS = getdate.o posixtm.o \
@@ -58,8 +58,10 @@ all: libfu.a
.SUFFIXES:
.SUFFIXES: .c .o
COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)
INCLUDES = -I.. -I$(srcdir)
.c.o:
$(CC) -c $(CPPFLAGS) $(DEFS) -I.. -I$(srcdir) $(CFLAGS) $<
$(COMPILE) $<
subdir = lib
Makefile: ../config.status Makefile.in
@@ -83,6 +85,7 @@ mostlyclean: clean
distclean: clean
rm -f Makefile *.tab.c tposixtm.c
rm -rf .deps
maintainer-clean: distclean
rm -f TAGS getdate.c posixtm.c
@@ -140,3 +143,8 @@ installdirs maintainer-clean mostlyclean uninstall
# Tell versions [3.59,3.63) of GNU make not to export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:
# The following include directive is uncommented automatically
# when this package is configured with the --with-autodep option.
# You need GNU make and a C compiler that can generate dependencies.
@AUTODEP_COMMENT@include @top_srcdir@/mkdep-Makefile

View File

@@ -56,7 +56,7 @@ void (*error_print_progname) () = NULL;
extern char *program_name;
#if HAVE_STRERROR
# ifndef strerror /* On some systems, sterror is a macro */
# ifndef strerror /* On some systems, strerror is a macro */
char *strerror ();
# endif
#else

View File

@@ -1,21 +1,25 @@
/* euidaccess -- check if effective user id can access file
Copyright (C) 1990, 1991 Free Software Foundation, Inc.
Copyright (C) 1990, 1991, 1995 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This file is part of the GNU C Library.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
/* Written by David MacKenzie and Torbjorn Granlund. */
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
Cambridge, MA 02139, USA. */
/* Written by David MacKenzie and Torbjorn Granlund.
Adapted for GNU C library by Roland McGrath. */
#ifdef HAVE_CONFIG_H
#include <config.h>
@@ -36,7 +40,7 @@
#endif
#endif /* S_IEXEC */
#ifdef HAVE_UNISTD_H
#if defined (HAVE_UNISTD_H) || defined (_LIBC)
#include <unistd.h>
#endif
@@ -74,6 +78,13 @@ extern int errno;
#define R_OK 4
#endif
#ifdef _LIBC
#define group_member __group_member
#else
/* The user's real user id. */
static uid_t uid;
@@ -86,67 +97,17 @@ static uid_t euid;
/* The user's effective group id. */
static gid_t egid;
int group_member ();
/* Nonzero if UID, GID, EUID, and EGID have valid values. */
static int have_ids = 0;
/* Like euidaccess, except that a pointer to a filled-in stat structure
describing the file is provided instead of a filename.
Because this function is almost guaranteed to fail on systems that
use ACLs, a third argument *PATH may be used. If it is non-NULL,
it is assumed to be the name of the file corresponding to STATP.
Then, if the user is not running set-uid or set-gid, use access
instead of attempting a manual and non-portable comparison. */
int
eaccess_stat (statp, mode, path)
const struct stat *statp;
int mode;
const char *path;
{
int granted;
mode &= (X_OK | W_OK | R_OK); /* Clear any bogus bits. */
if (mode == F_OK)
return 0; /* The file exists. */
if (have_ids == 0)
{
have_ids = 1;
uid = getuid ();
gid = getgid ();
euid = geteuid ();
egid = getegid ();
}
if (path && uid == euid && gid == egid)
{
return access (path, mode);
}
/* The super-user can read and write any file, and execute any file
that anyone can execute. */
if (euid == 0 && ((mode & X_OK) == 0
|| (statp->st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))))
return 0;
if (euid == statp->st_uid)
granted = (unsigned) (statp->st_mode & (mode << 6)) >> 6;
else if (egid == statp->st_gid
#ifdef HAVE_GETGROUPS
|| group_member (statp->st_gid)
int group_member ();
#else
#define group_member(gid) 0
#endif
)
granted = (unsigned) (statp->st_mode & (mode << 3)) >> 3;
else
granted = (statp->st_mode & mode);
if (granted == mode)
return 0;
errno = EACCESS;
return -1;
}
#endif
/* Return 0 if the user has permission of type MODE on file PATH;
otherwise, return -1 and set `errno' to EACCESS.
@@ -160,7 +121,12 @@ euidaccess (path, mode)
int mode;
{
struct stat stats;
int granted;
#ifdef _LIBC
uid_t uid = getuid (), euid = geteuid ();
gid_t gid = getgid (), egid = getegid ();
#else
if (have_ids == 0)
{
have_ids = 1;
@@ -169,45 +135,37 @@ euidaccess (path, mode)
euid = geteuid ();
egid = getegid ();
}
#endif
if (uid == euid && gid == egid)
{
return access (path, mode);
}
/* If we are not set-uid or set-gid, access does the same. */
return access (path, mode);
if (stat (path, &stats))
return -1;
return eaccess_stat (&stats, mode, path);
}
#ifdef TEST
#include <stdio.h>
#include <errno.h>
void error ();
char *program_name;
int
main (argc, argv)
int argc;
char **argv;
{
char *file;
int mode;
int err;
program_name = argv[0];
if (argc < 3)
abort ();
file = argv[1];
mode = atoi (argv[2]);
err = euidaccess (file, mode);
printf ("%d\n", err);
if (err != 0)
error (0, errno, "%s", file);
exit (0);
}
mode &= (X_OK | W_OK | R_OK); /* Clear any bogus bits. */
#if R_OK != S_IROTH || W_OK != S_IWOTH || X_OK != S_IXOTH
?error Oops, portability assumptions incorrect.
#endif
if (mode == F_OK)
return 0; /* The file exists. */
/* The super-user can read and write any file, and execute any file
that anyone can execute. */
if (euid == 0 && ((mode & X_OK) == 0
|| (stats.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))))
return 0;
if (euid == stats.st_uid)
granted = (unsigned) (stats.st_mode & (mode << 6)) >> 6;
else if (egid == stats.st_gid || group_member (stats.st_gid))
granted = (unsigned) (stats.st_mode & (mode << 3)) >> 3;
else
granted = (stats.st_mode & mode);
if (granted == mode)
return 0;
errno = EACCESS;
return -1;
}

View File

@@ -21,7 +21,7 @@
#include <config.h>
#endif
#if !defined (HAVE_ST_BLOCKS) && !defined(_POSIX_SOURCE)
#if !defined (HAVE_ST_BLOCKS) && !defined(_POSIX_VERSION)
#include <sys/types.h>
#include <sys/param.h>

View File

@@ -73,7 +73,7 @@ adjust_blocks (blocks, fromsize, tosize)
abort ();
if (fromsize <= 0)
return -1;
if (fromsize == tosize) /* E.g., from 512 to 512. */
return blocks;
else if (fromsize > tosize) /* E.g., from 2048 to 512. */
@@ -144,6 +144,21 @@ get_fs_usage (path, disk, fsp)
if (statfs (path, &fsd) < 0)
return -1;
#ifdef STATFS_TRUNCATES_BLOCK_COUNTS
/* In SunOS 4.1.2, 4.1.3, and 4.1.3_U1, the block counts in the
struct statfs are truncated to 2GB. These conditions detect that
truncation, presumably without botching the 4.1.1 case, in which
the values are not truncated. The correct counts are stored in
undocumented spare fields. */
if (fsd.f_blocks == 0x1fffff && fsd.f_spare[0] > 0)
{
fsd.f_blocks = fsd.f_spare[0];
fsd.f_bfree = fsd.f_spare[1];
fsd.f_bavail = fsd.f_spare[2];
}
#endif /* STATFS_TRUNCATES_BLOCK_COUNTS */
#define CONVERT_BLOCKS(b) adjust_blocks ((b), fsd.f_bsize, 512)
#endif

126
lib/getline.c Normal file
View File

@@ -0,0 +1,126 @@
/* getline.c -- Replacement for GNU C library function getline
Copyright (C) 1993 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Written by Jan Brittenson, bson@gnu.ai.mit.edu. */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <sys/types.h>
#include <stdio.h>
#define NDEBUG
#include <assert.h>
#if STDC_HEADERS
#include <stdlib.h>
#else
char *malloc (), *realloc ();
#endif
/* Always add at least this many bytes when extending the buffer. */
#define MIN_CHUNK 64
/* Read up to (and including) a TERMINATOR from STREAM into *LINEPTR
+ OFFSET (and null-terminate it). *LINEPTR is a pointer returned from
malloc (or NULL), pointing to *N characters of space. It is realloc'd
as necessary. Return the number of characters read (not including the
null terminator), or -1 on error or EOF. */
int
getstr (lineptr, n, stream, terminator, offset)
char **lineptr;
size_t *n;
FILE *stream;
char terminator;
int offset;
{
int nchars_avail; /* Allocated but unused chars in *LINEPTR. */
char *read_pos; /* Where we're reading into *LINEPTR. */
int ret;
if (!lineptr || !n || !stream)
return -1;
if (!*lineptr)
{
*n = MIN_CHUNK;
*lineptr = malloc (*n);
if (!*lineptr)
return -1;
}
nchars_avail = *n - offset;
read_pos = *lineptr + offset;
for (;;)
{
register int c = getc (stream);
/* We always want at least one char left in the buffer, since we
always (unless we get an error while reading the first char)
NUL-terminate the line buffer. */
assert(*n - nchars_avail == read_pos - *lineptr);
if (nchars_avail < 2)
{
if (*n > MIN_CHUNK)
*n *= 2;
else
*n += MIN_CHUNK;
nchars_avail = *n + *lineptr - read_pos;
*lineptr = realloc (*lineptr, *n);
if (!*lineptr)
return -1;
read_pos = *n - nchars_avail + *lineptr;
assert(*n - nchars_avail == read_pos - *lineptr);
}
if (c == EOF || ferror (stream))
{
/* Return partial line, if any. */
if (read_pos == *lineptr)
return -1;
else
break;
}
*read_pos++ = c;
nchars_avail--;
if (c == terminator)
/* Return the line. */
break;
}
/* Done - NUL terminate and return the number of chars read. */
*read_pos = '\0';
ret = read_pos - (*lineptr + offset);
return ret;
}
int
getline (lineptr, n, stream)
char **lineptr;
size_t *n;
FILE *stream;
{
return getstr (lineptr, n, stream, '\n', 0);
}

17
lib/getline.h Normal file
View File

@@ -0,0 +1,17 @@
#ifndef _getline_h_
#define _getline_h_ 1
#include <stdio.h>
#ifndef __P
#if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
#define __P(args) args
#else
#define __P(args) ()
#endif /* GCC. */
#endif /* Not __P. */
int
getline __P ((char **_lineptr, size_t *_n, FILE *_stream));
#endif /* _getline_h_ */

View File

@@ -59,12 +59,15 @@
#include <stdlib.h>
#endif /* GNU C library. */
#ifndef _
/* This is for other GNU distributions with internationalized messages.
The GNU C Library itself does not yet support such messages. */
#if HAVE_LIBINTL_H
When compiling libc, the _ macro is predefined. */
#ifdef HAVE_LIBINTL_H
# include <libintl.h>
# define _(msgid) gettext (msgid)
#else
# define gettext(msgid) (msgid)
# define _(msgid) (msgid)
#endif
#endif
/* This version of `getopt' appears to the caller like standard Unix `getopt'
@@ -521,7 +524,7 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only)
if (ambig && !exact)
{
if (opterr)
fprintf (stderr, gettext ("%s: option `%s' is ambiguous\n"),
fprintf (stderr, _("%s: option `%s' is ambiguous\n"),
argv[0], argv[optind]);
nextchar += strlen (nextchar);
optind++;
@@ -544,12 +547,12 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only)
if (argv[optind - 1][1] == '-')
/* --option */
fprintf (stderr,
gettext ("%s: option `--%s' doesn't allow an argument\n"),
_("%s: option `--%s' doesn't allow an argument\n"),
argv[0], pfound->name);
else
/* +option or -option */
fprintf (stderr,
gettext ("%s: option `%c%s' doesn't allow an argument\n"),
_("%s: option `%c%s' doesn't allow an argument\n"),
argv[0], argv[optind - 1][0], pfound->name);
nextchar += strlen (nextchar);
@@ -564,7 +567,7 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only)
{
if (opterr)
fprintf (stderr,
gettext ("%s: option `%s' requires an argument\n"),
_("%s: option `%s' requires an argument\n"),
argv[0], argv[optind - 1]);
nextchar += strlen (nextchar);
return optstring[0] == ':' ? ':' : '?';
@@ -592,11 +595,11 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only)
{
if (argv[optind][1] == '-')
/* --option */
fprintf (stderr, gettext ("%s: unrecognized option `--%s'\n"),
fprintf (stderr, _("%s: unrecognized option `--%s'\n"),
argv[0], nextchar);
else
/* +option or -option */
fprintf (stderr, gettext ("%s: unrecognized option `%c%s'\n"),
fprintf (stderr, _("%s: unrecognized option `%c%s'\n"),
argv[0], argv[optind][0], nextchar);
}
nextchar = (char *) "";
@@ -621,10 +624,10 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only)
{
if (posixly_correct)
/* 1003.2 specifies the format of this message. */
fprintf (stderr, gettext ("%s: illegal option -- %c\n"),
fprintf (stderr, _("%s: illegal option -- %c\n"),
argv[0], c);
else
fprintf (stderr, gettext ("%s: invalid option -- %c\n"),
fprintf (stderr, _("%s: invalid option -- %c\n"),
argv[0], c);
}
optopt = c;
@@ -660,7 +663,7 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only)
{
/* 1003.2 specifies the format of this message. */
fprintf (stderr,
gettext ("%s: option requires an argument -- %c\n"),
_("%s: option requires an argument -- %c\n"),
argv[0], c);
}
optopt = c;

View File

@@ -1,45 +1,54 @@
/* Copyright (C) 1993, 1994 Free Software Foundation, Inc.
Contributed by Noel Cragg (noel@cs.oberlin.edu), with fixes by
Michael E. Calwas (calwas@ttd.teradyne.com) and
Wade Hampton (tasi029@tmn.com).
/* Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc.
Contributed by Paul Eggert (eggert@twinsun.com).
This file is part of the GNU C Library.
NOTE: The canonical source of this file is maintained with the GNU C Library.
Bugs can be reported to bug-glibc@prep.ai.mit.edu.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
This program is distributed in the hope that it will be useful,
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
Cambridge, MA 02139, USA. */
/* Define this to have a standalone program to test this implementation of
mktime. */
/* #define DEBUG */
/* #define DEBUG 1 */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
/* Assume that leap seconds are possible, unless told otherwise.
If the host has a `zic' command with a `-L leapsecondfilename' option,
then it supports leap seconds; otherwise it probably doesn't. */
#ifndef LEAP_SECONDS_POSSIBLE
#define LEAP_SECONDS_POSSIBLE 1
#endif
#include <sys/types.h> /* Some systems define `time_t' here. */
#include <time.h>
#ifndef __isleap
/* Nonzero if YEAR is a leap year (every 4 years,
except every 100th isn't, and every 400th is). */
#define __isleap(year) \
((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
#if __STDC__ || __GNU_LIBRARY__ || STDC_HEADERS
#include <limits.h>
#endif
#if DEBUG
#include <stdio.h>
#if __STDC__ || __GNU_LIBRARY__ || STDC_HEADERS
#include <stdlib.h>
#endif
/* Make it work even if the system's libc has its own mktime routine. */
#define mktime my_mktime
#endif /* DEBUG */
#ifndef __P
#if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
#define __P(args) args
@@ -48,456 +57,352 @@ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#endif /* GCC. */
#endif /* Not __P. */
/* How many days are in each month. */
const unsigned short int __mon_lengths[2][12] =
#ifndef CHAR_BIT
#define CHAR_BIT 8
#endif
#ifndef INT_MIN
#define INT_MIN (~0 << (sizeof (int) * CHAR_BIT - 1))
#endif
#ifndef INT_MAX
#define INT_MAX (~0 - INT_MIN)
#endif
#ifndef TIME_T_MIN
#define TIME_T_MIN (0 < (time_t) -1 ? (time_t) 0 \
: ~ (time_t) 0 << (sizeof (time_t) * CHAR_BIT - 1))
#endif
#ifndef TIME_T_MAX
#define TIME_T_MAX (~ (time_t) 0 - TIME_T_MIN)
#endif
#define TM_YEAR_BASE 1900
#define EPOCH_YEAR 1970
#ifndef __isleap
/* Nonzero if YEAR is a leap year (every 4 years,
except every 100th isn't, and every 400th is). */
#define __isleap(year) \
((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
#endif
/* How many days come before each month (0-12). */
const unsigned short int __mon_yday[2][13] =
{
/* Normal years. */
{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
/* Leap years. */
{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
{ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
};
static int times_through_search; /* This library routine should never
hang -- make sure we always return
when we're searching for a value */
static time_t ydhms_tm_diff __P ((int, int, int, int, int, const struct tm *));
time_t __mktime_internal __P ((struct tm *,
struct tm *(*) (const time_t *, struct tm *),
time_t *));
#ifdef DEBUG
#include <stdio.h>
#include <ctype.h>
int debugging_enabled = 0;
/* Print the values in a `struct tm'. */
static void
printtm (it)
struct tm *it;
{
printf ("%02d/%02d/%04d %02d:%02d:%02d (%s) yday:%03d dst:%d gmtoffset:%ld",
it->tm_mon + 1,
it->tm_mday,
it->tm_year + 1900,
it->tm_hour,
it->tm_min,
it->tm_sec,
it->tm_zone,
it->tm_yday,
it->tm_isdst,
it->tm_gmtoff);
}
#endif
static time_t
dist_tm (t1, t2)
struct tm *t1;
struct tm *t2;
{
time_t distance = 0;
unsigned long int v1, v2;
int diff_flag = 0;
v1 = v2 = 0;
#define doit(x, secs) \
v1 += t1->x * secs; \
v2 += t2->x * secs; \
if (!diff_flag) \
{ \
if (t1->x < t2->x) \
diff_flag = -1; \
else if (t1->x > t2->x) \
diff_flag = 1; \
}
doit (tm_year, 31536000); /* Okay, not all years have 365 days. */
doit (tm_mon, 2592000); /* Okay, not all months have 30 days. */
doit (tm_mday, 86400);
doit (tm_hour, 3600);
doit (tm_min, 60);
doit (tm_sec, 1);
#undef doit
/* We should also make sure that the sign of DISTANCE is correct -- if
DIFF_FLAG is positive, the distance should be positive and vice versa. */
distance = (v1 > v2) ? (v1 - v2) : (v2 - v1);
if (diff_flag < 0)
distance = -distance;
if (times_through_search > 20) /* Arbitrary # of calls, but makes sure we
never hang if there's a problem with
this algorithm. */
{
distance = diff_flag;
}
/* We need this DIFF_FLAG business because it is forseeable that the
distance may be zero when, in actuality, the two structures are
different. This is usually the case when the dates are 366 days apart
and one of the years is a leap year. */
if (distance == 0 && diff_flag)
distance = 86400 * diff_flag;
return distance;
}
/* MKTIME converts the values in a struct tm to a time_t. The values
in tm_wday and tm_yday are ignored; other values can be put outside
of legal ranges since they will be normalized. This routine takes
care of that normalization. */
void
do_normalization (tmptr)
struct tm *tmptr;
{
#define normalize(foo,x,y,bar); \
while (tmptr->foo < x) \
{ \
tmptr->bar--; \
tmptr->foo = (y - (x - tmptr->foo) + 1); \
} \
while (tmptr->foo > y) \
{ \
tmptr->foo = (x + (tmptr->foo - y) - 1); \
tmptr->bar++; \
}
normalize (tm_sec, 0, 59, tm_min);
normalize (tm_min, 0, 59, tm_hour);
normalize (tm_hour, 0, 23, tm_mday);
/* Do the month first, so day range can be found. */
normalize (tm_mon, 0, 11, tm_year);
/* Since the day range modifies the month, we should be careful how
we reference the array of month lengths -- it is possible that
the month will go negative, hence the modulo...
Also, tm_year is the year - 1900, so we have to 1900 to have it
work correctly. */
normalize (tm_mday, 1,
__mon_lengths[__isleap (tmptr->tm_year + 1900)]
[((tmptr->tm_mon < 0)
? (12 + (tmptr->tm_mon % 12))
: (tmptr->tm_mon % 12)) ],
tm_mon);
/* Do the month again, because the day may have pushed it out of range. */
normalize (tm_mon, 0, 11, tm_year);
/* Do the day again, because the month may have changed the range. */
normalize (tm_mday, 1,
__mon_lengths[__isleap (tmptr->tm_year + 1900)]
[((tmptr->tm_mon < 0)
? (12 + (tmptr->tm_mon % 12))
: (tmptr->tm_mon % 12)) ],
tm_mon);
#ifdef DEBUG
if (debugging_enabled)
{
printf (" After normalizing:\n ");
printtm (tmptr);
putchar ('\n');
}
#endif
}
/* Here's where the work gets done. */
#define BAD_STRUCT_TM ((time_t) -1)
time_t
_mktime_internal (timeptr, producer)
struct tm *timeptr;
struct tm *(*producer) __P ((const time_t *));
{
struct tm our_tm; /* our working space */
struct tm *me = &our_tm; /* a pointer to the above */
time_t result; /* the value we return */
*me = *timeptr; /* copy the struct tm that was passed
in by the caller */
/***************************/
/* Normalize the structure */
/***************************/
/* This routine assumes that the value of TM_ISDST is -1, 0, or 1.
If the user didn't pass it in that way, fix it. */
if (me->tm_isdst > 0)
me->tm_isdst = 1;
else if (me->tm_isdst < 0)
me->tm_isdst = -1;
do_normalization (me);
/* Get out of here if it's not possible to represent this struct.
If any of the values in the normalized struct tm are negative,
our algorithms won't work. Luckily, we only need to check the
year at this point; normalization guarantees that all values will
be in correct ranges EXCEPT the year. */
if (me->tm_year < 0)
return BAD_STRUCT_TM;
/*************************************************/
/* Find the appropriate time_t for the structure */
/*************************************************/
/* Modified b-search -- make intelligent guesses as to where the
time might lie along the timeline, assuming that our target time
lies a linear distance (w/o considering time jumps of a
particular region).
Assume that time does not fluctuate at all along the timeline --
e.g., assume that a day will always take 86400 seconds, etc. --
and come up with a hypothetical value for the time_t
representation of the struct tm TARGET, in relation to the guess
variable -- it should be pretty close!
After testing this, the maximum number of iterations that I had
on any number that I tried was 3! Not bad.
The reason this is not a subroutine is that we will modify some
fields in the struct tm (yday and mday). I've never felt good
about side-effects when writing structured code... */
{
struct tm *guess_tm;
time_t guess = 0;
time_t distance = 0;
time_t last_distance = 0;
times_through_search = 0;
do
{
guess += distance;
times_through_search++;
guess_tm = (*producer) (&guess);
#ifdef DEBUG
if (debugging_enabled)
{
printf (" Guessing time_t == %d\n ", (int) guess);
printtm (guess_tm);
putchar ('\n');
}
#endif
/* How far is our guess from the desired struct tm? */
distance = dist_tm (me, guess_tm);
/* Handle periods of time where a period of time is skipped.
For example, 2:15 3 April 1994 does not exist, because DST
is in effect. The distance function will alternately
return values of 3600 and -3600, because it doesn't know
that the requested time doesn't exist. In these situations
(even if the skip is not exactly an hour) the distances
returned will be the same, but alternating in sign. We
want the later time, so check to see that the distance is
oscillating and we've chosen the correct of the two
possibilities.
Useful: 3 Apr 94 765356300, 30 Oct 94 783496000 */
if ((distance == -last_distance) && (distance < last_distance))
{
/* If the caller specified that the DST flag was off, it's
not possible to represent this time. */
if (me->tm_isdst == 0)
{
#ifdef DEBUG
printf (" Distance is oscillating -- dst flag nixes struct!\n");
#endif
return BAD_STRUCT_TM;
}
#ifdef DEBUG
printf (" Distance is oscillating -- chose the later time.\n");
#endif
distance = 0;
}
if ((distance == 0) && (me->tm_isdst != -1)
&& (me->tm_isdst != guess_tm->tm_isdst))
{
/* If we're in this code, we've got the right time but the
wrong daylight savings flag. We need to move away from
the time that we have and approach the other time from
the other direction. That is, if I've requested the
non-DST version of a time and I get the DST version
instead, I want to put us forward in time and search
backwards to get the other time. I checked all of the
configuration files for the tz package -- no entry
saves more than two hours, so I think we'll be safe by
moving 24 hours in one direction. IF THE AMOUNT OF
TIME SAVED IN THE CONFIGURATION FILES CHANGES, THIS
VALUE MAY NEED TO BE ADJUSTED. Luckily, we can never
have more than one level of overlaps, or this would
never work. */
#define SKIP_VALUE 86400
if (guess_tm->tm_isdst == 0)
/* we got the later one, but want the earlier one */
distance = -SKIP_VALUE;
else
distance = SKIP_VALUE;
#ifdef DEBUG
printf (" Got the right time, wrong DST value -- adjusting\n");
#endif
}
last_distance = distance;
} while (distance != 0);
/* Check to see that the dst flag matches */
if (me->tm_isdst != -1)
{
if (me->tm_isdst != guess_tm->tm_isdst)
{
#ifdef DEBUG
printf (" DST flag doesn't match! FIXME?\n");
#endif
return BAD_STRUCT_TM;
}
}
result = guess; /* Success! */
/* On successful completion, the values of tm_wday and tm_yday
have to be set appropriately. */
/* me->tm_yday = guess_tm->tm_yday;
me->tm_mday = guess_tm->tm_mday; */
*me = *guess_tm;
}
/* Update the caller's version of the structure */
*timeptr = *me;
return result;
}
time_t
#ifdef DEBUG /* make it work even if the system's
libc has it's own mktime routine */
my_mktime (timeptr)
#if ! HAVE_LOCALTIME_R && ! defined (localtime_r)
#ifdef _LIBC
#define localtime_r __localtime_r
#else
mktime (timeptr)
#endif
struct tm *timeptr;
/* Approximate localtime_r as best we can in its absence. */
#define localtime_r my_localtime_r
static struct tm *localtime_r __P ((const time_t *, struct tm *));
static struct tm *
localtime_r (t, tp)
const time_t *t;
struct tm *tp;
{
return _mktime_internal (timeptr, localtime);
struct tm *l = localtime (t);
if (! l)
return 0;
*tp = *l;
return tp;
}
#endif /* ! _LIBC */
#endif /* ! HAVE_LOCALTIME_R && ! defined (localtime_r) */
/* Yield the difference between (YEAR-YDAY HOUR:MIN:SEC) and (*TP),
measured in seconds, ignoring leap seconds.
YEAR uses the same numbering as TM->tm_year.
All values are in range, except possibly YEAR.
If overflow occurs, yield the low order bits of the correct answer. */
static time_t
ydhms_tm_diff (year, yday, hour, min, sec, tp)
int year, yday, hour, min, sec;
const struct tm *tp;
{
time_t ay = year + (time_t) (TM_YEAR_BASE - 1);
time_t by = tp->tm_year + (time_t) (TM_YEAR_BASE - 1);
time_t intervening_leap_days =
(ay/4 - by/4) - (ay/100 - by/100) + (ay/400 - by/400);
time_t years = ay - by;
time_t days = (365 * years + intervening_leap_days
+ (yday - tp->tm_yday));
return (60 * (60 * (24 * days + (hour - tp->tm_hour))
+ (min - tp->tm_min))
+ (sec - tp->tm_sec));
}
/* Convert *TP to a time_t value. */
time_t
mktime (tp)
struct tm *tp;
{
static time_t localtime_offset;
return __mktime_internal (tp, localtime_r, &localtime_offset);
}
/* Convert *TP to a time_t value, inverting
the monotonic and mostly-unit-linear conversion function CONVERT.
Use *OFFSET to keep track of a guess at the offset of the result,
compared to what the result would be for UTC without leap seconds.
If *OFFSET's guess is correct, only one CONVERT call is needed. */
time_t
__mktime_internal (tp, convert, offset)
struct tm *tp;
struct tm *(*convert) __P ((const time_t *, struct tm *));
time_t *offset;
{
time_t t, dt, t0;
struct tm tm;
/* The maximum number of probes (calls to CONVERT) should be enough
to handle any combinations of time zone rule changes, solar time,
and leap seconds. Posix.1 prohibits leap seconds, but some hosts
have them anyway. */
int remaining_probes = 4;
/* Time requested. Copy it in case CONVERT modifies *TP; this can
occur if TP is localtime's returned value and CONVERT is localtime. */
int sec = tp->tm_sec;
int min = tp->tm_min;
int hour = tp->tm_hour;
int mday = tp->tm_mday;
int mon = tp->tm_mon;
int year_requested = tp->tm_year;
int isdst = tp->tm_isdst;
/* Ensure that mon is in range, and set year accordingly. */
int mon_remainder = mon % 12;
int negative_mon_remainder = mon_remainder < 0;
int mon_years = mon / 12 - negative_mon_remainder;
int year = year_requested + mon_years;
/* The other values need not be in range:
the remaining code handles minor overflows correctly,
assuming int and time_t arithmetic wraps around.
Major overflows are caught at the end. */
/* Calculate day of year from year, month, and day of month.
The result need not be in range. */
int yday = ((__mon_yday[__isleap (year + TM_YEAR_BASE)]
[mon_remainder + 12 * negative_mon_remainder])
+ mday - 1);
#if LEAP_SECONDS_POSSIBLE
/* Handle out-of-range seconds specially,
since ydhms_tm_diff assumes every minute has 60 seconds. */
int sec_requested = sec;
if (sec < 0)
sec = 0;
if (59 < sec)
sec = 59;
#endif
/* Invert CONVERT by probing. First assume the same offset as last time.
Then repeatedly use the error to improve the guess. */
tm.tm_year = EPOCH_YEAR - TM_YEAR_BASE;
tm.tm_yday = tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
t0 = ydhms_tm_diff (year, yday, hour, min, sec, &tm);
for (t = t0 + *offset;
(dt = ydhms_tm_diff (year, yday, hour, min, sec, (*convert) (&t, &tm)));
t += dt)
if (--remaining_probes == 0)
return -1;
/* Check whether tm.tm_isdst has the requested value, if any. */
if (0 <= isdst && 0 <= tm.tm_isdst)
{
int dst_diff = (isdst != 0) - (tm.tm_isdst != 0);
if (dst_diff)
{
/* Move two hours in the direction indicated by the disagreement,
probe some more, and switch to a new time if found.
The largest known fallback due to daylight savings is two hours:
once, in Newfoundland, 1988-10-30 02:00 -> 00:00. */
time_t ot = t - 2 * 60 * 60 * dst_diff;
while (--remaining_probes != 0)
{
struct tm otm;
if (! (dt = ydhms_tm_diff (year, yday, hour, min, sec,
(*convert) (&ot, &otm))))
{
t = ot;
tm = otm;
break;
}
if ((ot += dt) == t)
break; /* Avoid a redundant probe. */
}
}
}
*offset = t - t0;
#if LEAP_SECONDS_POSSIBLE
if (sec_requested != tm.tm_sec)
{
/* Adjust time to reflect the tm_sec requested, not the normalized value.
Also, repair any damage from a false match due to a leap second. */
t += sec_requested - sec + (sec == 0 && tm.tm_sec == 60);
(*convert) (&t, &tm);
}
#endif
if (TIME_T_MAX / INT_MAX / 366 / 24 / 60 / 60 < 3)
{
/* time_t isn't large enough to rule out overflows in ydhms_tm_diff,
so check for major overflows. A gross check suffices,
since if t has overflowed, it is off by a multiple of
TIME_T_MAX - TIME_T_MIN + 1. So ignore any component of
the difference that is bounded by a small value. */
double dyear = (double) year_requested + mon_years - tm.tm_year;
double dday = 366 * dyear + mday;
double dsec = 60 * (60 * (24 * dday + hour) + min) + sec_requested;
if (TIME_T_MAX / 3 - TIME_T_MIN / 3 < (dsec < 0 ? - dsec : dsec))
return -1;
}
*tp = tm;
return t;
}
#ifdef weak_alias
weak_alias (mktime, timelocal)
#endif
#ifdef DEBUG
void
#if DEBUG
static int
not_equal_tm (a, b)
struct tm *a;
struct tm *b;
{
return ((a->tm_sec ^ b->tm_sec)
| (a->tm_min ^ b->tm_min)
| (a->tm_hour ^ b->tm_hour)
| (a->tm_mday ^ b->tm_mday)
| (a->tm_mon ^ b->tm_mon)
| (a->tm_year ^ b->tm_year)
| (a->tm_mday ^ b->tm_mday)
| (a->tm_yday ^ b->tm_yday)
| (a->tm_isdst ^ b->tm_isdst));
}
static void
print_tm (tp)
struct tm *tp;
{
printf ("%04d-%02d-%02d %02d:%02d:%02d yday %03d wday %d isdst %d",
tp->tm_year + TM_YEAR_BASE, tp->tm_mon + 1, tp->tm_mday,
tp->tm_hour, tp->tm_min, tp->tm_sec,
tp->tm_yday, tp->tm_wday, tp->tm_isdst);
}
static int
check_result (tk, tmk, tl, tml)
time_t tk;
struct tm tmk;
time_t tl;
struct tm tml;
{
if (tk != tl || not_equal_tm (&tmk, &tml))
{
printf ("mktime (");
print_tm (&tmk);
printf (")\nyields (");
print_tm (&tml);
printf (") == %ld, should be %ld\n", (long) tl, (long) tk);
return 1;
}
return 0;
}
int
main (argc, argv)
int argc;
char *argv[];
char **argv;
{
int time;
int result_time;
struct tm *tmptr;
if (argc == 1)
int status = 0;
struct tm tm, tmk, tml;
time_t tk, tl;
char trailer;
if ((argc == 3 || argc == 4)
&& (sscanf (argv[1], "%d-%d-%d%c",
&tm.tm_year, &tm.tm_mon, &tm.tm_mday, &trailer)
== 3)
&& (sscanf (argv[2], "%d:%d:%d%c",
&tm.tm_hour, &tm.tm_min, &tm.tm_sec, &trailer)
== 3))
{
long q;
printf ("starting long test...\n");
for (q = 10000000; q < 1000000000; q += 599)
{
struct tm *tm = localtime ((time_t *) &q);
if ((q % 10000) == 0) { printf ("%ld\n", q); fflush (stdout); }
if (q != my_mktime (tm))
{ printf ("failed for %ld\n", q); fflush (stdout); }
}
printf ("test finished\n");
exit (0);
tm.tm_year -= TM_YEAR_BASE;
tm.tm_mon--;
tm.tm_isdst = argc == 3 ? -1 : atoi (argv[3]);
tmk = tm;
tl = mktime (&tmk);
tml = *localtime (&tl);
printf ("mktime returns %ld == ", (long) tl);
print_tm (&tmk);
printf ("\n");
status = check_result (tl, tmk, tl, tml);
}
if (argc != 2)
else if (argc == 4 || (argc == 5 && strcmp (argv[4], "-") == 0))
{
printf ("wrong # of args\n");
exit (0);
time_t from = atol (argv[1]);
time_t by = atol (argv[2]);
time_t to = atol (argv[3]);
if (argc == 4)
for (tl = from; tl <= to; tl += by)
{
tml = *localtime (&tl);
tmk = tml;
tk = mktime (&tmk);
status |= check_result (tk, tmk, tl, tml);
}
else
for (tl = from; tl <= to; tl += by)
{
/* Null benchmark. */
tml = *localtime (&tl);
tmk = tml;
tk = tl;
status |= check_result (tk, tmk, tl, tml);
}
}
debugging_enabled = 1; /* We want to see the info */
else
printf ("Usage:\
\t%s YYYY-MM-DD HH:MM:SS [ISDST] # Test given time.\n\
\t%s FROM BY TO # Test values FROM, FROM+BY, ..., TO.\n\
\t%s FROM BY TO - # Do not test those values (for benchmark).\n",
argv[0], argv[0], argv[0]);
++argv;
time = atoi (*argv);
tmptr = localtime ((time_t *) &time);
printf ("Localtime tells us that a time_t of %d represents\n ", time);
printtm (tmptr);
putchar ('\n');
printf (" Given localtime's return val, mktime returns %d which is\n ",
(int) my_mktime (tmptr));
printtm (tmptr);
putchar ('\n');
#if 0
tmptr->tm_sec -= 20;
tmptr->tm_min -= 20;
tmptr->tm_hour -= 20;
tmptr->tm_mday -= 20;
tmptr->tm_mon -= 20;
tmptr->tm_year -= 20;
tmptr->tm_gmtoff -= 20000; /* This has no effect! */
tmptr->tm_zone = NULL; /* Nor does this! */
tmptr->tm_isdst = -1;
#endif
tmptr->tm_hour += 1;
tmptr->tm_isdst = -1;
printf ("\n\nchanged ranges: ");
printtm (tmptr);
putchar ('\n');
result_time = my_mktime (tmptr);
printf ("\nmktime: %d\n", result_time);
tmptr->tm_isdst = 0;
printf ("\n\nchanged ranges: ");
printtm (tmptr);
putchar ('\n');
result_time = my_mktime (tmptr);
printf ("\nmktime: %d\n", result_time);
return status;
}
#endif /* DEBUG */
#endif /* DEBUG */
/*
Local Variables:
compile-command: "gcc -g mktime.c -o mktime -DDEBUG"
compile-command: "gcc -DDEBUG=1 -Wall -O -g mktime.c -o mktime"
End:
*/

View File

@@ -225,7 +225,7 @@ read_filesystem_list (need_fs_type, all_fs)
me->me_dev = xatoi (devopt + 4);
}
else
me->me_dev = -1; /* Magic; means not known yet. */
me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
me->me_next = NULL;
/* Add to the linked list. */
@@ -256,7 +256,7 @@ read_filesystem_list (need_fs_type, all_fs)
#else
me->me_type = fstype_to_string (fsp->f_type);
#endif
me->me_dev = -1; /* Magic; means not known yet. */
me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
me->me_next = NULL;
/* Add to the linked list. */
@@ -317,7 +317,7 @@ read_filesystem_list (need_fs_type, all_fs)
me->me_devname = xstrdup (stats[counter].f_mntfromname);
me->me_mountdir = xstrdup (stats[counter].f_mntonname);
me->me_type = mnt_names[stats[counter].f_type];
me->me_dev = -1; /* Magic; means not known yet. */
me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
me->me_next = NULL;
/* Add to the linked list. */
@@ -350,7 +350,7 @@ read_filesystem_list (need_fs_type, all_fs)
strcpy (me->me_devname + 5, mnt.mt_dev);
#endif
me->me_mountdir = xstrdup (mnt.mt_filsys);
me->me_dev = -1; /* Magic; means not known yet. */
me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
me->me_type = "";
#ifdef GETFSTYP /* SVR3. */
if (need_fs_type)
@@ -384,7 +384,7 @@ read_filesystem_list (need_fs_type, all_fs)
me->me_devname = xstrdup ( (*ent)->mt_resource);
me->me_mountdir = xstrdup( (*ent)->mt_directory);
me->me_type = xstrdup ((*ent)->mt_fstype);
me->me_dev = -1; /* Magic; means not known yet. */
me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
me->me_next = NULL;
/* Add to the linked list. */
@@ -412,7 +412,7 @@ read_filesystem_list (need_fs_type, all_fs)
me->me_devname = xstrdup (mnt.mnt_special);
me->me_mountdir = xstrdup (mnt.mnt_mountp);
me->me_type = xstrdup (mnt.mnt_fstype);
me->me_dev = -1; /* Magic; means not known yet. */
me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
me->me_next = NULL;
/* Add to the linked list. */
@@ -464,7 +464,7 @@ read_filesystem_list (need_fs_type, all_fs)
}
me->me_mountdir = xstrdup (thisent + vmp->vmt_data[VMT_STUB].vmt_off);
me->me_type = xstrdup (fstype_to_string (vmp->vmt_gfstype));
me->me_dev = -1; /* vmt_fsid might be the info we want. */
me->me_dev = (dev_t) -1; /* vmt_fsid might be the info we want. */
me->me_next = NULL;
/* Add to the linked list. */

View File

@@ -264,7 +264,8 @@ char *alloca ();
/* Define how to allocate the failure stack. */
#ifdef REL_ALLOC
#if defined (REL_ALLOC) && defined (REGEX_MALLOC)
#define REGEX_ALLOCATE_STACK(size) \
r_alloc (&failure_stack_ptr, (size))
#define REGEX_REALLOCATE_STACK(source, osize, nsize) \
@@ -272,7 +273,7 @@ char *alloca ();
#define REGEX_FREE_STACK(ptr) \
r_alloc_free (&failure_stack_ptr)
#else /* not REL_ALLOC */
#else /* not using relocating allocator */
#ifdef REGEX_MALLOC
@@ -290,7 +291,7 @@ char *alloca ();
#define REGEX_FREE_STACK(arg)
#endif /* not REGEX_MALLOC */
#endif /* not REL_ALLOC */
#endif /* not using relocating allocator */
/* True if `size1' is non-NULL and PTR is pointing anywhere inside
@@ -1156,29 +1157,30 @@ typedef struct
/* Push the info, starting with the registers. */ \
DEBUG_PRINT1 ("\n"); \
\
for (this_reg = lowest_active_reg; this_reg <= highest_active_reg; \
this_reg++) \
{ \
DEBUG_PRINT2 (" Pushing reg: %d\n", this_reg); \
DEBUG_STATEMENT (num_regs_pushed++); \
if (!(RE_NO_POSIX_BACKTRACKING & bufp->syntax)) \
for (this_reg = lowest_active_reg; this_reg <= highest_active_reg; \
this_reg++) \
{ \
DEBUG_PRINT2 (" Pushing reg: %d\n", this_reg); \
DEBUG_STATEMENT (num_regs_pushed++); \
\
DEBUG_PRINT2 (" start: 0x%x\n", regstart[this_reg]); \
PUSH_FAILURE_POINTER (regstart[this_reg]); \
\
DEBUG_PRINT2 (" end: 0x%x\n", regend[this_reg]); \
PUSH_FAILURE_POINTER (regend[this_reg]); \
DEBUG_PRINT2 (" start: 0x%x\n", regstart[this_reg]); \
PUSH_FAILURE_POINTER (regstart[this_reg]); \
\
DEBUG_PRINT2 (" info: 0x%x\n ", reg_info[this_reg]); \
DEBUG_PRINT2 (" match_null=%d", \
REG_MATCH_NULL_STRING_P (reg_info[this_reg])); \
DEBUG_PRINT2 (" active=%d", IS_ACTIVE (reg_info[this_reg])); \
DEBUG_PRINT2 (" matched_something=%d", \
MATCHED_SOMETHING (reg_info[this_reg])); \
DEBUG_PRINT2 (" ever_matched=%d", \
EVER_MATCHED_SOMETHING (reg_info[this_reg])); \
DEBUG_PRINT1 ("\n"); \
PUSH_FAILURE_ELT (reg_info[this_reg].word); \
} \
DEBUG_PRINT2 (" end: 0x%x\n", regend[this_reg]); \
PUSH_FAILURE_POINTER (regend[this_reg]); \
\
DEBUG_PRINT2 (" info: 0x%x\n ", reg_info[this_reg]); \
DEBUG_PRINT2 (" match_null=%d", \
REG_MATCH_NULL_STRING_P (reg_info[this_reg])); \
DEBUG_PRINT2 (" active=%d", IS_ACTIVE (reg_info[this_reg])); \
DEBUG_PRINT2 (" matched_something=%d", \
MATCHED_SOMETHING (reg_info[this_reg])); \
DEBUG_PRINT2 (" ever_matched=%d", \
EVER_MATCHED_SOMETHING (reg_info[this_reg])); \
DEBUG_PRINT1 ("\n"); \
PUSH_FAILURE_ELT (reg_info[this_reg].word); \
} \
\
DEBUG_PRINT2 (" Pushing low active reg: %d\n", lowest_active_reg);\
PUSH_FAILURE_INT (lowest_active_reg); \
@@ -1215,9 +1217,11 @@ typedef struct
#define MAX_FAILURE_ITEMS ((num_regs - 1) * NUM_REG_ITEMS + NUM_NONREG_ITEMS)
/* We actually push this many items. */
#define NUM_FAILURE_ITEMS \
((highest_active_reg - lowest_active_reg + 1) * NUM_REG_ITEMS \
+ NUM_NONREG_ITEMS)
#define NUM_FAILURE_ITEMS \
(((RE_NO_POSIX_BACKTRACKING & bufp->syntax \
? 0 : highest_active_reg - lowest_active_reg + 1) \
* NUM_REG_ITEMS) \
+ NUM_NONREG_ITEMS)
/* How many items can still be added to the stack without overflowing it. */
#define REMAINING_AVAIL_SLOTS ((fail_stack).size - (fail_stack).avail)
@@ -1275,18 +1279,29 @@ typedef struct
low_reg = (unsigned) POP_FAILURE_INT (); \
DEBUG_PRINT2 (" Popping low active reg: %d\n", low_reg); \
\
for (this_reg = high_reg; this_reg >= low_reg; this_reg--) \
if (!(RE_NO_POSIX_BACKTRACKING & bufp->syntax)) \
for (this_reg = high_reg; this_reg >= low_reg; this_reg--) \
{ \
DEBUG_PRINT2 (" Popping reg: %d\n", this_reg); \
\
reg_info[this_reg].word = POP_FAILURE_ELT (); \
DEBUG_PRINT2 (" info: 0x%x\n", reg_info[this_reg]); \
\
regend[this_reg] = (const char *) POP_FAILURE_POINTER (); \
DEBUG_PRINT2 (" end: 0x%x\n", regend[this_reg]); \
\
regstart[this_reg] = (const char *) POP_FAILURE_POINTER (); \
DEBUG_PRINT2 (" start: 0x%x\n", regstart[this_reg]); \
} \
else \
{ \
DEBUG_PRINT2 (" Popping reg: %d\n", this_reg); \
\
reg_info[this_reg].word = POP_FAILURE_ELT (); \
DEBUG_PRINT2 (" info: 0x%x\n", reg_info[this_reg]); \
\
regend[this_reg] = (const char *) POP_FAILURE_POINTER (); \
DEBUG_PRINT2 (" end: 0x%x\n", regend[this_reg]); \
\
regstart[this_reg] = (const char *) POP_FAILURE_POINTER (); \
DEBUG_PRINT2 (" start: 0x%x\n", regstart[this_reg]); \
for (this_reg = highest_active_reg; this_reg > high_reg; this_reg--) \
{ \
reg_info[this_reg].word = 0; \
regend[this_reg] = 0; \
regstart[this_reg] = 0; \
} \
highest_active_reg = high_reg; \
} \
\
set_regs_matched_done = 0; \
@@ -1364,11 +1379,13 @@ static reg_errcode_t compile_range ();
if necessary. Also cast from a signed character in the constant
string passed to us by the user to an unsigned char that we can use
as an array index (in, e.g., `translate'). */
#ifndef PATFETCH
#define PATFETCH(c) \
do {if (p == pend) return REG_EEND; \
c = (unsigned char) *p++; \
if (translate) c = translate[c]; \
if (translate) c = (unsigned char) translate[c]; \
} while (0)
#endif
/* Fetch the next character in the uncompiled pattern, with no
translation. */
@@ -1385,7 +1402,10 @@ static reg_errcode_t compile_range ();
cast the subscript to translate because some data is declared as
`char *', to avoid warnings when a string constant is passed. But
when we use a character as a subscript we must make it unsigned. */
#define TRANSLATE(d) (translate ? translate[(unsigned char) (d)] : (d))
#ifndef TRANSLATE
#define TRANSLATE(d) \
(translate ? (char) translate[(unsigned char) (d)] : (d))
#endif
/* Macros for outputting the compiled pattern into `buffer'. */
@@ -1651,7 +1671,7 @@ regex_compile (pattern, size, syntax, bufp)
const char *pend = pattern + size;
/* How to translate the characters in the pattern. */
char *translate = bufp->translate;
RE_TRANSLATE_TYPE translate = bufp->translate;
/* Address of the count-byte of the most recently inserted `exactn'
command. This makes it possible to tell if a new exact-match
@@ -2817,7 +2837,7 @@ group_in_compile_stack (compile_stack, regnum)
static reg_errcode_t
compile_range (p_ptr, pend, translate, syntax, b)
const char **p_ptr, *pend;
char *translate;
RE_TRANSLATE_TYPE translate;
reg_syntax_t syntax;
unsigned char *b;
{
@@ -3037,7 +3057,7 @@ re_compile_fastmap (bufp)
case at_dot:
case after_dot:
continue;
#endif /* not emacs */
#endif /* emacs */
case no_op:
@@ -3251,7 +3271,7 @@ re_search_2 (bufp, string1, size1, string2, size2, startpos, range, regs, stop)
{
int val;
register char *fastmap = bufp->fastmap;
register char *translate = bufp->translate;
register RE_TRANSLATE_TYPE translate = bufp->translate;
int total_size = size1 + size2;
int endpos = startpos + range;
@@ -3260,9 +3280,10 @@ re_search_2 (bufp, string1, size1, string2, size2, startpos, range, regs, stop)
return -1;
/* Fix up RANGE if it might eventually take us outside
the virtual concatenation of STRING1 and STRING2. */
if (endpos < -1)
range = -1 - startpos;
the virtual concatenation of STRING1 and STRING2.
Make sure we won't move STARTPOS below 0 or above TOTAL_SIZE. */
if (endpos < 0)
range = 0 - startpos;
else if (endpos > total_size)
range = total_size - startpos;
@@ -3276,6 +3297,17 @@ re_search_2 (bufp, string1, size1, string2, size2, startpos, range, regs, stop)
range = 1;
}
#ifdef emacs
/* In a forward search for something that starts with \=.
don't keep searching past point. */
if (bufp->used > 0 && (re_opcode_t) bufp->buffer[0] == at_dot && range > 0)
{
range = PT - startpos;
if (range <= 0)
return -1;
}
#endif /* emacs */
/* Update the fastmap now if not correct already. */
if (fastmap && !bufp->fastmap_accurate)
if (re_compile_fastmap (bufp) == -2)
@@ -3527,7 +3559,7 @@ re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
unsigned char *just_past_start_mem = 0;
/* We use this to map every character in the string. */
char *translate = bufp->translate;
RE_TRANSLATE_TYPE translate = bufp->translate;
/* Failure point stack. Each place that can handle a failure further
down the line pushes a failure point on this stack. It consists of
@@ -3928,7 +3960,8 @@ re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
do
{
PREFETCH ();
if (translate[(unsigned char) *d++] != (char) *p++)
if ((unsigned char) translate[(unsigned char) *d++]
!= (unsigned char) *p++)
goto fail;
}
while (--mcnt);
@@ -4342,7 +4375,7 @@ re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
for that group and all inner ones, so that if we fail back
to this point, the group's information will be correct.
For example, in \(a*\)*\1, we need the preceding group,
and in \(\(a*\)b*\)\2, we need the inner group. */
and in \(zz\(a*\)b*\)\2, we need the inner group. */
/* We can't use `p' to check ahead because we push
a failure point to `p + mcnt' after we do this. */
@@ -4681,13 +4714,6 @@ re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
if (PTR_CHAR_POS ((unsigned char *) d) <= point)
goto fail;
break;
#if 0 /* not emacs19 */
case at_dot:
DEBUG_PRINT1 ("EXECUTING at_dot.\n");
if (PTR_CHAR_POS ((unsigned char *) d) + 1 != point)
goto fail;
break;
#endif /* not emacs19 */
case syntaxspec:
DEBUG_PRINT2 ("EXECUTING syntaxspec %d.\n", mcnt);
@@ -5057,7 +5083,7 @@ static int
bcmp_translate (s1, s2, len, translate)
unsigned char *s1, *s2;
register int len;
char *translate;
RE_TRANSLATE_TYPE translate;
{
register unsigned char *p1 = s1, *p2 = s2;
while (len)
@@ -5229,7 +5255,9 @@ regcomp (preg, pattern, cflags)
{
unsigned i;
preg->translate = (char *) malloc (CHAR_SET_SIZE);
preg->translate
= (RE_TRANSLATE_TYPE) malloc (CHAR_SET_SIZE
* sizeof (*(RE_TRANSLATE_TYPE)0));
if (preg->translate == NULL)
return (int) REG_ESPACE;

View File

@@ -279,6 +279,10 @@ typedef enum
compiled, the `re_nsub' field is available. All other fields are
private to the regex routines. */
#ifndef RE_TRANSLATE_TYPE
#define RE_TRANSLATE_TYPE char *
#endif
struct re_pattern_buffer
{
/* [[[begin pattern_buffer]]] */
@@ -305,7 +309,7 @@ struct re_pattern_buffer
comparing them, or zero for no translation. The translation
is applied to a pattern when it is compiled and to a string
when it is matched. */
char *translate;
RE_TRANSLATE_TYPE translate;
/* Number of subexpressions found by the compiler. */
size_t re_nsub;

39
lib/strpbrk.c Normal file
View File

@@ -0,0 +1,39 @@
/* Copyright (C) 1991, 1994 Free Software Foundation, Inc.
NOTE: The canonical source of this file is maintained with the GNU C Library.
Bugs can be reported to bug-glibc@prep.ai.mit.edu.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
/* Find the first ocurrence in S of any character in ACCEPT. */
char *
strpbrk (s, accept)
register const char *s;
register const char *accept;
{
while (*s != '\0')
{
const char *a = accept;
while (*a != '\0')
if (*a++ == *s)
return (char *) s;
++s;
}
return 0;
}

View File

@@ -63,9 +63,12 @@ struct group *getgrnam ();
struct group *getgrgid ();
#endif
#ifdef _POSIX_SOURCE
#define endpwent()
#define endgrent()
#ifndef HAVE_ENDGRENT
# define endgrent() ((void) 0)
#endif
#ifndef HAVE_ENDPWENT
# define endpwent() ((void) 0)
#endif
/* Perform the equivalent of the statement `dest = strdup (src);',

View File

@@ -24,15 +24,15 @@ extern int errno;
#endif
#if HAVE_LIMITS_H
#include <limits.h>
# include <limits.h>
#endif
#ifndef ULONG_MAX
#define ULONG_MAX ((unsigned long) ~(unsigned long) 0)
# define ULONG_MAX ((unsigned long) ~(unsigned long) 0)
#endif
#ifndef LONG_MAX
#define LONG_MAX ((long int) (ULONG_MAX >> 1))
# define LONG_MAX ((long int) (ULONG_MAX >> 1))
#endif
#include "xstrtol.h"

View File

@@ -1,3 +1,109 @@
Wed Nov 1 23:11:05 1995 Jim Meyering (meyering@comco.com)
* cp.c (copy): Use euidaccess instead of euidaccess_stat.
* mv.c (do_move): Likewise.
* rm.c (remove_file, remove_dir): Likewise.
Sun Oct 29 06:06:13 1995 Jim Meyering (meyering@comco.com)
* aclocal.m4 (jm_WITH_AUTODEPS): New directive.
* configure.in: Use it.
* lib/Makefile.in (INCLUDE, COMPILE): New variables.
(.c.o): Rewrite to be more like src/Makefile.in.
Add line that (--with-autodeps) will include mkdep-Makefile.
(distclean): Remove .deps.
* src/Makefile.in: Likewise.
* src/Makefile.in (test.o): Remove special rule.
* mkdep-Makefile: New file.
* Makefile.in (DISTFILES): Add mkdep-Makefile.
* doc/Makefile.in (mostlyclean): Remove *.info.
* touch.c: Change long option name `--file' to `--reference'.
Leave --file as an alias, for now. It will be removed later.
(usage): Reflect option name change. From Franc,ois Pinard.
Wed Oct 18 23:09:55 1995 Jim Meyering (meyering@comco.com)
* configure.in (AC_CHECK_HEADERS): Add sys/wait.h and sys/ioctl.h.
(AC_CHECK_FUNCS): Add endpwent.
* fileblocks.c: Use _POSIX_VERSION, not _POSIX_SOURCE.
* userspec.c [endgrent]: Test !HAVE_ENDGRENT rather than _POSIX_SOURCE.
[endpwent]: Test !HAVE_ENDPWENT rather than _POSIX_SOURCE.
* chgrp.c [endgrent]: Test !HAVE_ENDGRENT rather than _POSIX_SOURCE.
* chown.c [endpwent]: Test !HAVE_ENDPWENT rather than _POSIX_SOURCE.
[endgrent]: Remove unused definition.
* df.c (main): Fail if the same file system type was both selected
and excluded. Reported by Paul Close pdc@lunch.engr.sgi.com.
* rm.c (duplicate_entry): Always return 0 if !D_INO_IN_DIRENT,
rather than if _POSIX_SOURCE.
* install.c: Use HAVE_SYS_WAIT_H, not _POSIX_VERSION in conditional
inclusion of sys/wait.h.
[endgrent]: Test !HAVE_ENDGRENT rather than _POSIX_SOURCE.
[endpwent]: Test !HAVE_ENDPWENT rather than _POSIX_SOURCE.
* ls.c Use HAVE_SYS_IOCTL_H, rather than !_POSIX_SOURCE || _AIX.
Thu Oct 5 21:49:34 1995 Jim Meyering (meyering@comco.com)
* configure.in (HAVE_STRUCT_UTIMBUF): Add new test. Testing for
the existence of <utime.h> is insufficient on some Next systems.
* acconfig.h (HAVE_STRUCT_UTIMBUF): Add it.
* system.h [!HAVE_UTIME_H]: Don't declare struct utimbuf here.
[!HAVE_STRUCT_UTIMBUF]: Declare struct utimbuf here instead.
* chgrp.c: Include limits.h.
[!INT_MAX]: Define it.
* df.c (show_point): Cast -2 to dev_t before assignment.
* mountlist.c (read_filesystem_list): Cast -1 to dev_t before
assignment.
Sun Oct 1 13:22:36 1995 Jim Meyering (meyering@comco.com)
* configure.in (AC_REPLACE_FUNCS): Add strtoul.
* strtoul.c: New file.
* lib/Makefile.in (SOURCES): Add strtoul.c.
* acconfig.h (STATFS_TRUNCATES_BLOCK_COUNTS): Add it.
* configure.in (STATFS_TRUNCATES_BLOCK_COUNTS): New check to enable
workaround for SunOS statfs brokenness. Block counts in struct
statfs for partitions 2GB and larger are truncated, but correct
values are stored in f_spare array member.
* fsusage.c (get_fs_usage) [STATFS_TRUNCATES_BLOCK_COUNTS]: Copy
untruncated block counts from f_spare array into proper members
of struct statfs. From Eirik Fuller (eirik@netapp.com);
* ls.c (dired_dump_obstack): Don't generate any output if the
obstack is empty.
(main): Always initialize and dump subdired_obstack, not just if -R.
`ls -lDR dir dir2' was using uninitialized subdired_obstack.
Reported by Samuli K{rkk{inen <hskarkka@snakemail.hut.fi>.
Tue Sep 26 23:05:01 1995 Jim Meyering (meyering@comco.com)
* man/Makefile.in (install-data, uninstall): Use sed not basename.
The GNU Coding Standard suggests that only a select set of
relatively standard utilities be used in Makefiles. basename is
not among them. Suggested by Ulrich Drepper.
Mon Sep 25 23:12:37 1995 Jim Meyering <meyering@gremlin.comco.com>
* src/df.c (show_point): Ignore mtab entries with either
nonexistent mount points or with inconsistent device number.
From Eirik Fuller <eirik@synopsys.com>.
Wed Aug 9 00:33:05 1995 Jim Meyering (meyering@comco.com)
* mknod.c (my_strtol): Remove function.

View File

@@ -1,3 +1,20 @@
User-visible changes in release 3.13:
* rename touch long option name --file to --reference.
`touch --file' will continue to work a little longer.
* df fails if the same file system type is both selected and excluded.
* df works around SunOS statfs brokenness wrt filesystems larger than 2GB
* df better handles inconsistent mtab entries
* `ls -lDR dir dir2' works
* `ls -c' does what it's supposed to
* all programs include program name in --version output
* `ls --quote-name' works
* mv properly determines whether src and dest are the same file
Before, it could (though with very low probability) fail to do the move,
reporting that distinct source and destination are the same file.
* du --dereference (-L) works with directory symlinks
* du works on SunOS 4 systems even when accounting is enabled
* many programs that convert strings to integers now use strtol or strtoul
and detect overflow
User-visible changes in release 3.12:
* None.
User-visible changes in release 3.11:
@@ -52,7 +69,7 @@ Major changes in release 3.9:
They used to succeed, ignoring the implicitly contradictory trailing slash.
Major changes in release 3.8:
* install isn't as likely to produce spurious errors
* install isn't as likely to produce spurious errors
* avoid redundant compilations for `dir' and `vdir';
* configure properly defines STAT_STATFS2_BSIZE on a Pyramid MIServer
running OSx 5.1
@@ -78,7 +95,7 @@ Major changes in release 3.5:
Major changes in release 3.4:
* cp -p and mv preserve setuid and setgid bits
* chown works on systems where sizeof(uid_t) != sizeof(int)
* chown works on systems where sizeof(uid_t) != sizeof(int)
or sizeof(uid) != sizeof(gid)
* catch errors from spurious slashes at ends of arguments

View File

@@ -1,3 +1,40 @@
Sun Oct 29 08:47:50 1995 Jim Meyering (meyering@comco.com)
* test.c [TEST_STANDALONE]: Define.
* src/Makefile.in (test.o): Remove special rule.
Sat Oct 28 00:49:13 1995 Jim Meyering (meyering@comco.com)
* aclocal.m4 (jm_WITH_AUTODEPS): New directive.
* configure.in: Use it.
* lib/Makefile.in (INCLUDE, COMPILE): New variables.
(.c.o): Rewrite to be more like src/Makefile.in.
Add line that (--with-autodeps) will include mkdep-Makefile.
(distclean): Remove .deps.
* src/Makefile.in: Likewise.
* mkdep-Makefile: New file.
* Makefile.in (DISTFILES): Add mkdep-Makefile.
* doc/Makefile.in (mostlyclean): Remove *.info.
* date.c: New option --reference=FILE (-r FILE) analogous to the
like-named touch option.
(main): Recognize it and give diagnostic for misuse.
(usage): Describe briefly.
From Franc,ois Pinard.
* date.c (batch_convert): Close input stream also when it's not stdin.
(main): Reorganize to do option-consistency checks before all else.
Tue Sep 26 23:05:01 1995 Jim Meyering (meyering@comco.com)
* man/Makefile.in (install-data, uninstall): Use sed not basename.
The GNU Coding Standard suggests that only a select set of
relatively standard utilities be used in Makefiles. basename is
not among them. Suggested by Ulrich Drepper.
Tue Aug 8 22:57:34 1995 Jim Meyering (meyering@comco.com)
* yes.c: Include system.h to get definition of _.

View File

@@ -1,3 +1,204 @@
* unexpand.c: Reorder functions to obviate forward dcls. Remove
forward dcls. Protoize. Add `const' attribute to some parameters.
Mon Oct 30 23:15:56 1995 Jim Meyering (meyering@comco.com)
* wc.c: Reorder functions to obviate forward dcls. Remove
forward dcls. Protoize. Add `const' attribute to some parameters.
* uniq.c: Likewise.
* split.c: Likewise.
* split.c (isdigits, convint): Remove these.
(main): Use xstrtol instead.
Sun Oct 29 14:04:36 1995 Jim Meyering (meyering@comco.com)
* paste.c (main): Move function body to end of file.
Remove forward dcls and protoize.
* sum.c (main): Likewise.
* nl.c: Protoize. Reorder functions to obviate forward dcls.
Remove forward dcls.
* tac.c: Likewise.
* src/Makefile.in (OBJECTS): Reflect that all of the above
now use prototypes.
* sum.c (bsd_sum_file): Give file name parameter const attribute.
(sysv_sum_file): Likewise.
* tac.c (xwrite): Give output buffer parameter const attribute.
(output): Likewise for both parameters.
(tac): Likewise for file name parameter.
(tac_file): Likewise.
Sat Oct 28 16:02:39 1995 Jim Meyering (meyering@comco.com)
* md5sum.c (md5_check): Use the same message format when there is
a single file and it gets a read error or checksum mismatch as when
there are more. Suggestion from Greg Troxel (gdt@b-sgi.bbn.com).
Thu Oct 26 00:11:35 1995 Jim Meyering (meyering@comco.com)
* sort.c (xtmpfopen): New function to set proper permissions on
temporary files. Use it instead of xfopen. Reported by Erik Corry
(erik@kroete2.freinet.de).
Mon Oct 23 23:17:04 1995 Jim Meyering (meyering@comco.com)
* aclocal.m4 (jm_WITH_AUTODEPS): New directive.
* configure.in: Use it.
* lib/Makefile.in (INCLUDE, COMPILE): New variables.
(.c.o): Rewrite to be more like src/Makefile.in.
* src/Makefile.in (distclean): Remove .deps.
Include @top_srcdir@/mkdep-Makefile.
* mkdep.Makefile: New file.
* Makefile.in (DISTFILES): Add mkdep-Makefile.
* doc/Makefile.in (mostlyclean): Also remove *.info.
Thu Oct 19 17:38:28 1995 Jim Meyering (meyering@comco.com)
* od.c: Indent cpp directives.
* tr.c (BEGIN_STATE): Use INT_MAX - 1 so as not to interfere
with large repeat counts.
(struct E_string): New struct.
(find_closing_delim): Take E_string arg rather than char* and length.
(find_bracketed_repeat): Likewise.
(star_digits_closebracket): New function.
(append_char_class): No longer give diagnostic.
(append_equiv_class): Likewise.
(build_spec_list): Give them here instead, allowing string1 like
[:*][:upper:] that got errors before.
Take E_string arg rather than char*.
Convert switch stmts into if-then so as to use ES_MATCH.
Tue Oct 17 22:48:00 1995 Jim Meyering (meyering@comco.com)
* cat.c: Protoize. Reorder functions to obviate forward dcls.
Remove forward dcls.
* expand.c: Likewise.
* fold.c: Likewise.
* head.c: Likewise.
* od.c: Likewise.
* sort.c: Likewise.
* tail.c: Likewise.
* src/Makefile.in (OBJECTS): Reflect that all of the above
now use prototypes.
* head.c: Add `const' attribute to dcls of lots of formals.
* sort.c: Add `const' attribute to dcls of lots of formals.
Move struct dcls to precede dcls of file-scope variables.
(monthtab, keyhead): Separate variable dcls from type dcls.
Fri Oct 13 20:38:39 1995 Jim Meyering (meyering@comco.com)
* join.c (add_field_list): Allow SPACE and TAB as well as `,' as
list item separators, per POSIX spec.
(prjoin): Rewrite loop that iterates over field specs.
Handle case in which file spec is 0.
Sun Oct 8 22:41:15 1995 Jim Meyering (meyering@comco.com)
* strpbrk.c: New file.
* lib/Makefile.in (SOURCES): Add strpbrk.c.
Remove bcopy.c.
Sat Oct 7 22:27:01 1995 Jim Meyering (meyering@comco.com)
* join.c (add_field): No longer return a value.
(decode_field_spec): New function.
(add_field_list): Rewrite to be more strict.
Before, `,1.2' was accepted as valid.
(main): Use xstrtol instead atoi.
Combine nearly identical -a and -v cases.
Close input files.
Fri Oct 6 23:10:01 1995 Jim Meyering (meyering@comco.com)
* join.c (main): Report `too few/many non-option arguments'
then print --help output rather than just the latter.
Properly interpret obsolescent usage like `join -o 2.1 2.1 2.2'.
(usage): Describe POSIX -1, -2 options and deprecate -j* ones
* join.c (usage): Move to precede all other functions.
* join.c: Protoize.
Tue Oct 3 22:44:05 1995 Jim Meyering (meyering@comco.com)
* csplit.c, sort.c, tac.c: Test SA_INTERRUPT, not _POSIX_VERSION,
to determine whether `sigaction' functions are available.
Reported by Paul Nevai <nevai@ops.mps.ohio-state.edu>.
Fix suggested by Karl Berry.
* md5sum.c (main): Declare counter, N_STRINGS, to be an integral
type, not `char'.
* cut.c: Convert many declarations using `int' to use `unsigned int'
to avoid warnings from `gcc -Wall' about comparing signed and
unsigned types.
(set_fields): Use memset (not open coded loop) to initialize array.
Thu Sep 28 23:16:05 1995 Jim Meyering (meyering@comco.com)
* Version 1.13.
* Makefile.in (DISTFILES): Remove README.alpha for major release.
* od.c (decode_one_format): Remove spurious semicolon.
From John Kodis (kodis@daacdev1.stx.com).
Tue Sep 26 23:05:01 1995 Jim Meyering (meyering@comco.com)
* man/Makefile.in (install-data, uninstall): Use sed not basename.
The GNU Coding Standard suggests that only a select set of
relatively standard utilities be used in Makefiles. basename is
not among them. Suggested by Ulrich Drepper.
Sun Sep 24 08:36:47 1995 Jim Meyering (meyering@comco.com)
* cksum.c: Protoize.
* cut.c: Protoize.
* src/Makefile.in (OBJECTS): Reflect that cksum.c and cut.c use
prototypes.
(cksum): Depend on cksum$O.
(cut): Depend on cut$O.
Sat Sep 23 15:43:46 1995 Jim Meyering (meyering@comco.com)
* Version 1.12.2.
* Makefile.in (DISTFILES): Add README.alpha.
* lib/Makfile.in: (GETOPT, MEMCHR, REGEX): New variables.
(OBJECTS): Use them instead of hardcoding object file names.
Suggested by Ulrich Drepper.
* md5sum.c (md5_check): Distinguish between open/read failure
and checksum mismatch.
Mon Sep 18 23:15:05 1995 Jim Meyering (meyering@comco.com)
* md5sum.c: Protoize.
* src/Makefile.in (OBJECTS): Change md5sum.o to md5sum$O.
(join.o, md5sum$O, sort.o) Depend on ../lib/long-options.h.
(md5sum): Depend on md5sum$O.
* md5sum.c (main, usage): Remove -h, -s, -v short options.
Rename --verbose to --warn, --quiet to --status.
(main): Handle --help and --version using parse_long_options.
(md5_check): Check ferror.
* sort.c (tempname): Replace `16' with a more readable expansion.
Make sure that counter never exceeds 99999.
(checkfp): Rearrange loop to avoid duplicate test.
Move a couple dcls from function scope into inner block.
Tue Aug 8 21:49:27 1995 Jim Meyering (meyering@comco.com)
* md5sum.c (main): Fail if either --verbose or --quiet is specified
@@ -5,7 +206,7 @@ Tue Aug 8 21:49:27 1995 Jim Meyering (meyering@comco.com)
* md5sum.c (md5_check): Fail if no valid line is found.
Don't use the word `fail' unless there were failures --
say `all N tests passed.'
instead, say `all N tests passed.'
* md5sum.c (main) [handling --string option]: Don't output
nonstandard `b' binary flag. From Greg Troxel (gdt@bbn.com).

View File

@@ -1,4 +1,13 @@
User-visible changes in release 1.14
* join accepts POSIX `-o 0' field specifier.
* tr 'a[b*512]' '[a*]' < /dev/null terminates
* tr '[:*3][:digit:]' 'a-m' and tr 'a[=*2][=c=]' 'xyyz' no longer fail
* special characters in tr's string1 and string2 may be escaped with backslash
User-visible changes in release 1.13
* md5sum: with --check, distinguish between open/read failure and bad checksum
* md5sum: remove -h, -s, -v short options
* md5sum: rename --verbose to --warn, --quiet to --status
* md5sum --check fails if it finds no properly formatted checksum lines
* sort -c prints `disorder on...' message on standard error, not stdout
* sort -k works as described in the texinfo documentation
* tail works on NetBSD

681
src/cat.c
View File

@@ -14,11 +14,11 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/* Differences from the Unix cat:
* Always unbuffered, -u is ignored.
* 100 times faster with -v -u.
* 20 times faster with -v.
* Usually much faster than other versions of cat, the difference
is especially apparent when using the -v option.
By tege@sics.se, Torbjorn Granlund, advised by rms, Richard Stallman. */
@@ -43,10 +43,6 @@ char *xmalloc ();
int full_write ();
int safe_read ();
static void cat ();
static void next_line_num ();
static void simple_cat ();
/* Name under which this program was invoked. */
char *program_name;
@@ -80,8 +76,7 @@ static int newlines2 = 0;
static int exit_stat = 0;
static void
usage (status)
int status;
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
@@ -114,11 +109,338 @@ With no FILE, or when FILE is -, read standard input.\n\
exit (status);
}
/* Compute the next line number. */
static void
next_line_num (void)
{
char *endp = line_num_end;
do
{
if ((*endp)++ < '9')
return;
*endp-- = '0';
}
while (endp >= line_num_start);
*--line_num_start = '1';
if (line_num_start < line_num_print)
line_num_print--;
}
/* Plain cat. Copies the file behind `input_desc' to the file behind
`output_desc'. */
static void
simple_cat (
/* Pointer to the buffer, used by reads and writes. */
unsigned char *buf,
/* Number of characters preferably read or written by each read and write
call. */
int bufsize)
{
/* Actual number of characters read, and therefore written. */
int n_read;
/* Loop until the end of the file. */
for (;;)
{
/* Read a block of input. */
n_read = safe_read (input_desc, buf, bufsize);
if (n_read < 0)
{
error (0, errno, "%s", infile);
exit_stat = 1;
return;
}
/* End of this file? */
if (n_read == 0)
break;
/* Write this block out. */
if (full_write (output_desc, buf, n_read) < 0)
error (1, errno, _("write error"));
}
}
/* Cat the file behind INPUT_DESC to the file behind OUTPUT_DESC.
Called if any option more than -u was specified.
A newline character is always put at the end of the buffer, to make
an explicit test for buffer end unnecessary. */
static void
cat (
/* Pointer to the beginning of the input buffer. */
unsigned char *inbuf,
/* Number of characters read in each read call. */
int insize,
/* Pointer to the beginning of the output buffer. */
unsigned char *outbuf,
/* Number of characters written by each write call. */
int outsize,
/* Variables that have values according to the specified options. */
int quote,
int output_tabs,
int numbers,
int numbers_at_empty_lines,
int mark_line_ends,
int squeeze_empty_lines)
{
/* Last character read from the input buffer. */
unsigned char ch;
/* Pointer to the next character in the input buffer. */
unsigned char *bpin;
/* Pointer to the first non-valid byte in the input buffer, i.e. the
current end of the buffer. */
unsigned char *eob;
/* Pointer to the position where the next character shall be written. */
unsigned char *bpout;
/* Number of characters read by the last read call. */
int n_read;
/* Determines how many consecutive newlines there have been in the
input. 0 newlines makes NEWLINES -1, 1 newline makes NEWLINES 1,
etc. Initially 0 to indicate that we are at the beginning of a
new line. The "state" of the procedure is determined by
NEWLINES. */
int newlines = newlines2;
#ifdef FIONREAD
/* If nonzero, use the FIONREAD ioctl, as an optimization.
(On Ultrix, it is not supported on NFS filesystems.) */
int use_fionread = 1;
#endif
/* The inbuf pointers are initialized so that BPIN > EOB, and thereby input
is read immediately. */
eob = inbuf;
bpin = eob + 1;
bpout = outbuf;
for (;;)
{
do
{
/* Write if there are at least OUTSIZE bytes in OUTBUF. */
if (bpout - outbuf >= outsize)
{
unsigned char *wp = outbuf;
do
{
if (full_write (output_desc, wp, outsize) < 0)
error (1, errno, _("write error"));
wp += outsize;
}
while (bpout - wp >= outsize);
/* Move the remaining bytes to the beginning of the
buffer. */
memmove (outbuf, wp, bpout - wp);
bpout = outbuf + (bpout - wp);
}
/* Is INBUF empty? */
if (bpin > eob)
{
#ifdef FIONREAD
int n_to_read = 0;
/* Is there any input to read immediately?
If not, we are about to wait,
so write all buffered output before waiting. */
if (use_fionread
&& ioctl (input_desc, FIONREAD, &n_to_read) < 0)
{
/* Ultrix returns EOPNOTSUPP on NFS;
HP-UX returns ENOTTY on pipes.
SunOS returns EINVAL and
More/BSD returns ENODEV on special files
like /dev/null.
Irix-5 returns ENOSYS on pipes. */
if (errno == EOPNOTSUPP || errno == ENOTTY
|| errno == EINVAL || errno == ENODEV
#ifdef ENOSYS
|| errno == ENOSYS
#endif
)
use_fionread = 0;
else
{
error (0, errno, _("cannot do ioctl on `%s'"), infile);
exit_stat = 1;
newlines2 = newlines;
return;
}
}
if (n_to_read == 0)
#endif
{
int n_write = bpout - outbuf;
if (full_write (output_desc, outbuf, n_write) < 0)
error (1, errno, _("write error"));
bpout = outbuf;
}
/* Read more input into INBUF. */
n_read = safe_read (input_desc, inbuf, insize);
if (n_read < 0)
{
error (0, errno, "%s", infile);
exit_stat = 1;
newlines2 = newlines;
return;
}
if (n_read == 0)
{
newlines2 = newlines;
return;
}
/* Update the pointers and insert a sentinel at the buffer
end. */
bpin = inbuf;
eob = bpin + n_read;
*eob = '\n';
}
else
{
/* It was a real (not a sentinel) newline. */
/* Was the last line empty?
(i.e. have two or more consecutive newlines been read?) */
if (++newlines > 0)
{
/* Are multiple adjacent empty lines to be substituted by
single ditto (-s), and this was the second empty line? */
if (squeeze_empty_lines && newlines >= 2)
{
ch = *bpin++;
continue;
}
/* Are line numbers to be written at empty lines (-n)? */
if (numbers && numbers_at_empty_lines)
{
next_line_num ();
bpout = (unsigned char *) stpcpy (bpout, line_num_print);
}
}
/* Output a currency symbol if requested (-e). */
if (mark_line_ends)
*bpout++ = '$';
/* Output the newline. */
*bpout++ = '\n';
}
ch = *bpin++;
}
while (ch == '\n');
/* Are we at the beginning of a line, and line numbers are requested? */
if (newlines >= 0 && numbers)
{
next_line_num ();
bpout = (unsigned char *) stpcpy (bpout, line_num_print);
}
/* Here CH cannot contain a newline character. */
/* The loops below continue until a newline character is found,
which means that the buffer is empty or that a proper newline
has been found. */
/* If quoting, i.e. at least one of -v, -e, or -t specified,
scan for chars that need conversion. */
if (quote)
for (;;)
{
if (ch >= 32)
{
if (ch < 127)
*bpout++ = ch;
else if (ch == 127)
*bpout++ = '^',
*bpout++ = '?';
else
{
*bpout++ = 'M',
*bpout++ = '-';
if (ch >= 128 + 32)
if (ch < 128 + 127)
*bpout++ = ch - 128;
else
*bpout++ = '^',
*bpout++ = '?';
else
*bpout++ = '^',
*bpout++ = ch - 128 + 64;
}
}
else if (ch == '\t' && output_tabs)
*bpout++ = '\t';
else if (ch == '\n')
{
newlines = -1;
break;
}
else
*bpout++ = '^',
*bpout++ = ch + 64;
ch = *bpin++;
}
else
/* Not quoting, neither of -v, -e, or -t specified. */
for (;;)
{
if (ch == '\t' && !output_tabs)
*bpout++ = '^',
*bpout++ = ch + 64;
else if (ch != '\n')
*bpout++ = ch;
else
{
newlines = -1;
break;
}
ch = *bpin++;
}
}
}
void
main (argc, argv)
int argc;
char *argv[];
main (int argc, char **argv)
{
/* Optimal size of i/o operations of output. */
int outsize;
@@ -397,336 +719,3 @@ main (argc, argv)
exit (exit_stat);
}
/* Plain cat. Copies the file behind `input_desc' to the file behind
`output_desc'. */
static void
simple_cat (buf, bufsize)
/* Pointer to the buffer, used by reads and writes. */
unsigned char *buf;
/* Number of characters preferably read or written by each read and write
call. */
int bufsize;
{
/* Actual number of characters read, and therefore written. */
int n_read;
/* Loop until the end of the file. */
for (;;)
{
/* Read a block of input. */
n_read = safe_read (input_desc, buf, bufsize);
if (n_read < 0)
{
error (0, errno, "%s", infile);
exit_stat = 1;
return;
}
/* End of this file? */
if (n_read == 0)
break;
/* Write this block out. */
if (full_write (output_desc, buf, n_read) < 0)
error (1, errno, _("write error"));
}
}
/* Cat the file behind INPUT_DESC to the file behind OUTPUT_DESC.
Called if any option more than -u was specified.
A newline character is always put at the end of the buffer, to make
an explicit test for buffer end unnecessary. */
static void
cat (inbuf, insize, outbuf, outsize, quote,
output_tabs, numbers, numbers_at_empty_lines,
mark_line_ends, squeeze_empty_lines)
/* Pointer to the beginning of the input buffer. */
unsigned char *inbuf;
/* Number of characters read in each read call. */
int insize;
/* Pointer to the beginning of the output buffer. */
unsigned char *outbuf;
/* Number of characters written by each write call. */
int outsize;
/* Variables that have values according to the specified options. */
int quote;
int output_tabs;
int numbers;
int numbers_at_empty_lines;
int mark_line_ends;
int squeeze_empty_lines;
{
/* Last character read from the input buffer. */
unsigned char ch;
/* Pointer to the next character in the input buffer. */
unsigned char *bpin;
/* Pointer to the first non-valid byte in the input buffer, i.e. the
current end of the buffer. */
unsigned char *eob;
/* Pointer to the position where the next character shall be written. */
unsigned char *bpout;
/* Number of characters read by the last read call. */
int n_read;
/* Determines how many consecutive newlines there have been in the
input. 0 newlines makes NEWLINES -1, 1 newline makes NEWLINES 1,
etc. Initially 0 to indicate that we are at the beginning of a
new line. The "state" of the procedure is determined by
NEWLINES. */
int newlines = newlines2;
#ifdef FIONREAD
/* If nonzero, use the FIONREAD ioctl, as an optimization.
(On Ultrix, it is not supported on NFS filesystems.) */
int use_fionread = 1;
#endif
/* The inbuf pointers are initialized so that BPIN > EOB, and thereby input
is read immediately. */
eob = inbuf;
bpin = eob + 1;
bpout = outbuf;
for (;;)
{
do
{
/* Write if there are at least OUTSIZE bytes in OUTBUF. */
if (bpout - outbuf >= outsize)
{
unsigned char *wp = outbuf;
do
{
if (full_write (output_desc, wp, outsize) < 0)
error (1, errno, _("write error"));
wp += outsize;
}
while (bpout - wp >= outsize);
/* Move the remaining bytes to the beginning of the
buffer. */
memmove (outbuf, wp, bpout - wp);
bpout = outbuf + (bpout - wp);
}
/* Is INBUF empty? */
if (bpin > eob)
{
#ifdef FIONREAD
int n_to_read = 0;
/* Is there any input to read immediately?
If not, we are about to wait,
so write all buffered output before waiting. */
if (use_fionread
&& ioctl (input_desc, FIONREAD, &n_to_read) < 0)
{
/* Ultrix returns EOPNOTSUPP on NFS;
HP-UX returns ENOTTY on pipes.
SunOS returns EINVAL and
More/BSD returns ENODEV on special files
like /dev/null.
Irix-5 returns ENOSYS on pipes. */
if (errno == EOPNOTSUPP || errno == ENOTTY
|| errno == EINVAL || errno == ENODEV
#ifdef ENOSYS
|| errno == ENOSYS
#endif
)
use_fionread = 0;
else
{
error (0, errno, _("cannot do ioctl on `%s'"), infile);
exit_stat = 1;
newlines2 = newlines;
return;
}
}
if (n_to_read == 0)
#endif
{
int n_write = bpout - outbuf;
if (full_write (output_desc, outbuf, n_write) < 0)
error (1, errno, _("write error"));
bpout = outbuf;
}
/* Read more input into INBUF. */
n_read = safe_read (input_desc, inbuf, insize);
if (n_read < 0)
{
error (0, errno, "%s", infile);
exit_stat = 1;
newlines2 = newlines;
return;
}
if (n_read == 0)
{
newlines2 = newlines;
return;
}
/* Update the pointers and insert a sentinel at the buffer
end. */
bpin = inbuf;
eob = bpin + n_read;
*eob = '\n';
}
else
{
/* It was a real (not a sentinel) newline. */
/* Was the last line empty?
(i.e. have two or more consecutive newlines been read?) */
if (++newlines > 0)
{
/* Are multiple adjacent empty lines to be substituted by
single ditto (-s), and this was the second empty line? */
if (squeeze_empty_lines && newlines >= 2)
{
ch = *bpin++;
continue;
}
/* Are line numbers to be written at empty lines (-n)? */
if (numbers && numbers_at_empty_lines)
{
next_line_num ();
bpout = (unsigned char *) stpcpy (bpout, line_num_print);
}
}
/* Output a currency symbol if requested (-e). */
if (mark_line_ends)
*bpout++ = '$';
/* Output the newline. */
*bpout++ = '\n';
}
ch = *bpin++;
}
while (ch == '\n');
/* Are we at the beginning of a line, and line numbers are requested? */
if (newlines >= 0 && numbers)
{
next_line_num ();
bpout = (unsigned char *) stpcpy (bpout, line_num_print);
}
/* Here CH cannot contain a newline character. */
/* The loops below continue until a newline character is found,
which means that the buffer is empty or that a proper newline
has been found. */
/* If quoting, i.e. at least one of -v, -e, or -t specified,
scan for chars that need conversion. */
if (quote)
for (;;)
{
if (ch >= 32)
{
if (ch < 127)
*bpout++ = ch;
else if (ch == 127)
*bpout++ = '^',
*bpout++ = '?';
else
{
*bpout++ = 'M',
*bpout++ = '-';
if (ch >= 128 + 32)
if (ch < 128 + 127)
*bpout++ = ch - 128;
else
*bpout++ = '^',
*bpout++ = '?';
else
*bpout++ = '^',
*bpout++ = ch - 128 + 64;
}
}
else if (ch == '\t' && output_tabs)
*bpout++ = '\t';
else if (ch == '\n')
{
newlines = -1;
break;
}
else
*bpout++ = '^',
*bpout++ = ch + 64;
ch = *bpin++;
}
else
/* Not quoting, neither of -v, -e, or -t specified. */
for (;;)
{
if (ch == '\t' && !output_tabs)
*bpout++ = '^',
*bpout++ = ch + 64;
else if (ch != '\n')
*bpout++ = ch;
else
{
newlines = -1;
break;
}
ch = *bpin++;
}
}
}
/* Compute the next line number. */
static void
next_line_num ()
{
char *endp = line_num_end;
do
{
if ((*endp)++ < '9')
return;
*endp-- = '0';
}
while (endp >= line_num_start);
*--line_num_start = '1';
if (line_num_start < line_num_print)
line_num_print--;
}

View File

@@ -23,6 +23,18 @@
#include <grp.h>
#include <getopt.h>
#if HAVE_LIMITS_H
# include <limits.h>
#endif
#ifndef UINT_MAX
# define UINT_MAX ((unsigned int) ~(unsigned int) 0)
#endif
#ifndef INT_MAX
# define INT_MAX ((int) (UINT_MAX >> 1))
#endif
#include "system.h"
#include "version.h"
#include "xstrtoul.h"
@@ -32,8 +44,8 @@
struct group *getgrnam ();
#endif
#ifdef _POSIX_VERSION
#define endgrent()
#ifndef HAVE_ENDGRENT
# define endgrent() ((void) 0)
#endif
char *group_member ();

View File

@@ -45,9 +45,8 @@ struct group *getgrnam ();
struct group *getgrgid ();
#endif
#ifdef _POSIX_SOURCE
#define endgrent()
#define endpwent()
#ifndef HAVE_ENDPWENT
# define endpwent() ((void) 0)
#endif
char *savedir ();

View File

@@ -195,9 +195,7 @@ static int have_read_stdin;
Return 0 if successful, -1 if an error occurs. */
static int
cksum (file, print_name)
char *file;
int print_name;
cksum (char *file, int print_name)
{
unsigned char buf[BUFLEN];
unsigned long crc = 0;
@@ -261,8 +259,7 @@ cksum (file, print_name)
}
static void
usage (status)
int status;
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
@@ -284,9 +281,7 @@ Print CRC checksum and byte counts of each FILE.\n\
}
void
main (argc, argv)
int argc;
char **argv;
main (int argc, char **argv)
{
int i, c;
int errors = 0;

View File

@@ -42,10 +42,13 @@ struct dir_attr
struct dir_attr *next;
};
int stat ();
int lstat ();
char *dirname ();
char *xstrdup ();
enum backup_type get_version ();
int eaccess_stat ();
int euidaccess ();
int full_write ();
static int do_copy ();
@@ -553,7 +556,7 @@ copy (src_path, dst_path, new_dst, device, ancestors)
{
if (flag_interactive)
{
if (eaccess_stat (&dst_sb, W_OK, dst_path) != 0)
if (euidaccess (dst_path, W_OK) != 0)
fprintf (stderr,
"%s: overwrite `%s', overriding mode %04o? ",
program_name, dst_path,
@@ -591,7 +594,7 @@ copy (src_path, dst_path, new_dst, device, ancestors)
if (S_ISDIR (dst_sb.st_mode))
{
/* Temporarily change mode to allow overwriting. */
if (eaccess_stat (&dst_sb, W_OK | X_OK) != 0)
if (euidaccess (dst_path, W_OK | X_OK) != 0)
{
if (chmod (dst_path, 0700))
{

View File

@@ -1435,9 +1435,9 @@ main (argc, argv)
char **argv;
{
int optc;
#ifdef _POSIX_VERSION
#ifdef SA_INTERRUPT
struct sigaction oldact, newact;
#endif /* _POSIX_VERSION */
#endif /* SA_INTERRUPT */
program_name = argv[0];
global_argv = argv;
@@ -1447,7 +1447,7 @@ main (argc, argv)
remove_files = TRUE;
prefix = DEFAULT_PREFIX;
#ifdef _POSIX_VERSION
#ifdef SA_INTERRUPT
newact.sa_handler = interrupt_handler;
sigemptyset (&newact.sa_mask);
newact.sa_flags = 0;
@@ -1467,7 +1467,7 @@ main (argc, argv)
sigaction (SIGTERM, NULL, &oldact);
if (oldact.sa_handler != SIG_IGN)
sigaction (SIGTERM, &newact, NULL);
#else /* !_POSIX_VERSION */
#else
if (signal (SIGHUP, SIG_IGN) != SIG_IGN)
signal (SIGHUP, interrupt_handler);
if (signal (SIGINT, SIG_IGN) != SIG_IGN)

View File

@@ -104,8 +104,8 @@
struct range_pair
{
int lo;
int hi;
unsigned int lo;
unsigned int hi;
};
char *xmalloc ();
@@ -127,11 +127,11 @@ static int field_1_bufsize;
or degenerate range specification; this doesn't include the starting
index of right-open-ended ranges. For example, with either range spec
`2-5,9-', `2-3,5,9-' this variable would be set to 5. */
static int max_range_endpoint;
static unsigned int max_range_endpoint;
/* If nonzero, this is the index of the first field in a range that goes
to end of line. */
static int eol_range_start;
static unsigned int eol_range_start;
/* In byte mode, which bytes to output.
In field mode, which DELIM-separated fields to output.
@@ -188,8 +188,7 @@ static struct option const longopts[] =
};
static void
usage (status)
int status;
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
@@ -243,11 +242,7 @@ With no FILE, or when FILE is -, read standard input.\n\
including the null terminator), or -1 on error or EOF. */
static int
getstr (lineptr, n, stream, terminator)
char **lineptr;
int *n;
FILE *stream;
char terminator;
getstr (char **lineptr, int *n, FILE *stream, char terminator)
{
int nchars_avail; /* Allocated but unused chars in *LINEPTR. */
char *read_pos; /* Where we're reading into *LINEPTR. */
@@ -314,10 +309,9 @@ getstr (lineptr, n, stream, terminator)
}
static int
print_kth (k)
int k;
print_kth (unsigned int k)
{
return ((eol_range_start > 0 && eol_range_start <= k)
return ((0 < eol_range_start && eol_range_start <= k)
|| (k <= max_range_endpoint && printable_field[k]));
}
@@ -338,12 +332,11 @@ print_kth (k)
one bit per field index instead of a whole `int' per index. */
static int
set_fields (fieldstr)
const char *fieldstr;
set_fields (const char *fieldstr)
{
int initial = 1; /* Value of first number in a range. */
unsigned int initial = 1; /* Value of first number in a range. */
unsigned int value = 0; /* If nonzero, a number being accumulated. */
int dash_found = 0; /* Nonzero if a '-' is found in this field. */
int value = 0; /* If nonzero, a number being accumulated. */
int field_found = 0; /* Non-zero if at least one field spec
has been processed. */
@@ -409,7 +402,7 @@ set_fields (fieldstr)
/* No, the new sequence starts before the
old. Does the old range going to end of line
extend into the new range? */
if (value >= eol_range_start - 1)
if (value + 1 >= eol_range_start)
{
/* Yes. Simply move the end of line marker. */
eol_range_start = initial;
@@ -471,13 +464,12 @@ set_fields (fieldstr)
(i.e. `2-6' or `-4', but not `5-') in FIELDSTR. */
printable_field = (int *) xmalloc ((max_range_endpoint + 1) * sizeof (int));
for (i = 1; i <= max_range_endpoint; i++)
printable_field[i] = 0;
memset (printable_field, 0, (max_range_endpoint + 1) * sizeof (int));
/* Set the array entries corresponding to integers in the ranges of RP. */
for (i = 0; i < n_rp; i++)
{
int j;
unsigned int j;
for (j = rp[i].lo; j <= rp[i].hi; j++)
{
printable_field[j] = 1;
@@ -492,10 +484,9 @@ set_fields (fieldstr)
/* Read from stream STREAM, printing to standard output any selected bytes. */
static void
cut_bytes (stream)
FILE *stream;
cut_bytes (FILE *stream)
{
int byte_idx; /* Number of chars in the line so far. */
unsigned int byte_idx; /* Number of chars in the line so far. */
byte_idx = 0;
while (1)
@@ -529,11 +520,10 @@ cut_bytes (stream)
/* Read from stream STREAM, printing to standard output any selected fields. */
static void
cut_fields (stream)
FILE *stream;
cut_fields (FILE *stream)
{
int c;
int field_idx;
unsigned int field_idx;
int found_any_selected_field;
int buffer_first_field;
@@ -632,8 +622,7 @@ cut_fields (stream)
}
static void
cut_stream (stream)
FILE *stream;
cut_stream (FILE *stream)
{
if (operating_mode == byte_mode)
cut_bytes (stream);
@@ -645,8 +634,7 @@ cut_stream (stream)
Return 0 if successful, 1 if not. */
static int
cut_file (file)
char *file;
cut_file (char *file)
{
FILE *stream;
@@ -683,9 +671,7 @@ cut_file (file)
}
void
main (argc, argv)
int argc;
char **argv;
main (int argc, char **argv)
{
int optc, exit_status = 0;

View File

@@ -64,6 +64,7 @@ static struct option const long_options[] =
{"date", required_argument, NULL, 'd'},
{"file", required_argument, NULL, 'f'},
{"help", no_argument, &show_help, 1},
{"reference", required_argument, NULL, 'r'},
{"set", required_argument, NULL, 's'},
{"uct", no_argument, NULL, 'u'},
{"utc", no_argument, NULL, 'u'},
@@ -82,7 +83,6 @@ batch_convert (input_filename, format)
const char *input_filename;
const char *format;
{
int have_read_stdin;
int status;
FILE *in_stream;
char *line;
@@ -94,7 +94,6 @@ batch_convert (input_filename, format)
{
input_filename = _("standard input");
in_stream = stdin;
have_read_stdin = 1;
}
else
{
@@ -103,7 +102,6 @@ batch_convert (input_filename, format)
{
error (0, errno, "%s", input_filename);
}
have_read_stdin = 0;
}
line = NULL;
@@ -132,8 +130,8 @@ batch_convert (input_filename, format)
}
}
if (have_read_stdin && fclose (stdin) == EOF)
error (2, errno, _("standard input"));
if (fclose (in_stream) == EOF)
error (2, errno, input_filename);
if (line != NULL)
free (line);
@@ -148,31 +146,36 @@ main (argc, argv)
{
int optc;
const char *datestr = NULL;
const char *set_datestr = NULL;
time_t when;
int set_date = 0;
int print_date = 0;
char *format;
char *batch_file = NULL;
char *reference = NULL;
struct stat refstats;
int n_args;
int status;
int option_specified_date;
program_name = argv[0];
while ((optc = getopt_long (argc, argv, "d:f:s:u", long_options, (int *) 0))
!= EOF)
while (optc = getopt_long (argc, argv, "d:f:r:s:u", long_options, (int *) 0),
optc != EOF)
switch (optc)
{
case 0:
break;
case 'd':
datestr = optarg;
print_date = 1;
break;
case 'f':
batch_file = optarg;
break;
case 'r':
reference = optarg;
break;
case 's':
datestr = optarg;
set_datestr = optarg;
set_date = 1;
break;
case 'u':
@@ -193,7 +196,18 @@ main (argc, argv)
n_args = argc - optind;
if (set_date && print_date)
option_specified_date = ((datestr ? 1 : 0)
+ (batch_file ? 1 : 0)
+ (reference ? 1 : 0));
if (option_specified_date > 1)
{
error (0, 0,
_("the options to specify dates for printing are mutually exclusive"));
usage (1);
}
if (set_date && option_specified_date)
{
error (0, 0,
_("the options to print and set the time may not be used together"));
@@ -206,23 +220,20 @@ main (argc, argv)
usage (1);
}
if ((set_date || print_date || batch_file != NULL)
if ((set_date || option_specified_date)
&& n_args == 1 && argv[optind][0] != '+')
{
error (0, 0, _("\
when using the print, set time, or batch options, any\n\
when using an option to specify date(s), any\n\
non-option argument must be a format string beginning with `+'"));
usage (1);
}
if (set_date)
datestr = set_datestr;
if (batch_file != NULL)
{
if (set_date || print_date)
{
error (0, 0, _("\
neither print nor set options may be used when reading dates from a file"));
usage (1);
}
status = batch_convert (batch_file,
(n_args == 1 ? argv[optind] + 1 : NULL));
}
@@ -230,7 +241,7 @@ neither print nor set options may be used when reading dates from a file"));
{
status = 0;
if (!print_date && !set_date)
if (!option_specified_date && !set_date)
{
if (n_args == 1 && argv[optind][0] != '+')
{
@@ -244,7 +255,6 @@ neither print nor set options may be used when reading dates from a file"));
else
{
/* Prepare to print the current date/time. */
print_date = 1;
datestr = _("undefined");
time (&when);
format = (n_args == 1 ? argv[optind] + 1 : NULL);
@@ -252,8 +262,15 @@ neither print nor set options may be used when reading dates from a file"));
}
else
{
/* (print_date || set_date) */
when = get_date (datestr, NULL);
/* (option_specified_date || set_date) */
if (reference != NULL)
{
if (stat (reference, &refstats))
error (1, errno, "%s", reference);
when = refstats.st_mtime;
}
else
when = get_date (datestr, NULL);
format = (n_args == 1 ? argv[optind] + 1 : NULL);
}
@@ -337,6 +354,7 @@ Display the current time in the given FORMAT, or set the system date.\n\
\n\
-d, --date=STRING display time described by STRING, not `now'\n\
-f, --file=DATEFILE like --date once for each line of DATEFILE\n\
-r, --reference=FILE display the last modification time of FILE\n\
-s, --set=STRING set time described by STRING\n\
-u, --utc, --universal print or set Coordinated Universal Time\n\
--help display this help and exit\n\

View File

@@ -213,6 +213,29 @@ main (argc, argv)
if (show_help)
usage (0);
/* Fail if the same file system type was both selected and excluded. */
{
int match = 0;
struct fs_type_list *i;
for (i = fs_select_list; i; i = i->fs_next)
{
struct fs_type_list *j;
for (j = fs_exclude_list; j; j = j->fs_next)
{
if (strcmp (i->fs_name, j->fs_name) == 0)
{
error (0, 0,
"file system type `%s' both selected and excluded",
i->fs_name);
match = 1;
break;
}
}
}
if (match)
exit (1);
}
if (optind == argc)
{
#ifdef lint
@@ -346,12 +369,17 @@ show_point (point, statp)
{
error (0, errno, "%s", me->me_mountdir);
exit_status = 1;
me->me_dev = -2; /* So we won't try and fail repeatedly. */
/* So we won't try and fail repeatedly. */
me->me_dev = (dev_t) -2;
}
}
if (statp->st_dev == me->me_dev)
{
/* Skip bogus mtab entries. */
if (stat (me->me_mountdir, &disk_stats) != 0 ||
disk_stats.st_dev != me->me_dev)
continue;
show_dev (me->me_devname, me->me_mountdir, me->me_type);
return;
}
@@ -526,8 +554,8 @@ or all filesystems by default.\n\
-k, --kilobytes use 1024 blocks, not 512 despite POSIXLY_CORRECT\n\
--sync invoke sync before getting usage info (default)\n\
--no-sync do not invoke sync before getting usage info\n\
-t, --type=TYPE limit the listing to TYPE filesystems type\n\
-x, --exclude-type=TYPE limit the listing to not TYPE filesystems type\n\
-t, --type=TYPE limit listing to filesystems of type TYPE\n\
-x, --exclude-type=TYPE limit listing to filesystems not of type TYPE\n\
-v (ignored)\n\
-P, --portability use the POSIX output format\n\
-T, --print-type print filesystem type\n\

View File

@@ -90,6 +90,9 @@ typedef struct
char *text; /* Pointer to the text. */
} *string, stringstruct;
int stat ();
int lstat ();
char *savedir ();
char *xmalloc ();
char *xrealloc ();

View File

@@ -56,13 +56,6 @@
char *xmalloc ();
char *xrealloc ();
static FILE *next_file ();
static void add_tabstop ();
static void expand ();
static void parse_tabstops ();
static void usage ();
static void validate_tabstops ();
/* The name this program was run with. */
char *program_name;
@@ -112,90 +105,53 @@ static struct option const longopts[] =
{NULL, 0, NULL, 0}
};
void
main (argc, argv)
int argc;
char **argv;
static void
usage (int status)
{
int tabval = -1; /* Value of tabstop being read, or -1. */
int c; /* Option character. */
have_read_stdin = 0;
exit_status = 0;
convert_entire_line = 1;
tab_list = NULL;
first_free_tab = 0;
program_name = argv[0];
while ((c = getopt_long (argc, argv, "it:,0123456789", longopts, (int *) 0))
!= EOF)
{
switch (c)
{
case 0:
break;
case '?':
usage (1);
case 'i':
convert_entire_line = 0;
break;
case 't':
parse_tabstops (optarg);
break;
case ',':
add_tabstop (tabval);
tabval = -1;
break;
default:
if (tabval == -1)
tabval = 0;
tabval = tabval * 10 + c - '0';
break;
}
}
if (show_version)
{
printf ("expand - %s\n", version_string);
exit (0);
}
if (show_help)
usage (0);
add_tabstop (tabval);
validate_tabstops (tab_list, first_free_tab);
if (first_free_tab == 0)
tab_size = 8;
else if (first_free_tab == 1)
tab_size = tab_list[0];
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
tab_size = 0;
{
printf (_("\
Usage: %s [OPTION]... [FILE]...\n\
"),
program_name);
printf (_("\
Convert tabs in each FILE to spaces, writing to standard output.\n\
With no FILE, or when FILE is -, read standard input.\n\
\n\
-i, --initial do not convert TABs after non whitespace\n\
-t, --tabs=NUMBER have tabs NUMBER characters apart, not 8\n\
-t, --tabs=LIST use comma separated list of explicit tab positions\n\
--help display this help and exit\n\
--version output version information and exit\n\
\n\
Instead of -t NUMBER or -t LIST, -NUMBER or -LIST may be used.\n\
"));
}
exit (status);
}
if (optind == argc)
file_list = stdin_argv;
else
file_list = &argv[optind];
/* Add tab stop TABVAL to the end of `tab_list', except
if TABVAL is -1, do nothing. */
expand ();
if (have_read_stdin && fclose (stdin) == EOF)
error (1, errno, "-");
if (ferror (stdout) || fclose (stdout) == EOF)
error (1, errno, _("write error"));
exit (exit_status);
static void
add_tabstop (int tabval)
{
if (tabval == -1)
return;
if (first_free_tab % TABLIST_BLOCK == 0)
tab_list = (int *) xrealloc (tab_list, first_free_tab
+ TABLIST_BLOCK * sizeof (tab_list[0]));
tab_list[first_free_tab++] = tabval;
}
/* Add the comma or blank separated list of tabstops STOPS
to the list of tabstops. */
static void
parse_tabstops (stops)
char *stops;
parse_tabstops (char *stops)
{
int tabval = -1;
@@ -219,28 +175,11 @@ parse_tabstops (stops)
add_tabstop (tabval);
}
/* Add tab stop TABVAL to the end of `tab_list', except
if TABVAL is -1, do nothing. */
static void
add_tabstop (tabval)
int tabval;
{
if (tabval == -1)
return;
if (first_free_tab % TABLIST_BLOCK == 0)
tab_list = (int *) xrealloc (tab_list, first_free_tab
+ TABLIST_BLOCK * sizeof (tab_list[0]));
tab_list[first_free_tab++] = tabval;
}
/* Check that the list of tabstops TABS, with ENTRIES entries,
contains only nonzero, ascending values. */
static void
validate_tabstops (tabs, entries)
int *tabs;
int entries;
validate_tabstops (int *tabs, int entries)
{
int prev_tab = 0;
int i;
@@ -255,11 +194,58 @@ validate_tabstops (tabs, entries)
}
}
/* Close the old stream pointer FP if it is non-NULL,
and return a new one opened to read the next input file.
Open a filename of `-' as the standard input.
Return NULL if there are no more input files. */
static FILE *
next_file (FILE *fp)
{
static char *prev_file;
char *file;
if (fp)
{
if (ferror (fp))
{
error (0, errno, "%s", prev_file);
exit_status = 1;
}
if (fp == stdin)
clearerr (fp); /* Also clear EOF. */
else if (fclose (fp) == EOF)
{
error (0, errno, "%s", prev_file);
exit_status = 1;
}
}
while ((file = *file_list++) != NULL)
{
if (file[0] == '-' && file[1] == '\0')
{
have_read_stdin = 1;
prev_file = file;
return stdin;
}
fp = fopen (file, "r");
if (fp)
{
prev_file = file;
return fp;
}
error (0, errno, "%s", file);
exit_status = 1;
}
return NULL;
}
/* Change tabs to spaces, writing to stdout.
Read each file in `file_list', in order. */
static void
expand ()
expand (void)
{
FILE *fp; /* Input stream. */
int c; /* Each input character. */
@@ -336,79 +322,78 @@ expand ()
}
}
/* Close the old stream pointer FP if it is non-NULL,
and return a new one opened to read the next input file.
Open a filename of `-' as the standard input.
Return NULL if there are no more input files. */
static FILE *
next_file (fp)
FILE *fp;
void
main (int argc, char **argv)
{
static char *prev_file;
char *file;
int tabval = -1; /* Value of tabstop being read, or -1. */
int c; /* Option character. */
if (fp)
have_read_stdin = 0;
exit_status = 0;
convert_entire_line = 1;
tab_list = NULL;
first_free_tab = 0;
program_name = argv[0];
while ((c = getopt_long (argc, argv, "it:,0123456789", longopts, (int *) 0))
!= EOF)
{
if (ferror (fp))
switch (c)
{
error (0, errno, "%s", prev_file);
exit_status = 1;
}
if (fp == stdin)
clearerr (fp); /* Also clear EOF. */
else if (fclose (fp) == EOF)
{
error (0, errno, "%s", prev_file);
exit_status = 1;
case 0:
break;
case '?':
usage (1);
case 'i':
convert_entire_line = 0;
break;
case 't':
parse_tabstops (optarg);
break;
case ',':
add_tabstop (tabval);
tabval = -1;
break;
default:
if (tabval == -1)
tabval = 0;
tabval = tabval * 10 + c - '0';
break;
}
}
while ((file = *file_list++) != NULL)
if (show_version)
{
if (file[0] == '-' && file[1] == '\0')
{
have_read_stdin = 1;
prev_file = file;
return stdin;
}
fp = fopen (file, "r");
if (fp)
{
prev_file = file;
return fp;
}
error (0, errno, "%s", file);
exit_status = 1;
printf ("expand - %s\n", version_string);
exit (0);
}
return NULL;
}
static void
usage (status)
int status;
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
if (show_help)
usage (0);
add_tabstop (tabval);
validate_tabstops (tab_list, first_free_tab);
if (first_free_tab == 0)
tab_size = 8;
else if (first_free_tab == 1)
tab_size = tab_list[0];
else
{
printf (_("\
Usage: %s [OPTION]... [FILE]...\n\
"),
program_name);
printf (_("\
Convert tabs in each FILE to spaces, writing to standard output.\n\
With no FILE, or when FILE is -, read standard input.\n\
\n\
-i, --initial do not convert TABs after non whitespace\n\
-t, --tabs=NUMBER have tabs NUMBER characters apart, not 8\n\
-t, --tabs=LIST use comma separated list of explicit tab positions\n\
--help display this help and exit\n\
--version output version information and exit\n\
\n\
Instead of -t NUMBER or -t LIST, -NUMBER or -LIST may be used.\n\
"));
}
exit (status);
tab_size = 0;
if (optind == argc)
file_list = stdin_argv;
else
file_list = &argv[optind];
expand ();
if (have_read_stdin && fclose (stdin) == EOF)
error (1, errno, "-");
if (ferror (stdout) || fclose (stdout) == EOF)
error (1, errno, _("write error"));
exit (exit_status);
}

View File

@@ -35,9 +35,6 @@ char *xmalloc ();
/* The name this program was run with. */
char *program_name;
static int adjust_column ();
static int fold_file ();
/* If nonzero, try to break on whitespace. */
static int break_spaces;
@@ -62,10 +59,9 @@ static struct option const longopts[] =
{"version", no_argument, &show_version, 1},
{NULL, 0, NULL, 0}
};
static void
usage (status)
int status;
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
@@ -88,82 +84,30 @@ standard output.\n\
exit (status);
}
void
main (argc, argv)
int argc;
char **argv;
/* Assuming the current column is COLUMN, return the column that
printing C will move the cursor to.
The first column is 0. */
static int
adjust_column (int column, char c)
{
int width = 80;
int i;
int optc;
int errs = 0;
program_name = argv[0];
break_spaces = count_bytes = have_read_stdin = 0;
/* Turn any numeric options into -w options. */
for (i = 1; i < argc; i++)
if (!count_bytes)
{
if (argv[i][0] == '-' && ISDIGIT (argv[i][1]))
if (c == '\b')
{
char *s;
s = xmalloc (strlen (argv[i]) + 2);
s[0] = '-';
s[1] = 'w';
strcpy (s + 2, argv[i] + 1);
argv[i] = s;
if (column > 0)
column--;
}
else if (c == '\r')
column = 0;
else if (c == '\t')
column = column + 8 - column % 8;
else /* if (isprint (c)) */
column++;
}
while ((optc = getopt_long (argc, argv, "bsw:", longopts, (int *) 0))
!= EOF)
{
switch (optc)
{
case 0:
break;
case 'b': /* Count bytes rather than columns. */
count_bytes = 1;
break;
case 's': /* Break at word boundaries. */
break_spaces = 1;
break;
case 'w': /* Line width. */
width = atoi (optarg);
if (width < 1)
error (1, 0, _("%s: invalid line width"), optarg);
break;
default:
usage (1);
}
}
if (show_version)
{
printf ("fold - %s\n", version_string);
exit (0);
}
if (show_help)
usage (0);
if (argc == optind)
errs |= fold_file ("-", width);
else
for (i = optind; i < argc; i++)
errs |= fold_file (argv[i], width);
if (have_read_stdin && fclose (stdin) == EOF)
error (1, errno, "-");
if (fclose (stdout) == EOF)
error (1, errno, _("write error"));
exit (errs);
column++;
return column;
}
/* Fold file FILENAME, or standard input if FILENAME is "-",
@@ -171,9 +115,7 @@ main (argc, argv)
Return 0 if successful, 1 if an error occurs. */
static int
fold_file (filename, width)
char *filename;
int width;
fold_file (char *filename, int width)
{
FILE *istream;
register int c;
@@ -289,30 +231,78 @@ fold_file (filename, width)
return 0;
}
/* Assuming the current column is COLUMN, return the column that
printing C will move the cursor to.
The first column is 0. */
static int
adjust_column (column, c)
int column;
char c;
void
main (int argc, char **argv)
{
if (!count_bytes)
int width = 80;
int i;
int optc;
int errs = 0;
program_name = argv[0];
break_spaces = count_bytes = have_read_stdin = 0;
/* Turn any numeric options into -w options. */
for (i = 1; i < argc; i++)
{
if (c == '\b')
if (argv[i][0] == '-' && ISDIGIT (argv[i][1]))
{
if (column > 0)
column--;
char *s;
s = xmalloc (strlen (argv[i]) + 2);
s[0] = '-';
s[1] = 'w';
strcpy (s + 2, argv[i] + 1);
argv[i] = s;
}
else if (c == '\r')
column = 0;
else if (c == '\t')
column = column + 8 - column % 8;
else /* if (isprint (c)) */
column++;
}
while ((optc = getopt_long (argc, argv, "bsw:", longopts, (int *) 0))
!= EOF)
{
switch (optc)
{
case 0:
break;
case 'b': /* Count bytes rather than columns. */
count_bytes = 1;
break;
case 's': /* Break at word boundaries. */
break_spaces = 1;
break;
case 'w': /* Line width. */
width = atoi (optarg);
if (width < 1)
error (1, 0, _("%s: invalid line width"), optarg);
break;
default:
usage (1);
}
}
if (show_version)
{
printf ("fold - %s\n", version_string);
exit (0);
}
if (show_help)
usage (0);
if (argc == optind)
errs |= fold_file ("-", width);
else
column++;
return column;
for (i = optind; i < argc; i++)
errs |= fold_file (argv[i], width);
if (have_read_stdin && fclose (stdin) == EOF)
error (1, errno, "-");
if (fclose (stdout) == EOF)
error (1, errno, _("write error"));
exit (errs);
}

View File

@@ -54,15 +54,6 @@ enum header_mode
int safe_read ();
static int head ();
static int head_bytes ();
static int head_file ();
static int head_lines ();
static long atou ();
static void parse_unit ();
static void usage ();
static void write_header ();
/* The name this program was run with. */
char *program_name;
@@ -87,10 +78,179 @@ static struct option const long_options[] =
{NULL, 0, NULL, 0}
};
static void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("\
Usage: %s [OPTION]... [FILE]...\n\
"),
program_name);
printf (_("\
Print first 10 lines of each FILE to standard output.\n\
With more than one FILE, precede each with a header giving the file name.\n\
With no FILE, or when FILE is -, read standard input.\n\
\n\
-c, --bytes=SIZE print first SIZE bytes\n\
-n, --lines=NUMBER print first NUMBER lines instead of first 10\n\
-q, --quiet, --silent never print headers giving file names\n\
-v, --verbose always print headers giving file names\n\
--help display this help and exit\n\
--version output version information and exit\n\
\n\
SIZE may have a multiplier suffix: b for 512, k for 1K, m for 1 Meg.\n\
If -VALUE is used as first OPTION, read -c VALUE when one of\n\
multipliers bkm follows concatenated, else read -n VALUE.\n\
"));
}
exit (status);
}
/* Convert STR, a string of ASCII digits, into an unsigned integer.
Return -1 if STR does not represent a valid unsigned integer. */
static long
atou (const char *str)
{
int value;
for (value = 0; ISDIGIT (*str); ++str)
value = value * 10 + *str - '0';
return *str ? -1 : value;
}
static void
parse_unit (char *str)
{
int arglen = strlen (str);
if (arglen == 0)
return;
switch (str[arglen - 1])
{
case 'b':
unit_size = 512;
str[arglen - 1] = '\0';
break;
case 'k':
unit_size = 1024;
str[arglen - 1] = '\0';
break;
case 'm':
unit_size = 1048576;
str[arglen - 1] = '\0';
break;
}
}
static void
write_header (const char *filename)
{
static int first_file = 1;
printf ("%s==> %s <==\n", (first_file ? "" : "\n"), filename);
first_file = 0;
}
static int
head_bytes (const char *filename, int fd, long int bytes_to_write)
{
char buffer[BUFSIZE];
int bytes_read;
while (bytes_to_write)
{
bytes_read = safe_read (fd, buffer, BUFSIZE);
if (bytes_read < 0)
{
error (0, errno, "%s", filename);
return 1;
}
if (bytes_read == 0)
break;
if (bytes_read > bytes_to_write)
bytes_read = bytes_to_write;
if (fwrite (buffer, 1, bytes_read, stdout) == 0)
error (1, errno, _("write error"));
bytes_to_write -= bytes_read;
}
return 0;
}
static int
head_lines (const char *filename, int fd, long int lines_to_write)
{
char buffer[BUFSIZE];
int bytes_read;
int bytes_to_write;
while (lines_to_write)
{
bytes_read = safe_read (fd, buffer, BUFSIZE);
if (bytes_read < 0)
{
error (0, errno, "%s", filename);
return 1;
}
if (bytes_read == 0)
break;
bytes_to_write = 0;
while (bytes_to_write < bytes_read)
if (buffer[bytes_to_write++] == '\n' && --lines_to_write == 0)
break;
if (fwrite (buffer, 1, bytes_to_write, stdout) == 0)
error (1, errno, _("write error"));
}
return 0;
}
static int
head (const char *filename, int fd, long int number)
{
if (unit_size)
return head_bytes (filename, fd, number);
else
return head_lines (filename, fd, number);
}
static int
head_file (const char *filename, long int number)
{
int fd;
if (!strcmp (filename, "-"))
{
have_read_stdin = 1;
filename = _("standard input");
if (print_headers)
write_header (filename);
return head (filename, 0, number);
}
else
{
fd = open (filename, O_RDONLY);
if (fd >= 0)
{
int errors;
if (print_headers)
write_header (filename);
errors = head (filename, fd, number);
if (close (fd) == 0)
return errors;
}
error (0, errno, "%s", filename);
return 1;
}
}
void
main (argc, argv)
int argc;
char **argv;
main (int argc, char **argv)
{
enum header_mode header_mode = multiple_files;
int exit_status = 0;
@@ -168,6 +328,7 @@ main (argc, argv)
case 'n':
unit_size = 0;
getnum:
/* FIXME: use xstrtoul instead. */
number = atou (optarg);
if (number == -1)
error (1, 0, _("invalid number `%s'"), optarg);
@@ -218,189 +379,3 @@ main (argc, argv)
exit (exit_status);
}
static int
head_file (filename, number)
char *filename;
long number;
{
int fd;
if (!strcmp (filename, "-"))
{
have_read_stdin = 1;
filename = _("standard input");
if (print_headers)
write_header (filename);
return head (filename, 0, number);
}
else
{
fd = open (filename, O_RDONLY);
if (fd >= 0)
{
int errors;
if (print_headers)
write_header (filename);
errors = head (filename, fd, number);
if (close (fd) == 0)
return errors;
}
error (0, errno, "%s", filename);
return 1;
}
}
static void
write_header (filename)
char *filename;
{
static int first_file = 1;
printf ("%s==> %s <==\n", (first_file ? "" : "\n"), filename);
first_file = 0;
}
static int
head (filename, fd, number)
char *filename;
int fd;
long number;
{
if (unit_size)
return head_bytes (filename, fd, number);
else
return head_lines (filename, fd, number);
}
static int
head_bytes (filename, fd, bytes_to_write)
char *filename;
int fd;
long bytes_to_write;
{
char buffer[BUFSIZE];
int bytes_read;
while (bytes_to_write)
{
bytes_read = safe_read (fd, buffer, BUFSIZE);
if (bytes_read < 0)
{
error (0, errno, "%s", filename);
return 1;
}
if (bytes_read == 0)
break;
if (bytes_read > bytes_to_write)
bytes_read = bytes_to_write;
if (fwrite (buffer, 1, bytes_read, stdout) == 0)
error (1, errno, _("write error"));
bytes_to_write -= bytes_read;
}
return 0;
}
static int
head_lines (filename, fd, lines_to_write)
char *filename;
int fd;
long lines_to_write;
{
char buffer[BUFSIZE];
int bytes_read;
int bytes_to_write;
while (lines_to_write)
{
bytes_read = safe_read (fd, buffer, BUFSIZE);
if (bytes_read < 0)
{
error (0, errno, "%s", filename);
return 1;
}
if (bytes_read == 0)
break;
bytes_to_write = 0;
while (bytes_to_write < bytes_read)
if (buffer[bytes_to_write++] == '\n' && --lines_to_write == 0)
break;
if (fwrite (buffer, 1, bytes_to_write, stdout) == 0)
error (1, errno, _("write error"));
}
return 0;
}
static void
parse_unit (str)
char *str;
{
int arglen = strlen (str);
if (arglen == 0)
return;
switch (str[arglen - 1])
{
case 'b':
unit_size = 512;
str[arglen - 1] = '\0';
break;
case 'k':
unit_size = 1024;
str[arglen - 1] = '\0';
break;
case 'm':
unit_size = 1048576;
str[arglen - 1] = '\0';
break;
}
}
/* Convert STR, a string of ASCII digits, into an unsigned integer.
Return -1 if STR does not represent a valid unsigned integer. */
static long
atou (str)
char *str;
{
int value;
for (value = 0; ISDIGIT (*str); ++str)
value = value * 10 + *str - '0';
return *str ? -1 : value;
}
static void
usage (status)
int status;
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("\
Usage: %s [OPTION]... [FILE]...\n\
"),
program_name);
printf (_("\
Print first 10 lines of each FILE to standard output.\n\
With more than one FILE, precede each with a header giving the file name.\n\
With no FILE, or when FILE is -, read standard input.\n\
\n\
-c, --bytes=SIZE print first SIZE bytes\n\
-n, --lines=NUMBER print first NUMBER lines instead of first 10\n\
-q, --quiet, --silent never print headers giving file names\n\
-v, --verbose always print headers giving file names\n\
--help display this help and exit\n\
--version output version information and exit\n\
\n\
SIZE may have a multiplier suffix: b for 512, k for 1K, m for 1 Meg.\n\
If -VALUE is used as first OPTION, read -c VALUE when one of\n\
multipliers bkm follows concatenated, else read -n VALUE.\n\
"));
}
exit (status);
}

View File

@@ -65,19 +65,25 @@
#include "makepath.h"
#include "error.h"
#ifdef _POSIX_VERSION
#if HAVE_SYS_WAIT_H
#include <sys/wait.h>
#else
#endif
struct passwd *getpwnam ();
struct group *getgrnam ();
#ifndef _POSIX_VERSION
uid_t getuid ();
gid_t getgid ();
int wait ();
#endif
#ifdef _POSIX_SOURCE
#define endgrent()
#define endpwent()
#ifndef HAVE_ENDGRENT
# define endgrent() ((void) 0)
#endif
#ifndef HAVE_ENDPWENT
# define endpwent() ((void) 0)
#endif
/* True if C is an ASCII octal digit. */

View File

@@ -15,26 +15,55 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Written by Mike Haertel, mike@gnu.ai.mit.edu. */
Written by Mike Haertel, mike@gnu.ai.mit.edu. */
#include <config.h>
#ifdef __GNUC__
#define alloca __builtin_alloca
#else /* not __GNUC__ */
#if HAVE_ALLOCA_H
#include <alloca.h>
#else /* not HAVE_ALLOCA_H */
#ifdef _AIX
#pragma alloca
#else /* not _AIX */
char *alloca ();
#endif /* not _AIX */
#endif /* not HAVE_ALLOCA_H */
#endif /* not __GNUC__ */
/* Get isblank from GNU libc. */
#define _GNU_SOURCE
#include <stdio.h>
#define NDEBUG
#include <assert.h>
#include <sys/types.h>
#include <getopt.h>
#if HAVE_LIMITS_H
# include <limits.h>
#endif
#ifndef UINT_MAX
# define UINT_MAX ((unsigned int) ~(unsigned int) 0)
#endif
#ifndef INT_MAX
# define INT_MAX ((int) (UINT_MAX >> 1))
#endif
#include "system.h"
#include "version.h"
#include "long-options.h"
#include "xstrtol.h"
#include "error.h"
#define join system_join
char *xmalloc ();
char *xrealloc ();
static void usage ();
/* Undefine, to avoid warning about redefinition on some systems. */
#undef min
@@ -42,69 +71,74 @@ static void usage ();
#define min(A, B) ((A) < (B) ? (A) : (B))
#define max(A, B) ((A) > (B) ? (A) : (B))
/* An element of the list describing the format of each
output line. */
/* An element of the list identifying which fields to print for each
output line. */
struct outlist
{
int file; /* File to take field from (1 or 2). */
int field; /* Field number to print. */
/* File number: 0, 1, or 2. 0 means use the join field.
1 means use the first file argument, 2 the second. */
int file;
/* Field index (zero-based), specified only when FILE is 1 or 2. */
int field;
struct outlist *next;
};
/* A field of a line. */
/* A field of a line. */
struct field
{
const char *beg; /* First character in field. */
size_t len; /* The length of the field. */
const char *beg; /* First character in field. */
size_t len; /* The length of the field. */
};
/* A line read from an input file. Newlines are not stored. */
/* A line read from an input file. Newlines are not stored. */
struct line
{
char *beg; /* First character in line. */
char *lim; /* Character after last character in line. */
int nfields; /* Number of elements in `fields'. */
int nfields_allocated; /* Number of elements in `fields'. */
char *beg; /* First character in line. */
char *lim; /* Character after last character in line. */
int nfields; /* Number of elements in `fields'. */
int nfields_allocated; /* Number of elements in `fields'. */
struct field *fields;
};
/* One or more consecutive lines read from a file that all have the
same join field value. */
same join field value. */
struct seq
{
int count; /* Elements used in `lines'. */
int alloc; /* Elements allocated in `lines'. */
int count; /* Elements used in `lines'. */
int alloc; /* Elements allocated in `lines'. */
struct line *lines;
};
/* The name this program was run with. */
/* The name this program was run with. */
char *program_name;
/* If nonzero, print unpairable lines in file 1 or 2. */
/* If nonzero, print unpairable lines in file 1 or 2. */
static int print_unpairables_1, print_unpairables_2;
/* If nonzero, print pairable lines. */
/* If nonzero, print pairable lines. */
static int print_pairables;
/* Empty output field filler. */
/* Empty output field filler. */
static char *empty_filler;
/* Field to join on. */
/* Field to join on. */
static int join_field_1, join_field_2;
/* List of fields to print. */
static struct outlist *outlist;
/* List of fields to print. */
static struct outlist outlist_head;
/* Last element in `outlist', where a new element can be added. */
static struct outlist *outlist_end;
/* Last element in `outlist', where a new element can be added. */
static struct outlist *outlist_end = &outlist_head;
/* Tab character separating fields; if this is NUL fields are separated
by any nonempty string of white space, otherwise by exactly one
tab character. */
tab character. */
static char tab;
/* When using getopt_long_only, no long option can start with
a character that is a short option. */
a character that is a short option. */
static struct option const longopts[] =
{
{"j", required_argument, NULL, 'j'},
@@ -117,10 +151,48 @@ static struct option const longopts[] =
static struct line uni_blank;
static void
ADD_FIELD (line, field, len)
struct line *line;
const char *field;
size_t len;
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("\
Usage: %s [OPTION]... FILE1 FILE2\n\
"),
program_name);
printf (_("\
For each pair of input lines with identical join fields, write a line to\n\
standard output. The default join field is the first, delimited\n\
by whitespace. When FILE1 or FILE2 (not both) is -, read standard input.\n\
\n\
-a SIDE print unpairable lines coming from file SIDE\n\
-e EMPTY replace missing input fields with EMPTY\n\
-j FIELD (Obsolescent) equivalent to `-1 FIELD -2 FIELD'\n\
-j1 FIELD (Obsolescent) equivalent to `-1 FIELD'\n\
-j2 FIELD (Obsolescent) equivalent to `-2 FIELD'\n\
-1 FIELD join on this FIELD of file 1\n\
-2 FIELD join on this FIELD of file 2\n\
-o FORMAT obey FORMAT while constructing output line\n\
-t CHAR use CHAR as input and output field separator\n\
-v SIDE like -a SIDE, but suppress joined output lines\n\
--help display this help and exit\n\
--version output version information and exit\n\
\n\
Unless -t CHAR is given, leading blanks separate fields and are ignored,\n\
else fields are separated by CHAR. Any FIELD is a field number counted\n\
from 1. FORMAT is one or more comma or blank separated specifications,\n\
each being `SIDE.FIELD' or `0'. Default FORMAT outputs the join field,\n\
the remaining fields from FILE1, the remaining fields from FILE2, all\n\
separated by CHAR.\n\
"));
}
exit (status);
}
static void
ADD_FIELD (struct line *line, const char *field, size_t len)
{
if (line->nfields >= line->nfields_allocated)
{
@@ -134,11 +206,10 @@ ADD_FIELD (line, field, len)
++(line->nfields);
}
/* Fill in the `fields' structure in LINE. */
/* Fill in the `fields' structure in LINE. */
static void
xfields (line)
struct line *line;
xfields (struct line *line)
{
int i;
register char *ptr, *lim;
@@ -181,12 +252,10 @@ xfields (line)
}
/* Read a line from FP into LINE and split it into fields.
Return 0 if EOF, 1 otherwise. */
Return 0 if EOF, 1 otherwise. */
static int
get_line (fp, line)
FILE *fp;
struct line *line;
get_line (FILE *fp, struct line *line)
{
static int linesize = 80;
int c, i;
@@ -223,8 +292,7 @@ get_line (fp, line)
}
static void
freeline (line)
struct line *line;
freeline (struct line *line)
{
free ((char *) line->fields);
free (line->beg);
@@ -232,20 +300,17 @@ freeline (line)
}
static void
initseq (seq)
struct seq *seq;
initseq (struct seq *seq)
{
seq->count = 0;
seq->alloc = 1;
seq->lines = (struct line *) xmalloc (seq->alloc * sizeof (struct line));
}
/* Read a line from FP and add it to SEQ. Return 0 if EOF, 1 otherwise. */
/* Read a line from FP and add it to SEQ. Return 0 if EOF, 1 otherwise. */
static int
getseq (fp, seq)
FILE *fp;
struct seq *seq;
getseq (FILE *fp, struct seq *seq)
{
if (seq->count == seq->alloc)
{
@@ -263,8 +328,7 @@ getseq (fp, seq)
}
static void
delseq (seq)
struct seq *seq;
delseq (struct seq *seq)
{
int i;
for (i = 0; i < seq->count; i++)
@@ -274,15 +338,13 @@ delseq (seq)
}
/* Return <0 if the join field in LINE1 compares less than the one in LINE2;
>0 if it compares greater; 0 if it compares equal. */
>0 if it compares greater; 0 if it compares equal. */
static int
keycmp (line1, line2)
struct line *line1;
struct line *line2;
keycmp (struct line *line1, struct line *line2)
{
const char *beg1, *beg2; /* Start of field to compare in each file. */
int len1, len2; /* Length of fields to compare. */
const char *beg1, *beg2; /* Start of field to compare in each file. */
int len1, len2; /* Length of fields to compare. */
int diff;
if (join_field_1 < line1->nfields)
@@ -318,12 +380,10 @@ keycmp (line1, line2)
}
/* Print field N of LINE if it exists and is nonempty, otherwise
`empty_filler' if it is nonempty. */
`empty_filler' if it is nonempty. */
static void
prfield (n, line)
int n;
struct line *line;
prfield (int n, struct line *line)
{
int len;
@@ -339,22 +399,47 @@ prfield (n, line)
fputs (empty_filler, stdout);
}
/* Print the join of LINE1 and LINE2. */
/* Print the join of LINE1 and LINE2. */
static void
prjoin (line1, line2)
struct line *line1;
struct line *line2;
prjoin (struct line *line1, struct line *line2)
{
const struct outlist *outlist;
outlist = outlist_head.next;
if (outlist)
{
struct outlist *o;
const struct outlist *o;
prfield (outlist->field - 1, outlist->file == 1 ? line1 : line2);
for (o = outlist->next; o; o = o->next)
o = outlist;
while (1)
{
int field;
struct line *line;
if (o->file == 0)
{
if (line1 == &uni_blank)
{
line = line2;
field = join_field_2;
}
else
{
line = line1;
field = join_field_1;
}
}
else
{
line = (o->file == 1 ? line1 : line2);
field = o->field;
}
prfield (field, line);
o = o->next;
if (o == NULL)
break;
putchar (tab ? tab : ' ');
prfield (o->field - 1, o->file == 1 ? line1 : line2);
}
putchar ('\n');
}
@@ -395,7 +480,7 @@ prjoin (line1, line2)
}
}
/* Print the join of the files in FP1 and FP2. */
/* Print the join of the files in FP1 and FP2. */
static void
join (fp1, fp2)
@@ -406,7 +491,7 @@ join (fp1, fp2)
struct line line;
int diff, i, j, eof1, eof2;
/* Read the first line of each file. */
/* Read the first line of each file. */
initseq (&seq1);
getseq (fp1, &seq1);
initseq (&seq2);
@@ -435,7 +520,7 @@ join (fp1, fp2)
}
/* Keep reading lines from file1 as long as they continue to
match the current line from file2. */
match the current line from file2. */
eof1 = 0;
do
if (!getseq (fp1, &seq1))
@@ -447,7 +532,7 @@ join (fp1, fp2)
while (!keycmp (&seq1.lines[seq1.count - 1], &seq2.lines[0]));
/* Keep reading lines from file2 as long as they continue to
match the current line from file1. */
match the current line from file1. */
eof2 = 0;
do
if (!getseq (fp2, &seq2))
@@ -512,85 +597,118 @@ join (fp1, fp2)
delseq (&seq2);
}
/* Add a field spec for field FIELD of file FILE to `outlist' and return 1,
unless either argument is invalid; then just return 0. */
/* Add a field spec for field FIELD of file FILE to `outlist'. */
static int
add_field (file, field)
int file;
int field;
static void
add_field (int file, int field)
{
struct outlist *o;
if (file < 1 || file > 2 || field < 1)
return 0;
assert (file == 0 || file == 1 || file == 2);
assert (field >= 0);
o = (struct outlist *) xmalloc (sizeof (struct outlist));
o->file = file;
o->field = field;
o->next = NULL;
/* Add to the end of the list so the fields are in the right order. */
if (outlist == NULL)
outlist = o;
else
outlist_end->next = o;
/* Add to the end of the list so the fields are in the right order. */
outlist_end->next = o;
outlist_end = o;
return 1;
}
/* Add the comma or blank separated field spec(s) in STR to `outlist'.
Return the number of fields added. */
/* Convert a single field specifier string, S, to a *FILE_INDEX, *FIELD_INDEX
pair. In S, the field index string is 1-based; *FIELD_INDEX is zero-based.
If S is valid, return zero. Otherwise, give a diagnostic, don't update
*FILE_INDEX or *FIELD_INDEX, and return non-zero. */
static int
add_field_list (str)
char *str;
decode_field_spec (const char *s, int *file_index, int *field_index)
{
int added = 0;
int file = -1, field = -1;
int dot_found = 0;
int valid = 0;
for (; *str; str++)
/* The first character must be 0, 1, or 2. */
switch (s[0])
{
if (*str == ',' || ISBLANK (*str))
case '0':
if (s[1] == '\0')
{
added += add_field (file, field);
uni_blank.nfields = max (uni_blank.nfields, field);
file = field = -1;
dot_found = 0;
*file_index = 0;
/* Leave *field_index undefined. */
valid = 1;
}
else if (*str == '.')
dot_found = 1;
else if (ISDIGIT (*str))
{
if (!dot_found)
else
{
/* `0' must be all alone -- no `.FIELD'. */
error (0, 0, _("invalid field specifier: `%s'"), s);
}
break;
case '1':
case '2':
if (s[1] == '.' && s[2] != '\0')
{
strtol_error s_err;
long int tmp_long;
s_err = xstrtol (s + 2, NULL, 10, &tmp_long, NULL);
if (s_err != LONGINT_OK || tmp_long <= 0 || tmp_long > INT_MAX)
{
if (file == -1)
file = 0;
file = file * 10 + *str - '0';
error (0, 0, _("invalid field number: `%s'"), s + 2);
}
else
{
if (field == -1)
field = 0;
field = field * 10 + *str - '0';
*file_index = s[0] - '0';
/* Convert to a zero-based index. */
*field_index = (int) tmp_long - 1;
valid = 1;
}
}
else
return 0;
}
break;
uni_blank.nfields = max (uni_blank.nfields, field);
added += add_field (file, field);
return added;
default:
error (0, 0, _("invalid file number in field spec: `%s'"), s);
break;
}
return !valid;
}
/* Create a blank line with COUNT fields separated by tabs. */
/* Add the comma or blank separated field spec(s) in STR to `outlist'.
Return non-zero to indicate failure. */
static int
add_field_list (const char *c_str)
{
char *p, *str;
/* Make a writable copy of c_str. */
str = (char *) alloca (strlen (c_str) + 1);
strcpy (str, c_str);
p = str;
do
{
int invalid;
int file_index, field_index;
char *spec_item = p;
p = strpbrk (p, ", \t");
if (p)
*p++ = 0;
invalid = decode_field_spec (spec_item, &file_index, &field_index);
if (invalid)
return 1;
add_field (file_index, field_index);
uni_blank.nfields = max (uni_blank.nfields, field_index);
}
while (p);
return 0;
}
/* Create a blank line with COUNT fields separated by tabs. */
void
make_blank (blank, count)
struct line *blank;
int count;
make_blank (struct line *blank, int count)
{
int i;
blank->nfields = count;
@@ -607,13 +725,11 @@ make_blank (blank, count)
}
void
main (argc, argv)
int argc;
char *argv[];
main (int argc, char **argv)
{
char *names[2];
FILE *fp1, *fp2;
int optc, prev_optc = 0, nfiles, val;
int optc, prev_optc = 0, nfiles;
program_name = argv[0];
@@ -629,19 +745,25 @@ main (argc, argv)
while ((optc = getopt_long_only (argc, argv, "-a:e:1:2:o:t:v:", longopts,
(int *) 0)) != EOF)
{
long int val;
switch (optc)
{
case 0:
break;
case 'v':
print_pairables = 0;
/* Fall through. */
case 'a':
val = atoi (optarg);
if (xstrtol (optarg, NULL, 10, &val, NULL) != LONGINT_OK
|| (val != 1 && val != 2))
error (2, 0, _("invalid field number: `%s'"), optarg);
if (val == 1)
print_unpairables_1 = 1;
else if (val == 2)
print_unpairables_2 = 1;
else
error (2, 0, _("invalid file number for `-a'"));
print_unpairables_2 = 1;
break;
case 'e':
@@ -649,56 +771,52 @@ main (argc, argv)
break;
case '1':
val = atoi (optarg);
if (val <= 0)
error (2, 0, _("invalid field number for `-1'"));
join_field_1 = val - 1;
if (xstrtol (optarg, NULL, 10, &val, NULL) != LONGINT_OK
|| val <= 0 || val > INT_MAX)
{
error (2, 0, _("invalid field number for file 1: `%s'"), optarg);
}
join_field_1 = (int) val - 1;
break;
case '2':
val = atoi (optarg);
if (val <= 0)
error (2, 0, _("invalid field number for `-2'"));
join_field_2 = val - 1;
if (xstrtol (optarg, NULL, 10, &val, NULL) != LONGINT_OK
|| val <= 0 || val > INT_MAX)
error (2, 0, _("invalid field number for file 2: `%s'"), optarg);
join_field_2 = (int) val - 1;
break;
case 'j':
val = atoi (optarg);
if (val <= 0)
error (2, 0, _("invalid field number for `-j'"));
join_field_1 = join_field_2 = val - 1;
if (xstrtol (optarg, NULL, 10, &val, NULL) != LONGINT_OK
|| val <= 0 || val > INT_MAX)
error (2, 0, _("invalid field number: `%s'"), optarg);
join_field_1 = join_field_2 = (int) val - 1;
break;
case 'o':
if (add_field_list (optarg) == 0)
error (2, 0, _("invalid field list for `-o'"));
if (add_field_list (optarg))
exit (1);
break;
case 't':
tab = *optarg;
break;
case 'v':
val = atoi (optarg);
if (val == 1)
print_unpairables_1 = 1;
else if (val == 2)
print_unpairables_2 = 1;
else
error (2, 0, _("invalid file number for `-v'"));
print_pairables = 0;
break;
case 1: /* Non-option argument. */
if (prev_optc == 'o')
case 1: /* Non-option argument. */
if (prev_optc == 'o' && optind <= argc - 2)
{
/* Might be continuation of args to -o. */
if (add_field_list (optarg) > 0)
continue; /* Don't change `prev_optc'. */
if (add_field_list (optarg))
exit (1);
/* Might be continuation of args to -o. */
continue; /* Don't change `prev_optc'. */
}
if (nfiles > 1)
usage (1);
{
error (0, 0, "too many non-option arguments");
usage (1);
}
names[nfiles++] = optarg;
break;
@@ -713,7 +831,10 @@ main (argc, argv)
make_blank (&uni_blank, uni_blank.nfields);
if (nfiles != 2)
usage (1);
{
error (0, 0, "too few non-option arguments");
usage (1);
}
fp1 = strcmp (names[0], "-") ? fopen (names[0], "r") : stdin;
if (!fp1)
@@ -725,6 +846,10 @@ main (argc, argv)
error (1, errno, _("both files cannot be standard input"));
join (fp1, fp2);
if (fp1 != stdin && fclose (fp1) == EOF)
error (1, errno, "%s", names[0]);
if (fp2 != stdin && fclose (fp2) == EOF)
error (1, errno, "%s", names[1]);
if ((fp1 == stdin || fp2 == stdin) && fclose (stdin) == EOF)
error (1, errno, "-");
if (ferror (stdout) || fclose (stdout) == EOF)
@@ -732,42 +857,3 @@ main (argc, argv)
exit (0);
}
static void
usage (status)
int status;
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("\
Usage: %s [OPTION]... FILE1 FILE2\n\
"),
program_name);
printf (_("\
For each pair of input lines with identical join fields, write a line to\n\
standard output. The default join field is the first, delimited\n\
by whitespace. When FILE1 or FILE2 (not both) is -, read standard input.\n\
\n\
-a SIDE print unpairable lines coming from file SIDE\n\
-e EMPTY replace missing input fields with EMPTY\n\
-j FIELD join on this FIELD for both files\n\
-[j]SIDE FIELD join on this FIELD for file SIDE\n\
-o FORMAT obey FORMAT while constructing output line\n\
-t CHAR use CHAR as input and output field separator\n\
-v SIDE like -a SIDE, but suppress joined output lines\n\
--help display this help and exit\n\
--version output version information and exit\n\
\n\
SIDE is 1 for FILE1 or 2 for FILE2. Unless -t CHAR is given, leading blanks\n\
separate fields and are ignored, else fields are separated by CHAR.\n\
Any FIELD is a field number counted from 1. FORMAT is one or more\n\
comma or blank separated specifications, each being `SIDE.FIELD'.\n\
Default FORMAT outputs the join field, the remaining fields from\n\
FILE1, the remaining fields from FILE2, all separated by CHAR.\n\
"));
}
exit (status);
}

View File

@@ -38,13 +38,16 @@
#include <config.h>
#include <sys/types.h>
#if !defined(_POSIX_SOURCE) || defined(_AIX)
#include <sys/ioctl.h>
#if HAVE_SYS_IOCTL_H
# include <sys/ioctl.h>
#endif
#include <stdio.h>
#include <grp.h>
#include <pwd.h>
#include <getopt.h>
#if HAVE_LIMITS_H
/* limits.h must come before system.h because limits.h on some systems
undefs PATH_MAX, whereas system.h includes pathmax.h which sets
@@ -548,8 +551,11 @@ static size_t dired_pos;
/* With --dired, store pairs of beginning and ending indices of filenames. */
static struct obstack dired_obstack;
/* With --dired and --recursive, store pairs of beginning and ending
indices of directory names. */
/* With --dired, store pairs of beginning and ending indices of any
directory names that appear as headers (just before `total' line)
for lists of directory entries. Such directory names are seen when
listing hierarchies using -R and when a directory is listed with at
least one other command line argument. */
static struct obstack subdired_obstack;
/* Save the current index on the specified obstack, OBS. */
@@ -586,15 +592,20 @@ dired_dump_obstack (prefix, os)
const char *prefix;
struct obstack *os;
{
int i, n_pos;
size_t *pos;
int n_pos;
fputs (prefix, stdout);
n_pos = obstack_object_size (os) / sizeof (size_t);
pos = (size_t *) obstack_finish (os);
for (i = 0; i < n_pos; i++)
printf (" %d", (int) pos[i]);
fputs ("\n", stdout);
if (n_pos > 0)
{
int i;
size_t *pos;
pos = (size_t *) obstack_finish (os);
fputs (prefix, stdout);
for (i = 0; i < n_pos; i++)
printf (" %d", (int) pos[i]);
fputs ("\n", stdout);
}
}
void
@@ -631,8 +642,7 @@ main (argc, argv)
if (dired && format == long_format)
{
obstack_init (&dired_obstack);
if (trace_dirs)
obstack_init (&subdired_obstack);
obstack_init (&subdired_obstack);
}
nfiles = 100;
@@ -686,8 +696,7 @@ main (argc, argv)
{
/* No need to free these since we're about to exit. */
dired_dump_obstack ("//DIRED//", &dired_obstack);
if (trace_dirs)
dired_dump_obstack ("//SUBDIRED//", &subdired_obstack);
dired_dump_obstack ("//SUBDIRED//", &subdired_obstack);
}
exit (exit_status);

View File

@@ -26,6 +26,7 @@
#include <stdio.h>
#include <sys/types.h>
#include "long-options.h"
#include "md5.h"
#include "getline.h"
#include "system.h"
@@ -62,11 +63,13 @@
/* Nonzero if any of the files read were the standard input. */
static int have_read_stdin;
/* FIXME: comment. */
static int quiet = 0;
/* With --check, don't generate any output.
The exit code indicates success or failure. */
static int status_only = 0;
/* FIXME: comment. */
static int verbose = 0;
/* With --check, print a message to standard error warning about each
improperly formatted MD5 checksum line. */
static int warn = 0;
/* The name this program was run with. */
char *program_name;
@@ -75,20 +78,17 @@ static const struct option long_options[] =
{
{ "binary", no_argument, 0, 'b' },
{ "check", no_argument, 0, 'c' },
{ "help", no_argument, 0, 'h' },
{ "quiet", no_argument, 0, 'q' },
{ "string", required_argument, 0, 's' },
{ "status", no_argument, 0, 2 },
{ "string", required_argument, 0, 1 },
{ "text", no_argument, 0, 't' },
{ "verbose", no_argument, 0, 'v' },
{ "version", no_argument, 0, 'V' },
{ "warn", no_argument, 0, 'w' },
{ NULL, 0, NULL, 0 }
};
char *xmalloc ();
static void
usage (status)
int status;
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
@@ -100,22 +100,23 @@ Usage: %s [OPTION] [FILE]...\n\
or: %s [OPTION] --string=STRING ...\n\
Print or check MD5 checksums.\n\
With no FILE, or when FILE is -, read standard input.\n\
\n\
-h, --help display this help and exit\n\
-q, --quiet don't output anything, status code shows success\n\
-v, --verbose verbose output level\n\
-V, --version output version information and exit\n\
\n\
-b, --binary read files in binary mode\n\
-t, --text read files in text mode (default)\n\
\n\
-c, --check check MD5 sums against given list\n\
-s, --string=STRING compute checksum for STRING\n\
\n\
The following two options are useful only when verifying checksums:\n\
--status don't output anything, status code shows success\n\
-w, --warn warn about improperly formated MD5 checksum lines\n\
\n\
--string=STRING compute checksum for STRING\n\
--help display this help and exit\n\
--version output version information and exit\n\
\n\
The sums are computed as described in RFC 1321. When checking, the input\n\
should be a former output of this program. The default mode is to print\n\
a line with checksum, a character indicating type (`*' for binary, ` ' for\n\
text), and name for each FILE. The --quiet and --verbose options are\n\
text), and name for each FILE. The --status and --warn options are\n\
meaningful only when verifying checksums.\n"),
program_name, program_name, program_name);
@@ -125,9 +126,7 @@ meaningful only when verifying checksums.\n"),
/* FIXME: this format loses with filenames containing newline. */
static int
split_3 (s, u, binary, w)
char *s, **u, **w;
int *binary;
split_3 (char *s, char **u, int *binary, char **w)
{
size_t i;
@@ -167,11 +166,8 @@ split_3 (s, u, binary, w)
return 1;
}
/* FIXME: use strcspn. */
static int
hex_digits (s)
const char *s;
hex_digits (const char *s)
{
while (*s)
{
@@ -183,12 +179,11 @@ hex_digits (s)
}
/* FIXME: allow newline in filename by encoding it. */
/* FIXME: distinguish between file open/read failure and inconsistent
checksum. */
static int
md5_file (filename, binary, md5_result)
const char *filename;
int binary;
unsigned char *md5_result;
md5_file (const char *filename, int binary, unsigned char *md5_result)
{
FILE *fp;
int err;
@@ -231,13 +226,12 @@ md5_file (filename, binary, md5_result)
}
static int
md5_check (checkfile_name, binary)
const char *checkfile_name;
int binary;
md5_check (const char *checkfile_name, int binary)
{
FILE *checkfile_stream;
int n_tests = 0;
int n_tests_failed = 0;
int n_properly_formated_lines = 0;
int n_mismatched_checksums = 0;
int n_open_or_read_failures = 0;
unsigned char md5buffer[16];
size_t line_number;
char *line;
@@ -287,9 +281,10 @@ md5_check (checkfile_name, binary)
err = split_3 (line, &md5num, &type_flag, &filename);
if (err || !hex_digits (md5num))
{
if (verbose)
if (warn)
{
error (0, 0, _("%s: %lu: invalid MD5 checksum line"),
error (0, 0,
_("%s: %lu: improperly formatted MD5 checksum line"),
checkfile_name, (unsigned long) line_number);
}
}
@@ -301,11 +296,20 @@ md5_check (checkfile_name, binary)
'c', 'd', 'e', 'f' };
int fail;
++n_tests;
++n_properly_formated_lines;
fail = md5_file (filename, binary, md5buffer);
if (!fail)
if (fail)
{
++n_open_or_read_failures;
if (!status_only)
{
printf (_("%s: FAILED open or read\n"), filename);
fflush (stdout);
}
}
else
{
size_t cnt;
/* Compare generated binary number with text representation
@@ -318,100 +322,96 @@ md5_check (checkfile_name, binary)
break;
}
if (cnt != 16)
fail = 1;
}
++n_mismatched_checksums;
if (fail)
++n_tests_failed;
if (!quiet)
{
printf ("%s: %s\n", filename, (fail ? _("FAILED") : _("OK")));
fflush (stdout);
if (!status_only)
{
printf ("%s: %s\n", filename,
(cnt != 16 ? _("FAILED") : _("OK")));
fflush (stdout);
}
}
}
}
while (!feof (checkfile_stream) && !ferror (checkfile_stream));
/* FIXME: check ferror!! */
if (line)
free (line);
if (ferror (checkfile_stream))
{
error (0, 0, "%s: read error", checkfile_name);
return 1;
}
if (checkfile_stream != stdin && fclose (checkfile_stream) == EOF)
{
error (0, errno, "%s", checkfile_name);
return 1;
}
if (n_tests == 0)
if (n_properly_formated_lines == 0)
{
/* FIXME: warn (or even fail?) if no tests are found? */
/* Warn if no tests are found. */
error (0, 0, _("%s: no properly formatted MD5 checksum lines found"),
checkfile_name);
}
else
{
if (!quiet)
if (!status_only)
{
if (n_tests_failed == 0)
int n_computed_checkums = (n_properly_formated_lines
- n_open_or_read_failures);
if (n_open_or_read_failures > 0)
{
printf (n_tests == 1
? _("the single test passed\n")
: _("all %d tests passed\n"), n_tests);
error (0, 0,
_("WARNING: %d of %d listed file%s could not be read\n"),
n_open_or_read_failures, n_properly_formated_lines,
(n_properly_formated_lines == 1 ? "" : "s"));
}
else
if (n_mismatched_checksums > 0)
{
printf (n_tests == 1
? _("the single test failed\n")
: _("%d out of %d tests failed\n"),
n_tests_failed, n_tests);
error (0, 0,
_("WARNING: %d of %d computed checksum%s did NOT match\n"),
n_mismatched_checksums, n_computed_checkums,
(n_computed_checkums == 1 ? "" : "s"));
}
}
}
return ((n_tests > 0 && n_tests_failed == 0) ? 0 : 1);
return ((n_properly_formated_lines > 0 && n_mismatched_checksums == 0
&& n_open_or_read_failures == 0) ? 0 : 1);
}
int
main (argc, argv)
int argc;
char *argv[];
main (int argc, char **argv)
{
unsigned char md5buffer[16];
int do_check = 0;
int do_help = 0;
int do_version = 0;
int opt;
char **string = NULL;
char n_strings = 0;
size_t n_strings = 0;
size_t i;
size_t err = 0;
/* FIXME: comment. */
/* Text is default of the Plumb/Lankester format. */
int binary = 0;
/* Setting values of global variables. */
program_name = argv[0];
while ((opt = getopt_long (argc, argv, "bchqs:tvV", long_options, NULL))
parse_long_options (argc, argv, "md5sum", version_string, usage);
while ((opt = getopt_long (argc, argv, "bctw", long_options, NULL))
!= EOF)
switch (opt)
{
case 0: /* long option */
break;
case 'b':
binary = 1;
break;
case 'c':
do_check = 1;
break;
case 'h':
do_help = 1;
break;
case 'q':
quiet = 1;
verbose = 0;
break;
case 's':
case 1: /* --string */
{
if (string == NULL)
string = (char **) xmalloc ((argc - 1) * sizeof (char *));
@@ -421,15 +421,22 @@ main (argc, argv)
string[n_strings++] = optarg;
}
break;
case 'b':
binary = 1;
break;
case 'c':
do_check = 1;
break;
case 2:
status_only = 1;
warn = 0;
break;
case 't':
binary = 0;
break;
case 'v':
quiet = 0;
verbose = 1;
break;
case 'V':
do_version = 1;
case 'w':
status_only = 0;
warn = 1;
break;
default:
usage (EXIT_FAILURE);
@@ -441,21 +448,24 @@ main (argc, argv)
exit (EXIT_SUCCESS);
}
if (do_help)
usage (EXIT_SUCCESS);
if (n_strings > 0 && do_check != 0)
if (n_strings > 0 && do_check)
{
error (0, 0,
_("the --string and --check options are mutually exclusive"));
usage (EXIT_FAILURE);
}
if ((quiet || verbose) && do_check == 0)
if (status_only && !do_check)
{
error (0, 0,
_("the --quiet and --verbose options are meaningful only\n\
when verifying checksums"));
_("the --status option is meaningful only when verifying checksums"));
usage (EXIT_FAILURE);
}
if (warn && !do_check)
{
error (0, 0,
_("the --warn option is meaningful only when verifying checksums"));
usage (EXIT_FAILURE);
}
@@ -477,7 +487,18 @@ when verifying checksums"));
printf (" \"%s\"\n", string[i]);
}
}
else if (do_check == 0)
else if (do_check)
{
if (optind + 1 < argc)
{
error (0, 0,
_("only one argument may be specified when using --check"));
usage (EXIT_FAILURE);
}
err = md5_check ((optind == argc) ? "-" : argv[optind], binary);
}
else
{
if (optind == argc)
argv[argc++] = "-";
@@ -498,17 +519,6 @@ when verifying checksums"));
}
}
}
else
{
if (optind + 1 < argc)
{
error (0, 0,
_("only one argument may be specified when using --check"));
usage (EXIT_FAILURE);
}
err = md5_check ((optind == argc) ? "-" : argv[optind], binary);
}
if (fclose (stdout) == EOF)
error (EXIT_FAILURE, errno, _("write error"));

View File

@@ -62,7 +62,7 @@ int yesno ();
int safe_read ();
int full_write ();
void strip_trailing_slashes ();
int eaccess_stat ();
int euidaccess ();
char *stpcpy ();
static int copy_reg ();
@@ -276,7 +276,7 @@ do_move (source, dest)
return 0;
if (!override_mode && (interactive || stdin_tty)
&& eaccess_stat (&dest_stats, W_OK, dest))
&& euidaccess (dest, W_OK))
{
fprintf (stderr, "%s: replace `%s', overriding mode %04o? ",
program_name, dest,

577
src/nl.c
View File

@@ -55,18 +55,6 @@ enum section
char *xmalloc ();
char *xrealloc ();
static enum section check_section ();
static int build_type_arg ();
static int nl_file ();
static void usage ();
static void process_file ();
static void proc_header ();
static void proc_body ();
static void proc_footer ();
static void proc_text ();
static void print_lineno ();
static void build_print_fmt ();
/* The name this program was run with. */
char *program_name;
@@ -175,10 +163,286 @@ static struct option const longopts[] =
{NULL, 0, NULL, 0}
};
/* Print a usage message and quit. */
static void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("\
Usage: %s [OPTION]... [FILE]...\n\
"),
program_name);
printf (_("\
Write each FILE to standard output, with line numbers added.\n\
With no FILE, or when FILE is -, read standard input.\n\
\n\
-b, --body-numbering=STYLE use STYLE for numbering body lines\n\
-d, --section-delimiter=CC use CC for separating logical pages\n\
-f, --footer-numbering=STYLE use STYLE for numbering footer lines\n\
-h, --header-numbering=STYLE use STYLE for numbering header lines\n\
-i, --page-increment=NUMBER line number increment at each line\n\
-l, --join-blank-lines=NUMBER group of NUMBER empty lines counted as one\n\
-n, --number-format=FORMAT insert line numbers according to FORMAT\n\
-p, --no-renumber do not reset line numbers at logical pages\n\
-s, --number-separator=STRING add STRING after (possible) line number\n\
-v, --first-page=NUMBER first line number on each logical page\n\
-w, --number-width=NUMBER use NUMBER columns for line numbers\n\
--help display this help and exit\n\
--version output version information and exit\n\
\n\
By default, selects -v1 -i1 -l1 -sTAB -w6 -nrn -hn -bt -fn. CC are\n\
two delimiter characters for separating logical pages, a missing\n\
second character implies :. Type \\\\ for \\. STYLE is one of:\n\
\n\
a number all lines\n\
t number only nonempty lines\n\
n number no lines\n\
pREGEXP number only lines that contain a match for REGEXP\n\
\n\
FORMAT is one of:\n\
\n\
ln left justified, no leading zeros\n\
rn right justified, no leading zeros\n\
rz right justified, leading zeros\n\
\n\
"));
}
exit (status);
}
/* Build the printf format string, based on `lineno_format'. */
static void
build_print_fmt (void)
{
/* 12 = 10 chars for lineno_width, 1 for %, 1 for \0. */
print_fmt = xmalloc (strlen (separator_str) + 12);
switch (lineno_format)
{
case FORMAT_RIGHT_NOLZ:
sprintf (print_fmt, "%%%dd%s", lineno_width, separator_str);
break;
case FORMAT_RIGHT_LZ:
sprintf (print_fmt, "%%0%dd%s", lineno_width, separator_str);
break;
case FORMAT_LEFT:
sprintf (print_fmt, "%%-%dd%s", lineno_width, separator_str);
break;
}
}
/* Set the command line flag TYPEP and possibly the regex pointer REGEXP,
according to `optarg'. */
static int
build_type_arg (char **typep, struct re_pattern_buffer *regexp)
{
const char *errmsg;
int rval = TRUE;
int optlen;
switch (*optarg)
{
case 'a':
case 't':
case 'n':
*typep = optarg;
break;
case 'p':
*typep = optarg++;
optlen = strlen (optarg);
regexp->allocated = optlen * 2;
regexp->buffer = (unsigned char *) xmalloc (regexp->allocated);
regexp->translate = NULL;
regexp->fastmap = xmalloc (256);
regexp->fastmap_accurate = 0;
errmsg = re_compile_pattern (optarg, optlen, regexp);
if (errmsg)
error (1, 0, "%s", errmsg);
break;
default:
rval = FALSE;
break;
}
return rval;
}
/* Print and increment the line number. */
static void
print_lineno (void)
{
printf (print_fmt, line_no);
line_no += page_incr;
}
/* Switch to a header section. */
static void
proc_header (void)
{
current_type = header_type;
current_regex = &header_regex;
if (reset_numbers)
line_no = page_start;
putchar ('\n');
}
/* Switch to a body section. */
static void
proc_body (void)
{
current_type = body_type;
current_regex = &body_regex;
putchar ('\n');
}
/* Switch to a footer section. */
static void
proc_footer (void)
{
current_type = footer_type;
current_regex = &footer_regex;
putchar ('\n');
}
/* Process a regular text line in `line_buf'. */
static void
proc_text (void)
{
static int blank_lines = 0; /* Consecutive blank lines so far. */
switch (*current_type)
{
case 'a':
if (blank_join > 1)
{
if (line_buf.length || ++blank_lines == blank_join)
{
print_lineno ();
blank_lines = 0;
}
else
printf (print_no_line_fmt);
}
else
print_lineno ();
break;
case 't':
if (line_buf.length)
print_lineno ();
else
printf (print_no_line_fmt);
break;
case 'n':
printf (print_no_line_fmt);
break;
case 'p':
if (re_search (current_regex, line_buf.buffer, line_buf.length,
0, line_buf.length, (struct re_registers *) 0) < 0)
printf (print_no_line_fmt);
else
print_lineno ();
break;
}
fwrite (line_buf.buffer, sizeof (char), line_buf.length, stdout);
putchar ('\n');
}
/* Return the type of line in `line_buf'. */
static enum section
check_section (void)
{
if (line_buf.length < 2 || memcmp (line_buf.buffer, section_del, 2))
return Text;
if (line_buf.length == header_del_len
&& !memcmp (line_buf.buffer, header_del, header_del_len))
return Header;
if (line_buf.length == body_del_len
&& !memcmp (line_buf.buffer, body_del, body_del_len))
return Body;
if (line_buf.length == footer_del_len
&& !memcmp (line_buf.buffer, footer_del, footer_del_len))
return Footer;
return Text;
}
/* Read and process the file pointed to by FP. */
static void
process_file (FILE *fp)
{
while (readline (&line_buf, fp))
{
switch ((int) check_section ())
{
case Header:
proc_header ();
break;
case Body:
proc_body ();
break;
case Footer:
proc_footer ();
break;
case Text:
proc_text ();
break;
}
}
}
/* Process file FILE to standard output.
Return 0 if successful, 1 if not. */
static int
nl_file (const char *file)
{
FILE *stream;
if (!strcmp (file, "-"))
{
have_read_stdin = 1;
stream = stdin;
}
else
{
stream = fopen (file, "r");
if (stream == NULL)
{
error (0, errno, "%s", file);
return 1;
}
}
process_file (stream);
if (ferror (stream))
{
error (0, errno, "%s", file);
return 1;
}
if (!strcmp (file, "-"))
clearerr (stream); /* Also clear EOF. */
else if (fclose (stream) == EOF)
{
error (0, errno, "%s", file);
return 1;
}
return 0;
}
void
main (argc, argv)
int argc;
char **argv;
main (int argc, char **argv)
{
int c, exit_status = 0;
@@ -320,286 +584,3 @@ main (argc, argv)
exit (exit_status);
}
/* Process file FILE to standard output.
Return 0 if successful, 1 if not. */
static int
nl_file (file)
char *file;
{
FILE *stream;
if (!strcmp (file, "-"))
{
have_read_stdin = 1;
stream = stdin;
}
else
{
stream = fopen (file, "r");
if (stream == NULL)
{
error (0, errno, "%s", file);
return 1;
}
}
process_file (stream);
if (ferror (stream))
{
error (0, errno, "%s", file);
return 1;
}
if (!strcmp (file, "-"))
clearerr (stream); /* Also clear EOF. */
else if (fclose (stream) == EOF)
{
error (0, errno, "%s", file);
return 1;
}
return 0;
}
/* Read and process the file pointed to by FP. */
static void
process_file (fp)
FILE *fp;
{
while (readline (&line_buf, fp))
{
switch ((int) check_section ())
{
case Header:
proc_header ();
break;
case Body:
proc_body ();
break;
case Footer:
proc_footer ();
break;
case Text:
proc_text ();
break;
}
}
}
/* Return the type of line in `line_buf'. */
static enum section
check_section ()
{
if (line_buf.length < 2 || memcmp (line_buf.buffer, section_del, 2))
return Text;
if (line_buf.length == header_del_len
&& !memcmp (line_buf.buffer, header_del, header_del_len))
return Header;
if (line_buf.length == body_del_len
&& !memcmp (line_buf.buffer, body_del, body_del_len))
return Body;
if (line_buf.length == footer_del_len
&& !memcmp (line_buf.buffer, footer_del, footer_del_len))
return Footer;
return Text;
}
/* Switch to a header section. */
static void
proc_header ()
{
current_type = header_type;
current_regex = &header_regex;
if (reset_numbers)
line_no = page_start;
putchar ('\n');
}
/* Switch to a body section. */
static void
proc_body ()
{
current_type = body_type;
current_regex = &body_regex;
putchar ('\n');
}
/* Switch to a footer section. */
static void
proc_footer ()
{
current_type = footer_type;
current_regex = &footer_regex;
putchar ('\n');
}
/* Process a regular text line in `line_buf'. */
static void
proc_text ()
{
static int blank_lines = 0; /* Consecutive blank lines so far. */
switch (*current_type)
{
case 'a':
if (blank_join > 1)
{
if (line_buf.length || ++blank_lines == blank_join)
{
print_lineno ();
blank_lines = 0;
}
else
printf (print_no_line_fmt);
}
else
print_lineno ();
break;
case 't':
if (line_buf.length)
print_lineno ();
else
printf (print_no_line_fmt);
break;
case 'n':
printf (print_no_line_fmt);
break;
case 'p':
if (re_search (current_regex, line_buf.buffer, line_buf.length,
0, line_buf.length, (struct re_registers *) 0) < 0)
printf (print_no_line_fmt);
else
print_lineno ();
break;
}
fwrite (line_buf.buffer, sizeof (char), line_buf.length, stdout);
putchar ('\n');
}
/* Print and increment the line number. */
static void
print_lineno ()
{
printf (print_fmt, line_no);
line_no += page_incr;
}
/* Build the printf format string, based on `lineno_format'. */
static void
build_print_fmt ()
{
/* 12 = 10 chars for lineno_width, 1 for %, 1 for \0. */
print_fmt = xmalloc (strlen (separator_str) + 12);
switch (lineno_format)
{
case FORMAT_RIGHT_NOLZ:
sprintf (print_fmt, "%%%dd%s", lineno_width, separator_str);
break;
case FORMAT_RIGHT_LZ:
sprintf (print_fmt, "%%0%dd%s", lineno_width, separator_str);
break;
case FORMAT_LEFT:
sprintf (print_fmt, "%%-%dd%s", lineno_width, separator_str);
break;
}
}
/* Set the command line flag TYPEP and possibly the regex pointer REGEXP,
according to `optarg'. */
static int
build_type_arg (typep, regexp)
char **typep;
struct re_pattern_buffer *regexp;
{
const char *errmsg;
int rval = TRUE;
int optlen;
switch (*optarg)
{
case 'a':
case 't':
case 'n':
*typep = optarg;
break;
case 'p':
*typep = optarg++;
optlen = strlen (optarg);
regexp->allocated = optlen * 2;
regexp->buffer = (unsigned char *) xmalloc (regexp->allocated);
regexp->translate = NULL;
regexp->fastmap = xmalloc (256);
regexp->fastmap_accurate = 0;
errmsg = re_compile_pattern (optarg, optlen, regexp);
if (errmsg)
error (1, 0, "%s", errmsg);
break;
default:
rval = FALSE;
break;
}
return rval;
}
/* Print a usage message and quit. */
static void
usage (status)
int status;
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("\
Usage: %s [OPTION]... [FILE]...\n\
"),
program_name);
printf (_("\
Write each FILE to standard output, with line numbers added.\n\
With no FILE, or when FILE is -, read standard input.\n\
\n\
-b, --body-numbering=STYLE use STYLE for numbering body lines\n\
-d, --section-delimiter=CC use CC for separating logical pages\n\
-f, --footer-numbering=STYLE use STYLE for numbering footer lines\n\
-h, --header-numbering=STYLE use STYLE for numbering header lines\n\
-i, --page-increment=NUMBER line number increment at each line\n\
-l, --join-blank-lines=NUMBER group of NUMBER empty lines counted as one\n\
-n, --number-format=FORMAT insert line numbers according to FORMAT\n\
-p, --no-renumber do not reset line numbers at logical pages\n\
-s, --number-separator=STRING add STRING after (possible) line number\n\
-v, --first-page=NUMBER first line number on each logical page\n\
-w, --number-width=NUMBER use NUMBER columns for line numbers\n\
--help display this help and exit\n\
--version output version information and exit\n\
\n\
By default, selects -v1 -i1 -l1 -sTAB -w6 -nrn -hn -bt -fn. CC are\n\
two delimiter characters for separating logical pages, a missing\n\
second character implies :. Type \\\\ for \\. STYLE is one of:\n\
\n\
a number all lines\n\
t number only nonempty lines\n\
n number no lines\n\
pREGEXP number only lines that contain a match for REGEXP\n\
\n\
FORMAT is one of:\n\
\n\
ln left justified, no leading zeros\n\
rn right justified, no leading zeros\n\
rz right justified, leading zeros\n\
\n\
"));
}
exit (status);
}

162
src/od.c
View File

@@ -12,8 +12,8 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/* Written by Jim Meyering. */
@@ -54,37 +54,37 @@ typedef double LONG_DOUBLE;
#endif
#if HAVE_LIMITS_H
#include <limits.h>
# include <limits.h>
#endif
#ifndef SCHAR_MAX
#define SCHAR_MAX 127
# define SCHAR_MAX 127
#endif
#ifndef SCHAR_MIN
#define SCHAR_MIN (-128)
# define SCHAR_MIN (-128)
#endif
#ifndef SHRT_MAX
#define SHRT_MAX 32767
# define SHRT_MAX 32767
#endif
#ifndef SHRT_MIN
#define SHRT_MIN (-32768)
# define SHRT_MIN (-32768)
#endif
#ifndef ULONG_MAX
#define ULONG_MAX ((unsigned long) ~(unsigned long) 0)
# define ULONG_MAX ((unsigned long) ~(unsigned long) 0)
#endif
#ifndef OFF_T_MAX
/* FIXME: is there a way to do this without relying on the
`8 bits per byte' assumption? */
#define OFF_T_MAX (~((off_t)1 << (sizeof (off_t) * 8 - 1)))
# define OFF_T_MAX (~((off_t)1 << (sizeof (off_t) * 8 - 1)))
#endif
#define STREQ(a,b) (strcmp((a), (b)) == 0)
#ifndef MAX
#define MAX(a, b) ((a) > (b) ? (a) : (b))
# define MAX(a, b) ((a) > (b) ? (a) : (b))
#endif
#ifndef MIN
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
# define MIN(a,b) (((a) < (b)) ? (a) : (b))
#endif
/* The default number of input bytes per output line. */
@@ -92,17 +92,17 @@ typedef double LONG_DOUBLE;
/* The number of decimal digits of precision in a float. */
#ifndef FLT_DIG
#define FLT_DIG 7
# define FLT_DIG 7
#endif
/* The number of decimal digits of precision in a double. */
#ifndef DBL_DIG
#define DBL_DIG 15
# define DBL_DIG 15
#endif
/* The number of decimal digits of precision in a long double. */
#ifndef LDBL_DIG
#define LDBL_DIG DBL_DIG
# define LDBL_DIG DBL_DIG
#endif
char *xmalloc ();
@@ -298,8 +298,7 @@ static struct option const long_options[] =
};
static void
usage (status)
int status;
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
@@ -374,9 +373,7 @@ uses -A o -t d2 -w 16.\n\
using Euclid's algorithm. */
static unsigned int
gcd (u, v)
unsigned int u;
unsigned int v;
gcd (unsigned int u, unsigned int v)
{
unsigned int t;
while (v != 0)
@@ -391,9 +388,7 @@ gcd (u, v)
/* Compute the least common multiple of U and V. */
static unsigned int
lcm (u, v)
unsigned int u;
unsigned int v;
lcm (unsigned int u, unsigned int v)
{
unsigned int t = gcd (u, v);
if (t == 0)
@@ -402,10 +397,8 @@ lcm (u, v)
}
static void
print_s_char (n_bytes, block, fmt_string)
long unsigned int n_bytes;
const char *block;
const char *fmt_string;
print_s_char (long unsigned int n_bytes, const char *block,
const char *fmt_string)
{
int i;
for (i = n_bytes; i > 0; i--)
@@ -420,10 +413,8 @@ print_s_char (n_bytes, block, fmt_string)
}
static void
print_char (n_bytes, block, fmt_string)
long unsigned int n_bytes;
const char *block;
const char *fmt_string;
print_char (long unsigned int n_bytes, const char *block,
const char *fmt_string)
{
int i;
for (i = n_bytes; i > 0; i--)
@@ -435,10 +426,8 @@ print_char (n_bytes, block, fmt_string)
}
static void
print_s_short (n_bytes, block, fmt_string)
long unsigned int n_bytes;
const char *block;
const char *fmt_string;
print_s_short (long unsigned int n_bytes, const char *block,
const char *fmt_string)
{
int i;
for (i = n_bytes / sizeof (unsigned short); i > 0; i--)
@@ -452,10 +441,8 @@ print_s_short (n_bytes, block, fmt_string)
}
}
static void
print_short (n_bytes, block, fmt_string)
long unsigned int n_bytes;
const char *block;
const char *fmt_string;
print_short (long unsigned int n_bytes, const char *block,
const char *fmt_string)
{
int i;
for (i = n_bytes / sizeof (unsigned short); i > 0; i--)
@@ -467,10 +454,8 @@ print_short (n_bytes, block, fmt_string)
}
static void
print_int (n_bytes, block, fmt_string)
long unsigned int n_bytes;
const char *block;
const char *fmt_string;
print_int (long unsigned int n_bytes, const char *block,
const char *fmt_string)
{
int i;
for (i = n_bytes / sizeof (unsigned int); i > 0; i--)
@@ -482,10 +467,8 @@ print_int (n_bytes, block, fmt_string)
}
static void
print_long (n_bytes, block, fmt_string)
long unsigned int n_bytes;
const char *block;
const char *fmt_string;
print_long (long unsigned int n_bytes, const char *block,
const char *fmt_string)
{
int i;
for (i = n_bytes / sizeof (unsigned long); i > 0; i--)
@@ -497,10 +480,8 @@ print_long (n_bytes, block, fmt_string)
}
static void
print_float (n_bytes, block, fmt_string)
long unsigned int n_bytes;
const char *block;
const char *fmt_string;
print_float (long unsigned int n_bytes, const char *block,
const char *fmt_string)
{
int i;
for (i = n_bytes / sizeof (float); i > 0; i--)
@@ -512,10 +493,8 @@ print_float (n_bytes, block, fmt_string)
}
static void
print_double (n_bytes, block, fmt_string)
long unsigned int n_bytes;
const char *block;
const char *fmt_string;
print_double (long unsigned int n_bytes, const char *block,
const char *fmt_string)
{
int i;
for (i = n_bytes / sizeof (double); i > 0; i--)
@@ -528,10 +507,8 @@ print_double (n_bytes, block, fmt_string)
#ifdef HAVE_LONG_DOUBLE
static void
print_long_double (n_bytes, block, fmt_string)
long unsigned int n_bytes;
const char *block;
const char *fmt_string;
print_long_double (long unsigned int n_bytes, const char *block,
const char *fmt_string)
{
int i;
for (i = n_bytes / sizeof (LONG_DOUBLE); i > 0; i--)
@@ -545,10 +522,8 @@ print_long_double (n_bytes, block, fmt_string)
#endif
static void
print_named_ascii (n_bytes, block, unused_fmt_string)
long unsigned int n_bytes;
const char *block;
const char *unused_fmt_string;
print_named_ascii (long unsigned int n_bytes, const char *block,
const char *unused_fmt_string)
{
int i;
for (i = n_bytes; i > 0; i--)
@@ -574,10 +549,8 @@ print_named_ascii (n_bytes, block, unused_fmt_string)
}
static void
print_ascii (n_bytes, block, unused_fmt_string)
long unsigned int n_bytes;
const char *block;
const char *unused_fmt_string;
print_ascii (long unsigned int n_bytes, const char *block,
const char *unused_fmt_string)
{
int i;
for (i = n_bytes; i > 0; i--)
@@ -639,10 +612,7 @@ print_ascii (n_bytes, block, unused_fmt_string)
the result of the conversion and return zero. */
static int
simple_strtoul (s, p, val)
const char *s;
const char **p;
long unsigned int *val;
simple_strtoul (const char *s, const char **p, long unsigned int *val)
{
unsigned long int sum;
@@ -674,10 +644,7 @@ simple_strtoul (s, p, val)
*/
static int
decode_one_format (s, next, tspec)
const char *s;
const char **next;
struct tspec *tspec;
decode_one_format (const char *s, const char **next, struct tspec *tspec)
{
enum size_spec size_spec;
unsigned long int size;
@@ -787,7 +754,7 @@ decode_one_format (s, next, tspec)
case SHORT:
print_function = (fmt == SIGNED_DECIMAL
? print_s_short
: print_short);;
: print_short);
break;
case INT:
@@ -909,8 +876,7 @@ decode_one_format (s, next, tspec)
necessary. Return zero if S is valid, non-zero otherwise. */
static int
decode_format_string (s)
const char *s;
decode_format_string (const char *s)
{
assert (s != NULL);
@@ -948,8 +914,7 @@ decode_format_string (s)
input. */
static int
skip (n_skip)
off_t n_skip;
skip (off_t n_skip)
{
int err;
@@ -1050,15 +1015,13 @@ skip (n_skip)
}
static const char *
format_address_none (address)
long unsigned int address;
format_address_none (long unsigned int address)
{
return "";
}
static const char *
format_address_std (address)
long unsigned int address;
format_address_std (long unsigned int address)
{
const char *address_string;
@@ -1068,8 +1031,7 @@ format_address_std (address)
}
static const char *
format_address_label (address)
long unsigned int address;
format_address_label (long unsigned int address)
{
const char *address_string;
assert (output_address_fmt_string != NULL);
@@ -1092,11 +1054,8 @@ format_address_label (address)
only when it has not been padded to length BYTES_PER_BLOCK. */
static void
write_block (current_offset, n_bytes, prev_block, curr_block)
long unsigned int current_offset;
long unsigned int n_bytes;
const char *prev_block;
const char *curr_block;
write_block (long unsigned int current_offset, long unsigned int n_bytes,
const char *prev_block, const char *curr_block)
{
static int first = 1;
static int prev_pair_equal = 0;
@@ -1141,7 +1100,7 @@ write_block (current_offset, n_bytes, prev_block, curr_block)
have occurred. */
static int
check_and_close ()
check_and_close (void)
{
int err;
@@ -1181,8 +1140,7 @@ check_and_close ()
occured, zero otherwise. */
static int
read_char (c)
int *c;
read_char (int *c)
{
int err;
@@ -1244,10 +1202,7 @@ read_char (c)
Otherwise return zero. */
static int
read_block (n, block, n_bytes_in_buffer)
size_t n;
char *block;
size_t *n_bytes_in_buffer;
read_block (size_t n, char *block, size_t *n_bytes_in_buffer)
{
int err;
@@ -1308,7 +1263,7 @@ read_block (n, block, n_bytes_in_buffer)
with the format specs. */
static int
get_lcm ()
get_lcm (void)
{
unsigned int i;
int l_c_m = 1;
@@ -1322,8 +1277,7 @@ get_lcm ()
return the offset it denotes. Otherwise, return -1. */
off_t
parse_old_offset (s)
const char *s;
parse_old_offset (const char *s)
{
int radix;
off_t offset;
@@ -1373,7 +1327,7 @@ parse_old_offset (s)
Otherwise, return zero. */
static int
dump ()
dump (void)
{
char *block[2];
off_t current_offset;
@@ -1466,7 +1420,7 @@ dump ()
occurs. Otherwise, return zero. */
static int
dump_strings ()
dump_strings (void)
{
size_t bufsize = MAX (100, string_min);
char *buf = xmalloc (bufsize);
@@ -1581,9 +1535,7 @@ dump_strings ()
}
int
main (argc, argv)
int argc;
char **argv;
main (int argc, char **argv)
{
int c;
int n_files;

View File

@@ -50,11 +50,6 @@
char *xmalloc ();
char *xrealloc ();
static char *collapse_escapes ();
static int paste_parallel ();
static int paste_serial ();
static void usage ();
/* Indicates that no delimiter should be added in the current position. */
#define EMPTY_DELIM '\0'
@@ -97,70 +92,6 @@ static struct option const longopts[] =
{0, 0, 0, 0}
};
void
main (argc, argv)
int argc;
char **argv;
{
int optc, exit_status;
char default_delims[2], zero_delims[3];
program_name = argv[0];
have_read_stdin = 0;
serial_merge = 0;
delims = default_delims;
strcpy (delims, "\t");
strcpy (zero_delims, "\\0");
while ((optc = getopt_long (argc, argv, "d:s", longopts, (int *) 0))
!= EOF)
{
switch (optc)
{
case 0:
break;
case 'd':
/* Delimiter character(s). */
if (optarg[0] == '\0')
optarg = zero_delims;
delims = optarg;
break;
case 's':
serial_merge++;
break;
default:
usage (1);
}
}
if (show_version)
{
printf ("paste - %s\n", version_string);
exit (0);
}
if (show_help)
usage (0);
if (optind == argc)
argv[argc++] = "-";
delim_end = collapse_escapes (delims);
if (!serial_merge)
exit_status = paste_parallel (argc - optind, &argv[optind]);
else
exit_status = paste_serial (argc - optind, &argv[optind]);
if (have_read_stdin && fclose (stdin) == EOF)
error (1, errno, "-");
if (ferror (stdout) || fclose (stdout) == EOF)
error (1, errno, _("write error"));
exit (exit_status);
}
/* Replace backslash representations of special characters in
STRPTR with their actual values.
The set of possible backslash characters has been expanded beyond
@@ -169,8 +100,7 @@ main (argc, argv)
Return a pointer to the character after the new end of STRPTR. */
static char *
collapse_escapes (strptr)
char *strptr;
collapse_escapes (char *strptr)
{
register char *strout;
@@ -227,9 +157,7 @@ collapse_escapes (strptr)
opened or read. */
static int
paste_parallel (nfiles, fnamptr)
int nfiles;
char **fnamptr;
paste_parallel (int nfiles, char **fnamptr)
{
int errors = 0; /* 1 if open or read errors occur. */
/* Number of files for which space is allocated in `delbuf' and `fileptr'.
@@ -399,9 +327,7 @@ paste_parallel (nfiles, fnamptr)
opened or read. */
static int
paste_serial (nfiles, fnamptr)
int nfiles;
char **fnamptr;
paste_serial (int nfiles, char **fnamptr)
{
int errors = 0; /* 1 if open or read errors occur. */
register int charnew, charold; /* Current and previous char read. */
@@ -478,8 +404,7 @@ paste_serial (nfiles, fnamptr)
}
static void
usage (status)
int status;
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
@@ -504,3 +429,65 @@ With no FILE, or when FILE is -, read standard input.\n\
}
exit (status);
}
void
main (int argc, char **argv)
{
int optc, exit_status;
char default_delims[2], zero_delims[3];
program_name = argv[0];
have_read_stdin = 0;
serial_merge = 0;
delims = default_delims;
strcpy (delims, "\t");
strcpy (zero_delims, "\\0");
while ((optc = getopt_long (argc, argv, "d:s", longopts, (int *) 0))
!= EOF)
{
switch (optc)
{
case 0:
break;
case 'd':
/* Delimiter character(s). */
if (optarg[0] == '\0')
optarg = zero_delims;
delims = optarg;
break;
case 's':
serial_merge++;
break;
default:
usage (1);
}
}
if (show_version)
{
printf ("paste - %s\n", version_string);
exit (0);
}
if (show_help)
usage (0);
if (optind == argc)
argv[argc++] = "-";
delim_end = collapse_escapes (delims);
if (!serial_merge)
exit_status = paste_parallel (argc - optind, &argv[optind]);
else
exit_status = paste_serial (argc - optind, &argv[optind]);
if (have_read_stdin && fclose (stdin) == EOF)
error (1, errno, "-");
if (ferror (stdout) || fclose (stdout) == EOF)
error (1, errno, _("write error"));
exit (exit_status);
}

View File

@@ -15,7 +15,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Written by Paul Rubin, David MacKenzie, and Richard Stallman. */
/* Written by Paul Rubin, David MacKenzie, and Richard Stallman. */
#include <config.h>
#include <stdio.h>
@@ -27,17 +27,17 @@
#include "error.h"
#ifdef D_INO_IN_DIRENT
#define D_INO(dp) ((dp)->d_ino)
# define D_INO(dp) ((dp)->d_ino)
#else
/* POSIX.1 doesn't have inodes, so fake them to avoid lots of ifdefs. */
#define D_INO(dp) 1
/* Some systems don't have inodes, so fake them to avoid lots of ifdefs. */
# define D_INO(dp) 1
#endif
char *basename ();
char *stpcpy ();
char *xmalloc ();
char *xrealloc ();
int eaccess_stat ();
int euidaccess ();
int yesno ();
void strip_trailing_slashes ();
@@ -51,31 +51,31 @@ static void usage ();
/* Name this program was run with. */
char *program_name;
/* Path of file now being processed; extended as necessary. */
/* Path of file now being processed; extended as necessary. */
static char *pathname;
/* Number of bytes currently allocated for `pathname';
made larger when necessary, but never smaller. */
static int pnsize;
/* If nonzero, display the name of each file removed. */
/* If nonzero, display the name of each file removed. */
static int verbose;
/* If nonzero, ignore nonexistant files. */
/* If nonzero, ignore nonexistant files. */
static int ignore_missing_files;
/* If nonzero, recursively remove directories. */
/* If nonzero, recursively remove directories. */
static int recursive;
/* If nonzero, query the user about whether to remove each file. */
/* If nonzero, query the user about whether to remove each file. */
static int interactive;
/* If nonzero, remove directories with unlink instead of rmdir, and don't
require a directory to be empty before trying to unlink it.
Only works for the super-user. */
Only works for the super-user. */
static int unlink_dirs;
/* If nonzero, stdin is a tty. */
/* If nonzero, stdin is a tty. */
static int stdin_tty;
/* If non-zero, display usage information and exit. */
@@ -114,7 +114,7 @@ main (argc, argv)
{
switch (c)
{
case 0: /* Long option. */
case 0: /* Long option. */
break;
case 'd':
unlink_dirs = 1;
@@ -183,7 +183,7 @@ main (argc, argv)
}
/* Remove file or directory `pathname' after checking appropriate things.
Return 0 if `pathname' is removed, 1 if not. */
Return 0 if `pathname' is removed, 1 if not. */
static int
rm ()
@@ -214,14 +214,14 @@ rm ()
/* Query the user if appropriate, and if ok try to remove the
non-directory `pathname', which STATP contains info about.
Return 0 if `pathname' is removed, 1 if not. */
Return 0 if `pathname' is removed, 1 if not. */
static int
remove_file (statp)
struct stat *statp;
{
if (!ignore_missing_files && (interactive || stdin_tty)
&& eaccess_stat (statp, W_OK, pathname)
&& euidaccess (pathname, W_OK)
#ifdef S_ISLNK
&& !S_ISLNK (statp->st_mode)
#endif
@@ -258,7 +258,7 @@ remove_file (statp)
/* If not in recursive mode, print an error message and return 1.
Otherwise, query the user if appropriate, then try to recursively
remove directory `pathname', which STATP contains info about.
Return 0 if `pathname' is removed, 1 if not. */
Return 0 if `pathname' is removed, 1 if not. */
static int
remove_dir (statp)
@@ -273,7 +273,7 @@ remove_dir (statp)
}
if (!ignore_missing_files && (interactive || stdin_tty)
&& eaccess_stat (statp, W_OK, pathname))
&& euidaccess (pathname, W_OK))
{
fprintf (stderr,
"%s: descend directory `%s', overriding mode %04o? ",
@@ -317,7 +317,7 @@ remove_dir (statp)
/* An element in a stack of pointers into `pathname'.
`pathp' points to where in `pathname' the terminating '\0' goes
for this level's directory name. */
for this level's directory name. */
struct pathstack
{
struct pathstack *next;
@@ -327,7 +327,7 @@ struct pathstack
/* Linked list of pathnames of directories in progress in recursive rm.
The entries actually contain pointers into `pathname'.
`pathstack' is the current deepest level. */
`pathstack' is the current deepest level. */
static struct pathstack *pathstack = NULL;
/* Read directory `pathname' and remove all of its entries,
@@ -336,7 +336,7 @@ static struct pathstack *pathstack = NULL;
Return 0 for success, error count for failure.
Upon return, `pathname' will have the same contents as before,
but its address might be different; in that case, `pnsize' will
be larger, as well. */
be larger, as well. */
static int
clear_directory (statp)
@@ -344,18 +344,18 @@ clear_directory (statp)
{
DIR *dirp;
struct dirent *dp;
char *name_space; /* Copy of directory's filenames. */
char *namep; /* Current entry in `name_space'. */
unsigned name_size; /* Bytes allocated for `name_space'. */
int name_length; /* Length of filename in `namep' plus '\0'. */
int pathname_length; /* Length of `pathname'. */
ino_t *inode_space; /* Copy of directory's inodes. */
ino_t *inodep; /* Current entry in `inode_space'. */
char *name_space; /* Copy of directory's filenames. */
char *namep; /* Current entry in `name_space'. */
unsigned name_size; /* Bytes allocated for `name_space'. */
int name_length; /* Length of filename in `namep' plus '\0'. */
int pathname_length; /* Length of `pathname'. */
ino_t *inode_space; /* Copy of directory's inodes. */
ino_t *inodep; /* Current entry in `inode_space'. */
unsigned n_inodes_allocated; /* There is space for this many inodes
in `inode_space'. */
int err = 0; /* Return status. */
struct pathstack pathframe; /* New top of stack. */
struct pathstack *pp; /* Temporary. */
in `inode_space'. */
int err = 0; /* Return status. */
struct pathstack pathframe; /* New top of stack. */
struct pathstack *pp; /* Temporary. */
name_size = statp->st_size;
name_space = (char *) xmalloc (name_size);
@@ -384,7 +384,7 @@ clear_directory (statp)
while ((dp = readdir (dirp)) != NULL)
{
/* Skip "." and ".." (some NFS filesystems' directories lack them). */
/* Skip "." and "..". */
if (dp->d_name[0] != '.'
|| (dp->d_name[1] != '\0'
&& (dp->d_name[1] != '.' || dp->d_name[2] != '\0')))
@@ -431,43 +431,43 @@ clear_directory (statp)
{
name_length = strlen (namep) + 1;
/* Satisfy GNU requirement that filenames can be arbitrarily long. */
/* Handle arbitrarily long filenames. */
if (pathname_length + 1 + name_length > pnsize)
{
char *new_pathname;
pnsize = (pathname_length + 1 + name_length) * 2;
new_pathname = xrealloc (pathname, pnsize);
/* Update the all the pointers in the stack to use the new area. */
/* Update all pointers in the stack to use the new area. */
for (pp = pathstack; pp != NULL; pp = pp->next)
pp->pathp += new_pathname - pathname;
pathname = new_pathname;
}
/* Add a new frame to the top of the path stack. */
/* Add a new frame to the top of the path stack. */
pathframe.pathp = pathname + pathname_length;
pathframe.inum = *inodep;
pathframe.next = pathstack;
pathstack = &pathframe;
/* Append '/' and the filename to current pathname, take care of the
file (which could result in recursive calls), and take the filename
back off. */
/* Append '/' and the filename to current pathname, take care of
the file (which could result in recursive calls), and take
the filename back off. */
*pathstack->pathp = '/';
strcpy (pathstack->pathp + 1, namep);
/* If the i-number has already appeared, there's an error. */
/* If the i-number has already appeared, there's an error. */
if (duplicate_entry (pathstack->next, pathstack->inum))
err++;
else if (rm ())
err++;
*pathstack->pathp = '\0';
pathstack = pathstack->next; /* Pop the stack. */
pathstack = pathstack->next; /* Pop the stack. */
}
}
/* Keep trying while there are still files to remove. */
/* Keep trying while there are still files to remove. */
while (namep > name_space && err == 0);
free (name_space);
@@ -480,14 +480,14 @@ clear_directory (statp)
if yes, return 1, and if no, exit.
This assumes that no one tries to remove filesystem mount points;
doing so could cause duplication of i-numbers that would not indicate
a corrupted file system. */
a corrupted file system. */
static int
duplicate_entry (stack, inum)
struct pathstack *stack;
ino_t inum;
{
#ifndef _POSIX_SOURCE
#ifdef D_INO_IN_DIRENT
struct pathstack *p;
for (p = stack; p != NULL; p = p->next)
@@ -501,9 +501,9 @@ NOTIFY YOUR SYSTEM MANAGER.\n\
Cycle detected:\n\
%s\n\
is the same file as\n", program_name, pathname);
*p->pathp = '\0'; /* Truncate pathname. */
*p->pathp = '\0'; /* Truncate pathname. */
fprintf (stderr, "%s\n", pathname);
*p->pathp = '/'; /* Put it back. */
*p->pathp = '/'; /* Put it back. */
if (interactive)
{
fprintf (stderr, "%s: continue? ", program_name);
@@ -515,7 +515,7 @@ is the same file as\n", program_name, pathname);
exit (1);
}
}
#endif
#endif /* D_INO_IN_DIRENT */
return 0;
}

View File

@@ -32,7 +32,7 @@
#include "long-options.h"
#include "error.h"
#ifdef _POSIX_VERSION
#ifdef HAVE_LIMITS_H
#include <limits.h>
#else
#ifndef UCHAR_MAX
@@ -45,8 +45,6 @@ char *realloc ();
void free ();
#endif
static void usage ();
/* Undefine, to avoid warning about redefinition on some systems. */
#undef min
#define min(a, b) ((a) < (b) ? (a) : (b))
@@ -61,6 +59,55 @@ static void usage ();
/* The kind of blanks for '-b' to skip in various options. */
enum blanktype { bl_start, bl_end, bl_both };
/* Lines are held in core as counted strings. */
struct line
{
char *text; /* Text of the line. */
int length; /* Length not including final newline. */
char *keybeg; /* Start of first key. */
char *keylim; /* Limit of first key. */
};
/* Arrays of lines. */
struct lines
{
struct line *lines; /* Dynamically allocated array of lines. */
int used; /* Number of slots used. */
int alloc; /* Number of slots allocated. */
int limit; /* Max number of slots to allocate. */
};
/* Input buffers. */
struct buffer
{
char *buf; /* Dynamically allocated buffer. */
int used; /* Number of bytes used. */
int alloc; /* Number of bytes allocated. */
int left; /* Number of bytes left after line parsing. */
};
struct keyfield
{
int sword; /* Zero-origin 'word' to start at. */
int schar; /* Additional characters to skip. */
int skipsblanks; /* Skip leading white space at start. */
int eword; /* Zero-origin first word after field. */
int echar; /* Additional characters in field. */
int skipeblanks; /* Skip trailing white space at finish. */
int *ignore; /* Boolean array of characters to ignore. */
char *translate; /* Translation applied to characters. */
int numeric; /* Flag for numeric comparison. */
int month; /* Flag for comparison by month name. */
int reverse; /* Reverse the sense of comparison. */
struct keyfield *next; /* Next keyfield to try. */
};
struct month
{
char *name;
int val;
};
/* The name this program was run with. */
char *program_name;
@@ -81,11 +128,7 @@ static char fold_toupper[UCHAR_LIM];
/* Table mapping 3-letter month names to integers.
Alphabetic order allows binary search. */
static struct month
{
char *name;
int val;
} const monthtab[] =
static struct month const monthtab[] =
{
{"APR", 4},
{"AUG", 8},
@@ -141,49 +184,54 @@ static int unique;
/* Nonzero if any of the input files are the standard input. */
static int have_read_stdin;
/* Lines are held in core as counted strings. */
struct line
{
char *text; /* Text of the line. */
int length; /* Length not including final newline. */
char *keybeg; /* Start of first key. */
char *keylim; /* Limit of first key. */
};
/* Arrays of lines. */
struct lines
{
struct line *lines; /* Dynamically allocated array of lines. */
int used; /* Number of slots used. */
int alloc; /* Number of slots allocated. */
int limit; /* Max number of slots to allocate. */
};
/* Input buffers. */
struct buffer
{
char *buf; /* Dynamically allocated buffer. */
int used; /* Number of bytes used. */
int alloc; /* Number of bytes allocated. */
int left; /* Number of bytes left after line parsing. */
};
/* Lists of key field comparisons to be tried. */
static struct keyfield
static struct keyfield keyhead;
static void
usage (int status)
{
int sword; /* Zero-origin 'word' to start at. */
int schar; /* Additional characters to skip. */
int skipsblanks; /* Skip leading white space at start. */
int eword; /* Zero-origin first word after field. */
int echar; /* Additional characters in field. */
int skipeblanks; /* Skip trailing white space at finish. */
int *ignore; /* Boolean array of characters to ignore. */
char *translate; /* Translation applied to characters. */
int numeric; /* Flag for numeric comparison. */
int month; /* Flag for comparison by month name. */
int reverse; /* Reverse the sense of comparison. */
struct keyfield *next; /* Next keyfield to try. */
} keyhead;
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("\
Usage: %s [OPTION]... [FILE]...\n\
"),
program_name);
printf (_("\
Write sorted concatenation of all FILE(s) to standard output.\n\
\n\
+POS1 [-POS2] start a key at POS1, end it before POS2\n\
-M compare (unknown) < `JAN' < ... < `DEC', imply -b\n\
-T DIRECT use DIRECT for temporary files, not $TMPDIR or %s\n\
-b ignore leading blanks in sort fields or keys\n\
-c check if given files already sorted, do not sort\n\
-d consider only [a-zA-Z0-9 ] characters in keys\n\
-f fold lower case to upper case characters in keys\n\
-i consider only [\\040-\\0176] characters in keys\n\
-k POS1[,POS2] same as +POS1 [-POS2], but all positions counted from 1\n\
-m merge already sorted files, do not sort\n\
-n compare according to string numerical value, imply -b\n\
-o FILE write result on FILE instead of standard output\n\
-r reverse the result of comparisons\n\
-s stabilize sort by disabling last resort comparison\n\
-t SEP use SEParator instead of non- to whitespace transition\n\
-u with -c, check for strict ordering\n\
-u with -m, only output the first of an equal sequence\n\
--help display this help and exit\n\
--version output version information and exit\n\
\n\
POS is F[.C][OPTS], where F is the field number and C the character\n\
position in the field, both counted from zero. OPTS is made up of one\n\
or more of Mbdfinr, this effectively disable global -Mbdfinr settings\n\
for that key. If no key given, use the entire line as key. With no\n\
FILE, or when FILE is -, read standard input.\n\
")
, DEFAULT_TMPDIR);
}
exit (status);
}
/* The list of temporary files. */
static struct tempnode
@@ -195,7 +243,7 @@ static struct tempnode
/* Clean up any remaining temporary files. */
static void
cleanup ()
cleanup (void)
{
struct tempnode *node;
@@ -206,8 +254,7 @@ cleanup ()
/* Allocate N bytes of memory dynamically, with error checking. */
char *
xmalloc (n)
unsigned n;
xmalloc (unsigned int n)
{
char *p;
@@ -227,9 +274,7 @@ xmalloc (n)
If N is 0, run free and return NULL. */
char *
xrealloc (p, n)
char *p;
unsigned n;
xrealloc (char *p, unsigned int n)
{
if (p == 0)
return xmalloc (n);
@@ -249,25 +294,48 @@ xrealloc (p, n)
}
static FILE *
xfopen (file, how)
char *file, *how;
xtmpfopen (const char *file)
{
FILE *fp = strcmp (file, "-") ? fopen (file, how) : stdin;
FILE *fp;
int fd;
if (fp == 0)
fd = open (file, O_WRONLY | O_CREAT | O_TRUNC, 0600);
if (fd < 0 || (fp = fdopen (fd, "w")) == NULL)
{
error (0, errno, "%s", file);
cleanup ();
exit (2);
}
return fp;
}
static FILE *
xfopen (const char *file, const char *how)
{
FILE *fp;
if (strcmp (file, "-") == 0)
{
fp = stdin;
}
else
{
if ((fp = fopen (file, how)) == NULL)
{
error (0, errno, "%s", file);
cleanup ();
exit (2);
}
}
if (fp == stdin)
have_read_stdin = 1;
return fp;
}
static void
xfclose (fp)
FILE *fp;
xfclose (FILE *fp)
{
if (fp == stdin)
{
@@ -296,10 +364,7 @@ xfclose (fp)
}
static void
xfwrite (buf, size, nelem, fp)
char *buf;
int size, nelem;
FILE *fp;
xfwrite (const char *buf, int size, int nelem, FILE *fp)
{
if (fwrite (buf, size, nelem, fp) != nelem)
{
@@ -312,19 +377,25 @@ xfwrite (buf, size, nelem, fp)
/* Return a name for a temporary file. */
static char *
tempname ()
tempname (void)
{
static int seq;
static unsigned int seq;
int len = strlen (temp_file_prefix);
char *name = xmalloc (len + 16);
struct tempnode *node =
(struct tempnode *) xmalloc (sizeof (struct tempnode));
char *name = xmalloc (len + 1 + sizeof ("sort") - 1 + 5 + 5 + 1);
struct tempnode *node;
node = (struct tempnode *) xmalloc (sizeof (struct tempnode));
sprintf (name,
"%s%ssort%5.5d%5.5d",
temp_file_prefix,
(len && temp_file_prefix[len - 1] != '/') ? "/" : "",
(unsigned int) getpid () & 0xffff, ++seq);
(unsigned int) getpid () & 0xffff, seq);
/* Make sure that SEQ's value fits in 5 digits. */
++seq;
if (seq >= 100000)
seq = 0;
node->name = name;
node->next = temphead.next;
temphead.next = node;
@@ -335,8 +406,7 @@ tempname ()
remove it if it is found on the list. */
static void
zaptemp (name)
char *name;
zaptemp (char *name)
{
struct tempnode *node, *temp;
@@ -356,7 +426,7 @@ zaptemp (name)
/* Initialize the character class tables. */
static void
inittables ()
inittables (void)
{
int i;
@@ -380,9 +450,7 @@ inittables ()
/* Initialize BUF, allocating ALLOC bytes initially. */
static void
initbuf (buf, alloc)
struct buffer *buf;
int alloc;
initbuf (struct buffer *buf, int alloc)
{
buf->alloc = alloc;
buf->buf = xmalloc (buf->alloc);
@@ -395,9 +463,7 @@ initbuf (buf, alloc)
of bytes buffered. */
static int
fillbuf (buf, fp)
struct buffer *buf;
FILE *fp;
fillbuf (struct buffer *buf, FILE *fp)
{
int cc;
@@ -439,10 +505,7 @@ fillbuf (buf, fp)
for, ever. */
static void
initlines (lines, alloc, limit)
struct lines *lines;
int alloc;
int limit;
initlines (struct lines *lines, int alloc, int limit)
{
lines->alloc = alloc;
lines->lines = (struct line *) xmalloc (lines->alloc * sizeof (struct line));
@@ -454,9 +517,7 @@ initlines (lines, alloc, limit)
by KEY in LINE. */
static char *
begfield (line, key)
struct line *line;
struct keyfield *key;
begfield (const struct line *line, const struct keyfield *key)
{
register char *ptr = line->text, *lim = ptr + line->length;
register int sword = key->sword, schar = key->schar;
@@ -492,9 +553,7 @@ begfield (line, key)
in LINE specified by KEY. */
static char *
limfield (line, key)
struct line *line;
struct keyfield *key;
limfield (const struct line *line, const struct keyfield *key)
{
register char *ptr = line->text, *lim = ptr + line->length;
register int eword = key->eword, echar = key->echar;
@@ -527,12 +586,10 @@ limfield (line, key)
}
/* Find the lines in BUF, storing pointers and lengths in LINES.
Also replace newlines with NULs. */
Also replace newlines in BUF with NULs. */
static void
findlines (buf, lines)
struct buffer *buf;
struct lines *lines;
findlines (struct buffer *buf, struct lines *lines)
{
register char *beg = buf->buf, *lim = buf->buf + buf->used, *ptr;
struct keyfield *key = keyhead.next;
@@ -596,8 +653,7 @@ findlines (buf, lines)
of the fraction. Strings not of this form are considered to be zero. */
static int
fraccompare (a, b)
register char *a, *b;
fraccompare (register const char *a, register const char *b)
{
register tmpa = UCHAR (*a), tmpb = UCHAR (*b);
@@ -652,12 +708,12 @@ fraccompare (a, b)
hideously fast. */
static int
numcompare (a, b)
register char *a, *b;
numcompare (register const char *a, register const char *b)
{
register int tmpa, tmpb, loga, logb, tmp;
tmpa = UCHAR (*a), tmpb = UCHAR (*b);
tmpa = UCHAR (*a);
tmpb = UCHAR (*b);
while (blanks[tmpa])
tmpa = UCHAR (*++a);
@@ -751,9 +807,7 @@ numcompare (a, b)
0 if the name in S is not recognized. */
static int
getmonth (s, len)
char *s;
int len;
getmonth (const char *s, int len)
{
char month[4];
register int i, lo = 0, hi = 12;
@@ -782,8 +836,7 @@ getmonth (s, len)
are no more keys or a difference is found. */
static int
keycompare (a, b)
struct line *a, *b;
keycompare (const struct line *a, const struct line *b)
{
register char *texta, *textb, *lima, *limb, *translate;
register int *ignore;
@@ -913,8 +966,7 @@ keycompare (a, b)
depending on whether A compares less than, equal to, or greater than B. */
static int
compare (a, b)
register struct line *a, *b;
compare (register const struct line *a, register const struct line *b)
{
int diff, tmpa, tmpb, mini;
@@ -953,19 +1005,17 @@ compare (a, b)
}
/* Check that the lines read from the given FP come in order. Return
1 if they do and 0 if there is a disorder. */
1 if they do and 0 if there is a disorder.
FIXME: return number of first out-of-order line if not sorted. */
static int
checkfp (fp)
FILE *fp;
checkfp (FILE *fp)
{
struct buffer buf; /* Input buffer. */
struct lines lines; /* Lines scanned from the buffer. */
struct line *prev_line; /* Pointer to previous line. */
struct line temp; /* Copy of previous line. */
int cc; /* Character count. */
int cmp; /* Result of calling compare. */
int alloc, i, success = 1;
int alloc, sorted = 1;
initbuf (&buf, mergealloc);
initlines (&lines, mergealloc / linelength + 1,
@@ -974,66 +1024,69 @@ checkfp (fp)
temp.text = xmalloc (alloc);
cc = fillbuf (&buf, fp);
if (cc == 0)
goto finish;
findlines (&buf, &lines);
if (cc)
do
{
/* Compare each line in the buffer with its successor. */
for (i = 0; i < lines.used - 1; ++i)
{
cmp = compare (&lines.lines[i], &lines.lines[i + 1]);
if ((unique && cmp >= 0) || (cmp > 0))
{
success = 0;
goto finish;
}
}
while (1)
{
struct line *prev_line; /* Pointer to previous line. */
int cmp; /* Result of calling compare. */
int i;
/* Save the last line of the buffer and refill the buffer. */
prev_line = lines.lines + lines.used - 1;
if (prev_line->length > alloc)
{
while (prev_line->length + 1 > alloc)
alloc *= 2;
temp.text = xrealloc (temp.text, alloc);
}
memcpy (temp.text, prev_line->text, prev_line->length + 1);
temp.length = prev_line->length;
temp.keybeg = temp.text + (prev_line->keybeg - prev_line->text);
temp.keylim = temp.text + (prev_line->keylim - prev_line->text);
/* Compare each line in the buffer with its successor. */
for (i = 0; i < lines.used - 1; ++i)
{
cmp = compare (&lines.lines[i], &lines.lines[i + 1]);
if ((unique && cmp >= 0) || (cmp > 0))
{
sorted = 0;
goto finish;
}
}
cc = fillbuf (&buf, fp);
if (cc)
{
findlines (&buf, &lines);
/* Make sure the line saved from the old buffer contents is
less than or equal to the first line of the new buffer. */
cmp = compare (&temp, &lines.lines[0]);
if ((unique && cmp >= 0) || (cmp > 0))
{
success = 0;
break;
}
}
}
while (cc);
/* Save the last line of the buffer and refill the buffer. */
prev_line = lines.lines + (lines.used - 1);
if (prev_line->length > alloc)
{
while (prev_line->length + 1 > alloc)
alloc *= 2;
temp.text = xrealloc (temp.text, alloc);
}
memcpy (temp.text, prev_line->text, prev_line->length + 1);
temp.length = prev_line->length;
temp.keybeg = temp.text + (prev_line->keybeg - prev_line->text);
temp.keylim = temp.text + (prev_line->keylim - prev_line->text);
cc = fillbuf (&buf, fp);
if (cc == 0)
break;
findlines (&buf, &lines);
/* Make sure the line saved from the old buffer contents is
less than or equal to the first line of the new buffer. */
cmp = compare (&temp, &lines.lines[0]);
if ((unique && cmp >= 0) || (cmp > 0))
{
sorted = 0;
break;
}
}
finish:
xfclose (fp);
free (buf.buf);
free ((char *) lines.lines);
free (temp.text);
return success;
return sorted;
}
/* Merge lines from FPS onto OFP. NFPS cannot be greater than NMERGE.
Close FPS before returning. */
static void
mergefps (fps, nfps, ofp)
FILE *fps[], *ofp;
register int nfps;
mergefps (FILE **fps, register int nfps, FILE *ofp)
{
struct buffer buffer[NMERGE]; /* Input buffers for each file. */
struct lines lines[NMERGE]; /* Line tables for each buffer. */
@@ -1195,9 +1248,7 @@ mergefps (fps, nfps, ofp)
/* Sort the array LINES with NLINES members, using TEMP for temporary space. */
static void
sortlines (lines, nlines, temp)
struct line *lines, *temp;
int nlines;
sortlines (struct line *lines, int nlines, struct line *temp)
{
register struct line *lo, *hi, *t;
register int nlo, nhi;
@@ -1238,9 +1289,7 @@ sortlines (lines, nlines, temp)
Return a count of disordered files. */
static int
check (files, nfiles)
char *files[];
int nfiles;
check (char **files, int nfiles)
{
int i, disorders = 0;
FILE *fp;
@@ -1260,10 +1309,7 @@ check (files, nfiles)
/* Merge NFILES FILES onto OFP. */
static void
merge (files, nfiles, ofp)
char *files[];
int nfiles;
FILE *ofp;
merge (char **files, int nfiles, FILE *ofp)
{
int i, j, t;
char *temp;
@@ -1276,7 +1322,7 @@ merge (files, nfiles, ofp)
{
for (j = 0; j < NMERGE; ++j)
fps[j] = xfopen (files[i * NMERGE + j], "r");
tfp = xfopen (temp = tempname (), "w");
tfp = xtmpfopen (temp = tempname ());
mergefps (fps, NMERGE, tfp);
xfclose (tfp);
for (j = 0; j < NMERGE; ++j)
@@ -1285,7 +1331,7 @@ merge (files, nfiles, ofp)
}
for (j = 0; j < nfiles % NMERGE; ++j)
fps[j] = xfopen (files[i * NMERGE + j], "r");
tfp = xfopen (temp = tempname (), "w");
tfp = xtmpfopen (temp = tempname ());
mergefps (fps, nfiles % NMERGE, tfp);
xfclose (tfp);
for (j = 0; j < nfiles % NMERGE; ++j)
@@ -1304,10 +1350,7 @@ merge (files, nfiles, ofp)
/* Sort NFILES FILES onto OFP. */
static void
sort (files, nfiles, ofp)
char **files;
int nfiles;
FILE *ofp;
sort (char **files, int nfiles, FILE *ofp)
{
struct buffer buf;
struct lines lines;
@@ -1315,7 +1358,7 @@ sort (files, nfiles, ofp)
int i, ntmp;
FILE *fp, *tfp;
struct tempnode *node;
int ntemp = 0;
int n_temp_files = 0;
char **tempfiles;
initbuf (&buf, sortalloc);
@@ -1338,12 +1381,12 @@ sort (files, nfiles, ofp)
xrealloc ((char *) tmp, ntmp * sizeof (struct line));
}
sortlines (lines.lines, lines.used, tmp);
if (feof (fp) && !nfiles && !ntemp && !buf.left)
if (feof (fp) && !nfiles && !n_temp_files && !buf.left)
tfp = ofp;
else
{
++ntemp;
tfp = xfopen (tempname (), "w");
++n_temp_files;
tfp = xtmpfopen (tempname ());
}
for (i = 0; i < lines.used; ++i)
if (!unique || i == 0
@@ -1362,13 +1405,13 @@ sort (files, nfiles, ofp)
free ((char *) lines.lines);
free ((char *) tmp);
if (ntemp)
if (n_temp_files)
{
tempfiles = (char **) xmalloc (ntemp * sizeof (char *));
i = ntemp;
tempfiles = (char **) xmalloc (n_temp_files * sizeof (char *));
i = n_temp_files;
for (node = temphead.next; i > 0; node = node->next)
tempfiles[--i] = node->name;
merge (tempfiles, ntemp, ofp);
merge (tempfiles, n_temp_files, ofp);
free ((char *) tempfiles);
}
}
@@ -1376,8 +1419,7 @@ sort (files, nfiles, ofp)
/* Insert key KEY at the end of the list (`keyhead'). */
static void
insertkey (key)
struct keyfield *key;
insertkey (struct keyfield *key)
{
struct keyfield *k = &keyhead;
@@ -1388,8 +1430,7 @@ insertkey (key)
}
static void
badfieldspec (s)
char *s;
badfieldspec (const char *s)
{
error (2, 0, _("invalid field specification `%s'"), s);
}
@@ -1397,19 +1438,18 @@ badfieldspec (s)
/* Handle interrupts and hangups. */
static void
sighandler (sig)
int sig;
sighandler (int sig)
{
#ifdef _POSIX_VERSION
#ifdef SA_INTERRUPT
struct sigaction sigact;
sigact.sa_handler = SIG_DFL;
sigemptyset (&sigact.sa_mask);
sigact.sa_flags = 0;
sigaction (sig, &sigact, NULL);
#else /* !_POSIX_VERSION */
#else /* !SA_INTERRUPT */
signal (sig, SIG_DFL);
#endif /* _POSIX_VERSION */
#endif /* SA_INTERRUPT */
cleanup ();
kill (getpid (), sig);
}
@@ -1420,10 +1460,8 @@ sighandler (sig)
BLANKTYPE is the kind of blanks that 'b' should skip. */
static char *
set_ordering (s, key, blanktype)
register char *s;
struct keyfield *key;
enum blanktype blanktype;
set_ordering (register const char *s, struct keyfield *key,
enum blanktype blanktype)
{
while (*s)
{
@@ -1463,17 +1501,15 @@ set_ordering (s, key, blanktype)
key->reverse = 1;
break;
default:
return s;
return (char *) s;
}
++s;
}
return s;
return (char *) s;
}
void
main (argc, argv)
int argc;
char *argv[];
main (int argc, char **argv)
{
struct keyfield *key = NULL, gkey;
char *s;
@@ -1481,9 +1517,9 @@ main (argc, argv)
int checkonly = 0, mergeonly = 0, nfiles = 0;
char *minus = "-", *outfile = minus, **files, *tmp;
FILE *ofp;
#ifdef _POSIX_VERSION
#ifdef SA_INTERRUPT
struct sigaction oldact, newact;
#endif /* _POSIX_VERSION */
#endif /* SA_INTERRUPT */
program_name = argv[0];
@@ -1496,7 +1532,7 @@ main (argc, argv)
if (temp_file_prefix == NULL)
temp_file_prefix = DEFAULT_TMPDIR;
#ifdef _POSIX_VERSION
#ifdef SA_INTERRUPT
newact.sa_handler = sighandler;
sigemptyset (&newact.sa_mask);
newact.sa_flags = 0;
@@ -1513,7 +1549,7 @@ main (argc, argv)
sigaction (SIGTERM, NULL, &oldact);
if (oldact.sa_handler != SIG_IGN)
sigaction (SIGTERM, &newact, NULL);
#else /* !_POSIX_VERSION */
#else /* !SA_INTERRUPT */
if (signal (SIGINT, SIG_IGN) != SIG_IGN)
signal (SIGINT, sighandler);
if (signal (SIGHUP, SIG_IGN) != SIG_IGN)
@@ -1522,7 +1558,7 @@ main (argc, argv)
signal (SIGPIPE, sighandler);
if (signal (SIGTERM, SIG_IGN) != SIG_IGN)
signal (SIGTERM, sighandler);
#endif /* !_POSIX_VERSION */
#endif /* !SA_INTERRUPT */
gkey.sword = gkey.eword = -1;
gkey.ignore = NULL;
@@ -1807,7 +1843,7 @@ main (argc, argv)
fp = xfopen (files[i], "r");
tmp = tempname ();
ofp = xfopen (tmp, "w");
ofp = xtmpfopen (tmp);
while ((cc = fread (buf, 1, sizeof buf, fp)) > 0)
xfwrite (buf, 1, cc, ofp);
if (ferror (fp))
@@ -1847,50 +1883,3 @@ main (argc, argv)
exit (0);
}
static void
usage (status)
int status;
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("\
Usage: %s [OPTION]... [FILE]...\n\
"),
program_name);
printf (_("\
Write sorted concatenation of all FILE(s) to standard output.\n\
\n\
+POS1 [-POS2] start a key at POS1, end it before POS2\n\
-M compare (unknown) < `JAN' < ... < `DEC', imply -b\n\
-T DIRECT use DIRECT for temporary files, not $TMPDIR or %s\n\
-b ignore leading blanks in sort fields or keys\n\
-c check if given files already sorted, do not sort\n\
-d consider only [a-zA-Z0-9 ] characters in keys\n\
-f fold lower case to upper case characters in keys\n\
-i consider only [\\040-\\0176] characters in keys\n\
-k POS1[,POS2] same as +POS1 [-POS2], but all positions counted from 1\n\
-m merge already sorted files, do not sort\n\
-n compare according to string numerical value, imply -b\n\
-o FILE write result on FILE instead of standard output\n\
-r reverse the result of comparisons\n\
-s stabilize sort by disabling last resort comparison\n\
-t SEP use SEParator instead of non- to whitespace transition\n\
-u with -c, check for strict ordering\n\
-u with -m, only output the first of an equal sequence\n\
--help display this help and exit\n\
--version output version information and exit\n\
\n\
POS is F[.C][OPTS], where F is the field number and C the character\n\
position in the field, both counted from zero. OPTS is made up of one\n\
or more of Mbdfinr, this effectively disable global -Mbdfinr settings\n\
for that key. If no key given, use the entire line as key. With no\n\
FILE, or when FILE is -, read standard input.\n\
")
, DEFAULT_TMPDIR);
}
exit (status);
}

View File

@@ -26,23 +26,28 @@
#include <stdio.h>
#include <getopt.h>
#include <sys/types.h>
#if HAVE_LIMITS_H
# include <limits.h>
#endif
#ifndef UINT_MAX
# define UINT_MAX ((unsigned int) ~(unsigned int) 0)
#endif
#ifndef INT_MAX
# define INT_MAX ((int) (UINT_MAX >> 1))
#endif
#include "system.h"
#include "version.h"
#include "error.h"
#include "xstrtol.h"
char *xmalloc ();
int full_write ();
int safe_read ();
static int convint ();
static int isdigits ();
static int stdread ();
static void line_bytes_split ();
static void bytes_split ();
static void cwrite ();
static void lines_split ();
static void next_file_name ();
/* The name this program was run with. */
char *program_name;
@@ -82,9 +87,7 @@ static struct option const longopts[] =
};
static void
usage (status, reason)
int status;
char *reason;
usage (int status, const char *reason)
{
if (reason != NULL)
fprintf (stderr, "%s: %s\n", program_name, reason);
@@ -115,10 +118,234 @@ SIZE may have a multiplier suffix: b for 512, k for 1K, m for 1 Meg.\n\
exit (status);
}
/* Compute the next sequential output file name suffix and store it
into the string `outfile' at the position pointed to by `outfile_mid'. */
static void
next_file_name (void)
{
int x;
char *ne;
unsigned int i;
static int first_call = 1;
/* Status for outfile name generation. */
static unsigned outfile_count = 0;
static unsigned outfile_name_limit = 25 * 26;
static unsigned outfile_name_generation = 1;
if (!first_call)
outfile_count++;
first_call = 0;
if (outfile_count < outfile_name_limit)
{
for (ne = outfile_end - 1; ; ne--)
{
x = *ne;
if (x != 'z')
break;
*ne = 'a';
}
*ne = x + 1;
return;
}
outfile_count = 0;
outfile_name_limit *= 26;
outfile_name_generation++;
*outfile_mid++ = 'z';
for (i = 0; i <= outfile_name_generation; i++)
outfile_mid[i] = 'a';
outfile_end += 2;
}
/* Write BYTES bytes at BP to an output file.
If NEW_FILE_FLAG is nonzero, open the next output file.
Otherwise add to the same output file already in use. */
static void
cwrite (int new_file_flag, const char *bp, int bytes)
{
if (new_file_flag)
{
if (output_desc >= 0 && close (output_desc) < 0)
error (1, errno, "%s", outfile);
next_file_name ();
output_desc = open (outfile, O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (output_desc < 0)
error (1, errno, "%s", outfile);
}
if (full_write (output_desc, bp, bytes) < 0)
error (1, errno, "%s", outfile);
}
/* Read NCHARS bytes from the input file into BUF.
Return the number of bytes successfully read.
If this is less than NCHARS, do not call `stdread' again. */
static int
stdread (char *buf, int nchars)
{
int n_read;
int to_be_read = nchars;
while (to_be_read)
{
n_read = safe_read (input_desc, buf, to_be_read);
if (n_read < 0)
return -1;
if (n_read == 0)
break;
to_be_read -= n_read;
buf += n_read;
}
return nchars - to_be_read;
}
/* Split into pieces of exactly NCHARS bytes.
Use buffer BUF, whose size is BUFSIZE. */
static void
bytes_split (int nchars, char *buf, int bufsize)
{
int n_read;
int new_file_flag = 1;
int to_read;
int to_write = nchars;
char *bp_out;
do
{
n_read = stdread (buf, bufsize);
if (n_read < 0)
error (1, errno, "%s", infile);
bp_out = buf;
to_read = n_read;
for (;;)
{
if (to_read < to_write)
{
if (to_read) /* do not write 0 bytes! */
{
cwrite (new_file_flag, bp_out, to_read);
to_write -= to_read;
new_file_flag = 0;
}
break;
}
else
{
cwrite (new_file_flag, bp_out, to_write);
bp_out += to_write;
to_read -= to_write;
new_file_flag = 1;
to_write = nchars;
}
}
}
while (n_read == bufsize);
}
/* Split into pieces of exactly NLINES lines.
Use buffer BUF, whose size is BUFSIZE. */
static void
lines_split (int nlines, char *buf, int bufsize)
{
int n_read;
char *bp, *bp_out, *eob;
int new_file_flag = 1;
int n = 0;
do
{
n_read = stdread (buf, bufsize);
if (n_read < 0)
error (1, errno, "%s", infile);
bp = bp_out = buf;
eob = bp + n_read;
*eob = '\n';
for (;;)
{
while (*bp++ != '\n')
; /* this semicolon takes most of the time */
if (bp > eob)
{
if (eob != bp_out) /* do not write 0 bytes! */
{
cwrite (new_file_flag, bp_out, eob - bp_out);
new_file_flag = 0;
}
break;
}
else
if (++n >= nlines)
{
cwrite (new_file_flag, bp_out, bp - bp_out);
bp_out = bp;
new_file_flag = 1;
n = 0;
}
}
}
while (n_read == bufsize);
}
/* Split into pieces that are as large as possible while still not more
than NCHARS bytes, and are split on line boundaries except
where lines longer than NCHARS bytes occur. */
static void
line_bytes_split (int nchars)
{
int n_read;
char *bp;
int eof = 0;
int n_buffered = 0;
char *buf = (char *) xmalloc (nchars);
do
{
/* Fill up the full buffer size from the input file. */
n_read = stdread (buf + n_buffered, nchars - n_buffered);
if (n_read < 0)
error (1, errno, "%s", infile);
n_buffered += n_read;
if (n_buffered != nchars)
eof = 1;
/* Find where to end this chunk. */
bp = buf + n_buffered;
if (n_buffered == nchars)
{
while (bp > buf && bp[-1] != '\n')
bp--;
}
/* If chunk has no newlines, use all the chunk. */
if (bp == buf)
bp = buf + n_buffered;
/* Output the chars as one output file. */
cwrite (1, buf, bp - buf);
/* Discard the chars we just output; move rest of chunk
down to be the start of the next chunk. Source and
destination probably overlap. */
n_buffered -= bp - buf;
if (n_buffered > 0)
memmove (buf, bp, n_buffered);
}
while (!eof);
free (buf);
}
void
main (argc, argv)
int argc;
char *argv[];
main (int argc, char **argv)
{
struct stat stat_buf;
int num; /* numeric argument from command line */
@@ -144,6 +371,7 @@ main (argc, argv)
{
/* This is the argv-index of the option we will read next. */
int this_optind = optind ? optind : 1;
long int tmp_long;
c = getopt_long (argc, argv, "0123456789b:l:C:", longopts, (int *) 0);
if (c == EOF)
@@ -158,25 +386,30 @@ main (argc, argv)
if (split_type != type_undef)
usage (2, _("cannot split in more than one way"));
split_type = type_bytes;
if (convint (optarg, &accum) == -1)
if (xstrtol (optarg, NULL, 10, &tmp_long, "bkm") != LONGINT_OK
|| tmp_long < 0 || tmp_long > INT_MAX)
usage (2, _("invalid number of bytes"));
accum = (int) tmp_long;
break;
case 'l':
if (split_type != type_undef)
usage (2, _("cannot split in more than one way"));
split_type = type_lines;
if (!isdigits (optarg))
if (xstrtol (optarg, NULL, 10, &tmp_long, "") != LONGINT_OK
|| tmp_long < 0 || tmp_long > INT_MAX)
usage (2, _("invalid number of lines"));
accum = atoi (optarg);
accum = (int) tmp_long;
break;
case 'C':
if (split_type != type_undef)
usage (2, _("cannot split in more than one way"));
split_type = type_byteslines;
if (convint (optarg, &accum) == -1)
if (xstrtol (optarg, NULL, 10, &tmp_long, "bkm") != LONGINT_OK
|| tmp_long < 0 || tmp_long > INT_MAX)
usage (2, _("invalid number of bytes"));
accum = (int) tmp_long;
break;
case '0':
@@ -292,294 +525,3 @@ main (argc, argv)
exit (0);
}
/* Return nonzero if the string STR is composed entirely of decimal digits. */
static int
isdigits (str)
char *str;
{
do
{
if (!ISDIGIT (*str))
return 0;
str++;
}
while (*str);
return 1;
}
/* Put the value of the number in STR into *VAL.
STR can specify a positive integer, optionally ending in `k'
to mean kilo or `m' to mean mega.
Return 0 if STR is valid, -1 if not. */
static int
convint (str, val)
char *str;
int *val;
{
int multiplier = 1;
int arglen = strlen (str);
if (arglen > 1)
{
switch (str[arglen - 1])
{
case 'b':
multiplier = 512;
str[arglen - 1] = '\0';
break;
case 'k':
multiplier = 1024;
str[arglen - 1] = '\0';
break;
case 'm':
multiplier = 1048576;
str[arglen - 1] = '\0';
break;
}
}
if (!isdigits (str))
return -1;
*val = atoi (str) * multiplier;
return 0;
}
/* Split into pieces of exactly NCHARS bytes.
Use buffer BUF, whose size is BUFSIZE. */
static void
bytes_split (nchars, buf, bufsize)
int nchars;
char *buf;
int bufsize;
{
int n_read;
int new_file_flag = 1;
int to_read;
int to_write = nchars;
char *bp_out;
do
{
n_read = stdread (buf, bufsize);
if (n_read < 0)
error (1, errno, "%s", infile);
bp_out = buf;
to_read = n_read;
for (;;)
{
if (to_read < to_write)
{
if (to_read) /* do not write 0 bytes! */
{
cwrite (new_file_flag, bp_out, to_read);
to_write -= to_read;
new_file_flag = 0;
}
break;
}
else
{
cwrite (new_file_flag, bp_out, to_write);
bp_out += to_write;
to_read -= to_write;
new_file_flag = 1;
to_write = nchars;
}
}
}
while (n_read == bufsize);
}
/* Split into pieces of exactly NLINES lines.
Use buffer BUF, whose size is BUFSIZE. */
static void
lines_split (nlines, buf, bufsize)
int nlines;
char *buf;
int bufsize;
{
int n_read;
char *bp, *bp_out, *eob;
int new_file_flag = 1;
int n = 0;
do
{
n_read = stdread (buf, bufsize);
if (n_read < 0)
error (1, errno, "%s", infile);
bp = bp_out = buf;
eob = bp + n_read;
*eob = '\n';
for (;;)
{
while (*bp++ != '\n')
; /* this semicolon takes most of the time */
if (bp > eob)
{
if (eob != bp_out) /* do not write 0 bytes! */
{
cwrite (new_file_flag, bp_out, eob - bp_out);
new_file_flag = 0;
}
break;
}
else
if (++n >= nlines)
{
cwrite (new_file_flag, bp_out, bp - bp_out);
bp_out = bp;
new_file_flag = 1;
n = 0;
}
}
}
while (n_read == bufsize);
}
/* Split into pieces that are as large as possible while still not more
than NCHARS bytes, and are split on line boundaries except
where lines longer than NCHARS bytes occur. */
static void
line_bytes_split (nchars)
int nchars;
{
int n_read;
char *bp;
int eof = 0;
int n_buffered = 0;
char *buf = (char *) xmalloc (nchars);
do
{
/* Fill up the full buffer size from the input file. */
n_read = stdread (buf + n_buffered, nchars - n_buffered);
if (n_read < 0)
error (1, errno, "%s", infile);
n_buffered += n_read;
if (n_buffered != nchars)
eof = 1;
/* Find where to end this chunk. */
bp = buf + n_buffered;
if (n_buffered == nchars)
{
while (bp > buf && bp[-1] != '\n')
bp--;
}
/* If chunk has no newlines, use all the chunk. */
if (bp == buf)
bp = buf + n_buffered;
/* Output the chars as one output file. */
cwrite (1, buf, bp - buf);
/* Discard the chars we just output; move rest of chunk
down to be the start of the next chunk. Source and
destination probably overlap. */
n_buffered -= bp - buf;
if (n_buffered > 0)
memmove (buf, bp, n_buffered);
}
while (!eof);
free (buf);
}
/* Write BYTES bytes at BP to an output file.
If NEW_FILE_FLAG is nonzero, open the next output file.
Otherwise add to the same output file already in use. */
static void
cwrite (new_file_flag, bp, bytes)
int new_file_flag;
char *bp;
int bytes;
{
if (new_file_flag)
{
if (output_desc >= 0 && close (output_desc) < 0)
error (1, errno, "%s", outfile);
next_file_name ();
output_desc = open (outfile, O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (output_desc < 0)
error (1, errno, "%s", outfile);
}
if (full_write (output_desc, bp, bytes) < 0)
error (1, errno, "%s", outfile);
}
/* Read NCHARS bytes from the input file into BUF.
Return the number of bytes successfully read.
If this is less than NCHARS, do not call `stdread' again. */
static int
stdread (buf, nchars)
char *buf;
int nchars;
{
int n_read;
int to_be_read = nchars;
while (to_be_read)
{
n_read = safe_read (input_desc, buf, to_be_read);
if (n_read < 0)
return -1;
if (n_read == 0)
break;
to_be_read -= n_read;
buf += n_read;
}
return nchars - to_be_read;
}
/* Compute the next sequential output file name suffix and store it
into the string `outfile' at the position pointed to by `outfile_mid'. */
static void
next_file_name ()
{
int x;
char *ne;
unsigned int i;
static int first_call = 1;
/* Status for outfile name generation. */
static unsigned outfile_count = 0;
static unsigned outfile_name_limit = 25 * 26;
static unsigned outfile_name_generation = 1;
if (!first_call)
outfile_count++;
first_call = 0;
if (outfile_count < outfile_name_limit)
{
for (ne = outfile_end - 1; ; ne--)
{
x = *ne;
if (x != 'z')
break;
*ne = 'a';
}
*ne = x + 1;
return;
}
outfile_count = 0;
outfile_name_limit *= 26;
outfile_name_generation++;
*outfile_mid++ = 'z';
for (i = 0; i <= outfile_name_generation; i++)
outfile_mid[i] = 'a';
outfile_end += 2;
}

129
src/sum.c
View File

@@ -28,9 +28,6 @@
#include "version.h"
#include "error.h"
static int bsd_sum_file ();
static int sysv_sum_file ();
int safe_read ();
/* The name this program was run with. */
@@ -57,8 +54,7 @@ static struct option const longopts[] =
};
static void
usage (status)
int status;
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
@@ -83,64 +79,6 @@ With no FILE, or when FILE is -, read standard input.\n\
exit (status);
}
void
main (argc, argv)
int argc;
char **argv;
{
int errors = 0;
int optc;
int files_given;
int (*sum_func) () = bsd_sum_file;
program_name = argv[0];
have_read_stdin = 0;
while ((optc = getopt_long (argc, argv, "rs", longopts, (int *) 0)) != -1)
{
switch (optc)
{
case 0:
break;
case 'r': /* For SysV compatibility. */
sum_func = bsd_sum_file;
break;
case 's':
sum_func = sysv_sum_file;
break;
default:
usage (1);
}
}
if (show_version)
{
printf ("sum - %s\n", version_string);
exit (0);
}
if (show_help)
usage (0);
files_given = argc - optind;
if (files_given == 0)
{
if ((*sum_func) ("-", files_given) < 0)
errors = 1;
}
else
for (; optind < argc; optind++)
if ((*sum_func) (argv[optind], files_given) < 0)
errors = 1;
if (have_read_stdin && fclose (stdin) == EOF)
error (1, errno, "-");
exit (errors);
}
/* Calculate and print the rotated checksum and the size in 1K blocks
of file FILE, or of the standard input if FILE is "-".
If PRINT_NAME is >1, print FILE next to the checksum and size.
@@ -148,9 +86,7 @@ main (argc, argv)
Return 0 if successful, -1 if an error occurs. */
static int
bsd_sum_file (file, print_name)
char *file;
int print_name;
bsd_sum_file (const char *file, int print_name)
{
register FILE *fp;
register unsigned long checksum = 0; /* The checksum mod 2^16. */
@@ -210,9 +146,7 @@ bsd_sum_file (file, print_name)
Return 0 if successful, -1 if an error occurs. */
static int
sysv_sum_file (file, print_name)
char *file;
int print_name;
sysv_sum_file (const char *file, int print_name)
{
int fd;
unsigned char buf[8192];
@@ -265,3 +199,60 @@ sysv_sum_file (file, print_name)
return 0;
}
void
main (int argc, char **argv)
{
int errors = 0;
int optc;
int files_given;
int (*sum_func) () = bsd_sum_file;
program_name = argv[0];
have_read_stdin = 0;
while ((optc = getopt_long (argc, argv, "rs", longopts, (int *) 0)) != -1)
{
switch (optc)
{
case 0:
break;
case 'r': /* For SysV compatibility. */
sum_func = bsd_sum_file;
break;
case 's':
sum_func = sysv_sum_file;
break;
default:
usage (1);
}
}
if (show_version)
{
printf ("sum - %s\n", version_string);
exit (0);
}
if (show_help)
usage (0);
files_given = argc - optind;
if (files_given == 0)
{
if ((*sum_func) ("-", files_given) < 0)
errors = 1;
}
else
for (; optind < argc; optind++)
if ((*sum_func) (argv[optind], files_given) < 0)
errors = 1;
if (have_read_stdin && fclose (stdin) == EOF)
error (1, errno, "-");
exit (errors);
}

View File

@@ -141,7 +141,11 @@ off_t lseek ();
#ifdef HAVE_UTIME_H
#include <utime.h>
#else
#endif
/* Some systems (even some that do have <utime.h>) don't declare this
structure anywhere. */
#ifndef HAVE_STRUCT_UTIMBUF
struct utimbuf
{
long actime;

626
src/tac.c
View File

@@ -63,16 +63,6 @@ char *realloc ();
char *mktemp ();
static RETSIGTYPE cleanup ();
static int tac ();
static int tac_file ();
static int tac_stdin ();
static char *xmalloc ();
static char *xrealloc ();
static void output ();
static void save_stdin ();
static void xwrite ();
int full_write ();
int safe_read ();
@@ -110,6 +100,9 @@ static unsigned buffer_size;
/* The compiled regular expression representing `separator'. */
static struct re_pattern_buffer compiled_separator;
/* The name of a temporary file containing a copy of pipe input. */
static char *tempfile;
/* If non-zero, display usage information and exit. */
static int show_help;
@@ -127,8 +120,7 @@ static struct option const longopts[] =
};
static void
usage (status)
int status;
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
@@ -153,281 +145,91 @@ With no FILE, or when FILE is -, read standard input.\n\
exit (status);
}
void
main (argc, argv)
int argc;
char **argv;
static RETSIGTYPE
cleanup (void)
{
const char *error_message; /* Return value from re_compile_pattern. */
int optc, errors;
int have_read_stdin = 0;
program_name = argv[0];
errors = 0;
separator = "\n";
sentinel_length = 1;
separator_ends_record = 1;
while ((optc = getopt_long (argc, argv, "brs:", longopts, (int *) 0))
!= EOF)
{
switch (optc)
{
case 0:
break;
case 'b':
separator_ends_record = 0;
break;
case 'r':
sentinel_length = 0;
break;
case 's':
separator = optarg;
if (*separator == 0)
error (1, 0, _("separator cannot be empty"));
break;
default:
usage (1);
}
}
if (show_version)
{
printf ("tac - %s\n", version_string);
exit (0);
}
if (show_help)
usage (0);
if (sentinel_length == 0)
{
compiled_separator.allocated = 100;
compiled_separator.buffer = (unsigned char *)
xmalloc (compiled_separator.allocated);
compiled_separator.fastmap = xmalloc (256);
compiled_separator.translate = 0;
error_message = re_compile_pattern (separator, strlen (separator),
&compiled_separator);
if (error_message)
error (1, 0, "%s", error_message);
}
else
match_length = sentinel_length = strlen (separator);
read_size = INITIAL_READSIZE;
/* A precaution that will probably never be needed. */
while (sentinel_length * 2 >= read_size)
read_size *= 2;
buffer_size = read_size * 2 + sentinel_length + 2;
buffer = xmalloc (buffer_size);
if (sentinel_length)
{
strcpy (buffer, separator);
buffer += sentinel_length;
}
else
++buffer;
if (optind == argc)
{
have_read_stdin = 1;
errors = tac_stdin ();
}
else
for (; optind < argc; ++optind)
{
if (strcmp (argv[optind], "-") == 0)
{
have_read_stdin = 1;
errors |= tac_stdin ();
}
else
errors |= tac_file (argv[optind]);
}
/* Flush the output buffer. */
output ((char *) NULL, (char *) NULL);
if (have_read_stdin && close (0) < 0)
error (1, errno, "-");
if (close (1) < 0)
error (1, errno, _("write error"));
exit (errors);
}
/* The name of a temporary file containing a copy of pipe input. */
char *tempfile;
/* Print the standard input in reverse, saving it to temporary
file `tempfile' first if it is a pipe.
Return 0 if ok, 1 if an error occurs. */
static int
tac_stdin ()
{
/* Previous values of signal handlers. */
RETSIGTYPE (*sigint) (), (*sighup) (), (*sigpipe) (), (*sigterm) ();
int errors;
struct stat stats;
#ifdef _POSIX_VERSION
struct sigaction oldact, newact;
#endif /* _POSIX_VERSION */
/* No tempfile is needed for "tac < file".
Use fstat instead of checking for errno == ESPIPE because
lseek doesn't work on some special files but doesn't return an
error, either. */
if (fstat (0, &stats))
{
error (0, errno, _("standard input"));
return 1;
}
if (S_ISREG (stats.st_mode))
return tac (0, _("standard input"));
#ifdef _POSIX_VERSION
newact.sa_handler = cleanup;
sigemptyset (&newact.sa_mask);
newact.sa_flags = 0;
sigaction (SIGINT, NULL, &oldact);
sigint = oldact.sa_handler;
if (sigint != SIG_IGN)
sigaction (SIGINT, &newact, NULL);
sigaction (SIGHUP, NULL, &oldact);
sighup = oldact.sa_handler;
if (sighup != SIG_IGN)
sigaction (SIGHUP, &newact, NULL);
sigaction (SIGPIPE, NULL, &oldact);
sigpipe = oldact.sa_handler;
if (sigpipe != SIG_IGN)
sigaction (SIGPIPE, &newact, NULL);
sigaction (SIGTERM, NULL, &oldact);
sigterm = oldact.sa_handler;
if (sigterm != SIG_IGN)
sigaction (SIGTERM, &newact, NULL);
#else /* !_POSIX_VERSION */
sigint = signal (SIGINT, SIG_IGN);
if (sigint != SIG_IGN)
signal (SIGINT, cleanup);
sighup = signal (SIGHUP, SIG_IGN);
if (sighup != SIG_IGN)
signal (SIGHUP, cleanup);
sigpipe = signal (SIGPIPE, SIG_IGN);
if (sigpipe != SIG_IGN)
signal (SIGPIPE, cleanup);
sigterm = signal (SIGTERM, SIG_IGN);
if (sigterm != SIG_IGN)
signal (SIGTERM, cleanup);
#endif /* _POSIX_VERSION */
save_stdin ();
errors = tac_file (tempfile);
unlink (tempfile);
#ifdef _POSIX_VERSION
newact.sa_handler = sigint;
sigaction (SIGINT, &newact, NULL);
newact.sa_handler = sighup;
sigaction (SIGHUP, &newact, NULL);
newact.sa_handler = sigterm;
sigaction (SIGTERM, &newact, NULL);
newact.sa_handler = sigpipe;
sigaction (SIGPIPE, &newact, NULL);
#else /* !_POSIX_VERSION */
signal (SIGINT, sigint);
signal (SIGHUP, sighup);
signal (SIGTERM, sigterm);
signal (SIGPIPE, sigpipe);
#endif /* _POSIX_VERSION */
return errors;
exit (1);
}
/* Make a copy of the standard input in `tempfile'. */
/* Allocate N bytes of memory dynamically, with error checking. */
static char *
xmalloc (unsigned int n)
{
char *p;
p = malloc (n);
if (p == 0)
{
error (0, 0, _("virtual memory exhausted"));
cleanup ();
}
return p;
}
/* Change the size of memory area P to N bytes, with error checking. */
static char *
xrealloc (char *p, unsigned int n)
{
p = realloc (p, n);
if (p == 0)
{
error (0, 0, _("virtual memory exhausted"));
cleanup ();
}
return p;
}
static void
save_stdin ()
xwrite (int desc, const char *buffer, int size)
{
static char *template = NULL;
static char *tempdir;
int fd;
int bytes_read;
if (template == NULL)
if (full_write (desc, buffer, size) < 0)
{
tempdir = getenv ("TMPDIR");
if (tempdir == NULL)
tempdir = DEFAULT_TMPDIR;
template = xmalloc (strlen (tempdir) + 11);
}
sprintf (template, "%s/tacXXXXXX", tempdir);
tempfile = mktemp (template);
fd = creat (tempfile, 0600);
if (fd == -1)
{
error (0, errno, "%s", tempfile);
cleanup ();
}
while ((bytes_read = safe_read (0, buffer, read_size)) > 0)
if (full_write (fd, buffer, bytes_read) < 0)
{
error (0, errno, "%s", tempfile);
cleanup ();
}
if (close (fd) < 0)
{
error (0, errno, "%s", tempfile);
cleanup ();
}
if (bytes_read == -1)
{
error (0, errno, _("read error"));
error (0, errno, _("write error"));
cleanup ();
}
}
/* Print FILE in reverse.
Return 0 if ok, 1 if an error occurs. */
/* Print the characters from START to PAST_END - 1.
If START is NULL, just flush the buffer. */
static int
tac_file (file)
char *file;
static void
output (const char *start, const char *past_end)
{
int fd, errors;
static char buffer[WRITESIZE];
static int bytes_in_buffer = 0;
int bytes_to_add = past_end - start;
int bytes_available = WRITESIZE - bytes_in_buffer;
fd = open (file, O_RDONLY);
if (fd == -1)
if (start == 0)
{
error (0, errno, "%s", file);
return 1;
xwrite (STDOUT_FILENO, buffer, bytes_in_buffer);
bytes_in_buffer = 0;
return;
}
errors = tac (fd, file);
if (close (fd) < 0)
/* Write out as many full buffers as possible. */
while (bytes_to_add >= bytes_available)
{
error (0, errno, "%s", file);
return 1;
memcpy (buffer + bytes_in_buffer, start, bytes_available);
bytes_to_add -= bytes_available;
start += bytes_available;
xwrite (STDOUT_FILENO, buffer, WRITESIZE);
bytes_in_buffer = 0;
bytes_available = WRITESIZE;
}
return errors;
memcpy (buffer + bytes_in_buffer, start, bytes_to_add);
bytes_in_buffer += bytes_to_add;
}
/* Print in reverse the file open on descriptor FD for reading FILE.
Return 0 if ok, 1 if an error occurs. */
static int
tac (fd, file)
int fd;
char *file;
tac (int fd, const char *file)
{
/* Pointer to the location in `buffer' where the search for
the next separator will begin. */
@@ -590,90 +392,264 @@ tac (fd, file)
}
}
/* Print the characters from START to PAST_END - 1.
If START is NULL, just flush the buffer. */
/* Print FILE in reverse.
Return 0 if ok, 1 if an error occurs. */
static void
output (start, past_end)
char *start;
char *past_end;
static int
tac_file (const char *file)
{
static char buffer[WRITESIZE];
static int bytes_in_buffer = 0;
int bytes_to_add = past_end - start;
int bytes_available = WRITESIZE - bytes_in_buffer;
int fd, errors;
if (start == 0)
fd = open (file, O_RDONLY);
if (fd == -1)
{
xwrite (STDOUT_FILENO, buffer, bytes_in_buffer);
bytes_in_buffer = 0;
return;
error (0, errno, "%s", file);
return 1;
}
/* Write out as many full buffers as possible. */
while (bytes_to_add >= bytes_available)
errors = tac (fd, file);
if (close (fd) < 0)
{
memcpy (buffer + bytes_in_buffer, start, bytes_available);
bytes_to_add -= bytes_available;
start += bytes_available;
xwrite (STDOUT_FILENO, buffer, WRITESIZE);
bytes_in_buffer = 0;
bytes_available = WRITESIZE;
error (0, errno, "%s", file);
return 1;
}
memcpy (buffer + bytes_in_buffer, start, bytes_to_add);
bytes_in_buffer += bytes_to_add;
return errors;
}
static RETSIGTYPE
cleanup ()
/* Make a copy of the standard input in `tempfile'. */
static void
save_stdin (void)
{
static char *template = NULL;
static char *tempdir;
int fd;
int bytes_read;
if (template == NULL)
{
tempdir = getenv ("TMPDIR");
if (tempdir == NULL)
tempdir = DEFAULT_TMPDIR;
template = xmalloc (strlen (tempdir) + 11);
}
sprintf (template, "%s/tacXXXXXX", tempdir);
tempfile = mktemp (template);
fd = creat (tempfile, 0600);
if (fd == -1)
{
error (0, errno, "%s", tempfile);
cleanup ();
}
while ((bytes_read = safe_read (0, buffer, read_size)) > 0)
if (full_write (fd, buffer, bytes_read) < 0)
{
error (0, errno, "%s", tempfile);
cleanup ();
}
if (close (fd) < 0)
{
error (0, errno, "%s", tempfile);
cleanup ();
}
if (bytes_read == -1)
{
error (0, errno, _("read error"));
cleanup ();
}
}
/* Print the standard input in reverse, saving it to temporary
file `tempfile' first if it is a pipe.
Return 0 if ok, 1 if an error occurs. */
static int
tac_stdin (void)
{
/* Previous values of signal handlers. */
RETSIGTYPE (*sigint) (), (*sighup) (), (*sigpipe) (), (*sigterm) ();
int errors;
struct stat stats;
#ifdef SA_INTERRUPT
struct sigaction oldact, newact;
#endif /* SA_INTERRUPT */
/* No tempfile is needed for "tac < file".
Use fstat instead of checking for errno == ESPIPE because
lseek doesn't work on some special files but doesn't return an
error, either. */
if (fstat (0, &stats))
{
error (0, errno, _("standard input"));
return 1;
}
if (S_ISREG (stats.st_mode))
return tac (0, _("standard input"));
#ifdef SA_INTERRUPT
newact.sa_handler = cleanup;
sigemptyset (&newact.sa_mask);
newact.sa_flags = 0;
sigaction (SIGINT, NULL, &oldact);
sigint = oldact.sa_handler;
if (sigint != SIG_IGN)
sigaction (SIGINT, &newact, NULL);
sigaction (SIGHUP, NULL, &oldact);
sighup = oldact.sa_handler;
if (sighup != SIG_IGN)
sigaction (SIGHUP, &newact, NULL);
sigaction (SIGPIPE, NULL, &oldact);
sigpipe = oldact.sa_handler;
if (sigpipe != SIG_IGN)
sigaction (SIGPIPE, &newact, NULL);
sigaction (SIGTERM, NULL, &oldact);
sigterm = oldact.sa_handler;
if (sigterm != SIG_IGN)
sigaction (SIGTERM, &newact, NULL);
#else /* !SA_INTERRUPT */
sigint = signal (SIGINT, SIG_IGN);
if (sigint != SIG_IGN)
signal (SIGINT, cleanup);
sighup = signal (SIGHUP, SIG_IGN);
if (sighup != SIG_IGN)
signal (SIGHUP, cleanup);
sigpipe = signal (SIGPIPE, SIG_IGN);
if (sigpipe != SIG_IGN)
signal (SIGPIPE, cleanup);
sigterm = signal (SIGTERM, SIG_IGN);
if (sigterm != SIG_IGN)
signal (SIGTERM, cleanup);
#endif /* SA_INTERRUPT */
save_stdin ();
errors = tac_file (tempfile);
unlink (tempfile);
exit (1);
#ifdef SA_INTERRUPT
newact.sa_handler = sigint;
sigaction (SIGINT, &newact, NULL);
newact.sa_handler = sighup;
sigaction (SIGHUP, &newact, NULL);
newact.sa_handler = sigterm;
sigaction (SIGTERM, &newact, NULL);
newact.sa_handler = sigpipe;
sigaction (SIGPIPE, &newact, NULL);
#else /* !SA_INTERRUPT */
signal (SIGINT, sigint);
signal (SIGHUP, sighup);
signal (SIGTERM, sigterm);
signal (SIGPIPE, sigpipe);
#endif /* SA_INTERRUPT */
return errors;
}
static void
xwrite (desc, buffer, size)
int desc;
char *buffer;
int size;
void
main (int argc, char **argv)
{
if (full_write (desc, buffer, size) < 0)
const char *error_message; /* Return value from re_compile_pattern. */
int optc, errors;
int have_read_stdin = 0;
program_name = argv[0];
errors = 0;
separator = "\n";
sentinel_length = 1;
separator_ends_record = 1;
while ((optc = getopt_long (argc, argv, "brs:", longopts, (int *) 0))
!= EOF)
{
error (0, errno, _("write error"));
cleanup ();
switch (optc)
{
case 0:
break;
case 'b':
separator_ends_record = 0;
break;
case 'r':
sentinel_length = 0;
break;
case 's':
separator = optarg;
if (*separator == 0)
error (1, 0, _("separator cannot be empty"));
break;
default:
usage (1);
}
}
}
/* Allocate N bytes of memory dynamically, with error checking. */
static char *
xmalloc (n)
unsigned n;
{
char *p;
p = malloc (n);
if (p == 0)
if (show_version)
{
error (0, 0, _("virtual memory exhausted"));
cleanup ();
printf ("tac - %s\n", version_string);
exit (0);
}
return p;
}
/* Change the size of memory area P to N bytes, with error checking. */
if (show_help)
usage (0);
static char *
xrealloc (p, n)
char *p;
unsigned n;
{
p = realloc (p, n);
if (p == 0)
if (sentinel_length == 0)
{
error (0, 0, _("virtual memory exhausted"));
cleanup ();
compiled_separator.allocated = 100;
compiled_separator.buffer = (unsigned char *)
xmalloc (compiled_separator.allocated);
compiled_separator.fastmap = xmalloc (256);
compiled_separator.translate = 0;
error_message = re_compile_pattern (separator, strlen (separator),
&compiled_separator);
if (error_message)
error (1, 0, "%s", error_message);
}
return p;
else
match_length = sentinel_length = strlen (separator);
read_size = INITIAL_READSIZE;
/* A precaution that will probably never be needed. */
while (sentinel_length * 2 >= read_size)
read_size *= 2;
buffer_size = read_size * 2 + sentinel_length + 2;
buffer = xmalloc (buffer_size);
if (sentinel_length)
{
strcpy (buffer, separator);
buffer += sentinel_length;
}
else
++buffer;
if (optind == argc)
{
have_read_stdin = 1;
errors = tac_stdin ();
}
else
for (; optind < argc; ++optind)
{
if (strcmp (argv[optind], "-") == 0)
{
have_read_stdin = 1;
errors |= tac_stdin ();
}
else
errors |= tac_file (argv[optind]);
}
/* Flush the output buffer. */
output ((char *) NULL, (char *) NULL);
if (have_read_stdin && close (0) < 0)
error (1, errno, "-");
if (close (1) < 0)
error (1, errno, _("write error"));
exit (errors);
}

1451
src/tail.c

File diff suppressed because it is too large Load Diff

View File

@@ -28,6 +28,8 @@
#include <stdio.h>
#include <sys/types.h>
#define TEST_STANDALONE 1
#if !defined (TEST_STANDALONE)
# include "shell.h"
# include "posixstat.h"

View File

@@ -21,7 +21,7 @@
-d, --date=TIME Specify time and date in various formats.
-f Ignored.
-m, --time={mtime,modify} Change modification time only.
-r, --file=FILE Use the time and date of reference file FILE.
-r, --reference=FILE Use the time and date of reference file FILE.
-t TIME Specify time and date in the form
`MMDDhhmm[[CC]YY][.ss]'.
@@ -107,6 +107,7 @@ static struct option const longopts[] =
{"no-create", no_argument, 0, 'c'},
{"date", required_argument, 0, 'd'},
{"file", required_argument, 0, 'r'},
{"reference", required_argument, 0, 'r'},
{"help", no_argument, &show_help, 1},
{"version", no_argument, &show_version, 1},
{0, 0, 0, 0}
@@ -385,7 +386,7 @@ Update the access and modification times of each FILE to the current time.\n\
-d, --date=STRING parse STRING and use it instead of current time\n\
-f (ignored)\n\
-m change only the modification time\n\
-r, --file=REFERENCE use this file's times instead of current time\n\
-r, --reference=FILE use this file's times instead of current time\n\
-t STAMP use MMDDhhmm[[CC]YY][.ss] instead of current time\n\
--help display this help and exit\n\
--time=WORD access -a, atime -a, mtime -m, modify -m, use -a\n\

319
src/tr.c
View File

@@ -12,8 +12,8 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/* Written by Jim Meyering, meyering@cs.utexas.edu. */
@@ -29,6 +29,10 @@
#include <sys/types.h>
#include <getopt.h>
#if HAVE_LIMITS_H
# include <limits.h>
#endif
#include "system.h"
#include "version.h"
#include "error.h"
@@ -41,6 +45,14 @@
#define LONG_MAX ((long int) (ULONG_MAX >> 1))
#endif
#ifndef UINT_MAX
# define UINT_MAX ((unsigned int) ~(unsigned int) 0)
#endif
#ifndef INT_MAX
# define INT_MAX ((int) (UINT_MAX >> 1))
#endif
#ifndef UCHAR_MAX
#define UCHAR_MAX 0xFF
#endif
@@ -60,9 +72,10 @@ typedef int (*PFI) ();
/* The value for Spec_list->state that indicates to
get_next that it should initialize the tail pointer.
Its value doesn't matter as long as it can't be
confused with a valid character code. */
#define BEGIN_STATE (2 * N_CHARS)
Its value should be as large as possible to avoid conflict
a valid value for the state field -- and that may be as
large as any valid repeat_count. */
#define BEGIN_STATE (INT_MAX - 1)
/* The value for Spec_list->state that indicates to
get_next that the element pointed to by Spec_list->tail is
@@ -201,6 +214,22 @@ struct Spec_list
int has_restricted_char_class;
};
/* A representation for escaped string1 or string2. As a string is parsed,
any backslash-escaped characters (other than octal or \a, \b, \f, \n,
etc.) are marked as such in this structure by setting the corresponding
entry in the ESCAPED vector. */
struct E_string
{
unsigned char *s;
int *escaped;
size_t len;
};
/* Return non-zero if the Ith character of escaped string ES matches C
and is not escaped itself. */
#define ES_MATCH(ES, I, C) ((ES)->s[(I)] == (C) && !(ES)->escaped[(I)])
char *xmalloc ();
char *stpcpy ();
int safe_read ();
@@ -460,9 +489,17 @@ is_char_class_member (enum Char_class char_class, unsigned int c)
cannot contain actual (non-escaped) zero bytes. */
static int
unquote (unsigned char *s, size_t *len)
unquote (const unsigned char *s, struct E_string *es)
{
size_t i, j;
size_t len;
len = strlen (s);
es->s = xmalloc (len);
es->escaped = (int *) xmalloc (len * sizeof (es->escaped[0]));
for (i = 0; i < len; i++)
es->escaped[i] = 0;
j = 0;
for (i = 0; s[i]; i++)
@@ -542,18 +579,26 @@ unquote (unsigned char *s, size_t *len)
return 1;
default:
error (0, 0, _("invalid backslash escape `\\%c'"), s[i + 1]);
return 1;
if (posix_pedantic)
{
error (0, 0, _("invalid backslash escape `\\%c'"), s[i + 1]);
return 1;
}
else
{
c = s[i + 1];
es->escaped[j] = 1;
}
}
++i;
s[j++] = c;
es->s[j++] = c;
break;
default:
s[j++] = s[i];
es->s[j++] = s[i];
break;
}
}
*len = j;
es->len = j;
return 0;
}
@@ -709,23 +754,18 @@ append_range (struct Spec_list *list, unsigned int first, unsigned int last)
/* If CHAR_CLASS_STR is a valid character class string, append a
newly allocated structure representing that character class to the end
of the specification list LIST and return 0. If CHAR_CLASS_STR is not
a valid string, print an error message and return non-zero. */
a valid string return non-zero. */
static int
append_char_class (struct Spec_list *list, const unsigned char *char_class_str, size_t len)
append_char_class (struct Spec_list *list,
const unsigned char *char_class_str, size_t len)
{
enum Char_class char_class;
struct List_element *new;
char_class = look_up_char_class (char_class_str, len);
if (char_class == CC_NO_CLASS)
{
char *tmp = make_printable_str (char_class_str, len);
error (0, 0, _("invalid character class `%s'"), tmp);
free (tmp);
return 1;
}
return 1;
new = (struct List_element *) xmalloc (sizeof (struct List_element));
new->next = NULL;
new->type = RE_CHAR_CLASS;
@@ -742,7 +782,8 @@ append_char_class (struct Spec_list *list, const unsigned char *char_class_str,
is a non-negative repeat count. */
static void
append_repeated_char (struct Spec_list *list, unsigned int the_char, size_t repeat_count)
append_repeated_char (struct Spec_list *list, unsigned int the_char,
size_t repeat_count)
{
struct List_element *new;
@@ -760,22 +801,16 @@ append_repeated_char (struct Spec_list *list, unsigned int the_char, size_t repe
the length of that string, LEN, if LEN is exactly one, append
a newly allocated structure representing the specified
equivalence class to the specification list, LIST and return zero.
If LEN is not 1, issue an error message and return non-zero. */
If LEN is not 1, return non-zero. */
static int
append_equiv_class (struct Spec_list *list, const unsigned char *equiv_class_str, size_t len)
append_equiv_class (struct Spec_list *list,
const unsigned char *equiv_class_str, size_t len)
{
struct List_element *new;
if (len != 1)
{
char *tmp = make_printable_str (equiv_class_str, len);
error (0, 0, _("%s: equivalence class operand must be a single character"),
tmp);
free (tmp);
return 1;
}
return 1;
new = (struct List_element *) xmalloc (sizeof (struct List_element));
new->next = NULL;
new->type = RE_EQUIV_CLASS;
@@ -813,12 +848,14 @@ substr (const unsigned char *p, size_t first_idx, size_t last_idx)
zero bytes. */
static int
find_closing_delim (const unsigned char *p, size_t start_idx, size_t p_len, unsigned int pre_bracket_char, size_t *result_idx)
find_closing_delim (const struct E_string *es, size_t start_idx,
unsigned int pre_bracket_char, size_t *result_idx)
{
size_t i;
for (i = start_idx; i < p_len - 1; i++)
if (p[i] == pre_bracket_char && p[i + 1] == ']')
for (i = start_idx; i < es->len - 1; i++)
if (es->s[i] == pre_bracket_char && es->s[i + 1] == ']'
&& !es->escaped[i] && !es->escaped[i + 1])
{
*result_idx = i;
return 1;
@@ -879,22 +916,24 @@ non_neg_strtol (const unsigned char *s, size_t len, size_t *val)
and return -2. */
static int
find_bracketed_repeat (const unsigned char *p, size_t start_idx, size_t p_len, unsigned int *char_to_repeat, size_t *repeat_count, size_t *closing_bracket_idx)
find_bracketed_repeat (const struct E_string *es, size_t start_idx,
unsigned int *char_to_repeat, size_t *repeat_count,
size_t *closing_bracket_idx)
{
size_t i;
assert (start_idx + 1 < p_len);
if (p[start_idx + 1] != '*')
assert (start_idx + 1 < es->len);
if (!ES_MATCH (es, start_idx + 1, '*'))
return -1;
for (i = start_idx + 2; i < p_len; i++)
for (i = start_idx + 2; i < es->len; i++)
{
if (p[i] == ']')
if (ES_MATCH (es, i, ']'))
{
const unsigned char *digit_str;
size_t digit_str_len = i - start_idx - 2;
*char_to_repeat = p[start_idx];
*char_to_repeat = es->s[start_idx];
if (digit_str_len == 0)
{
/* We've matched [c*] -- no explicit repeat count. */
@@ -905,8 +944,9 @@ find_bracketed_repeat (const unsigned char *p, size_t start_idx, size_t p_len, u
/* Here, we have found [c*s] where s should be a string
of octal or decimal digits. */
digit_str = &p[start_idx + 2];
if (non_neg_strtol (digit_str, digit_str_len, repeat_count))
digit_str = &es->s[start_idx + 2];
if (non_neg_strtol (digit_str, digit_str_len, repeat_count)
|| *repeat_count > BEGIN_STATE)
{
char *tmp = make_printable_str (digit_str, digit_str_len);
error (0, 0, _("invalid repeat count `%s' in [c*n] construct"),
@@ -921,6 +961,30 @@ find_bracketed_repeat (const unsigned char *p, size_t start_idx, size_t p_len, u
return -1; /* No bracket found. */
}
/* Return non-zero if the string at ES->s[IDX] matches the regular
expression `\*[0-9]*\]', zero otherwise. To match, the `*' and
the `]' must not be escaped. */
static int
star_digits_closebracket (const struct E_string *es, int idx)
{
int i;
if (!ES_MATCH (es, idx, '*'))
return 0;
for (i = idx + 1; i < es->len; i++)
{
if (!ISDIGIT (es->s[i]))
{
if (ES_MATCH (es, i, ']'))
return 1;
return 0;
}
}
return 0;
}
/* Convert string UNESACPED_STRING (which has been preprocessed to
convert backslash-escape sequences) of length LEN characters into
a linked list of the following 5 types of constructs:
@@ -934,12 +998,12 @@ find_bracketed_repeat (const unsigned char *p, size_t start_idx, size_t p_len, u
- c Any other character is interpreted as itself. */
static int
build_spec_list (const unsigned char *unescaped_string, size_t len, struct Spec_list *result)
build_spec_list (const struct E_string *es, struct Spec_list *result)
{
const unsigned char *p;
size_t i;
p = unescaped_string;
p = es->s;
/* The main for-loop below recognizes the 4 multi-character constructs.
A character that matches (in its context) none of the multi-character
@@ -948,38 +1012,81 @@ build_spec_list (const unsigned char *unescaped_string, size_t len, struct Spec_
less are composed solely of normal characters. Hence, the index of
the outer for-loop runs only as far as LEN-2. */
for (i = 0; i + 2 < len;)
for (i = 0; i + 2 < es->len; /* empty */)
{
switch (p[i])
if (ES_MATCH (es, i, '['))
{
int fall_through;
int matched_multi_char_construct;
size_t closing_bracket_idx;
unsigned int char_to_repeat;
size_t repeat_count;
int err;
case '[':
fall_through = 0;
switch (p[i + 1])
matched_multi_char_construct = 1;
if (ES_MATCH (es, i + 1, ':')
|| ES_MATCH (es, i + 1, '='))
{
size_t closing_delim_idx;
size_t closing_bracket_idx;
unsigned int char_to_repeat;
size_t repeat_count;
int found;
case ':':
case '=':
found = find_closing_delim (p, i + 2, len, p[i + 1],
found = find_closing_delim (es, i + 2, p[i + 1],
&closing_delim_idx);
if (found)
{
int parse_failed;
unsigned char *opnd_str = substr (p, i + 2,
closing_delim_idx - 1);
size_t opnd_str_len = closing_delim_idx - 1 - (i + 2) + 1;
if (p[i + 1] == ':')
parse_failed = append_char_class (result, opnd_str,
(closing_delim_idx - 1) - (i + 2) + 1);
{
parse_failed = append_char_class (result, opnd_str,
opnd_str_len);
/* FIXME: big comment. */
if (parse_failed)
{
if (star_digits_closebracket (es, i + 2))
{
free (opnd_str);
goto try_bracketed_repeat;
}
else
{
char *tmp = make_printable_str (opnd_str,
opnd_str_len);
error (0, 0, _("invalid character class `%s'"),
tmp);
free (tmp);
return 1;
}
}
}
else
parse_failed = append_equiv_class (result, opnd_str,
(closing_delim_idx - 1) - (i + 2) + 1);
{
parse_failed = append_equiv_class (result, opnd_str,
opnd_str_len);
/* FIXME: big comment. */
if (parse_failed)
{
if (star_digits_closebracket (es, i + 2))
{
free (opnd_str);
goto try_bracketed_repeat;
}
else
{
char *tmp = make_printable_str (opnd_str,
opnd_str_len);
error (0, 0,
_("%s: equivalence class operand must be a single character"),
tmp);
free (tmp);
return 1;
}
}
}
free (opnd_str);
/* Return non-zero if append_*_class reports a problem. */
@@ -987,56 +1094,58 @@ build_spec_list (const unsigned char *unescaped_string, size_t len, struct Spec_
return 1;
else
i = closing_delim_idx + 2;
break;
continue;
}
/* Else fall through. This could be [:*] or [=*]. */
default:
/* Determine whether this is a bracketed repeat range
matching the RE \[.\*(dec_or_oct_number)?\]. */
err = find_bracketed_repeat (p, i + 1, len, &char_to_repeat,
&repeat_count,
&closing_bracket_idx);
if (err == 0)
{
append_repeated_char (result, char_to_repeat, repeat_count);
i = closing_bracket_idx + 1;
break;
}
else if (err == -1)
{
fall_through = 1;
}
else
/* Found a string that looked like [c*n] but the
numeric part was invalid. */
return 1;
break;
}
if (!fall_through)
break;
/* Here if we've tried to match [c*n], [:str:], and [=c=]
and none of them fit. So we still have to consider the
range `[-c' (from `[' to `c'). */
default:
/* Look ahead one char for ranges like a-z. */
if (p[i + 1] == '-')
try_bracketed_repeat:
/* Determine whether this is a bracketed repeat range
matching the RE \[.\*(dec_or_oct_number)?\]. */
err = find_bracketed_repeat (es, i + 1, &char_to_repeat,
&repeat_count,
&closing_bracket_idx);
if (err == 0)
{
if (append_range (result, p[i], p[i + 2]))
return 1;
i += 3;
append_repeated_char (result, char_to_repeat, repeat_count);
i = closing_bracket_idx + 1;
}
else if (err == -1)
{
matched_multi_char_construct = 0;
}
else
{
append_normal_char (result, p[i]);
++i;
/* Found a string that looked like [c*n] but the
numeric part was invalid. */
return 1;
}
break;
if (matched_multi_char_construct)
continue;
/* We reach this point if P does not match [:str:], [=c=],
[c*n], or [c*]. Now, see if P looks like a range `[-c'
(from `[' to `c'). */
}
/* Look ahead one char for ranges like a-z. */
if (ES_MATCH (es, i + 1, '-'))
{
if (append_range (result, p[i], p[i + 2]))
return 1;
i += 3;
}
else
{
append_normal_char (result, p[i]);
++i;
}
}
/* Now handle the (2 or fewer) remaining characters p[i]..p[len - 1]. */
for (; i < len; i++)
/* Now handle the (2 or fewer) remaining characters p[i]..p[es->len - 1]. */
for (; i < es->len; i++)
append_normal_char (result, p[i]);
return 0;
@@ -1317,13 +1426,13 @@ spec_init (struct Spec_list *spec_list)
of these passes detects an error, this function returns non-zero. */
static int
parse_str (unsigned char *s, struct Spec_list *spec_list)
parse_str (const unsigned char *s, struct Spec_list *spec_list)
{
size_t len;
struct E_string es;
if (unquote (s, &len))
if (unquote (s, &es))
return 1;
if (build_spec_list (s, len, spec_list))
if (build_spec_list (&es, spec_list))
return 1;
return 0;
}
@@ -1433,7 +1542,8 @@ appear in\n\tstring2 are `upper' and `lower'"));
if (s2->n_indefinite_repeats > 1)
{
error (1, 0, _("only one [c*] repeat construct may appear in string2"));
error (1, 0,
_("only one [c*] repeat construct may appear in string2"));
}
if (translating)
@@ -1765,7 +1875,8 @@ without squeezing repeats"));
}
if (squeeze_repeats && non_option_args == 0)
error (1, 0, _("at least one string must be given when squeezing repeats"));
error (1, 0,
_("at least one string must be given when squeezing repeats"));
spec_init (s1);
if (parse_str ((unsigned char *) argv[optind], s1))

View File

@@ -58,13 +58,6 @@
char *xmalloc ();
char *xrealloc ();
static FILE *next_file ();
static void add_tabstop ();
static void parse_tabstops ();
static void unexpand ();
static void usage ();
static void validate_tabstops ();
/* The name this program was run with. */
char *program_name;
@@ -114,90 +107,24 @@ static struct option const longopts[] =
{NULL, 0, NULL, 0}
};
void
main (argc, argv)
int argc;
char **argv;
/* Add tab stop TABVAL to the end of `tab_list', except
if TABVAL is -1, do nothing. */
static void
add_tabstop (int tabval)
{
int tabval = -1; /* Value of tabstop being read, or -1. */
int c; /* Option character. */
have_read_stdin = 0;
exit_status = 0;
convert_entire_line = 0;
tab_list = NULL;
first_free_tab = 0;
program_name = argv[0];
while ((c = getopt_long (argc, argv, "at:,0123456789", longopts, (int *) 0))
!= EOF)
{
switch (c)
{
case 0:
break;
case '?':
usage (1);
case 'a':
convert_entire_line = 1;
break;
case 't':
convert_entire_line = 1;
parse_tabstops (optarg);
break;
case ',':
add_tabstop (tabval);
tabval = -1;
break;
default:
if (tabval == -1)
tabval = 0;
tabval = tabval * 10 + c - '0';
break;
}
}
if (show_version)
{
printf ("unexpand - %s\n", version_string);
exit (0);
}
if (show_help)
usage (0);
add_tabstop (tabval);
validate_tabstops (tab_list, first_free_tab);
if (first_free_tab == 0)
tab_size = 8;
else if (first_free_tab == 1)
tab_size = tab_list[0];
else
tab_size = 0;
if (optind == argc)
file_list = stdin_argv;
else
file_list = &argv[optind];
unexpand ();
if (have_read_stdin && fclose (stdin) == EOF)
error (1, errno, "-");
if (fclose (stdout) == EOF)
error (1, errno, _("write error"));
exit (exit_status);
if (tabval == -1)
return;
if (first_free_tab % TABLIST_BLOCK == 0)
tab_list = (int *) xrealloc (tab_list, first_free_tab + TABLIST_BLOCK);
tab_list[first_free_tab++] = tabval;
}
/* Add the comma or blank separated list of tabstops STOPS
to the list of tabstops. */
static void
parse_tabstops (stops)
char *stops;
parse_tabstops (const char *stops)
{
int tabval = -1;
@@ -221,27 +148,11 @@ parse_tabstops (stops)
add_tabstop (tabval);
}
/* Add tab stop TABVAL to the end of `tab_list', except
if TABVAL is -1, do nothing. */
static void
add_tabstop (tabval)
int tabval;
{
if (tabval == -1)
return;
if (first_free_tab % TABLIST_BLOCK == 0)
tab_list = (int *) xrealloc (tab_list, first_free_tab + TABLIST_BLOCK);
tab_list[first_free_tab++] = tabval;
}
/* Check that the list of tabstops TABS, with ENTRIES entries,
contains only nonzero, ascending values. */
static void
validate_tabstops (tabs, entries)
int *tabs;
int entries;
validate_tabstops (const int *tabs, int entries)
{
int prev_tab = 0;
int i;
@@ -256,11 +167,58 @@ validate_tabstops (tabs, entries)
}
}
/* Close the old stream pointer FP if it is non-NULL,
and return a new one opened to read the next input file.
Open a filename of `-' as the standard input.
Return NULL if there are no more input files. */
static FILE *
next_file (FILE *fp)
{
static char *prev_file;
char *file;
if (fp)
{
if (ferror (fp))
{
error (0, errno, "%s", prev_file);
exit_status = 1;
}
if (fp == stdin)
clearerr (fp); /* Also clear EOF. */
else if (fclose (fp) == EOF)
{
error (0, errno, "%s", prev_file);
exit_status = 1;
}
}
while ((file = *file_list++) != NULL)
{
if (file[0] == '-' && file[1] == '\0')
{
have_read_stdin = 1;
prev_file = file;
return stdin;
}
fp = fopen (file, "r");
if (fp)
{
prev_file = file;
return fp;
}
error (0, errno, "%s", file);
exit_status = 1;
}
return NULL;
}
/* Change spaces to tabs, writing to stdout.
Read each file in `file_list', in order. */
static void
unexpand ()
unexpand (void)
{
FILE *fp; /* Input stream. */
int c; /* Each input character. */
@@ -391,57 +349,8 @@ unexpand ()
}
}
/* Close the old stream pointer FP if it is non-NULL,
and return a new one opened to read the next input file.
Open a filename of `-' as the standard input.
Return NULL if there are no more input files. */
static FILE *
next_file (fp)
FILE *fp;
{
static char *prev_file;
char *file;
if (fp)
{
if (ferror (fp))
{
error (0, errno, "%s", prev_file);
exit_status = 1;
}
if (fp == stdin)
clearerr (fp); /* Also clear EOF. */
else if (fclose (fp) == EOF)
{
error (0, errno, "%s", prev_file);
exit_status = 1;
}
}
while ((file = *file_list++) != NULL)
{
if (file[0] == '-' && file[1] == '\0')
{
have_read_stdin = 1;
prev_file = file;
return stdin;
}
fp = fopen (file, "r");
if (fp)
{
prev_file = file;
return fp;
}
error (0, errno, "%s", file);
exit_status = 1;
}
return NULL;
}
static void
usage (status)
int status;
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
@@ -467,3 +376,79 @@ Instead of -t NUMBER or -t LIST, -NUMBER or -LIST may be used.\n\
}
exit (status);
}
void
main (int argc, char **argv)
{
int tabval = -1; /* Value of tabstop being read, or -1. */
int c; /* Option character. */
have_read_stdin = 0;
exit_status = 0;
convert_entire_line = 0;
tab_list = NULL;
first_free_tab = 0;
program_name = argv[0];
while ((c = getopt_long (argc, argv, "at:,0123456789", longopts, (int *) 0))
!= EOF)
{
switch (c)
{
case 0:
break;
case '?':
usage (1);
case 'a':
convert_entire_line = 1;
break;
case 't':
convert_entire_line = 1;
parse_tabstops (optarg);
break;
case ',':
add_tabstop (tabval);
tabval = -1;
break;
default:
if (tabval == -1)
tabval = 0;
tabval = tabval * 10 + c - '0';
break;
}
}
if (show_version)
{
printf ("unexpand - %s\n", version_string);
exit (0);
}
if (show_help)
usage (0);
add_tabstop (tabval);
validate_tabstops (tab_list, first_free_tab);
if (first_free_tab == 0)
tab_size = 8;
else if (first_free_tab == 1)
tab_size = tab_list[0];
else
tab_size = 0;
if (optind == argc)
file_list = stdin_argv;
else
file_list = &argv[optind];
unexpand ();
if (have_read_stdin && fclose (stdin) == EOF)
error (1, errno, "-");
if (fclose (stdout) == EOF)
error (1, errno, _("write error"));
exit (exit_status);
}

View File

@@ -34,12 +34,6 @@
#undef min
#define min(x, y) ((x) < (y) ? (x) : (y))
static char *find_field ();
static int different ();
static void check_file ();
static void usage ();
static void writeline ();
/* The name this program was run with. */
char *program_name;
@@ -90,11 +84,183 @@ static struct option const longopts[] =
{"version", no_argument, &show_version, 1},
{NULL, 0, NULL, 0}
};
static void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("\
Usage: %s [OPTION]... [INPUT [OUTPUT]]\n\
"),
program_name);
printf (_("\
Discard all but one of successive identical lines from INPUT (or\n\
standard input), writing to OUTPUT (or standard output).\n\
\n\
-c, --count prefix lines by the number of occurrences\n\
-d, --repeated only print duplicate lines\n\
-f, --skip-fields=N avoid comparing the N first fields\n\
-s, --skip-chars=N avoid comparing the N first characters\n\
-u, --unique only print unique lines\n\
-w, --check-chars=N compare no more than N characters in lines\n\
-N same as -f N\n\
+N same as -s N\n\
--help display this help and exit\n\
--version output version information and exit\n\
\n\
A field is a run of whitespace, than non-whitespace characters.\n\
Fields are skipped before chars. \n\
"));
}
exit (status);
}
/* Given a linebuffer LINE,
return a pointer to the beginning of the line's field to be compared. */
static char *
find_field (const struct linebuffer *line)
{
register int count;
register char *lp = line->buffer;
register int size = line->length;
register int i = 0;
for (count = 0; count < skip_fields && i < size; count++)
{
while (i < size && ISBLANK (lp[i]))
i++;
while (i < size && !ISBLANK (lp[i]))
i++;
}
for (count = 0; count < skip_chars && i < size; count++)
i++;
return lp + i;
}
/* Return zero if two strings OLD and NEW match, nonzero if not.
OLD and NEW point not to the beginnings of the lines
but rather to the beginnings of the fields to compare.
OLDLEN and NEWLEN are their lengths. */
static int
different (const char *old, const char *new, int oldlen, int newlen)
{
register int order;
if (check_chars)
{
if (oldlen > check_chars)
oldlen = check_chars;
if (newlen > check_chars)
newlen = check_chars;
}
order = memcmp (old, new, min (oldlen, newlen));
if (order == 0)
return oldlen - newlen;
return order;
}
/* Output the line in linebuffer LINE to stream STREAM
provided that the switches say it should be output.
If requested, print the number of times it occurred, as well;
LINECOUNT + 1 is the number of times that the line occurred. */
static void
writeline (const struct linebuffer *line, FILE *stream, int linecount)
{
if ((mode == output_unique && linecount != 0)
|| (mode == output_repeated && linecount == 0))
return;
if (countmode == count_occurrences)
fprintf (stream, "%7d\t", linecount + 1);
fwrite (line->buffer, sizeof (char), line->length, stream);
putc ('\n', stream);
}
/* Process input file INFILE with output to OUTFILE.
If either is "-", use the standard I/O stream for it instead. */
static void
check_file (const char *infile, const char *outfile)
{
FILE *istream;
FILE *ostream;
struct linebuffer lb1, lb2;
struct linebuffer *thisline, *prevline, *exch;
char *prevfield, *thisfield;
int prevlen, thislen;
int match_count = 0;
if (!strcmp (infile, "-"))
istream = stdin;
else
istream = fopen (infile, "r");
if (istream == NULL)
error (1, errno, "%s", infile);
if (!strcmp (outfile, "-"))
ostream = stdout;
else
ostream = fopen (outfile, "w");
if (ostream == NULL)
error (1, errno, "%s", outfile);
thisline = &lb1;
prevline = &lb2;
initbuffer (thisline);
initbuffer (prevline);
if (readline (prevline, istream) == 0)
goto closefiles;
prevfield = find_field (prevline);
prevlen = prevline->length - (prevfield - prevline->buffer);
while (!feof (istream))
{
if (readline (thisline, istream) == 0)
break;
thisfield = find_field (thisline);
thislen = thisline->length - (thisfield - thisline->buffer);
if (!different (thisfield, prevfield, thislen, prevlen))
match_count++;
else
{
writeline (prevline, ostream, match_count);
match_count = 0;
exch = prevline;
prevline = thisline;
thisline = exch;
prevfield = thisfield;
prevlen = thislen;
}
}
writeline (prevline, ostream, match_count);
closefiles:
if (ferror (istream) || fclose (istream) == EOF)
error (1, errno, _("error reading %s"), infile);
if (ferror (ostream) || fclose (ostream) == EOF)
error (1, errno, _("error writing %s"), outfile);
free (lb1.buffer);
free (lb2.buffer);
}
void
main (argc, argv)
int argc;
char *argv[];
main (int argc, char **argv)
{
int optc;
char *infile = "-", *outfile = "-";
@@ -186,187 +352,3 @@ main (argc, argv)
exit (0);
}
/* Process input file INFILE with output to OUTFILE.
If either is "-", use the standard I/O stream for it instead. */
static void
check_file (infile, outfile)
char *infile, *outfile;
{
FILE *istream;
FILE *ostream;
struct linebuffer lb1, lb2;
struct linebuffer *thisline, *prevline, *exch;
char *prevfield, *thisfield;
int prevlen, thislen;
int match_count = 0;
if (!strcmp (infile, "-"))
istream = stdin;
else
istream = fopen (infile, "r");
if (istream == NULL)
error (1, errno, "%s", infile);
if (!strcmp (outfile, "-"))
ostream = stdout;
else
ostream = fopen (outfile, "w");
if (ostream == NULL)
error (1, errno, "%s", outfile);
thisline = &lb1;
prevline = &lb2;
initbuffer (thisline);
initbuffer (prevline);
if (readline (prevline, istream) == 0)
goto closefiles;
prevfield = find_field (prevline);
prevlen = prevline->length - (prevfield - prevline->buffer);
while (!feof (istream))
{
if (readline (thisline, istream) == 0)
break;
thisfield = find_field (thisline);
thislen = thisline->length - (thisfield - thisline->buffer);
if (!different (thisfield, prevfield, thislen, prevlen))
match_count++;
else
{
writeline (prevline, ostream, match_count);
match_count = 0;
exch = prevline;
prevline = thisline;
thisline = exch;
prevfield = thisfield;
prevlen = thislen;
}
}
writeline (prevline, ostream, match_count);
closefiles:
if (ferror (istream) || fclose (istream) == EOF)
error (1, errno, _("error reading %s"), infile);
if (ferror (ostream) || fclose (ostream) == EOF)
error (1, errno, _("error writing %s"), outfile);
free (lb1.buffer);
free (lb2.buffer);
}
/* Given a linebuffer LINE,
return a pointer to the beginning of the line's field to be compared. */
static char *
find_field (line)
struct linebuffer *line;
{
register int count;
register char *lp = line->buffer;
register int size = line->length;
register int i = 0;
for (count = 0; count < skip_fields && i < size; count++)
{
while (i < size && ISBLANK (lp[i]))
i++;
while (i < size && !ISBLANK (lp[i]))
i++;
}
for (count = 0; count < skip_chars && i < size; count++)
i++;
return lp + i;
}
/* Return zero if two strings OLD and NEW match, nonzero if not.
OLD and NEW point not to the beginnings of the lines
but rather to the beginnings of the fields to compare.
OLDLEN and NEWLEN are their lengths. */
static int
different (old, new, oldlen, newlen)
char *old;
char *new;
int oldlen;
int newlen;
{
register int order;
if (check_chars)
{
if (oldlen > check_chars)
oldlen = check_chars;
if (newlen > check_chars)
newlen = check_chars;
}
order = memcmp (old, new, min (oldlen, newlen));
if (order == 0)
return oldlen - newlen;
return order;
}
/* Output the line in linebuffer LINE to stream STREAM
provided that the switches say it should be output.
If requested, print the number of times it occurred, as well;
LINECOUNT + 1 is the number of times that the line occurred. */
static void
writeline (line, stream, linecount)
struct linebuffer *line;
FILE *stream;
int linecount;
{
if ((mode == output_unique && linecount != 0)
|| (mode == output_repeated && linecount == 0))
return;
if (countmode == count_occurrences)
fprintf (stream, "%7d\t", linecount + 1);
fwrite (line->buffer, sizeof (char), line->length, stream);
putc ('\n', stream);
}
static void
usage (status)
int status;
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("\
Usage: %s [OPTION]... [INPUT [OUTPUT]]\n\
"),
program_name);
printf (_("\
Discard all but one of successive identical lines from INPUT (or\n\
standard input), writing to OUTPUT (or standard output).\n\
\n\
-c, --count prefix lines by the number of occurrences\n\
-d, --repeated only print duplicate lines\n\
-f, --skip-fields=N avoid comparing the N first fields\n\
-s, --skip-chars=N avoid comparing the N first characters\n\
-u, --unique only print unique lines\n\
-w, --check-chars=N compare no more than N characters in lines\n\
-N same as -f N\n\
+N same as -s N\n\
--help display this help and exit\n\
--version output version information and exit\n\
\n\
A field is a run of whitespace, than non-whitespace characters.\n\
Fields are skipped before chars. \n\
"));
}
exit (status);
}

217
src/wc.c
View File

@@ -32,10 +32,6 @@
int safe_read ();
static void wc ();
static void wc_file ();
static void write_counts ();
/* The name this program was run with. */
char *program_name;
@@ -69,8 +65,7 @@ static struct option const longopts[] =
};
static void
usage (status)
int status;
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
@@ -95,106 +90,31 @@ read standard input.\n\
exit (status);
}
void
main (argc, argv)
int argc;
char **argv;
static void
write_counts (long unsigned int lines, long unsigned int words,
long unsigned int chars, const char *file)
{
int optc;
int nfiles;
program_name = argv[0];
exit_status = 0;
print_lines = print_words = print_chars = 0;
total_lines = total_words = total_chars = 0;
while ((optc = getopt_long (argc, argv, "clw", longopts, (int *) 0)) != EOF)
switch (optc)
{
case 0:
break;
case 'c':
print_chars = 1;
break;
case 'l':
print_lines = 1;
break;
case 'w':
print_words = 1;
break;
default:
usage (1);
}
if (show_version)
if (print_lines)
printf ("%7lu", lines);
if (print_words)
{
printf ("wc - %s\n", version_string);
exit (0);
if (print_lines)
putchar (' ');
printf ("%7lu", words);
}
if (show_help)
usage (0);
if (print_lines + print_words + print_chars == 0)
print_lines = print_words = print_chars = 1;
nfiles = argc - optind;
if (nfiles == 0)
if (print_chars)
{
have_read_stdin = 1;
wc (0, "");
if (print_lines || print_words)
putchar (' ');
printf ("%7lu", chars);
}
else
{
for (; optind < argc; ++optind)
wc_file (argv[optind]);
if (nfiles > 1)
write_counts (total_lines, total_words, total_chars, _("total"));
}
if (have_read_stdin && close (0))
error (1, errno, "-");
exit (exit_status);
if (*file)
printf (" %s", file);
putchar ('\n');
}
static void
wc_file (file)
char *file;
{
if (!strcmp (file, "-"))
{
have_read_stdin = 1;
wc (0, file);
}
else
{
int fd = open (file, O_RDONLY);
if (fd == -1)
{
error (0, errno, "%s", file);
exit_status = 1;
return;
}
wc (fd, file);
if (close (fd))
{
error (0, errno, "%s", file);
exit_status = 1;
}
}
}
static void
wc (fd, file)
int fd;
char *file;
wc (int fd, const char *file)
{
char buf[BUFFER_SIZE + 1];
register int bytes_read;
@@ -309,25 +229,94 @@ wc (fd, file)
}
static void
write_counts (lines, words, chars, file)
unsigned long lines, words, chars;
char *file;
wc_file (const char *file)
{
if (print_lines)
printf ("%7lu", lines);
if (print_words)
if (!strcmp (file, "-"))
{
if (print_lines)
putchar (' ');
printf ("%7lu", words);
have_read_stdin = 1;
wc (0, file);
}
if (print_chars)
else
{
if (print_lines || print_words)
putchar (' ');
printf ("%7lu", chars);
int fd = open (file, O_RDONLY);
if (fd == -1)
{
error (0, errno, "%s", file);
exit_status = 1;
return;
}
wc (fd, file);
if (close (fd))
{
error (0, errno, "%s", file);
exit_status = 1;
}
}
if (*file)
printf (" %s", file);
putchar ('\n');
}
void
main (int argc, char **argv)
{
int optc;
int nfiles;
program_name = argv[0];
exit_status = 0;
print_lines = print_words = print_chars = 0;
total_lines = total_words = total_chars = 0;
while ((optc = getopt_long (argc, argv, "clw", longopts, (int *) 0)) != EOF)
switch (optc)
{
case 0:
break;
case 'c':
print_chars = 1;
break;
case 'l':
print_lines = 1;
break;
case 'w':
print_words = 1;
break;
default:
usage (1);
}
if (show_version)
{
printf ("wc - %s\n", version_string);
exit (0);
}
if (show_help)
usage (0);
if (print_lines + print_words + print_chars == 0)
print_lines = print_words = print_chars = 1;
nfiles = argc - optind;
if (nfiles == 0)
{
have_read_stdin = 1;
wc (0, "");
}
else
{
for (; optind < argc; ++optind)
wc_file (argv[optind]);
if (nfiles > 1)
write_counts (total_lines, total_words, total_chars, _("total"));
}
if (have_read_stdin && close (0))
error (1, errno, "-");
exit (exit_status);
}

View File

@@ -1,4 +1,5 @@
t??.[12]
t*.log
t*.out
t*.in
t*.exp

View File

@@ -43,5 +43,7 @@
('6b', '-a1 -e -', "a 1\nb 2\nd 4\n", "a 21\nb 22\nc 23\nf 26\n", "a 1 21\nb 2 22\nd 4\n", 0);
('6c', '-a1 -e -', "a 21\nb 22\nc 23\nf 26\n", "a 1\nb 2\nd 4\n", "a 21 1\nb 22 2\nc 23\nf 26\n", 0);
('7a', '-a1 -e . -o 2.7', "a\nb\nc\n", "a x y\nb\nc\n", ".\n.\n.\n", 0);
('8a', '-a1 -e . -o 0,1.2', "a\nb\nc\nd G\n", "a x y\nb\nc\ne\n", "a .\nb .\nc .\nd G\n", 0);
('8b', '-a1 -a2 -e . -o 0,1.2', "a\nb\nc\nd G\n", "a x y\nb\nc\ne\n", "a .\nb .\nc .\nd G\ne .\n", 0);

View File

@@ -49,7 +49,7 @@
("u", "aabbaa", '-ds', 'b','a', "a", 0);
("v", "ZZ0123456789acbdefABCDEFZZ", \
'-ds', '[:xdigit:]','Z', "Z", 0);
# Try some data with 8th bit set in case something is mistakenly sign-extended.
# Try some data with 8th bit set in case something is mistakenly sign-extended.
("w", "\300\301\377\345\345\350\345", \
'-ds', '\350','\345', "\300\301\377\345", 0);
("x", "abcdefghijklmnop", '-s', 'abcdefghijklmn','[:*016]', ":op", 0);
@@ -61,3 +61,9 @@
("B", "", '', 'a',"''", "", 1);
("C", "abcxyzABCXYZ", '', '[:lower:]', '[:upper:]', "ABCXYZABCXYZ", 0);
("D", "abcxyzABCXYZ", '', '[:upper:]', '[:lower:]', "abcxyzabcxyz", 0);
("E", "a=c", '', 'a[=*2][=c=]', 'xyyz', "xyz", 0);
("F", ":1239", '', '[:*3][:digit:]', 'a-m', "cefgm", 0);
("G", "abc", '', 'a[b*512]c', '1[x*]2', "1x2", 0);
("H", "abc", '', 'a[b*513]c', '1[x*]2', "1x2", 0);
("I", "abc-z", '', 'a\-z', 'A-Z', "AbcBC", 0);