1 #include "mrilib.h"
2
3 /*----------------------------------------------------------------------
4 history:
5
6 ... [rwcox]
7 - Initial Version(s)
8
9 24 Mar 2005 [rickr]
10 - added options: -help, -new_char, -new_string, -unescape
11 ----------------------------------------------------------------------
12 */
13
14
15 void help_n_exit( void );
16 int suck_file( char *fname , char **fbuf ) ;
17
main(int argc,char * argv[])18 int main( int argc , char * argv[] )
19 {
20 int nbuf , ntarg , ii,jj, nfind , ff , quiet = 0;
21 char *fbuf , *targ ;
22 char *jstr=strdup("AFNI-rules-") ; int njstr=strlen(jstr) ;
23
24 int ac, unesc = 0; /* for -unescape option 24 Mar 2005 [rickr] */
25 int use_newstr = 0;
26 char newchar = 'x';
27
28 int nfname=0 ; /* for globbing */
29 char **fname=NULL ;
30
31 /* help? */
32
33 if( argc < 3 ) help_n_exit();
34
35 /* Check for arguments. If we don't get an exact match, continue, */
36 /* allowing the user to start a target string with '-'. */
37 for( ac = 1; ac < argc && argv[ac][0] == '-'; ac++ ){
38 if( strcmp(argv[ac], "-help") == 0 )
39 help_n_exit();
40
41 if( strcmp(argv[ac], "-new_char") == 0 ){
42 ac++;
43 if( ac >= argc ){
44 fprintf(stderr,"** -new_char option requires an argument\n");
45 exit(1);
46 }
47
48 newchar = argv[ac][0];
49 }
50
51 if ( strcmp(argv[ac], "-quiet") == 0) {
52 quiet++;
53 }
54
55 if( strcmp(argv[ac], "-new_string") == 0 ){
56 ac++;
57 if( ac >= argc ){
58 fprintf(stderr,"** -new_string option requires an argument\n");
59 exit(1);
60 }
61
62 jstr = strdup(argv[ac]);
63 njstr = strlen(jstr);
64 use_newstr = 1;
65 }
66
67 if( strcmp(argv[ac], "-unescape") == 0 )
68 unesc = 1;
69 }
70
71 if( ac > argc-2 ){
72 fprintf(stderr,"** missing target string or input files\n");
73 fprintf(stderr," (please see 'strblast -help')\n");
74 exit(1);
75 }
76
77 machdep() ;
78
79 /* load the target */
80
81 targ = argv[ac] ; ntarg = strlen(targ) ; ac++ ;
82 if( ntarg < 1 ){
83 fprintf(stderr,"** Can't enter an empty target string!\n") ;
84 exit(1) ;
85 }
86 if( unesc ){ /* let's leave argv alone, so dup the string */
87 char * tnew = strdup(targ);
88 if( !tnew ){ fprintf(stderr,"** cannot dup targetstring?!\n"); exit(1); }
89 for(ii=0, jj = 0; ii<ntarg; ii++, jj++){
90 if(tnew[ii] == '\\' && tnew[ii+1] == 't'){tnew[jj] = '\t'; ii++;}
91 else if(tnew[ii] == '\\' && tnew[ii+1] == 'n'){tnew[jj] = '\n'; ii++;}
92 else if(tnew[ii] == '\\' && tnew[ii+1] == 'r'){tnew[jj] = '\r'; ii++;}
93 else if(ii > jj) tnew[jj] = tnew[ii];
94 }
95 tnew[jj] = '\0'; /* and terminate */
96
97 /* now for the ol' switcheroo... */
98 targ = tnew; ntarg = jj;
99 }
100
101 /* if the replacement string is too long, truncate it */
102 if( ntarg < njstr ){
103 if( use_newstr ){ jstr[ntarg] = '\0' ; njstr = ntarg; }
104 else { jstr[0] = newchar ; njstr = 1; }
105 }
106
107 /* get input filenames */
108
109 MCW_warn_expand(1) ;
110 MCW_file_expand( argc-ac , argv+ac , &nfname , &fname ) ;
111 MCW_warn_expand(0) ;
112 if( nfname == 0 ){
113 fprintf(stderr,"** No files found from command line!\n") ;
114 exit(1) ;
115 }
116
117 /* loop over files */
118
119 for( ff=0 ; ff < nfname ; ff++ ){
120
121 /* read it all into memory */
122
123 fbuf = NULL ;
124 nbuf = suck_file( fname[ff] , &fbuf ) ;
125 if( nbuf < ntarg || fbuf == NULL ){
126 fprintf(stderr,"** Can't read input file %s\n",fname[ff]) ;
127 if( fbuf != NULL ) free(fbuf) ;
128 continue ;
129 }
130
131 /* scan for start character */
132
133 for( nfind=ii=0 ; ii < nbuf-ntarg ; ii++ ){
134
135 if( fbuf[ii] == targ[0] ){ /* if find it, check rest of string */
136
137 for( jj=1; jj < ntarg && fbuf[ii+jj]==targ[jj] ; jj++ ) ; /* nada */
138
139 if( jj == ntarg ){ /* found it */
140 nfind++ ;
141 for( jj=0 ; jj < njstr ; jj++ ) fbuf[ii+jj] = jstr[jj] ;
142 for( ; jj < ntarg ; jj++ ) fbuf[ii+jj] = newchar ;
143 /* only if found, noted by R Notestine 28 May 2009 [rickr] */
144 ii += ntarg-1 ; /* increment past found word, shy by 1 */
145 }
146 }
147 }
148
149 if( nfind > 0 ){
150 FILE *fp ;
151 if (quiet < 2)
152 fprintf(stderr,"++ Found %d copies of target %s in file %s\n",
153 nfind,targ,fname[ff] ) ;
154 fp = fopen( fname[ff] , "wb" ) ;
155 if( fp == NULL ){
156 fprintf(stderr,"** Can't open file %s for output!\n",fname[ff]) ;
157 exit(1) ;
158 }
159 fwrite( fbuf , 1 , nbuf , fp ) ; fclose(fp) ;
160 } else {
161 if (!quiet)
162 fprintf(stderr,"++ Found no copies of target %s in file %s\n",
163 targ , fname[ff] ) ;
164 }
165
166 free(fbuf) ;
167
168 } /* end of loop over files */
169
170 exit(0) ;
171 }
172
173 /*------------------------------------------------------------------*/
174
suck_file(char * fname,char ** fbuf)175 int suck_file( char *fname , char **fbuf )
176 {
177 int len , fd , ii ;
178 char * buf ;
179
180 if( fname == NULL || fname[0] == '\0' || fbuf == NULL ) return 0 ;
181
182 len = THD_filesize( fname ) ;
183 if( len <= 0 ) return 0 ;
184
185 buf = (char *) malloc( sizeof(char) * (len+4) ) ;
186 if( buf == NULL ) return 0 ;
187
188 fd = open( fname , O_RDONLY ) ;
189 if( fd < 0 ) return 0 ;
190
191 ii = read( fd , buf , len ) ;
192 close( fd ) ;
193 if( ii <= 0 ){ free(buf) ; return 0; }
194 *fbuf = buf ; return ii ;
195 }
196
help_n_exit(void)197 void help_n_exit( void )
198 {
199 printf("Usage: strblast [options] TARGETSTRING filename ...\n"
200 "Finds exact copies of the target string in each of\n"
201 "the input files, and replaces all characters with\n"
202 "some junk string.\n"
203 "\n"
204 "options:\n"
205 "\n"
206 " -help : show this help\n"
207 "\n"
208 " -new_char CHAR : replace TARGETSTRING with CHAR (repeated)\n"
209 "\n"
210 " This option is used to specify what TARGETSTRING is\n"
211 " replaced with. In this case, replace it with repeated\n"
212 " copies of the character CHAR.\n"
213 "\n"
214 " -new_string STRING : replace TARGETSTRING with STRING\n"
215 "\n"
216 " This option is used to specify what TARGETSTRING is\n"
217 " replaced with. In this case, replace it with the string\n"
218 " STRING. If STRING is not long enough, then CHAR from the\n"
219 " -new_char option will be used to complete the overwrite\n"
220 " (or the character 'x', by default).\n"
221 "\n"
222 " -unescape : parse TARGETSTRING for escaped characters\n"
223 " (includes '\\t', '\\n', '\\r')\n"
224 "\n"
225 " If this option is given, strblast will parse TARGETSTRING\n"
226 " replacing any escaped characters with their encoded ASCII\n"
227 " values.\n"
228 "\n"
229 " -quiet : Do not report files with no strings found.\n"
230 " use -quiet -quiet to avoid any reporting.\n"
231 "\n"
232 "Examples:\n"
233 " strings I.001 | more # see if Subject Name is present\n"
234 " strblast 'Subject Name' I.*\n"
235 "\n"
236 " strblast -unescape \"END OF LINE\\n\" infile.txt\n"
237 " strblast -new_char \" \" \"BAD STRING\" infile.txt\n"
238 " strblast -new_string \"GOOD\" \"BAD STRING\" infile.txt\n"
239 "\n"
240 "Notes and Warnings:\n"
241 " * strblast will modify the input files irreversibly!\n"
242 " You might want to test if they are still usable.\n"
243 " * strblast reads files into memory to operate on them.\n"
244 " If the file is too big to fit in memory, strblast\n"
245 " will fail.\n"
246 " * strblast will do internal wildcard expansion, so\n"
247 " if there are too many input files for your shell to\n"
248 " handle, you can do something like\n"
249 " strblast 'Subject Name' 'I.*'\n"
250 " and strblast will expand the 'I.*' wildcard for you.\n"
251 ) ;
252 exit(0) ;
253 }
254