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