diff --git a/src/grep.c b/src/grep.c new file mode 100644 index 0000000..78e12c3 --- /dev/null +++ b/src/grep.c @@ -0,0 +1,157 @@ +/* $Id$ */ +/* Copyright (c) 2017 Pierre Pronchery */ +/* This file is part of DeforaOS Unix utils */ +/* This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ + + + +#include +#include +#include +#include +#include +#include + +#ifndef PROGNAME +# define PROGNAME "grep" +#endif + + +/* grep */ +/* private */ +/* prototypes */ +static int _grep(int flags, char const * pattern, int filec, char * filev[]); + +static int _usage(void); + + +/* functions */ +/* grep */ +static int _grep_error(char const * message, int ret); +static int _grep_files(regex_t * reg, int filec, char * filev[]); +static int _grep_stream(regex_t * reg, FILE * fp, char const * filename); + +static int _grep(int flags, char const * pattern, int filec, char * filev[]) +{ + int ret; + regex_t reg; + int e; + char buf[128]; + int n; + + if((e = regcomp(®, pattern, flags)) != 0) + { + n = snprintf(buf, sizeof(buf), "%s: ", pattern); + if(n >= 0 && (unsigned)n < sizeof(buf)) + regerror(e, ®, &buf[n], sizeof(buf) - n); + else + regerror(e, ®, buf, sizeof(buf)); + return _grep_error(buf, 2); + } + if(filec == 0) + ret = _grep_stream(®, stdin, NULL); + else + ret = _grep_files(®, filec, filev); + regfree(®); + return ret; +} + +static int _grep_error(char const * message, int ret) +{ + fprintf(stderr, "%s: %s\n", PROGNAME, message); + return ret; +} + +static int _grep_files(regex_t * reg, int filec, char * filev[]) +{ + int ret = 1; + int i; + FILE * fp; + char buf[128]; + + for(i = 0; i < filec; i++) + { + if((fp = fopen(filev[i], "r")) == NULL) + { + snprintf(buf, sizeof(buf), "%s: %s", filev[i], + strerror(errno)); + ret = _grep_error(buf, 2); + continue; + } + if(_grep_stream(reg, fp, (filec > 1) ? filev[i] : NULL) == 0 + && ret == 1) + ret = 0; + if(fclose(fp) != 0) + { + snprintf(buf, sizeof(buf), "%s: %s", filev[i], + strerror(errno)); + ret = _grep_error(buf, 2); + } + } + return ret; +} + +static int _grep_stream(regex_t * reg, FILE * fp, char const * filename) +{ + int ret = 1; + char buf[BUFSIZ]; + regmatch_t match; + int e; + + while(fgets(buf, sizeof(buf), fp) != NULL) + if((e = regexec(reg, buf, 1, &match, 0)) == 0) + { + if(filename != NULL) + printf("%s:", filename); + printf("%s", buf); + if(ret == 1) + ret = 0; + } + else if(e != REG_NOMATCH) + { + regerror(e, reg, buf, sizeof(buf)); + ret = -_grep_error(buf, 1); + } + return ret; +} + + +/* usage */ +static int _usage(void) +{ + fputs("Usage: " PROGNAME " [-i][file...]\n", stderr); + return 1; +} + + +/* public */ +/* functions */ +/* main */ +int main(int argc, char * argv[]) +{ + int o; + int flags = 0; + + while((o = getopt(argc, argv, "i")) != -1) + switch(o) + { + case 'i': + flags |= REG_ICASE; + break; + default: + return _usage(); + } + if(optind == argc) + return _usage(); + return _grep(flags, argv[optind], argc - optind - 1, &argv[optind + 1]); +} diff --git a/src/project.conf b/src/project.conf index 7f99b00..6e59c96 100644 --- a/src/project.conf +++ b/src/project.conf @@ -1,4 +1,4 @@ -targets=basename,cat,chgrp,chmod,chown,cksum,cmp,cp,date,df,dirname,du,echo,false,file,find,head,id,kill,link,ln,locale,logname,ls,mkdir,mkfifo,more,mv,nice,pr,printf,ps,pwd,renice,rm,rmdir,sleep,strings,tail,test,time,touch,true,tty,uname,uniq,unlink,wc,who +targets=basename,cat,chgrp,chmod,chown,cksum,cmp,cp,date,df,dirname,du,echo,false,file,find,grep,head,id,kill,link,ln,locale,logname,ls,mkdir,mkfifo,more,mv,nice,pr,printf,ps,pwd,renice,rm,rmdir,sleep,strings,tail,test,time,touch,true,tty,uname,uniq,unlink,wc,who cflags=-W -Wall -g -O2 -pedantic -fPIE -D_FORTIFY_SOURCE=2 -fstack-protector-all ldflags=-pie -Wl,-z,relro -Wl,-z,now dist=Makefile,common.c @@ -87,6 +87,11 @@ type=binary sources=find.c install=$(BINDIR) +[grep] +type=binary +sources=grep.c +install=$(BINDIR) + [head] type=binary sources=head.c