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