Requirement: the first command line parameter of the program is the name of the file to be opened, and the remaining parameters specify the input and output operations to be performed on the file. Each parameter representing an operation begins with a letter, followed by a related value (separated by no spaces).
soffet: retrieve offset byte position from file
rlength: read the length byte data from the file at the current offset of the file, and explicitly
Rlength: reads the length byte data from the file at the offset of the current file, and explicitly displays it in hex
wstr: at the current file offset, the string specified by str is written by the file
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; }
Write a 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)