1 /*****************************************************************************
2 Major portions of this software are copyrighted by the Medical College
3 of Wisconsin, 1994-2000, and are released under the Gnu General Public
4 License, Version 2. See the file README.Copyright for details.
5 ******************************************************************************/
6
7 #include <stdio.h>
8 #include <string.h>
9 #include <stdlib.h>
10 #include <time.h>
11 #include "mrilib.h"
12
13 int ranco(int,int, long int) ;
14 extern int *z_rand_order(int bot, int top, long int seed);
usage_count(int detail)15 void usage_count(int detail) {
16 printf(
17 "Usage: count [options] bot top [step]\n"
18 "\n"
19 "* Produces many numbered copies of the root and/or suffix,\n"
20 " counting from 'bot' to 'top' with stride 'step'.\n"
21 "* If 'bot' > 'top', counts backwards with stride '-step'.\n"
22 "* If step is of the form 'R#', then '#' random counts are produced\n"
23 " in the range 'bot..top' (inclusive).\n"
24 "* If step is of the form 'S', then a random sequence of unique integers\n"
25 " in the range 'bot..top' (inclusive) is output.\n"
26 " A number after S ('S#') indicates the number of unique integers\n"
27 " to output. If # exceeds the number of unique values, the shuffled\n"
28 " sequence will simply repeat itself. (N.B.: 'S' is for 'Shuffle'.)\n"
29 "* 'bot' and 'top' must not be negative; step must be +ve (defaults to 1).\n"
30 "* 'bot' and 'top' can be any character between 'A' and 'Z' or 'a' and 'z'.\n"
31 " In these instances, the counting is from character bot \n"
32 " to character top. If you do not specify -form, the program\n"
33 " will automatically choose -form '%%c'. For example:\n"
34 " count a z\n"
35 " or to get the ASCII value of the characters:\n"
36 " count -form %%d a z\n"
37 "\n"
38 "Options:\n"
39 " -seed seed number for random number generator (for S and R above)\n"
40 " -sseed seed string for random number generator (for S and R above)\n"
41 " -column writes output, one number per line (with root and suffix, if any)\n"
42 " -digits n prints numbers with 'n' digits [default=4]\n"
43 " -form CFRM print the numbers with the CFRM formatting string. \n"
44 " e.g.: count -form %%c 49 130 \n"
45 " or count -form '%%03d<:-)' 97 99 \n"
46 " You can't use any type of C formatting, only those who\n"
47 " take an integer for an input. Using '%%f', or '%%s' will \n"
48 " cause a crash.\n"
49 " -form overrides -digits.\n"
50 " -root rrr prints string 'rrr' before the number [default=empty]\n"
51 " -sep s prints single character 's' between the numbers [default=blank]\n"
52 " [normally you would not use '-sep' with '-column']\n"
53 " -suffix sss prints string 'sss' after the number [default=empty]\n"
54 " -scale fff multiplies each number by the factor 'fff';\n"
55 " if this option is used, -digits is ignored and\n"
56 " the floating point format '%%g' is used for output.\n"
57 " ('fff' can be a floating point number.)\n"
58 " -comma put commas between the outputs, instead of spaces\n"
59 " (same as '-sep ,')\n"
60 " -skipnmodm n m skip over numbers with a modulus of n with m\n"
61 " -skipnmodm 15 16 would skip 15, 31, 47, ...\n"
62 " not valid with random number sequence options\n"
63 "\n"
64 "The main application of this program is for use in C shell programming:\n"
65 " foreach fred ( `count 1 20` )\n"
66 " mv wilma.${fred} barney.${fred}\n"
67 " end\n"
68 "The backward quote operator in the foreach statement executes the\n"
69 "count program, captures its output, and puts it on the command line.\n"
70 "The loop body renames each file wilma.0001 to wilma.0020 to barney.0001\n"
71 "to barney.0020. Read the man page for csh to get more information. In\n"
72 "particular, the csh built-in command '@' can be useful.\n"
73 "\n"
74 "Shuffle Example:\n"
75 "----------------\n"
76 "You can use the 'S' mode to reorder a dataset or 1D file randomly.\n"
77 "Suppose you have several 1D files with 60 columns and you want to rearrange\n"
78 "each one in the same random way -- interchanging columns to scramble some\n"
79 "stimulus amplitude modulation sequences, say:\n"
80 " count -dig 1 0 59 S > randorder.1D\n"
81 " 1dcat A.1D\"[`cat randorder.1D`]\" > Areordered.1D\n"
82 " 1dcat B.1D\"[`cat randorder.1D`]\" > Breordered.1D\n"
83 " 1dcat C.1D\"[`cat randorder.1D`]\" > Creordered.1D\n"
84 "Unlike 'R', which can produce duplicates, 'S' will give set of unique numbers.\n"
85 "\n"
86 "-- Written by RWCox back in the ancient mists of forgotten time --\n\n"
87 ) ;
88 return;
89 }
main(int argc,char * argv[])90 int main( int argc , char *argv[] )
91 {
92 int ii , bot = -1 , top = -1 , step = -1 ,
93 rando_count = 0, rando_num=0, col ;
94 int narg , ndig = 4 , iout ;
95 long int seed = 0;
96 static char root[6664] , fmt[128] , nfmr[36], suffix[6664], *ufrm=NULL;
97 float sclfac = 0.0 ;
98 int comma=0 , quiet = 0; /* 18 Jan 2007 */
99 char sep=' ' ;
100 int skipn = 0; /* skip numbers that modulus m = n 08 May 2007 */
101 int skipm = 0;
102 int skipout;
103
104 mainENTRY("count");machdep() ;
105
106 if (argc == 1) { usage_count(1); exit(0); } /* Bob's help shortcut */
107
108 /*** read arguments ***/
109
110 narg = 1 ;
111 root[0] = '\0' ;
112 suffix[0] = '\0' ;
113 col = 0;
114 rando_count = 0;
115 seed = 0;
116 quiet = 0;
117 do {
118
119 /*** switches ***/
120 if (strcmp(argv[narg], "-h") == 0 || strcmp(argv[narg], "-help") == 0) {
121 usage_count(strlen(argv[narg]) > 3 ? 2:1);
122 exit(0);
123 }
124
125 if( strncmp(argv[narg],"-digits",2) == 0 ){
126 ndig = strtol( argv[++narg] , NULL , 10 ) ;
127 if( ndig < 1 ) ERROR_exit("-digits value must be > 0") ;
128 continue ;
129 }
130
131 if( strncmp(argv[narg],"-quiet",5) == 0 ){
132 quiet = 1 ;
133 continue ;
134 }
135 if( strncmp(argv[narg],"-seed",5) == 0 ){
136 seed = strtol( argv[++narg] , NULL , 10 ) ;
137 continue ;
138 }
139 if( strncmp(argv[narg],"-sseed",5) == 0 ){
140 char *sseed=NULL;
141 static long int ppp[10] = { 3,5,7,11,13,17,19,23,29,31 } ;
142 int kk;
143 if (narg+1>= argc) ERROR_exit("Need argument after -sseed\n");
144 sseed=argv[++narg];
145 for (kk=0;kk<strlen(sseed);++kk){
146 seed += (long int)(sseed[kk]) *
147 ((long int)( (kk <= 16) ? (1<<kk) : (kk*7) )+ppp[kk%9]) ;
148 }
149 continue ;
150 }
151 if( strncmp(argv[narg],"-root",5) == 0 ){
152 strcpy(root,argv[++narg]) ;
153 continue ;
154 }
155
156 if( strncmp(argv[narg],"-column",4) == 0 ){
157 col = 1 ; comma = 0 ; sep = ' ' ;
158 continue ;
159 }
160
161 if( strncmp(argv[narg],"-sep",4) == 0 ){ /* 02 Mar 2007 [rickr] */
162 sep = argv[++narg][0] ;
163 if( !isprint(sep) )
164 WARNING_message("-sep character is not printable?!") ;
165 else if( argv[narg][1] != '\0' )
166 WARNING_message("-sep string '%s' has more than one character!",argv[narg]) ;
167 continue ;
168 }
169
170 if( strncmp(argv[narg],"-suffix",4) == 0 ){
171 strcpy(suffix,argv[++narg]) ;
172 continue ;
173 }
174
175 if( strncmp(argv[narg],"-scale",4) == 0 ){
176 sclfac = strtod(argv[++narg],NULL) ;
177 continue ;
178 }
179
180 if( strncmp(argv[narg],"-form",4) == 0 ){
181 ufrm = argv[++narg] ;
182 continue ;
183 }
184
185 if( strncmp(argv[narg],"-comma",4) == 0 ||
186 strncmp(argv[narg],"-,",2) == 0 ){
187 comma = 1 ; sep = ',' ; col = 0 ; continue ;
188 }
189
190 if( strncmp(argv[narg],"-skipnmodm",10) == 0 ){
191 skipn = strtol(argv[++narg],NULL,10) ;
192 skipm = strtol(argv[++narg],NULL,10) ;
193 continue ;
194 }
195
196
197 if( strncmp(argv[narg],"-",1) == 0 ){
198 fprintf( stderr , "unknown switch %s\n" , argv[narg] ) ;
199 exit(1) ;
200 }
201
202 /*** numbers ***/
203
204 if( bot < 0 ){
205 if ( strlen(argv[narg])==1 &&
206 ( (argv[narg][0]>='A' && argv[narg][0]<='Z') ||
207 (argv[narg][0]>='a' && argv[narg][0]<='z') ) ) {
208 bot = (int)argv[narg][0];
209 if (!ufrm) ufrm = "%c";
210 } else {
211 bot = strtol( argv[narg] , NULL , 10 ) ;
212 if( bot < 0 ){
213 fprintf( stderr , "illegal value of bot %d\n" , bot ) ;
214 exit(1) ;
215 }
216 }
217 continue ;
218 }
219
220 if( top < 0 ){
221 if ( strlen(argv[narg])==1 &&
222 ( (argv[narg][0]>='A' && argv[narg][0]<='Z') ||
223 (argv[narg][0]>='a' && argv[narg][0]<='z') ) ) {
224 top = (int)argv[narg][0];
225 if (!ufrm) ufrm = "%c";
226 } else {
227 top = strtol( argv[narg] , NULL , 10 ) ;
228 if( top < 0 ){
229 fprintf( stderr , "illegal value of top %d\n" , top ) ;
230 exit(1) ;
231 }
232 }
233 continue ;
234 }
235
236 if( step < 0 ){
237 if( argv[narg][0] == 'R' || argv[narg][0] == 'r' ){
238 rando_count = 1 ;
239 rando_num = strtol( argv[narg]+1 , NULL , 10 ) ;
240 if( rando_num <= 0 ){
241 fprintf( stderr , "illegal value of random count %d\n" , rando_num ) ;
242 exit(1) ;
243 }
244 continue ;
245 } else if( argv[narg][0] == 'S' || argv[narg][0] == 's' ){
246 rando_count = 2 ;
247 if (strlen(argv[narg]) > 1) {
248 rando_num = strtol( argv[narg]+1 , NULL , 10 ) ;
249 if( rando_num <= 0 ){
250 fprintf( stderr , "illegal value of shuffle count %d\n" , rando_num ) ;
251 exit(1) ;
252 }
253 } else {
254 rando_num = -1;
255 }
256 continue ;
257 }
258 step = strtol( argv[narg] , NULL , 10 ) ;
259 if( step <= 0 ){
260 fprintf( stderr , "illegal value of step %d\n" , step ) ;
261 exit(1) ;
262 }
263 continue ;
264 }
265
266 ERROR_message("too many arguments: %s\n", argv[narg]);
267 suggest_best_prog_option(argv[0], argv[narg]);
268 exit(1) ;
269 } while ( ++narg < argc ) ;
270
271 if (argc < 3) {
272 ERROR_message("Too few options, use -help for details");
273 exit(1);
274 }
275 /*** set up to iterate ***/
276 if (ufrm) {
277 sprintf (nfmr, "%s", ufrm);
278 } else {
279 sprintf (nfmr, "%%0%dd", ndig);
280 }
281 if( step <= 0 ) step = 1 ;
282 if (col == 0) {
283 if( sclfac == 0.0 ) sprintf( fmt , "%%s%s%%s" , nfmr ) ;
284 else strcpy ( fmt , " %s%g%s" ) ;
285 if( isspace(sep) ) strcat ( fmt," ") ;
286 } else {
287 if( sclfac == 0.0 ) sprintf( fmt , " %%s%s%%s\n" , nfmr ) ;
288 else strcpy ( fmt , " %s%g%s\n" ) ;
289 }
290 /*** iterate ***/
291 /* fprintf(stderr,"bot=%d, top=%d, step=%d\n", bot, top, step); */
292
293 if( rando_count == 0){
294 if( bot <= top ){
295 for( ii=bot ; ii <= top ; ii += step ) {
296 if(skipm) {
297 skipout = ii%skipm;
298 if(skipout==skipn) continue;
299 }
300 /* if (ii==top) suffix[0] = '\0'; */ /* ZSS Dec 06 */
301 if( sclfac == 0.0 ) printf( fmt , root , ii , suffix ) ;
302 else printf( fmt , root , sclfac*ii , suffix ) ;
303 if( ii <= top-step && !isspace(sep) ) printf("%c",sep) ;
304 }
305 } else {
306 for( ii=bot ; ii >= top ; ii -= step ) {
307 if(skipm) {
308 skipout = ii%skipm;
309 if(skipout==skipn)
310 continue;
311 }
312
313 /* if (ii==top) suffix[0] = '\0'; */ /* ZSS Dec 06 */
314 if( sclfac == 0.0 ) printf( fmt , root , ii , suffix ) ;
315 else printf( fmt , root , sclfac*ii , suffix ) ;
316 if( ii >= top+step && !isspace(sep) ) printf("%c",sep) ;
317 }
318 }
319 } else if (rando_count == 1) {
320 for( ii=0 ; ii < rando_num ; ii++ ){
321 iout = ranco( bot , top, seed) ;
322 /* if (ii==rando_num-1) suffix[0]='\0'; */
323 if( sclfac == 0.0 ) printf( fmt , root , iout , suffix ) ;
324 else printf( fmt , root , sclfac*iout , suffix ) ;
325 if( ii < rando_num-1 && !isspace(sep) ) printf("%c",sep) ;
326 }
327 } else if (rando_count == 2) {
328 int nmax, *ir = z_rand_order(bot, top, seed);
329 if (top < bot) nmax = bot-top+1;
330 else nmax = top-bot+1;
331 if (rando_num == -1) rando_num = nmax;
332 if (!quiet && nmax < rando_num) {
333 fprintf(stderr,
334 "Warning: "
335 "requested %d numbers in a shuffled sequence of %d unique values.\n"
336 " Sequence will repeat until %d values are output.\n",
337 rando_num, nmax, rando_num);
338 }
339 if (ir) {
340 for( ii=0 ; ii < rando_num ; ii++ ){
341 iout = ir[ii%nmax] ;
342 /* if (ii==rando_num-1) suffix[0]='\0'; */
343 if( sclfac == 0.0 ) printf( fmt , root , iout , suffix ) ;
344 else printf( fmt , root , sclfac*iout , suffix ) ;
345 if( ii < rando_num-1 && !isspace(sep) ) printf("%c",sep) ;
346 }
347 free(ir); ir = NULL;
348 } else {
349 fprintf(stderr,"Failure to plan!\n");
350 }
351 } else {
352 fprintf(stderr,"Should not be here!\n");
353 exit(1);
354 }
355
356 if( !col ) printf( "\n" ) ;
357 exit(0) ;
358 }
359
360 /*---------------------------------------------------------------------------*/
361
ranco(int bot,int top,long int seed)362 int ranco( int bot , int top , long int seed)
363 {
364 static int first = 1 ;
365 int ir , ii ;
366 double dr ;
367
368 if( first ){
369 if (seed) srand48(seed);
370 else srand48((long)time(NULL)+(long)getpid()) ;
371 dr = drand48() ;
372 ir = (int)(dr*100) ;
373 for( ii=0 ; ii < ir ; ii++ ) dr = drand48() ; /* warmup */
374 first = 0 ;
375 }
376
377 ir = bot + (top-bot+0.999999)*drand48() ;
378 return ir ;
379 }
380