需求:程序的第一个命令行参数为将要打开的文件名称,余下的参数则指定了文件上执行的输入输出操作。每个表示操作的参数都以一个字母开头,紧跟以相关值(中间无空格分隔)。
soffet:从文件开始检索到offset字节位置
rlength:在文件当前偏移量处,从文件中读取length字节数据,并以文本形式显式
Rlength:在当前文件偏移量处,从文件中读取length字节数据,并以十六进制形式显式
wstr:在当前文件偏移量处,由文件写入由str指定的字符串
main.c
#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;
}
写个Makefile
# Edit the following for your installation
CC = /usr/bin/cc
CXX = /usr/bin/g++
#==============================================================
# Compiler and linker flags
CXXFLAGS= -Wall -g
CFLAGS = -Wall -g
LFLAGS =
INCPATH =
LIBS=
####### Implicit rules
.SUFFIXES: .o .c .cpp .cc .cxx .C
.cpp.o:
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<"
.cc.o:
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<"
.cxx.o:
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<"
.C.o:
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<"
.c.o:
$(CC) -c $(CFLAGS) $(INCPATH) -o "$@" "$<"
#==============================================================
# This program's code files
prg = seektest
OBJS = main.o get_num.o
#==============================================================
# File dependencies and rules
all: $(prg)
$(prg): $(OBJS)
$(CC) -o $@ $(LFLAGS) $(OBJS) $(LIBS)
clean:
rm -f *~
rm -f *.o
rm -f core
cleanall:clean
rm -f $(prg)