1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1992-2007 AT&T Knowledge Ventures * 5 * and is licensed under the * 6 * Common Public License, Version 1.0 * 7 * by AT&T Knowledge Ventures * 8 * * 9 * A copy of the License is available at * 10 * http://www.opensource.org/licenses/cpl1.0.txt * 11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 12 * * 13 * Information and Software Systems Research * 14 * AT&T Research * 15 * Florham Park NJ * 16 * * 17 * Glenn Fowler <gsf@research.att.com> * 18 * David Korn <dgk@research.att.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@(#)$Id: head (AT&T Research) 2006-09-27 $\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, void* 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 int header = 1; 81 char* format = (char*)header_fmt+1; 82 83 cmdinit(argc, argv, context, ERROR_CATALOG, 0); 84 for (;;) 85 { 86 switch (optget(argv, usage)) 87 { 88 case 'c': 89 delim = -1; 90 /*FALLTHROUGH*/ 91 case 'n': 92 if (opt_info.offset && argv[opt_info.index][opt_info.offset] == 'c') 93 { 94 delim = -1; 95 opt_info.offset++; 96 } 97 if ((keep = opt_info.number) <=0) 98 error(2, "%s: %I*d: positive numeric option argument expected", opt_info.name, sizeof(keep), keep); 99 continue; 100 case 'q': 101 header = argc; 102 continue; 103 case 'v': 104 header = 0; 105 continue; 106 case 's': 107 skip = opt_info.number; 108 continue; 109 case '?': 110 error(ERROR_usage(2), "%s", opt_info.arg); 111 continue; 112 case ':': 113 error(2, "%s", opt_info.arg); 114 continue; 115 } 116 break; 117 } 118 argv += opt_info.index; 119 argc -= opt_info.index; 120 if (error_info.errors) 121 error(ERROR_usage(2), "%s", optusage(NiL)); 122 if (cp = *argv) 123 argv++; 124 do 125 { 126 if (!cp || streq(cp, "-")) 127 { 128 cp = "/dev/stdin"; 129 fp = sfstdin; 130 sfset(fp, SF_SHARE, 1); 131 } 132 else if (!(fp = sfopen(NiL, cp, "r"))) 133 { 134 error(ERROR_system(0), "%s: cannot open", cp); 135 continue; 136 } 137 if (argc > header) 138 sfprintf(sfstdout, format, cp); 139 format = (char*)header_fmt; 140 if (skip > 0) 141 sfmove(fp, NiL, skip, delim); 142 if (sfmove(fp, sfstdout, keep, delim) < 0 && errno != EPIPE) 143 error(ERROR_system(0), "%s: read error", cp); 144 if (fp != sfstdin) 145 sfclose(fp); 146 } while (cp = *argv++); 147 if (sfsync(sfstdout)) 148 error(ERROR_system(0), "write error"); 149 return error_info.errors != 0; 150 } 151