Код:
#define _LARGEFILE64_SOURCE
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include "getopt.h"
char* itoa(unsigned int val);
void dchk(int f);
int ferr();
int usage();
int main(int argc, char** argv){
register int ch, filenum;//filenum- FILE NUMber;
int longIndex;
register short sht=0, shn=0, shcc=0, num=0, num_nonblank=0;
//sht- SHow Tabulation; shn- SHow '\n' symbol(carriage return); shcc- SHow Control Characters; num- NUMber;
static const struct option longOpts[] = {
{ "show-nonprinting", no_argument, NULL, 'v' },
{ "show-tabs", no_argument, NULL, 'T' },
{ "show-ends", no_argument, NULL, 'E' },
{ "show-all", no_argument, NULL, 'A' },
{ "number", no_argument, NULL, 'n' },
{ "version", no_argument, NULL, 0 },
{ NULL, no_argument, NULL, 0 }
};
while((ch=getopt_long(argc, argv, "ETAethuni",longOpts,&longIndex))!= -1){
switch (ch) {
case 'n':
num = 1;
break;
case 'i':
num_nonblank = 1;
break;
case 'E':
shn = 1;
break;
case 'T':
sht=1;
break;
case 'A':{
shn=1;
sht=1;
shcc=1;
break;
}
case 'v':
shcc=1;
break;
case 'e':{
shcc=1;
shn=1;
break;
}
case 't':{
shcc=1;
sht=1;
break;
}
case '?':
case 'h':
usage();
case 'u':
break;
case 0:if(strcmp( "version",longOpts[longIndex].name)==0){
write(STDOUT_FILENO,"sysccat version 0.1\n",20);
_exit(0);
}
else usage();
}
}
argv+=optind;
argc-=optind;
if(argc==0)usage();
//if no options defined
if(!sht&&!shn&&!shcc&&!num)for(filenum=0;filenum<argc;++filenum){
int fd=open(argv[filenum],O_RDONLY);
if(fd<0)ferr();
dchk(fd);
off_t filesize=lseek(fd,0,SEEK_END);
lseek(fd,0,SEEK_SET);
char *c;
c=malloc(4096);
while(4096<filesize){
read(fd,c,4096);
write(STDOUT_FILENO,c,4096);
filesize-=4096;
}
free(c);
c=malloc(filesize);
read(fd,c,filesize);
write(STDOUT_FILENO,c,filesize);
free(c);
close(fd);
}
//if any option defined
else for(filenum=0;filenum<argc;++filenum){
char a;
int fd=open(argv[filenum],O_RDONLY);
if(fd<0)ferr();
dchk(fd);
if(num)write(STDOUT_FILENO,"1: ",3);
register int numline=1;//numline- NUMber of Line
while(read(fd,&a,1)>0){
if(num&&a=='\n'){
if(read(fd,&a,1)==0){
if(shn)write(STDOUT_FILENO,"$",1);
write(STDOUT_FILENO,&a,1);
}
else{
if(shn)write(STDOUT_FILENO,"$",1);
write(STDOUT_FILENO,"\n",1);
++numline;
write(STDOUT_FILENO,itoa(numline),strlen(itoa(numline)));
write(STDOUT_FILENO,": ",2);
lseek(fd, -1, SEEK_CUR);
}
}
else if(sht&&a=='\t')write(STDOUT_FILENO,"^I",2);
else if(shn&&a=='\n')write(STDOUT_FILENO,"$\n",2);
else if(shcc&&iscntrl(a)&&a!='\n'&&a!='\t'){
a+=64;
write(STDOUT_FILENO,"^",1);
write(STDOUT_FILENO,&a,1);
}
else write(STDOUT_FILENO,&a,1);
}
close(fd);
}
_exit(0);
}
int usage(){
write(STDOUT_FILENO,"Usage: sysccat [OPTIONS]... [FILE]...\n"
"-h or --help Displays this info and exit.\n"
"-n or --number Numbers the output strings.\n"
"--version Displays version and exit.\n"
"-v or --show-nonprinting Displays non-printing(control) characters, except for tabulation and carriage return/end-of-line symbols.\n"
"-A, -vET or --show-all Displays all control characters.\n"
"-t or -vT Displays all control characters, except for carriage return/end-of-line symbol.\n"
"-u Ignored; for POSIX compatibility.\n"
"-e or -vE Displays all control characters, except for tabulation symbol.\n",547);
_exit(0);
}
char* itoa(unsigned int val){
static char buf[11];
short i=10;
for(;val&&i;--i,val/=10)buf[i]=val%10+48;
return &buf[i+1];
}
int ferr(){
write(STDERR_FILENO,strerror(errno),strlen(strerror(errno)));
write(STDERR_FILENO,".\n",2);
_exit(1);
}
void dchk(int f){
struct stat fs;
fstat(f,&fs);
if(S_ISDIR(fs.st_mode)){
write(STDERR_FILENO,"It's a directory.\n",18);
close(f);
_exit(1);
}
}
P.S.: #include «getopt.h» ибо у меня свой getopt_long- с блэкджеком, шлюхами и не требующий #define _GNU_SOURCE, базирующийся на коде этой функции из Open и Net BSD.