1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1992-2013 AT&T Intellectual Property * 5 * and is licensed under the * 6 * Eclipse Public License, Version 1.0 * 7 * by AT&T Intellectual Property * 8 * * 9 * A copy of the License is available at * 10 * http://www.eclipse.org/org/documents/epl-v10.html * 11 * (with md5 checksum b35adb5213ca9657e911e9befb180842) * 12 * * 13 * Information and Software Systems Research * 14 * AT&T Research * 15 * Florham Park NJ * 16 * * 17 * Glenn Fowler <glenn.s.fowler@gmail.com> * 18 * David Korn <dgkorn@gmail.com> * 19 * * 20 ***********************************************************************/ 21 #pragma prototyped 22 /* 23 * David Korn 24 * AT&T Bell Laboratories 25 * 26 * output the beginning portion of one or more files 27 */ 28 29 static const char usage[] = 30 "[-n?\n@(#)$Id: head (AT&T Research) 2013-09-19 $\n]" 31 USAGE_LICENSE 32 "[+NAME?head - output beginning portion of one or more files ]" 33 "[+DESCRIPTION?\bhead\b copies one or more input files to standard " 34 "output stopping at a designated point for each file or to the end of " 35 "the file whichever comes first. Copying ends at the point indicated by " 36 "the options. By default a header of the form \b==> \b\afilename\a\b " 37 "<==\b is output before all but the first file but this can be changed " 38 "with the \b-q\b and \b-v\b options.]" 39 "[+?If no \afile\a is given, or if the \afile\a is \b-\b, \bhead\b " 40 "copies from standard input starting at the current location.]" 41 "[+?The option argument for \b-c\b, and \b-s\b can optionally be " 42 "followed by one of the following characters to specify a different unit " 43 "other than a single byte:]" 44 "{" 45 "[+b?512 bytes.]" 46 "[+k?1-killobyte.]" 47 "[+m?1-megabyte.]" 48 "}" 49 "[+?For backwards compatibility, \b-\b\anumber\a is equivalent to \b-n\b " 50 "\anumber\a.]" 51 "[n:lines?Copy \alines\a lines from each file.]#[lines:=10]" 52 "[c:bytes?Copy \achars\a bytes from each file.]#[chars]" 53 "[q:quiet|silent?Never ouput filename headers.]" 54 "[s:skip?Skip \askip\a characters or lines from each file before " 55 "copying.]#[skip]" 56 "[v:verbose?Always ouput filename headers.]" 57 "\n\n" 58 "[ file ... ]" 59 "\n\n" 60 "[+EXIT STATUS?]" 61 "{" 62 "[+0?All files copied successfully.]" 63 "[+>0?One or more files did not copy.]" 64 "}" 65 "[+SEE ALSO?\bcat\b(1), \btail\b(1)]" 66 ; 67 68 #include <cmd.h> 69 70 int 71 b_head(int argc, register char** argv, Shbltin_t* context) 72 { 73 static const char header_fmt[] = "\n==> %s <==\n"; 74 75 register Sfio_t* fp; 76 register char* cp; 77 register off_t keep = 10; 78 register off_t skip = 0; 79 register int delim = '\n'; 80 off_t moved; 81 int header = 1; 82 char* format = (char*)header_fmt+1; 83 84 cmdinit(argc, argv, context, ERROR_CATALOG, 0); 85 for (;;) 86 { 87 switch (optget(argv, usage)) 88 { 89 case 'c': 90 delim = -1; 91 /*FALLTHROUGH*/ 92 case 'n': 93 if (opt_info.offset && argv[opt_info.index][opt_info.offset] == 'c') 94 { 95 delim = -1; 96 opt_info.offset++; 97 } 98 if ((keep = opt_info.number) <=0) 99 error(2, "%s: %I*d: positive numeric option argument expected", opt_info.name, sizeof(keep), keep); 100 continue; 101 case 'q': 102 header = argc; 103 continue; 104 case 'v': 105 header = 0; 106 continue; 107 case 's': 108 skip = opt_info.number; 109 continue; 110 case '?': 111 error(ERROR_usage(2), "%s", opt_info.arg); 112 continue; 113 case ':': 114 error(2, "%s", opt_info.arg); 115 continue; 116 } 117 break; 118 } 119 argv += opt_info.index; 120 argc -= opt_info.index; 121 if (error_info.errors) 122 error(ERROR_usage(2), "%s", optusage(NiL)); 123 if (cp = *argv) 124 argv++; 125 do 126 { 127 if (!cp || streq(cp, "-")) 128 { 129 cp = "/dev/stdin"; 130 fp = sfstdin; 131 sfset(fp, SF_SHARE, 1); 132 } 133 else if (!(fp = sfopen(NiL, cp, "r"))) 134 { 135 error(ERROR_system(0), "%s: cannot open", cp); 136 continue; 137 } 138 if (argc > header) 139 sfprintf(sfstdout, format, cp); 140 format = (char*)header_fmt; 141 if (skip > 0) 142 { 143 if ((moved = sfmove(fp, NiL, skip, delim)) < 0 && !ERROR_PIPE(errno) && errno != EINTR) 144 error(ERROR_system(0), "%s: skip error", cp); 145 if (delim >= 0 && moved < skip) 146 goto next; 147 } 148 if ((moved = sfmove(fp, sfstdout, keep, delim)) < 0 && !ERROR_PIPE(errno) && errno != EINTR || 149 delim >= 0 && moved < keep && sfmove(fp, sfstdout, SF_UNBOUND, -1) < 0 && !ERROR_PIPE(errno) && errno != EINTR) 150 error(ERROR_system(0), "%s: read error", cp); 151 next: 152 if (fp != sfstdin) 153 sfclose(fp); 154 } while (cp = *argv++); 155 if (sfsync(sfstdout)) 156 error(ERROR_system(0), "write error"); 157 return error_info.errors != 0; 158 } 159