需求:程序的第一个命令行参数为将要打开的文件名称,余下的参数则指定了文件上执行的输入输出操作。每个表示操作的参数都以一个字母开头,紧跟以相关值(中间无空格分隔)。
soffet:从文件开始检索到offset字节位置
rlength:在文件当前偏移量处,从文件中读取length字节数据,并以文本形式显式
Rlength:在当前文件偏移量处,从文件中读取length字节数据,并以十六进制形式显式
wstr:在当前文件偏移量处,由文件写入由str指定的字符串
#include <sys/stat.h> #include <fcntl.h> #include <ctype.h> #include "get_num.h" #include <stdio.h> #include <stdlib.h> #include <string.h> int main(int argc, char *argv[]) { size_t len; off_t offset; int fd, ap, j; char *buf; ssize_t numRead, numWritten; /* usage */ if(argc < 3 || strcmp(argv[1], "--help") == 0) printf("%s file {r<length> | R<length> | w<string> | s<offset>} ...\n", argv[0]); /* open or create file */ fd = open(argv[1], O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); /* is system call success */ if(fd == -1) printf("open file error\n"); /* biz code */ for(ap = 2; ap < argc; ap++) { switch(argv[ap][0]) { case ‘r‘: /* Display bytes at current offset, as text */ case ‘R‘: /* Display bytes at current offset, in hex */ len = getLong(&argv[ap][1], GN_ANY_BASE, argv[ap]); /* alloc buffer */ buf = malloc(len); /* is alloc success */ if(buf == NULL) printf("malloc error\n"); numRead = read(fd, buf, len); if(numRead == -1) /* read fail */ printf("read\n"); /* end of file */ if(numRead == 0) printf("%s: end-of-file\n", argv[ap]); else { printf("%s: ", argv[ap]); for(j=0; j<numRead; j++) if(argv[ap][0] == ‘r‘) printf("%c", isprint((unsigned char) buf[j]) ? buf[j] : ‘?‘); else printf("%O2x ", (unsigned int) buf[j]); printf("\n"); } /* free memory */ free(buf); break; case ‘w‘: /* Write string at current offset */ numWritten = write(fd, &argv[ap][1], strlen(&argv[ap][1])); if(numWritten == -1) printf("write error\n"); printf("%s: wrote %ld bytes\n", argv[ap], (long) numWritten); break; case ‘s‘: offset = getLong(&argv[ap][1], GN_ANY_BASE, argv[ap]); if(lseek(fd, offset, SEEK_SET) == -1) printf("lseek error!\n"); printf("%s: seek successed\n", argv[ap]); break; default: printf("Argument must start with [rRws]: %s\n", argv[ap]); } } exit(0); }
get_num.h
#ifndef GET_NUM_H #define GET_NUM_H #define GN_NONNEG 01 /* Value must be >= 0 */ #define GN_GT_0 02 /* Value must be > 0 */ /* By default, integers are decimal */ #define GN_ANY_BASE 0100 /* Can use any base - like strtol(3) */ #define GN_BASE_8 0200 /* Value is expressed in octal */ #define GN_BASE_16 0400 /* Value is expressed in hexadecimal */ long getLong(const char *arg, int flags, const char *name); int getInt(const char *arg, int flags, const char *name); #endif
get_num.c
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <limits.h> #include <errno.h> #include "get_num.h" static void gnFail(const char *fname, const char *msg, const char *arg, const char *name) { fprintf(stderr, "%s error", fname); if (name != NULL) fprintf(stderr, " (in %s)", name); fprintf(stderr, ": %s\n", name); if(arg != NULL && *arg != ‘\0‘) fprintf(stderr, " offending text: %s\n", arg); exit(EXIT_FAILURE); } static long getNum(const char *fname, const char *arg, int flags, const char *name) { long res; char *endptr; int base; if(arg == NULL || *arg == ‘\0‘) gnFail(fname, "null or empty string", arg, name); base = (flags & GN_ANY_BASE) ? 0 : (flags & GN_BASE_8) ? 8 : (flags & GN_BASE_16) ? 16 : 10; errno = 0; res = strtol(arg, &endptr, base); if(errno != 0) gnFail(fname, "strtol() failed", arg, name); if(*endptr != ‘\0‘) gnFail(fname, "nonnumeric characters", arg, name); if((flags & GN_NONNEG) && res < 0) gnFail(fname, "negative value not allowed", arg, name); if((flags & GN_GT_0) && res <= 0) gnFail(fname, "value must be > 0", arg, name); return res; } long getLong(const char *arg, int flags, const char *name) { return getNum("getLong", arg, flags, name); } int getInt(const char *arg, int flags, const char *name) { long res; res = getNum("getInt", arg, flags, name); if(res > INT_MAX || res < INT_MIN) gnFail("getInt", "integer out of range", arg, name); return (int) res; }