source: MML/trunk/applications/common/grep.m @ 4

Last change on this file since 4 was 4, checked in by zhangj, 10 years ago

Initial import--MML version from SOLEIL@2013

File size: 32.1 KB
Line 
1% GREP
2%         a unix-like, very fast utility to find patterns
3%         in any files in folders and their subfolders
4%
5% SYNTAX
6%         help
7%                        GREP           show this screen
8%                        GREP -p        show extended help for PATTERN/FILE
9%                        GREP -f        show contents of output structure P
10%                        GREP -e        show examples
11%         search
12%                        GREP PATTERN FILE(*)
13%                        GREP OPT1 ... OPTn PATTERN FILE(*)
14%               [FL,P] = GREP(PATTERN,FILE(*))
15%               [FL,P] = GREP({PATTERN(s)},{FILE1(*),...,FILEn(*)})
16%               [FL,P] = GREP(OPT1,...,OPTn,PATTERN,FILE)
17%               [FL,P] = GREP(OPT1,...,OPTn,{PATTERN(s)},{FILE1(*),...,FILEn(*)})
18%
19% OPT   : arg   processing
20% ---------------------------------------------------------------------------------
21% -c    :       prints only a count of the lines that contain the pattern(s)
22% -D    :       debug mode: shows major processing steps
23% -d    :       debug mode: shows all   processing steps
24% -da   :       debug mode: shows all   output including debug messages
25% -e    :  PL   searches for a string in pattern-list PL or {PL1,...,PLn}
26%       : {PL}  useful syntax when the string contains an option flag character (-)
27%                  multiple instances of <-e PL> and/or <-e {PL,...}> may be listed
28%          PL      searches for the first token in pattern without white spaces
29%         {PL}     searches for complete pattern(s) including white spaces
30% -f    :  PF   takes the list of patterns from ASCII pattern-file PF
31%                  each line defines a single pattern that may include white spaces
32% -i    :       ignores upper/lower case distinction during comparisons
33% -I?   :  IL   only includes folders/files with at least one matching pattern
34%         {IL}     from IL or {IL1,...ILn}, which may include regular expressions
35%                  multple instances of <-I? IL> and/or <I? {IL,...}> may be listed
36%   -Id :       searches for inclusions in folders
37%   -If :       searches for inclusions in file names
38%   -Ip :       searches for inclusions in full paths: folder/filename
39% -l    :       prints the names of files with matching lines once
40% -n    :       precedes each line by its line number in the file
41% -Q    :       does not prefix output with file name
42% -R    :       uses the regular expression engine <regexp> [def: <strfind>]
43% -r    :       recursively searches in subfolder(s)
44% -s    :       works silently and displays only error messages
45% -u    :       does not produce underlined text
46% -V    :       prints name of each file before it is searched
47% -v    :       prints all lines except those that contain the pattern
48% -x    :       prints only lines that are matched entirely
49% -X?   :  XL   excludes folders/files with at least one matching pattern
50%         {XL}     from XL or {XL1,...XLn}, which may include regular expressions
51%                  multple instances of <-X? XL> and/or <X? {XL,...}> may be listed
52%   -Xd :       searches for exclusions in folders
53%   -Xf :       searches for exclusions in file names
54%   -Xp :       searches for exclusions in full paths: folder/filename
55%
56% NOTES         all folder separators are replaced by unix-style </> to facilitate
57%                  the use of regular expressions with <-I?|X?> options
58%               <-I?|X?> options allow wildcard searches using regular expressions
59%               clicking on underlined text opens the file at the matching line
60
61% created:
62%       us      14-Jan-1987
63% modified:
64%       us      04-Apr-2006 00:31:57
65
66%--------------------------------------------------------------------------------
67function        [pout,p]=grep(varargin)
68
69% program parameters
70                tim=clock;
71                ver='04-Apr-2006 00:31:57';
72
73% option table
74                com='command line';
75        otbl={
76%       flag    inival  nrpar   defpar  accum   desc
77%       -----------------------------------------------------------------------------------------
78        '-c'    false   0       []      0       'count matches'
79        '-D'    false   0       []      0       'major proc steps'
80        '-d'    false   0       []      0       'minor proc steps'
81        '-da'   false   0       []      0       'show all ouput including proc steps'
82        '-e'    false   1       {}      1       'pattern list'
83        '-f'    false   1       com     0       'pattern file'
84        '-i'    false   0       []      0       'ignore case'
85        '-Id'   false   1       {}      1       'only include folders with one matching token'
86        '-If'   false   1       {}      1       'only include files with one matching token'
87        '-Ip'   false   1       {}      1       'only include full paths with one matching token'
88        '-l'    false   0       []      0       'print file name'
89        '-n'    false   0       []      0       'print line number'
90        '-Q'    false   0       []      0       'no file name prefix'
91        '-R'    false   0       []      0       'regular expression engine'
92        '-r'    false   0       []      0       'search in subfolders'
93        '-s'    false   0       []      0       'quiet mode except error messages'
94        '-u'    false   0       []      0       'does not produce underlined text'
95        '-V'    false   0       []      0       'print file before search'
96        '-v'    false   0       []      0       'print non-matching lines'
97        '-x'    false   0       []      0       'complete match'
98        '-Xd'   false   1       {}      1       'exclude folders with matching token'
99        '-Xf'   false   1       {}      1       'exclude files with matching token'
100        '-Xp'   false   1       {}      1       'exclude full paths with matching token'
101        };
102
103        if      nargout
104                pout=[];
105        end
106
107% initialize engine
108                p=ini_par(ver,tim);
109                [p,msg]=set_opt(otbl,p,varargin{:});
110        if      ~isempty(msg)
111                p=show_res(100,p,msg);
112        if      nargout
113                pout=p;
114        end
115                return;
116        end
117                p.npat=p.opt.ns;
118                p.pattern=p.opt.pattern(:);
119                p.porigin=p.opt.f.val;
120
121% get subfolders
122                p=show_res(-100,p,sprintf('GREP> searching folders    ...'));
123                t1=clock;
124                p=get_folders(p);
125                p.runtime(2)=etime(clock,t1);
126                p=show_res( -99,p,sprintf('GREP> done %13.3f   %d folder(s)',p.runtime(1),p.nfolder));
127
128% get files
129        if      p.nfolder
130                p=show_res( -98,p,sprintf('GREP> searching files      ...'));
131                t1=clock;
132                p=get_files(p);
133                p.runtime(3)=etime(clock,t1);
134                p=show_res( -97,p,sprintf('GREP> done %13.3f   %d file(s)',p.runtime(2),p.nfiles));
135        end
136
137        if      nargout
138                pout=unique(p.files);
139        end
140                p=ini_par(p);
141                return;
142%--------------------------------------------------------------------------------
143%--------------------------------------------------------------------------------
144% SUBROUTINES
145%       - ehelp         extended help engine
146%       - ini_par       initialize structure
147%       - set_opt       input parser
148%       - get_folders   harvest input folders
149%       - get_folder    harvest subfolders/input folder
150%       - get_files     harvest files/input folder
151%       - get_file      harvest files
152%       - chk_path      check file/folder inclusion/exclusion
153%       - get_match     look for matches
154%       - update        update arrays
155%       - show_res      common display engine
156%       - show_entry    final  display engine
157%--------------------------------------------------------------------------------
158%--------------------------------------------------------------------------------
159function        p=ehelp(p,fnam,tag)
160
161                [fp,msg]=fopen(which(fnam),'rt');
162        if      fp > 0
163                hs=fread(fp,inf,'*char').';
164                fclose(fp);
165                ib=strfind(hs,tag);
166        if      isempty(ib)     ||...
167                numel(ib)<2
168                hs=sprintf('GREP> help sectio <%s> not found/not valid',tag);
169        else
170                hs=hs(ib(end-1)+length(tag)+1:ib(end)-1);
171                hs=strrep(hs,p.par.hdel,'');
172        end
173        else
174                hs=sprintf('%s: <%s>',msg,fnam);
175        end
176                disp(hs);
177                return;
178%--------------------------------------------------------------------------------
179function        p=ini_par(ver,tim)
180
181% clean up
182        if      isstruct(ver)
183                p=ver;
184                tim=p.par.tim;
185                p.nxfolder=p.par.chkex(1);
186                p.nxfiles=p.par.chkex(2);
187                p.nafolder=p.nfolder+p.nxfolder;
188                p.nafiles=p.nfiles+p.nxfiles;
189                p.mdepth=max(p.fdepth);
190        if      ~isempty(p.result)
191                p.result=char(p.result);
192        end
193        if      ~p.opt.D.flg    &&...
194                ~p.opt.d.flg
195                p=rmfield(p,'par');
196        end
197                p.runtime(1)=etime(clock,tim);
198                return;
199        end
200
201% initialize common structure
202% - parameters
203                magic='GREP';
204                fsep='/';
205
206% - special characters
207%   - EOL UNIX          = LF
208%   - EOL WINDOWS       = CR+LF
209                par.tab=sprintf('\t');  % 009 = TAB: horizontal tab
210                par.cr=sprintf('\r');   % 013 =  CR: carriage return
211                par.lf=sprintf('\n');   % 010 =  LF: line feed
212                par.fsep=fsep;
213                par.isold=0;
214                par.nbytes=0;
215                par.nlines=0;
216                par.mfc=1;
217                par.mlc=1;
218                par.cd=[];
219                par.cf=[];
220                par.cn=[];
221                par.cs=[];
222                par.s=[];
223                par.eol=[];
224                par.chkpath=false;      % true if I[]/X[] flags are set
225                par.chkex=[0,0];
226                par.hasmatch=false;
227                par.nmatch=0;
228                par.hdel='%$';
229                par.reft='<a href="matlab:opentoline(''%s'',%-1d)">%s</a>: %s';
230                par.tim=tim;
231
232% ID
233                p.magic=magic;
234                p.ver=ver;
235                p.mver=version;
236                p.rundate=datestr(tim);
237                p.runtime=[0,0,0];
238% parameters/options
239                p.opt=[];
240                p.msg=[];
241                p.par=par;
242
243                p.section_1='===== FOLDERS  =====';
244                p.nfolder=0;
245                p.nxfolder=0;
246                p.nafolder=0;
247                p.folder{1,1}=[];
248                p.fenum=[];
249                p.mdepth=0;
250                p.fdepth(1,1)=0;
251                p.section_2='===== PATTERNS =====';
252                p.npat=0;
253                p.pattern={};
254                p.porigin={};
255                p.section_3='===== FILES    =====';
256                p.nfiles=0;
257                p.nxfiles=0;
258                p.nafiles=0;
259                p.nbytes=0;
260                p.nlines=0;
261                p.section_4='===== MATCHES  =====';
262                p.mfiles=0;
263                p.mbytes=0;
264                p.mlines=0;
265                p.pfiles=0;
266                p.pcount=0;
267                p.files={};
268                p.lcount=[];
269                p.findex=[];
270                p.pindex=[];
271                p.line=[];
272                p.match={};
273                p.result={};
274                return;
275%--------------------------------------------------------------------------------
276function        [p,msg]=set_opt(otbl,p,varargin)
277
278                o=[];
279                msg=[];
280
281% set options
282% ...default options
283                o.des1='===== OPTIONS =====';
284        for     i=1:size(otbl,1)
285                fn=otbl{i,1}(2:end);
286                o.(fn).flg=otbl{i,2};
287                o.(fn).acc=otbl{i,5};
288                o.(fn).des=otbl{i,6};
289                o.(fn).def=otbl{i,4};
290                o.(fn).val=otbl{i,4};
291        end
292
293                argn=numel(varargin);
294        if      argn < 2
295        if      ~argn
296                help(mfilename);
297                msg=sprintf('GREP> needs at least two arguments');
298        elseif  numel(varargin{1}) > 1
299        switch  lower(varargin{1}(1:2))
300        case    {'-p'}
301                ehelp(p,mfilename,'___FORMAT___');
302                msg=true;
303        case    {'-e'}
304                ehelp(p,mfilename,'___EXAMPLE___');
305                msg=true;
306        case    {'-f'}
307                ehelp(p,mfilename,'___OUTPUT___');
308                msg=true;
309        otherwise
310                help(mfilename);
311                msg=sprintf('GREP> needs at least two arguments');
312        end
313        else
314                help(mfilename);
315                msg=sprintf('GREP> needs at least two arguments');
316        end
317                p.opt=o;
318                return;
319        end
320
321% ...user defined options
322% ...must account for syntax of various forms
323%       ('-a -b +c -d','-f',xxx,'-g +h',...)
324
325% ...reconstruct <varargin> as a string
326                pat=sprintf('GREP>ARG|%20.19f[',rand);
327                arg=varargin;
328                ic=cellfun(@(x) [pat,class(x),']'],arg,'uniformoutput',false);
329                il=cellfun('isclass',arg,'char');
330                ic(il)=arg(il);
331                ic=sprintf('%s ',ic{:});
332                ic=strread(ic,'%s');
333                [ox,io]=ismember(ic,otbl(:,1));         %#ok MLINT 2006a
334                ox=io(io>0);
335                ax=find(io);
336                argn=numel(ic);
337                iv=strfind(ic,pat);
338                iv=~cellfun('isempty',iv);
339                ic(iv)=arg(~il);
340
341        for     i=1:numel(ox)
342                ix=ox(i);
343                fn=otbl{ix,1}(2:end);
344                o.(fn).flg=xor(otbl{ix,2},1);
345        if      otbl{ix,3} > 0
346                vx=ax(i)+1:ax(i)+otbl{ix,3};
347        if      vx(end) <= argn
348        if      o.(fn).acc
349        if      ~iscell(ic(vx))
350                ic(vx)={ic(vx)};
351                o.(fn).val=[o.(fn).val;{ic(vx)}];
352        else
353                o.(fn).val=[o.(fn).val,ic{vx}];
354        end
355        else
356                o.(fn).val=ic(vx);
357        end
358        else
359                o.(fn).flg=otbl{ix,2};
360                msg=sprintf('GREP> parameter(s) missing for option <%s> [%-1d]',...
361                                otbl{ix,1},otbl{ix,3});
362        end
363        end
364        end
365
366        if      o.Id.flg        ||...
367                o.If.flg        ||...
368                o.Ip.flg        ||...
369                o.Xd.flg        ||...
370                o.Xf.flg        ||...
371                o.Xp.flg
372                p.par.chkpath=true;
373        end
374
375% get search template(s)/file(s)
376% ...templates
377                o.des2='===== INPUT =====';
378                o.arg={};
379                o.ns=0;
380                o.pattern=varargin{end-1};
381                o.nf=0;
382                o.files=varargin{end};
383
384        if      ~iscell(o.pattern)
385                o.pattern={o.pattern};
386        end
387        if      o.e.flg
388                o.pattern=o.e.val;
389        end
390        if      o.f.flg
391        if      iscell(o.f.val{1})
392                o.f.val{1}=o.f.val{1}{:};
393        end
394                pnam=o.f.val{1};
395        if      exist(pnam,'file')
396                o.pattern=textread(pnam,'%s','delimiter','\n','whitespace','');
397        else
398                msg=sprintf('GREP> pattern file not existing <%s>',pnam);
399        end
400        end
401                o.ns=numel(o.pattern);
402                o.arg=ic;
403
404% ...files
405        if      ~iscell(o.files)
406                o.files={o.files};
407        end
408                o.files=o.files(:);
409                o.ns=numel(o.pattern);
410                o.nf=numel(o.files);
411
412        for     i=1:o.nf
413        if      isempty(o.files{i})
414                o.files{i}=[cd,p.par.fsep,'*.*'];
415        end
416        if      o.files{i}(end)=='/'    ||...
417                o.files{i}(end)=='\'
418                o.files{i}=o.files{i}(1:end-1);
419        end
420                o.fpat{i}=o.files{i};
421                o.fnam{i}='*.*';
422                o.fext{i}='.*';
423        if      strcmp(o.fpat{i},'.')
424                o.fpat{i}=cd;
425        end
426        if      ~exist(o.files{i},'dir')
427                [o.fpat{i},o.fnam{i},o.fext{i}]=fileparts(o.files{i});
428        if      isempty(o.fpat{i})
429                o.fpat{i}=cd;
430        end
431        if      isempty(o.fnam{i})
432                o.fnam{i}='*';
433        end
434        if      isempty(o.fext{i})
435                o.fext{i}='.*';
436        end
437                o.fnam{i}=[o.fnam{i},o.fext{i}];
438        end
439        end
440
441% ...remove dup folders
442                o.npat=0;
443                o.xpat=1;
444                o.upat=1;
445                [o.fpat,ix]=sort(o.fpat(:));
446                o.files=o.files(ix);
447                o.fnam=o.fnam(ix);
448                o.fext=o.fext(ix);
449                [o.npat,o.npat,o.xpat]=unique(o.fpat);
450                o.npat=numel(o.npat);
451                o.upat=find([1;diff(o.xpat)]>0);
452
453                p.opt=o;
454                return;
455%--------------------------------------------------------------------------------
456function        p=get_folders(p)
457
458        for     i=1:p.opt.npat
459                cf=p.opt.fpat{p.opt.upat(i)};
460                cf=strrep(cf,filesep,p.par.fsep);
461                p=get_folder(p,cf,cf,0,i);
462        end
463                return;
464%--------------------------------------------------------------------------------
465function        p=get_folder(p,frot,crot,depth,ix)
466
467% recursively find all subfolders of a root
468% note  we CANNOT use <genpath> as it does not return all subfolders!
469%       eg,
470%       - @class  subfolders
471%       - private subfolders
472
473% root folders
474        if      ~depth
475                p=show_res(-10,p,sprintf('GREP> folder              <%s>',frot));
476        if      exist(frot,'dir')
477                [tf,p]=chk_path(1,p,frot,'***FOLDER***');
478        if      tf
479                p.nfolder=p.nfolder+1;
480                p.folder{p.nfolder,1}=strrep(frot,filesep,p.par.fsep);
481                p.fenum(p.nfolder,1)=ix;
482        end
483        else
484                msg=sprintf('GREP> folder not found <%s>',frot);
485                p=show_res(100,p,msg);
486        end
487        end
488
489        if      ~p.opt.r.flg
490                return;
491        end
492
493% subfolders
494                rd=dir(crot);
495                rx=[rd.isdir]==1;
496                rd=rd(rx);
497                nd=numel(rd);
498        for     i=1:nd
499        if      rd(i).isdir && ~all(rd(i).name=='.')    % rd(i).name(1) ~= '.'
500        if      ~isempty(crot)
501                nrot=[crot,p.par.fsep,rd(i).name];
502        else
503                nrot=rd(i).name;
504        end
505                nrot=strrep(nrot,filesep,p.par.fsep);
506                [tf,p]=chk_path(1,p,nrot,'***SUBFOLDER***');
507        if      tf
508                p.nfolder=p.nfolder+1;
509                depth=depth+1;
510                p.fdepth(p.nfolder,1)=depth;
511                p.folder{p.nfolder,1}=strrep(nrot,filesep,p.par.fsep);
512                p.fenum(p.nfolder,1)=ix;
513                p=show_res(-9,p,sprintf('- subfolder %5d/%6d  <%s>',depth,p.nfolder,nrot));
514                p=get_folder(p,frot,nrot,depth,ix);
515                depth=depth-1;
516        end
517        end
518        end
519        if      ~depth
520                p.par.isold=0;
521        end
522                return;
523%--------------------------------------------------------------------------------
524function        p=get_files(p)
525
526        for     i=1:p.opt.nf
527                cn=p.opt.fnam{i};
528                fx=find(p.fenum==p.opt.xpat(i));
529                cp=p.folder(fx);
530        for     j=1:numel(fx)
531                p.par.cd=cp{j};
532                p=show_res(-8,p,sprintf('GREP> files %5d/%7d <%s:%s>',i,j,p.par.cd,cn));
533                d=dir([p.par.cd,p.par.fsep,cn]);
534        if      ~isempty(d)
535        for     k=1:numel(d)
536        if      ~d(k).isdir
537                p.par.cf=[p.par.cd,p.par.fsep,d(k).name];
538                p.par.cn=d(k).name;
539                [tf,p]=chk_path(2,p,p.par.cf,p.par.cn);
540        if      tf
541                p=show_res(-7,p,sprintf('- file   %7d/%7d <%s>',k,numel(d),p.par.cf));
542                p=get_file(p);
543        end
544        end
545        end
546        end
547        end
548        end
549                return;
550%--------------------------------------------------------------------------------
551function        p=get_file(p)
552
553%D      if      exist(p.par.cf,'file')
554                [fp,msg]=fopen(p.par.cf,'rb');
555        if      fp < 0
556                msg=sprintf('GREP> cannot open file <%s>\nGREP> %s',p.par.cf,msg);
557                p=show_res(100,p,msg);
558        else
559                p.par.s=fread(fp,inf,'*char').';
560                fclose(fp);
561                p.par.nbytes=numel(p.par.s);
562        if      ispc
563                p.par.s=strrep(p.par.s,[p.par.cr,p.par.lf],p.par.lf);
564        end
565                p.par.s=strrep(p.par.s,char(0),'^');
566                p=show_res(2,p);
567                p=get_match(p);
568        end
569%D      end
570                return;
571%--------------------------------------------------------------------------------
572function        [tf,p]=chk_path(mode,p,fnam,frot)
573
574                tf=true;
575% - escape immediately if user did not choose inclusion/exclusion flags
576        if      ~p.par.chkpath
577                return;
578        end
579
580                ixi=true;
581                ixe=false;
582        switch  mode
583% include/exclude folders
584        case    1
585                smode='FOLDER';
586        if      p.opt.Id.flg
587                ix=regexp(fnam,p.opt.Id.val);
588                ixi=any(~cellfun('isempty',ix));
589        end
590        if      ixi
591        if      p.opt.Xd.flg
592                ix=regexp(fnam,p.opt.Xd.val);
593                ixe=any(~cellfun('isempty',ix));
594        end
595        end
596% incrementally include/exclude files/full paths
597        case    2
598                smode='FILE';
599        if      p.opt.If.flg
600                ix=regexp(frot,p.opt.If.val);
601                ixi=any(~cellfun('isempty',ix));
602        end
603        if      ixi
604        if      p.opt.Xf.flg
605                ix=regexp(frot,p.opt.Xf.val);
606                ixe=any(~cellfun('isempty',ix));
607        end
608        if      ~ixe
609                smode='PATH';
610        if      p.opt.Ip.flg
611                ix=regexp(fnam,p.opt.Ip.val);
612                ixi=any(~cellfun('isempty',ix));
613        end
614        if      ixi
615        if      p.opt.Xp.flg
616                ix=regexp(fnam,p.opt.Xp.val);
617                ixe=any(~cellfun('isempty',ix));
618        end     % does not match PATH Xp
619        end     % does not macht PATH Ip
620        end     % does not match FILE Xf
621        end     % does not match FILE If
622
623        end     % switch
624
625        if      ~ixi            ||...
626                ixe
627                p.par.chkex(mode)=p.par.chkex(mode)+1;
628                p=show_res(-50,p,sprintf('* exclude %7.7s         <%s>',smode,fnam));
629                tf=false;
630        end
631                return;
632%--------------------------------------------------------------------------------
633function        p=get_match(p)
634
635                p.par.hasmatch=false;
636                s=p.par.s;
637        if      p.opt.i.flg
638                s=lower(s);
639        end
640% find EOL marker(s)
641                p.par.eol=[0,strfind(s,p.par.lf),numel(s)+1];
642                p.par.nlines=numel(p.par.eol)-2;
643                p.nfiles=p.nfiles+1;
644                p.nbytes=p.nbytes+p.par.nbytes;
645                p.nlines=p.nlines+p.par.nlines;
646
647        for     j=1:p.opt.ns
648                str=p.opt.pattern{j};
649        if      p.opt.i.flg
650                str=lower(str);
651        end
652                p.par.cs=str;
653
654% find string pattern <str>
655        if      p.opt.R.flg
656                ix=regexp(s,str);
657        else
658                ix=strfind(s,str);
659        end
660
661                p.par.nmatch=0;
662        if      ~isempty(ix)
663
664% ...find line(s)
665                [lx,lx]=histc(ix,p.par.eol);    %#ok MLINT 2006a
666                lx=lx(find([diff(lx),1]));      %#ok MLINT 2006a
667
668% ...-v: only print non-matching lines
669        if      p.opt.v.flg
670                tl=1:numel(p.par.eol)-2;
671                ll=tl~=0;
672                ll(lx)=false;
673                lx=tl(ll);
674        end
675
676                nx=numel(lx);
677        if      nx
678                p=show_res(-2,p,lx,0);
679        for     i=1:nx
680                sx=p.par.eol(lx(i))+1:p.par.eol(lx(i)+1)-1;
681                nl=lx(i);
682                nm=p.par.s(sx);
683
684% ...-x: only print fully matching lines
685        if      ~p.opt.x.flg    ||...
686                numel(sx)==numel(str)
687                p.par.nmatch=p.par.nmatch+1;
688                p=show_res(3,p,nl,nm);
689        if      ~p.opt.c.flg    ||...
690                i==1
691                p=update(3,p,nl,nm);
692        end
693        end
694        end     % each  match
695        end     % found match
696        end     % found matches
697
698        if      p.par.nmatch
699                p.par.hasmatch=true;
700                p.pfiles=p.pfiles+1;
701                p.pcount=p.pcount+nx;
702                p.files(p.pfiles,1)={p.par.cf};
703                p.lcount(p.pfiles,1)=nx;
704                p.findex=[p.findex;repmat(p.pfiles,nx,1)];
705                p.pindex=[p.pindex;repmat(j,nx,1)];
706        if      p.opt.c.flg
707                p=show_res(4,p);
708        end
709        end
710
711        end     % for each <string>
712
713        if      p.par.hasmatch
714                p.mfiles=p.mfiles+1;
715                p.mbytes=p.mbytes+p.par.nbytes;
716                p.mlines=p.mlines+p.par.nlines;
717        end
718
719                return;
720%--------------------------------------------------------------------------------
721function        p=update(mode,p,varargin)
722
723        switch  mode
724        case    3
725                p.line(p.par.mlc,1)=varargin{1};
726                p.match(p.par.mlc,1)={varargin{2}};
727                p.par.mlc=p.par.mlc+1;
728        case    4
729                p.result(p.par.mfc,1)={varargin{1}};
730                p.par.mfc=p.par.mfc+1;
731        end
732                return;
733%--------------------------------------------------------------------------------
734function        p=show_res(mode,p,varargin)
735
736% common output engine
737
738%       mode    display entity
739%       -100    subfolder engine start
740%       -99     subfolder engine end
741%       -98     match engine start
742%       -97     match engine end
743%       -50     exclude folder/file
744%       -10     folder
745%       -9      subfolder
746%       -8      current folder
747%       -7      current file
748%       -2      match
749%       2       file before search
750%       3       line
751%       4       line count only
752%       100     error message
753
754% display all ouput
755                if      p.opt.da.flg
756                        p=show_entry(mode,p,varargin{:});
757                        return;
758                end
759
760% display selected ouput only
761                if      p.opt.s.flg     &&...
762                        mode < 100
763                        return;
764                else
765                if      mode < -10
766                if      ~p.opt.D.flg    &&...
767                        ~p.opt.d.flg
768                        return;
769                end
770                elseif  mode < 0
771                if      ~p.opt.d.flg
772                        return;
773                end
774                end
775                end
776                        p=show_entry(mode,p,varargin{:});
777                        return;
778%--------------------------------------------------------------------------------
779function        p=show_entry(mode,p,varargin)
780
781                        str=[];
782                        txt=[];         %#ok MLINT 2006a
783                        ref=[];
784        switch  mode
785        case    {-100 -99 -98 -97 -50 -10 -9 -8 -7}
786                        str=varargin{1};
787        case    -2
788                        str=sprintf('+ match  %16d <%s>',numel(varargin{1}),p.par.cf);
789        case    2
790                if      p.opt.V.flg
791                        str=sprintf('%s',p.par.cf);
792                end
793        case    3
794                if      p.opt.l.flg     &&...
795                        p.par.nmatch==1
796                        str=sprintf('%s [%s]',p.par.cf,p.par.cs);
797                end
798                if      ~p.opt.c.flg
799                if      p.opt.D.flg     ||...
800                        p.opt.d.flg
801                        ref=sprintf('%17d',varargin{1});
802                        txt=sprintf('%17d:        <%s>',varargin{1},varargin{2});
803                elseif  p.opt.n.flg     &&...
804                        ~p.opt.Q.flg
805                        ref=sprintf('%s:%-1d',p.par.cn,varargin{1});
806                        txt=sprintf('%s:%-1d: %s',p.par.cn,varargin{1},varargin{2});
807                elseif  p.opt.n.flg     &&...
808                        p.opt.Q.flg
809                        ref=sprintf('%-1d',varargin{1});
810                        txt=sprintf('%-1d: %s',varargin{1},varargin{2});
811                elseif  ~p.opt.Q.flg
812                        ref=sprintf('%s',p.par.cn);
813                        txt=sprintf('%s: %s',p.par.cn,varargin{2});
814                else
815                        txt=sprintf('%s',varargin{2});
816                end
817                if      ~isempty(ref)
818                if      ~p.opt.u.flg
819                        txt=sprintf(p.par.reft,p.par.cf,varargin{1},ref,varargin{2});
820                end
821                end
822                if      ~isempty(str)
823                        str=str2mat(str,txt);
824                else
825                        str=txt;
826                end
827                end
828        case    4
829                if      p.opt.c.flg
830                        str=sprintf('%-d',p.lcount(p.pfiles));
831                end
832        case    100
833                        p.msg=varargin{1};
834                if      ischar(p.msg)
835                        str=p.msg;
836                end
837        end
838
839                if      ~isempty(str)
840                        p=update(4,p,str);
841                        disp(str);
842                end
843                        return;
844%--------------------------------------------------------------------------------
845%--------------------------------------------------------------------------------
846% EXTENDED HELP SECTION
847%       formatted for pretty output
848%       do NOT change alignment
849%--------------------------------------------------------------------------------
850%       BOL delimiter   %$
851%       tag             contents
852%       ___FORMAT___    input formats
853%       ___OUTPUT___    P.field explanations
854%       ___EXAMPLE___   examples
855
856%{
857%$___FORMAT___
858%$  SYNTAX
859%$                       grep PATTERN FILE
860%$                       grep OPT1 ... OPTn PATTERN FILE
861%$              [FL,P] = grep(PATTERN,FILE)
862%$              [FL,P] = grep({PATTERN(s)}, {FILE(s)})
863%$              [FL,P] = grep(OPT1, ..., OPTn, PATTERN, FILE)
864%$              [FL,P] = grep(OPT1,...,OPTn,{PATTERN(s)},{FILE(s)})
865%$
866%$  input arguments/formats
867%$  ---------------------------------------------------------------------------------
868%$  OPT
869%$  ---------------------------------------------------------------------------------
870%$      for available options,
871%$      see <grep> or <help grep>
872%$
873%$      any mixture of  ...,'-a -b -d','-k','-y -z',...
874%$
875%$      note    the input parser will tokenize strings
876%$                 into single options and other arguments
877%$                 see: <P.opt.arg> for parsing results
878%$
879%$      special cases
880%$
881%$      -e      '-e -l'
882%$              add pattern <-l> AND    set option [-l]
883%$              '-e',{'-n'}
884%$              add pattern <-n> do NOT set option [-n]
885%$      -e      'this is'
886%$              by definition will only search for <this>
887%$      -e      {'this is','a test'}
888%$              will first search for <this is>
889%$              than <a test>
890%$      -s      silent mode will run much(!) faster
891%$              results can easily be extracted from P
892%$              see: <grep -f> for information
893%$
894%$      inclusion/exclusion of folder(s)/file(s)/full path(s)
895%$
896%$              assume this folder/file structure/contents
897%$                      z:/abc/def/ghi/foo.m
898%$                      z:/abc/def/ghi/foo.txt
899%$                      z:/abc/def/ghi/goo.p
900%$                      z:/abc/def/xxy/goo.p
901%$                      z:/abc/def/xxy/goo.txt
902%$              assume this root folder when running GREP
903%$                      z:/abc/def
904%$              assume the recursion flag [-r] is set
905%$
906%$      -Id     '/xx'
907%$              only searches in folder
908%$                      z:/abc/def/xxy  ... all files
909%$      -Id     'xx'
910%$      -If     '\.t'   (note regular expression for <.>)
911%$              ***or***
912%$      -Ip     'y/g.*\.t'
913%$              only searches in folder/file
914%$                      z:/abc/def/xxy/goo.txt
915%$      -Xd     '(de)|(xx)'
916%$              does not search any folder/file
917%$      -Xd     'x'
918%$              only searches in folder
919%$                      z:/abc/def/ghi  ... all files
920%$      -Xd     'x'
921%$      -Xf     'txt'
922%$              only searches in folder/files
923%$                      z:/abc/def/ghi/foo.m
924%$                      z:/abc/def/ghi/goo.p
925%$      -Xd     'xxx'
926%$      -If     'foo'
927%$              ***or***
928%$      -Ip     'ghi/fo'
929%$              only searches in folder/files
930%$                      z:/abc/def/ghi/foo.m
931%$                      z:/abc/def/ghi/foo.txt
932%$
933%$      note
934%$              ALL folder separators are replaced by
935%$                 unix-style </> for entry checks to
936%$                 facilitate the use of regular expression
937%$              leading/trailing </>s are significant
938%$              inclusions and exclusions are ANDed, but single tokens
939%$                 within an option are OREed for final results
940%$              multiple inclusions/exclusions may be
941%$                 listed in any order
942%$              using <-Ip> and <-Xp> only may be significantly slower
943%$                 compared to combinations of <-I[df]> and <-X[df]>
944%$              since folders are resolved sequentially in depth, <-Xd>
945%$                 options will exclude any subfolder below the
946%$                 excluded folder(s)
947%$
948%$  PATTERN
949%$  ---------------------------------------------------------------------------------
950%$       'p1'           will search      <p1> in each FILE
951%$      {'p1',...,'pn'} will search each <px> in each FILE
952%$
953%$      note     'p1' cannot include white spaces
954%$              {'p1'}   may include white spaces
955%$              <px> may be a regular expression [-R]
956%$              only one input type will be used at runtime
957%$              precedence: 1. -f / 2. -e / 3. PATTERN
958%$
959%$  FILE
960%$  ---------------------------------------------------------------------------------
961%$       'f1'           will search in      folder/file <f1>
962%$      {'f1',...,'fn'} will search in each folder/file <fx>
963%$
964%$      folder/file(s) are determined/expanded according to these rules
965%$
966%$      FILE            folder  file    remark
967%$      ----------------------------------------------------------
968%$      f*.x            ./      f*.x    uses current folder
969%$      /a/b            /a/b/   *.*     search all files in folder
970%$      /a/b/           /a/b/   *.*     search all files in folder
971%$      /a/b/*          /a/b/   *.*     search all files in folder
972%$      /a/b/*.x        /a/b/   *.x     search all  <.x> in folder
973%$      /a/b/f          /a/b/   f*.*    if <f> is NOT a folder
974%$      /a/b/f*.x       /a/b/   f*.x
975%$
976%$      note    if recursive folder search is selected [-r],
977%$                 file(s) will be searched in the root path and
978%$                 its subfolder(s)
979%$              the recursion engine does NOT use <genpath>
980%$              use the <-I?> and <-X?> options to use wildcard
981%$                 searches on folders/files
982%$
983%$  output arguments
984%$  ---------------------------------------------------------------------------------
985%$  FL  cell array with unique list of files with matching patterns
986%$  P   structure  with timing and result of the engines (for programmers)
987%$      see: <grep -f> for information about .fields
988%$___FORMAT___
989
990%$___OUTPUT___
991%$  SYNTAX
992%$                      [FL,P] = grep(...)
993%$
994%$  output arguments
995%$  ---------------------------------------------------------------------------------
996%$  FL          cell array with unique list of files with matching patterns
997%$  P           structure  with timings and result of the engines (for programmers)
998%$
999%$  P.fieldname:  contents              explanation
1000%$  ---------------------------------------------------------------------------------
1001%$        magic:  'GREP'                magic id
1002%$          ver:   char                 current GREP version
1003%$         mver:   char                 current ML   version
1004%$      rundate:   char                 datestr(clock)
1005%$      runtime:  [t1 t2 t3]            runtimes [sec]:
1006%$                                      - t1: full time spent in grep
1007%$                                      - t2: engine for (sub)folder(s)
1008%$                                      - t3: engine for pattern matching
1009%$          opt:  [struct]              current options and input args
1010%$          msg:   char                 error message(s)
1011%$    section_1:  '===== FOLDERS  ='    FOLDER STATS
1012%$      nfolder:   double               nr of unique folder(s) found
1013%$     nxfolder:   double               nr of excluded (sub)folder(s) [-Id|Xd]
1014%$     nafolder:   double               nr of all (sub)folder(s)
1015%$       folder:  {char}                unique folder name(s)
1016%$        fenum:   double               enumerator of (sub)folder(s) in .folder
1017%$                                      - subfolder(s) keep the .fenum of their root
1018%$       mdepth:   double               max depth of subfolder(s)
1019%$       fdepth:   double               depth of each subfolder [0: root]
1020%$    section_2:  '===== PATTERNS ='    PATTERN STATS
1021%$         npat:   double               nr of patterns
1022%$      pattern:  {char}                pattern(s)
1023%$      porigin:   char                 origin of pattern(s):
1024%$                                      - 'command line'
1025%$                                      -  name of pattern file [-f]
1026%$    section_3:  '===== FILES    ='    FILE STATS
1027%$       nfiles:   double               nr of files searched
1028%$      nxfiles:   double               nr of excluded file(s)  [-If|Xf]
1029%$      nafiles:   double               nr of all file(s) after [-Id|Xd]
1030%$       nbytes:   double               nr of bytes read
1031%$       nlines:   double               nr of lines searched
1032%$    section_4:  '===== MATCHES  ='    MATCH STATS
1033%$       mfiles:   double               nr of file(s) with matching patterns
1034%$       mbytes:   double               nr of bytes of .mfiles file(s)
1035%$       mlines:   double               nr of lines of .mfiles file(s)
1036%$       pfiles:   double               nr of .files with matching patterns
1037%$       pcount:   double               nr of lines with a match
1038%$        files:  {char}                file name for each match
1039%$                                      - repeated for each matching pattern
1040%$       lcount:  [double]              count of matching lines in .files [-c]
1041%$       findex:  [double]              index into .files   for each match
1042%$       pindex:  [double]              index into .pattern for each match
1043%$         line:  [double]              nr of matching line
1044%$        match:  {char}                matching line
1045%$       result:  [char]                runtime output
1046%$
1047%$  NOTE
1048%$      to reconstruct user defined results from P, which may be useful
1049%$      with the [-s] option, a programmer can use constructs like
1050%$      - file name|nr counts
1051%$              fmt=repmat(max(cellfun('length',P.files)),P.pfiles,1);
1052%$              r=[num2cell(fmt+3),...
1053%$                 P.files,...
1054%$                 num2cell(P.lcount)].';
1055%$              s=sprintf('%-*s: %5d\n',r{:})
1056%$      - file name|pattern|line nr|nr counts|matching line
1057%$              r=[P.files(P.findex),...
1058%$                 P.pattern(P.pindex),...
1059%$                 num2cell(P.line),...
1060%$                 num2cell(P.lcount(P.findex)),...
1061%$                 P.match]
1062%$___OUTPUT___
1063
1064%$___EXAMPLE___
1065% GREP EXAMPLES
1066% assume GREP.TXT is in your current working folder
1067        fnam='grep.txt';
1068% - show contents (note all spaces are TABs!)
1069        type(fnam);
1070
1071% simple case insensitive [-i] string search in GREP.M for instances of
1072%               Version
1073% listing file name [def] and the line number [-n] of occurrences
1074%-------------------------------------------------------------------------------
1075        grep -i -n Version grep.m
1076
1077% regular expression search [-R] in GREP.M for instances of
1078%               =true or =false
1079% listing line number [-n] but not the file name [-Q]
1080%-------------------------------------------------------------------------------
1081        grep -Q -n -R =true|=false grep.m
1082
1083% simple string search in GREP.M for exactly matching [-x] instances of
1084%               \t\tmsg=true;
1085% listing the file name [def] and the line number [-n] for each occurrence
1086%-------------------------------------------------------------------------------
1087        TAB=sprintf('\t');
1088        fl=grep('-x -n',[TAB,TAB,'msg=true;'],'grep.m');
1089
1090% simple string search in GREP.TXT for
1091%               every line of itself in turn
1092% using the pattern-file [-f] option and
1093% listing the full file name and pattern for each file with matches [-l]
1094% as well as the file name [def] for each occurrence
1095%-------------------------------------------------------------------------------
1096        fl=grep('-l -f',fnam,fnam);
1097
1098% simple string search in GREP.TXT for instances of
1099%               -n
1100% using the [-e] option since -n itself is an option flag (listing line number!)
1101% and listing the file name [def] for each non-matching line [-v] only
1102% - compare with previous example!
1103%-------------------------------------------------------------------------------
1104        fl=grep('-v -e',{'-n'},fnam);
1105
1106% full depth search [-r] of the entire ELFUN TOOLBOX for instances of
1107%               sign or cosine or atan
1108% listing the full file name and pattern for each file with matches [-l]
1109% as well as the file name [def] and the line number [-n] for each occurrence
1110%-------------------------------------------------------------------------------
1111        fpat=[matlabroot,'/toolbox/matlab/elfun'];
1112        fl=grep('-r -l -n',{'sign','cosine','atan'},fpat);
1113
1114% full depth search [-r] of the entire ELFUN TOOLBOX for instances of
1115%               sign or cosine or atan
1116% using the two versions of the [-e] option and
1117% listing the full file name and pattern for each file with matches [-l]
1118% as well as the count [-c] of all instances
1119%-------------------------------------------------------------------------------
1120        fl=grep('-r -l -c -e sign -e',{'cosine','atan'},fpat);
1121
1122% full depth search [-r] of the entire ELFUN TOOLBOX for instances of
1123%               sign or cosine or atan
1124%       only including files with a regular expression pattern [-If]
1125%               [Cc]ont
1126% using the two versions of the [-e] option and
1127% listing the full file name and pattern for each file with matches [-l]
1128% as well as the file name [def] and the line number [-n] for each occurrence
1129%-------------------------------------------------------------------------------
1130        fl=grep('-r -l -n -If [Cc]ont -e sign -e',{'cosine','atan'},fpat);
1131
1132% full depth search [-r] of the entire ELFUN TOOLBOX for instances of
1133%               sign or cosine or atan
1134%       only including files with a regular expression pattern [-If]
1135%               [Cc]ont
1136%       and excluding folders with a pattern [-Xd]
1137%               /ja
1138% - using the two versions of the [-e] option,
1139% and listing the full file name and pattern for each file with matches [-l]
1140% as well as the file name [def] and the line number [-n] for each occurrence
1141%-------------------------------------------------------------------------------
1142        fl=grep('-r -l -n -If [Cc]ont -e sign -e',{'cosine','atan'},'-Xd','/ja',fpat);
1143%$___EXAMPLE___
1144%---------------------------------------------------------------------------------
1145%}
Note: See TracBrowser for help on using the repository browser.