1 /*
2      library_utils.c: CCP4 Library Utilities
3      Copyright (C) 2001  CCLRC, Charles Ballard
4 
5      This library is free software: you can redistribute it and/or
6      modify it under the terms of the GNU Lesser General Public License
7      version 3, modified in accordance with the provisions of the
8      license to address the requirements of UK law.
9 
10      You should have received a copy of the modified GNU Lesser General
11      Public License along with this library.  If not, copies may be
12      downloaded from http://www.ccp4.ac.uk/ccp4license.php
13 
14      This program is distributed in the hope that it will be useful,
15      but WITHOUT ANY WARRANTY; without even the implied warranty of
16      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17      GNU Lesser General Public License for more details.
18 */
19 
20 /** @page utilities_page CCP4 Library Utilities
21  *
22  *  @section utilities_list File list
23 
24 <ul>
25 <li>library_utils.c
26 <li>ccp4_general.c
27 <li>ccp4_parser.c
28 <li>ccp4_program.c
29 </ul>
30 
31  *  @section utilities_overview Overview
32 
33 The CCP4 C-library provides many utility functions which either give
34 specific CCP4 functionality (e.g. traditional keyword parsing) or
35 are just generally useful (platform independent date).
36 
37  */
38 
39 /** @file library_utils.c
40  *  @brief   Utility functions.
41  *  @author  Charles Ballard
42  */
43 
44 #include "ccp4_sysdep.h"
45 #include <time.h>
46 #include <math.h>
47 #include "ccp4_utils.h"
48 #include "ccp4_errno.h"
49 
50 #if defined (_WIN32)
51 #include <windows.h>
52 #endif
53 
54 #define CCP4_ERRNO(y) (CCP4_ERR_UTILS | (y))
55 
56 /* rcsid[] = "$Id$" */
57 
58 /* static uint16 nativeIT = NATIVEIT; */ /* machine integer type - currently unused here */
59 static uint16 nativeFT = NATIVEFT; /* machine float type */
60 
61 /** .
62  *
63  * @return
64  */
ccp4_utils_translate_mode_float(float * out,const void * buffer,int dim,int mode)65 int ccp4_utils_translate_mode_float(float *out, const void *buffer, int dim, int mode)
66 {
67   unsigned char *ucp;
68   unsigned short *usp;
69   float *fp = out, *ufp, tmp1, tmp2;
70   register int ctr=0;
71 
72   switch(mode) {
73   case 0:
74     ucp = (unsigned char *)buffer;
75     for(ctr = 0; ctr < dim ; ++ctr)
76       *fp++ = (float) *ucp++;
77     break;
78   case 1:
79     usp = (unsigned short *)buffer;
80     for(ctr = 0; ctr < dim ; ++ctr)
81       *fp++ = (float) *usp++;
82     break;
83   case 3:
84     /* complex short (define type ?) */
85     usp = (unsigned short *)buffer;
86     for(ctr = 0; ctr < dim ; ++ctr) {
87       tmp1 = (float) *usp++;
88       tmp2 = (float) *usp++;
89       *fp++ = (float) sqrt(tmp1*tmp1 + tmp2*tmp2);
90     }
91     break;
92   case 4:
93     /* complex real (define type ?) */
94     ufp = (float *)buffer;
95     for(ctr = 0; ctr < dim ; ++ctr) {
96       tmp1 = *ufp++;
97       tmp2 = *ufp++;
98       *fp++ = (float) sqrt(tmp1*tmp1 + tmp2*tmp2);
99     }
100     break;
101   case 2:
102   default:
103     break;
104   }
105 
106   return (ctr);
107 }
108 
109 /** Gets the length of a Fortran string with trailing blanks removed.
110  *
111  * @return length of string
112  */
ccp4_utils_flength(char * s,int len)113 size_t ccp4_utils_flength (char *s, int len)
114 {
115   if (len <= 0 ) return 0;
116   while (s[--len] == ' ')
117     if (len == 0) return 0;
118   return (++len);
119 }
120 
121 /** .
122  *
123  * @return
124  */
ccp4_utils_print(const char * message)125 void ccp4_utils_print (const char *message)
126 {
127   printf ("%s\n",message);
128  }
129 
130 #if ! defined (VMS)
131 /** .
132  *
133  * @return
134  */
ccp4_utils_setenv(char * str)135 int ccp4_utils_setenv (char *str)
136 {
137 #if defined (sgi) || defined (sun) || defined (__hpux) || \
138     defined(_AIX) || defined (__OSF1__) || \
139     defined (__osf__) || defined (__FreeBSD__) || defined (linux) || \
140     defined (_WIN32) || defined __linux__
141   /* putenv is the POSIX.1, draft 3 proposed mechanism */
142 #if !(defined(__hpux) && defined(__HP_cc))
143   int putenv ();
144 #endif
145   char *param;
146 
147   if ( (param = (char *) ccp4_utils_malloc( (strlen(str)+1)*sizeof(char) )) == NULL) {
148     ccp4_errno = CCP4_ERRNO(errno);
149     return -1; }
150   strcpy(param,str);
151   return (putenv (param));
152   /* note the necessary lack of free() */
153 #else
154   /* setenv is not POSIX, BSD might have to use `index' */
155   int setenv ();
156   char *param1,*param2;
157 
158   if ( (param1 = (char *) ccp4_utils_malloc( (strlen(str)+1)*sizeof(char) )) == NULL) {
159     ccp4_errno = CCP4_ERRNO(errno);
160     return -1; }
161   strcpy(param1,str);
162   if ((param2 = (char *) strchr(param1, '=')) == NULL) {
163     ccp4_errno = CCP4_ERRNO(errno);
164     return -1; }
165   *param2++ = '\0';
166   return (setenv (param1, param2, 1));
167 #endif
168 }
169 #endif
170 
171 #if ! defined (VMS)
172 /** .
173  *
174  * @return
175  */
ccp4_utils_outbuf(void)176 int ccp4_utils_outbuf(void)
177 {
178 #if defined (sgi) || defined (sun) || \
179     defined (__OSF1__) || \
180     defined (__FreeBSD__)
181   return setlinebuf(stdout);
182 #else
183 #if defined (_MSC_VER)
184   return setvbuf(stdout, NULL, _IONBF, 80);
185 #else
186 #  if defined (_AIX)
187   return -1;
188 #  else
189   /* Windows requires size argument, though 0 works on unix */
190   return setvbuf(stdout, NULL, _IOLBF, 80);
191 #  endif
192 #endif
193 #endif
194 }
195 
196 /** .
197  *
198  * @return
199  */
ccp4_utils_noinpbuf(void)200 int ccp4_utils_noinpbuf(void)
201 {
202   return setvbuf(stdin, NULL, _IONBF, 0);
203 }
204 #endif
205 
ccp4_nan()206 union float_uint_uchar ccp4_nan ()
207 
208 #if NATIVEFT == DFNTF_BEIEEE || NATIVEFT == DFNTF_LEIEEE
209 #  define CCP4_NAN 0xfffa5a5a
210 #endif
211 /* For \idx{Convex} native mode and \idx{VAX} use a \idx{Rop} value:        */
212 /*                                                                          */
213 /* <magic numbers>=                                                         */
214 #if NATIVEFT == DFNTF_CONVEXNATIVE
215 #  define CCP4_NAN 0x80000000
216 #endif
217 #if NATIVEFT == DFNTF_VAX
218 #  define CCP4_NAN 0x00008000
219 #endif
220 #ifndef CCP4_NAN
221 #  error "CCP4_NAN isn't defined (needs NATIVEFT)"
222 #endif
223 {
224   union float_uint_uchar realnum;
225 
226   realnum.i = CCP4_NAN;
227   return (realnum);
228 }
229 
230 /** .
231  *
232  * @return
233  */
ccp4_utils_isnan(const union float_uint_uchar * realnum)234 int ccp4_utils_isnan (const union float_uint_uchar *realnum)
235 {
236     switch (nativeFT) {
237     case DFNTF_BEIEEE :
238     case DFNTF_LEIEEE :
239       return ((realnum->i & 0x7f800000) == 0x7f800000); /* exponent all 1s */
240     case DFNTF_CONVEXNATIVE :
241       return ((realnum->i & 0xff800000) == 0x80000000);
242     case DFNTF_VAX :
243       return ((realnum->i & 0x0000ff80) == 0x00008000);
244     default :
245       ccp4_fatal("CCP4_UTILS_ISNAN: bad nativeFT");
246       return 0;                   /* avoid compiler warning */
247     }
248 }
249 
250 #define MDFBIG -1.0E10          /* BIOMOL absence flag value */
251 /** .
252  *
253  * @return
254  */
ccp4_utils_bml(int ncols,union float_uint_uchar cols[])255 void ccp4_utils_bml (int ncols, union float_uint_uchar cols[])
256 {
257   int i;
258   for (i=0; i<ncols; i++)
259     if (cols[i].i != CCP4_NAN)
260       if (cols[i].f <= MDFBIG) cols[i].f = 0.0;
261 }
262 
263 /** .
264  *
265  * @return
266  */
ccp4_utils_wrg(int ncols,union float_uint_uchar cols[],float wminmax[])267 void ccp4_utils_wrg (int ncols, union float_uint_uchar cols[], float wminmax[])
268 {
269   int i;
270   for (i=0; i<ncols; i++)
271     if (cols[i].i != CCP4_NAN)
272        if (cols[i].f > MDFBIG) {
273          if (cols[i].f < wminmax[2*i]) wminmax[2*i] = cols[i].f;
274          if (cols[i].f > wminmax[1+2*i]) wminmax[1+2*i] = cols[i].f; }
275 }
276 
277 /** .
278  *
279  * @return
280  */
ccp4_utils_hgetlimits(int * IValueNotDet,float * ValueNotDet)281 void ccp4_utils_hgetlimits (int *IValueNotDet, float *ValueNotDet)
282 {
283   *IValueNotDet = INT_MAX;
284   *ValueNotDet  = FLT_MAX;
285 }
286 
287 #ifndef _WIN32
parse_mode(const char * cmode)288 static unsigned parse_mode(const char *cmode)
289 {
290   unsigned mode = 0;
291 #if defined (__APPLE__)
292   static const unsigned TBM = 0x07;
293 
294   switch (strlen(cmode)) {
295   case 4:
296     mode |= (*cmode & TBM) << 9 ;
297     mode |= (*(cmode+1) & TBM) << 6 ;
298     mode |= (*(cmode+2) & TBM) << 3 ;
299     mode |= (*(cmode+3) & TBM) ;
300     break;
301   case 3:
302     mode |= (*cmode & TBM) << 6 ;
303     mode |= (*(cmode+1) & TBM) << 3 ;
304     mode |= (*(cmode+2) & TBM) ;
305     break;
306   case 2:
307     mode |= (*cmode & TBM) << 3 ;
308     mode |= (*(cmode+1) & TBM) ;
309     break;
310   case 1:
311     mode |= (*cmode & TBM) ;
312     break;
313   default:
314     mode = 0x0fff ;
315   }
316 #else
317 /* Possible modes (see stat.h)
318   Currently pass 3-character string and interpret as octal.
319   Try also S_IRWXU, S_IRWXG, etc. */
320   sscanf(cmode,"%o",&mode);
321 #endif
322   return mode;
323 }
324 #endif
325 
326 /** .
327  *
328  * @return
329  */
ccp4_utils_mkdir(const char * path,const char * cmode)330 int ccp4_utils_mkdir (const char *path, const char *cmode)
331 {
332   int result;
333 #if defined(_WIN32)
334   result = mkdir(path);
335 #else
336   unsigned mode = parse_mode(cmode);
337   result = mkdir(path, (mode_t) mode);
338 #endif
339 
340   if (result == -1) {
341     if (errno == EEXIST) {
342       result = 1;
343     }
344   }
345   return (result);
346 }
347 
348 /** .
349  *
350  * @return
351  */
ccp4_utils_chmod(const char * path,const char * cmode)352 int ccp4_utils_chmod (const char *path, const char *cmode)
353 {
354 #if defined(_WIN32)
355   return (chmod(path,0x0fff));
356 #else
357   unsigned mode = parse_mode(cmode);
358   return (chmod(path, (mode_t) mode));
359 #endif
360 }
361 
362 /** This is a wrapper for the malloc function, which adds some
363  * error trapping.
364  *
365  * @return void
366  */
ccp4_utils_malloc(size_t size)367 void *ccp4_utils_malloc(size_t size)
368 
369 { void *val;
370 
371   val = malloc (size);
372   if (!val && size)
373     {
374       perror ("Failure in ccp4_utils_malloc");
375       abort ();
376     }
377   return val;}
378 
379 /** This is a wrapper for the realloc function, which adds some
380  * error trapping.
381  *
382  * @return
383  */
ccp4_utils_realloc(void * ptr,size_t size)384 void *ccp4_utils_realloc(void *ptr, size_t size)
385 { void *val;
386 
387   val = realloc (ptr, size);
388   if (!val && size)
389     {
390       perror ("Failure in ccp4_utils_realloc");
391       abort ();
392     }
393   return val;}
394 
395 /** This is a wrapper for the calloc function, which adds some
396  * error trapping.
397  *
398  * @return
399  */
ccp4_utils_calloc(size_t nelem,size_t elsize)400 void *ccp4_utils_calloc(size_t nelem , size_t elsize)
401 { void *val;
402 
403   val = calloc (nelem, elsize);
404   if (!val && elsize)
405     {
406       perror ("Failure in ccp4_utils_calloc");
407       abort ();
408     }
409   return val;}
410 
411 
412 /** Return the user's login name.
413  * Note that getlogin only works for processes attached to
414  * a terminal (and hence won't work from the GUI).
415  * @return pointer to character string containing login name.
416  */
ccp4_utils_username(void)417 char *ccp4_utils_username(void)
418 {
419   static char userid_unknown[] = "unknown";
420   char *userid = NULL;
421 #if defined(_WIN32)
422   static char windows_username[512];
423   DWORD bufsize = sizeof(windows_username);
424   if (GetUserName(windows_username, &bufsize))
425       userid = windows_username;
426 #else
427   userid = getlogin();
428 #endif
429   return userid ? userid : userid_unknown;
430 }
431 
is_sep(char c)432 static int is_sep(char c)
433 {
434 #ifdef _WIN32
435     /* allow alternative separator for Windows (for MSYS, Cygwin, Wine) */
436     return c == PATH_SEPARATOR || c == '/';
437 #else
438     return c == PATH_SEPARATOR;
439 #endif
440 }
441 
442 /** Extracts the basename from a full file name.
443  * Separators for directories and extensions are OS-specific.
444  * @param filename full file name string.
445  * @return pointer to basename
446  */
ccp4_utils_basename(const char * filename)447 char *ccp4_utils_basename(const char *filename)
448 {
449   int i, indx1=-1, length;
450   char *basename;
451 
452   for ( i = strlen(filename)-1; i >= 0; i-- ) {
453     if (is_sep(filename[i])) {
454       indx1 = i;
455       break;
456     }
457   }
458   length = strlen(filename) - indx1;
459   /* Search for extension separators must be performed backwards
460      in case filename has multiple extension separators */
461   for ( i = strlen(filename)-1; i >= (indx1 < 0 ? 0 : indx1) ; i-- ) {
462     if (filename[i] == EXT_SEPARATOR) {
463       length = i - indx1;
464       break;
465     }
466   }
467   basename = ccp4_utils_malloc(length*sizeof(char));
468   strncpy(basename,filename+indx1+1,length-1);
469   basename[length-1]='\0';
470   return basename;
471 }
472 
473 /** Extracts the pathname from a full file name.
474  * Separators for directories and extensions are OS-specific.
475  * @param filename full file name string.
476  * @return pointer to pathname with trailing separator.
477  */
ccp4_utils_pathname(const char * filename)478 char *ccp4_utils_pathname(const char *filename)
479 {
480   int i, indx1=-1, length;
481   char *pathname;
482 
483   for ( i = strlen(filename)-1; i >= 0; i-- ) {
484     if (is_sep(filename[i])) {
485       indx1 = i;
486       break;
487     }
488   }
489   length = indx1+2;
490   pathname = ccp4_utils_malloc(length*sizeof(char));
491   strncpy(pathname,filename,length-1);
492   pathname[length-1]='\0';
493   return pathname;
494 }
495 
496 /** Extracts the extension from a full file name.
497  * Separators for directories and extensions are OS-specific.
498  * @param filename full file name string.
499  * @return pointer to extension
500  */
ccp4_utils_extension(const char * filename)501 char *ccp4_utils_extension(const char *filename)
502 {
503   int i, indx1=-1, length=1;
504   char *extension;
505 
506   for ( i = strlen(filename)-1; i >= 0; i-- ) {
507     if (filename[i] == EXT_SEPARATOR) {
508       indx1 = i;
509       length = strlen(filename) - indx1;
510       break;
511     } else if (is_sep(filename[i])) {
512       indx1 = i;
513       length = 1;
514       break;
515     }
516   }
517   extension = ccp4_utils_malloc(length*sizeof(char));
518   strncpy(extension,filename+indx1+1,length-1);
519   extension[length-1]='\0';
520   return extension;
521 }
522 
523 /** Joins a leading directory with a filename.
524  * Separators for directories and extensions are OS-specific.
525  * @param dir  directory path.
526  * @param file file name string.
527  * @return pointer to joined directory-filename path.
528  */
ccp4_utils_joinfilenames(const char * dir,const char * file)529 char *ccp4_utils_joinfilenames(const char *dir, const char *file)
530 {
531   char *join=NULL;
532   int  lendir,lenfile,lenjoin;
533 
534   lendir = strlen(dir);
535   lenfile = strlen(file);
536   lenjoin = lendir + lenfile + 2;
537 
538   join = (char *) ccp4_utils_malloc(sizeof(char)*lenjoin);
539   if (!join) {
540     return NULL;
541   }
542 
543   strncpy(join,dir,lendir);
544   join[lendir] = PATH_SEPARATOR;
545   join[lendir+1] = '\0';
546   strncat(join,file,lenfile);
547   join[lenjoin-1] = '\0';
548 
549   return join;
550 }
551 
552 /** .
553  *
554  * @return
555  */
ccp4_utils_idate(int iarray[3])556 void ccp4_utils_idate (int iarray[3])
557 {
558      struct tm *lt=NULL;
559      time_t tim;
560      tim = time(NULL);
561      lt = localtime(&tim);
562      iarray[0] = lt->tm_mday;
563      iarray[1] = lt->tm_mon+1;  /* need range 1-12 */
564      iarray[2] = lt->tm_year + 1900;
565 }
566 
567 /** .
568  *
569  * @return
570  */
ccp4_utils_date(char * date)571 char *ccp4_utils_date(char *date)
572 {
573   int iarray[3];
574 
575   ccp4_utils_idate(iarray);
576   sprintf(date,"%2d/%2d/%4d",iarray[0],iarray[1],iarray[2]);
577   date[10] = '\0';
578 
579   return (date);
580 }
581 
582 /** Function to obtain current time.
583  * @param iarray Array containing hours, minutes and seconds.
584  * @return void.
585  */
ccp4_utils_itime(int iarray[3])586 void ccp4_utils_itime (int iarray[3])
587 {
588      struct tm *lt;
589      time_t tim;
590      tim = time(NULL);
591      lt = localtime(&tim);
592      iarray[0] = lt->tm_hour;
593      iarray[1] = lt->tm_min;
594      iarray[2] = lt->tm_sec;
595 }
596 
597 /** Alternative to ccp4_utils_itime with time as character string.
598  * @param time Character string of form HH:MM:SS
599  * @return pointer to character string.
600  */
ccp4_utils_time(char * time)601 char *ccp4_utils_time(char *time)
602 {
603   int iarray[3];
604 
605   ccp4_utils_itime(iarray);
606   sprintf(time,"%2.2d:%2.2d:%2.2d",iarray[0],iarray[1],iarray[2]);
607   time[8] = '\0';
608 
609   return (time);
610 }
611 
612 /** Function to obtain User and System times.
613  * @param tarray Array containing User and System times.
614  * @return Sum of User and System times.
615  */
ccp4_utils_etime(float tarray[2])616 float ccp4_utils_etime (float tarray[2])
617 {
618 #ifdef _WIN32
619   tarray[0] = tarray[1] = 0.;
620 #else
621   static long clk_tck = 0;
622 
623   struct tms buffer;
624   if (! clk_tck) clk_tck = sysconf(_SC_CLK_TCK);
625   (void) times(&buffer);
626   tarray[0] = (float) buffer.tms_utime / (float)clk_tck;
627   tarray[1] = (float) buffer.tms_stime / (float)clk_tck;
628 #endif
629   return (tarray[0]+tarray[1]);
630 }
631 
632 #if defined (_MSC_VER)
ccp4_erfc(double x)633 double ccp4_erfc( double x )
634 {
635   double t,z,ans;
636 
637   z=fabs(x);
638   t=1.0/(1.0+0.5*z);
639   ans=t*exp(-z*z-1.26551223+t*(1.00002368+t*(0.37409196+t*(0.09678418+
640       t*(-0.18628806+t*(0.27886807+t*(-1.13520398+t*(1.48851587+
641       t*(-0.82215223+t*0.17087277)))))))));
642   return  x >= 0.0 ? ans : 2.0-ans;
643 }
644 #endif
645 
646 #if defined (__APPLE__) && defined (__GNUC__) && ( __GNUC__ < 3 )
_carbon_init(int argc,char ** argv)647 void _carbon_init(int argc, char **argv) {}
_objcInit(void)648 void _objcInit(void) {}
649 #endif
650 
651 #if defined (__APPLE__) && defined (__GNUC__) && ( __GNUC__ == 3 ) && (__GNUC_MINOR__ == 1)
acosf(float x)652 float acosf(float x) {
653   return (float) acos( (double) x);
654 }
655 
atanf(float x)656 float atanf(float x) {
657   return (float) atan( (double) x);
658 }
659 
asinf(float x)660 float asinf(float x) {
661   return (float) asin( (double) x);
662 }
663 
664 #endif
665 
666 #  if (defined _MSC_VER)
rint(double x)667 double rint(double x) {
668   if (x >= 0.) {
669    return (double)(int)(x+.5);
670   }
671   return (double)(int)(x-.5);
672 }
673 #endif
674