1 
2 /* General Numerical routines support functions, */
3 /* and common Argyll support functions. */
4 /* (Perhaps these should be moved out of numlib at some stange ?) */
5 
6 /*
7  * Copyright 1997 - 2010 Graeme W. Gill
8  * All rights reserved.
9  *
10  * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
11  * see the License2.txt file for licencing details.
12  */
13 
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <math.h>
17 #include <string.h>
18 #include <limits.h>
19 #include <time.h>
20 #include <ctype.h>
21 #if defined (NT)
22 #define WIN32_LEAN_AND_MEAN
23 #include <windows.h>
24 #endif
25 #ifdef UNIX
26 #include <unistd.h>
27 #include <sys/param.h>
28 #include <sys/utsname.h>
29 #include <pthread.h>
30 #endif
31 #ifndef SALONEINSTLIB
32 #include "aconfig.h"
33 #else
34 #include "sa_config.h"
35 #endif
36 
37 #define NUMSUP_C
38 #include "numsup.h"
39 
40 /*
41  * TODO: Should probably break all the non-numlib stuff out into
42  *       a separate library, so that it can be ommitted.
43  *       Or enhance it so that numerical callers of error()
44  *       can get a callback on out of memory etc. ???
45  *
46  */
47 
48 /* Globals */
49 
50 char *exe_path = "\000";			/* Directory executable resides in ('/' dir separator) */
51 //char *error_program = "Unknown";	/* Name to report as responsible for an error */
52 
53 static int g_log_init = 0;	/* Initialised ? */
54 static int g_deb_init = 0;	/* Debug output Initialised ? */
55 extern a1log default_log;
56 extern a1log *g_log;
57 
58 /* Should Vector/Matrix Support functions return NULL on error, */
59 /* or call error() ? */
60 int ret_null_on_malloc_fail = 0;	/* Call error() */
61 
62 /******************************************************************/
63 /* Executable path routine. Sets default error_program too. */
64 /******************************************************************/
65 
66 /* Pass in argv[0] from main() */
67 /* Sets the error_program name too */
set_exe_path(char * argv0)68 void set_exe_path(char *argv0) {
69 	int i;
70 
71 	g_log->tag = argv0;
72 	i = strlen(argv0);
73 	if ((exe_path = malloc(i + 5)) == NULL) {
74 		a1loge(g_log, 1, "set_exe_path: malloc %d bytes failed\n",i+5);
75 		return;
76 	}
77 	strcpy(exe_path, argv0);
78 
79 #ifdef NT	/* CMD.EXE doesn't give us the full path in argv[0] :-( */
80 			/* so we need to fix this */
81 	{
82 		HMODULE mh;
83 		char *tpath = NULL;
84 		int pl;
85 
86 		/* Add an .exe extension if it is missing */
87 		if (i < 4 || _stricmp(exe_path +i -4, ".exe") != 0)
88 			strcat(exe_path, ".exe");
89 
90 		if ((mh = GetModuleHandle(exe_path)) == NULL) {
91 			a1loge(g_log, 1, "set_exe_path: GetModuleHandle '%s' failed with%d\n",
92 			                                            exe_path,GetLastError());
93 			exe_path[0] = '\000';
94 			return;
95 		}
96 
97 		/* Retry until we don't truncate the returned path */
98 		for (pl = 100; ; pl *= 2) {
99 			if (tpath != NULL)
100 				free(tpath);
101 			if ((tpath = malloc(pl)) == NULL) {
102 				a1loge(g_log, 1, "set_exe_path: malloc %d bytes failed\n",pl);
103 				exe_path[0] = '\000';
104 			return;
105 			}
106 			if ((i = GetModuleFileName(mh, tpath, pl)) == 0) {
107 				a1loge(g_log, 1, "set_exe_path: GetModuleFileName '%s' failed with%d\n",
108 				                                                tpath,GetLastError());
109 				exe_path[0] = '\000';
110 				return;
111 			}
112 			if (i < pl)		/* There was enough space */
113 				break;
114 		}
115 		free(exe_path);
116 		exe_path = tpath;
117 
118 		/* Convert from MSWindows to UNIX file separator convention */
119 		for (i = 0; ;i++) {
120 			if (exe_path[i] == '\000')
121 				break;
122 			if (exe_path[i] == '\\')
123 				exe_path[i] = '/';
124 		}
125 	}
126 #else		/* Neither does UNIX */
127 
128 	if (*exe_path != '/') {			/* Not already absolute */
129 		char *p, *cp;
130 		if (strchr(exe_path, '/') != 0) {	/* relative path */
131 			cp = ".:";				/* Fake a relative PATH */
132 		} else  {
133 			cp = getenv("PATH");
134 		}
135 		if (cp != NULL) {
136 			int found = 0;
137 			while((p = strchr(cp,':')) != NULL
138 			 || *cp != '\000') {
139 				char b1[PATH_MAX], b2[PATH_MAX];
140  				int ll;
141 				if (p == NULL)
142 					ll = strlen(cp);
143 				else
144 					ll = p - cp;
145 				if ((ll + 1 + strlen(exe_path) + 1) > PATH_MAX) {
146 					a1loge(g_log, 1, "set_exe_path: Search path exceeds PATH_MAX\n");
147 					exe_path[0] = '\000';
148 					return;
149 				}
150 				strncpy(b1, cp, ll);		/* Element of path to search */
151 				b1[ll] = '\000';
152 				strcat(b1, "/");
153 				strcat(b1, exe_path);		/* Construct path */
154 				if (realpath(b1, b2)) {
155 					if (access(b2, 0) == 0) {	/* See if exe exits */
156 						found = 1;
157 						free(exe_path);
158 						if ((exe_path = malloc(strlen(b2)+1)) == NULL) {
159 							a1loge(g_log, 1, "set_exe_path: malloc %d bytes failed\n",strlen(b2)+1);
160 							exe_path[0] = '\000';
161 							return;
162 						}
163 						strcpy(exe_path, b2);
164 						break;
165 					}
166 				}
167 				if (p == NULL)
168 					break;
169 				cp = p + 1;
170 			}
171 			if (found == 0)
172 				exe_path[0] = '\000';
173 		}
174 	}
175 #endif
176 	/* strip the executable path to the base */
177 	for (i = strlen(exe_path)-1; i >= 0; i--) {
178 		if (exe_path[i] == '/') {
179 			char *tpath;
180 			if ((tpath = malloc(strlen(exe_path + i))) == NULL) {
181 				a1loge(g_log, 1, "set_exe_path: malloc %d bytes failed\n",strlen(exe_path + i));
182 				exe_path[0] = '\000';
183 				return;
184 			}
185 			strcpy(tpath, exe_path + i + 1);
186 			g_log->tag = tpath;				/* Set g_log->tag to base name */
187 			exe_path[i+1] = '\000';				/* (The malloc never gets free'd) */
188 			break;
189 		}
190 	}
191 	/* strip off any .exe from the g_log->tag to be more readable */
192 	i = strlen(g_log->tag);
193 	if (i >= 4
194 	 && g_log->tag[i-4] == '.'
195 	 && (g_log->tag[i-3] == 'e' || g_log->tag[i-3] == 'E')
196 	 && (g_log->tag[i-2] == 'x' || g_log->tag[i-2] == 'X')
197 	 && (g_log->tag[i-1] == 'e' || g_log->tag[i-1] == 'E'))
198 		g_log->tag[i-4] = '\000';
199 
200 //	a1logd(g_log, 1, "exe_path = '%s'\n",exe_path);
201 //	a1logd(g_log, 1, "g_log->tag = '%s'\n",g_log->tag);
202 }
203 
204 /******************************************************************/
205 /* Check "ARGYLL_NOT_INTERACTIVE" environment variable.           */
206 /******************************************************************/
207 
208 /* Check if the "ARGYLL_NOT_INTERACTIVE" environment variable is */
209 /* set, and set cr_char to '\n' if it is. */
210 
211 int not_interactive = 0;
212 char cr_char = '\r';
213 
check_if_not_interactive()214 void check_if_not_interactive() {
215 	char *ev;
216 
217 	if ((ev = getenv("ARGYLL_NOT_INTERACTIVE")) != NULL) {
218 		not_interactive = 1;
219 		cr_char = '\n';
220 	} else {
221 		not_interactive = 0;
222 		cr_char = '\r';
223 	}
224 }
225 
226 /******************************************************************/
227 /* Default verbose/debug/error loger                              */
228 /* It's values can be overridden to redirect these messages.      */
229 /******************************************************************/
230 
231 static void va_loge(a1log *p, char *fmt, ...);
232 
233 #ifdef NT
234 
235 /* Get a string describing the MWin operating system */
236 
237 typedef struct {
238     DWORD dwOSVersionInfoSize;
239     DWORD dwMajorVersion;
240     DWORD dwMinorVersion;
241     DWORD dwBuildNumber;
242     DWORD dwPlatformId;
243     WCHAR  szCSDVersion[128];
244     WORD   wServicePackMajor;
245     WORD   wServicePackMinor;
246     WORD   wSuiteMask;
247     BYTE  wProductType;
248     BYTE  wReserved;
249 } osversioninfoexw;
250 
251 #ifndef VER_NT_DOMAIN_CONTROLLER
252 # define VER_NT_DOMAIN_CONTROLLER 0x0000002
253 # define VER_NT_SERVER 0x0000003
254 # define VER_NT_WORKSTATION 0x0000001
255 #endif
256 
get_sys_info()257 static char *get_sys_info() {
258 	static char sysinfo[100] = { "Unknown" };
259 	LONG (WINAPI *pfnRtlGetVersion)(osversioninfoexw*);
260 
261 	*(FARPROC *)&pfnRtlGetVersion
262 	 = GetProcAddress(GetModuleHandle("ntdll.dll"), "RtlGetVersion");
263 	if (pfnRtlGetVersion != NULL) {
264 	    osversioninfoexw ver = { 0 };
265 	    ver.dwOSVersionInfoSize = sizeof(ver);
266 
267 	    if (pfnRtlGetVersion(&ver) == 0) {
268 			if (ver.dwMajorVersion > 6 || (ver.dwMajorVersion == 6 && ver.dwMinorVersion > 3)) {
269 				if (ver.wProductType == VER_NT_WORKSTATION)
270 					sprintf(sysinfo,"Windows V%d.%d SP %d",
271 						ver.dwMajorVersion,ver.dwMinorVersion,
272 						ver.wServicePackMajor);
273 				else
274 					sprintf(sysinfo,"Windows Server 2016 V%d.%d SP %d",
275 						ver.dwMajorVersion,ver.dwMinorVersion,
276 						ver.wServicePackMajor);
277 
278 			} else if (ver.dwMajorVersion == 6 && ver.dwMinorVersion == 3) {
279 				if (ver.wProductType == VER_NT_WORKSTATION)
280 					sprintf(sysinfo,"Windows V8.1 SP %d",
281 						ver.wServicePackMajor);
282 				else
283 					sprintf(sysinfo,"Windows Server 2012 R2 SP %d",
284 						ver.wServicePackMajor);
285 
286 			} else if (ver.dwMajorVersion == 6 && ver.dwMinorVersion == 2) {
287 				if (ver.wProductType == VER_NT_WORKSTATION)
288 					sprintf(sysinfo,"Windows V8 SP %d",
289 						ver.wServicePackMajor);
290 				else
291 					sprintf(sysinfo,"Windows Server SP %d",
292 						ver.wServicePackMajor);
293 
294 			} else if (ver.dwMajorVersion == 6 && ver.dwMinorVersion == 1) {
295 				if (ver.wProductType == VER_NT_WORKSTATION)
296 					sprintf(sysinfo,"Windows V7 SP %d",
297 						ver.wServicePackMajor);
298 				else
299 					sprintf(sysinfo,"Windows Server 2008 R2 SP %d",
300 						ver.wServicePackMajor);
301 
302 			} else if (ver.dwMajorVersion == 6 && ver.dwMinorVersion == 0) {
303 				if (ver.wProductType == VER_NT_WORKSTATION)
304 					sprintf(sysinfo,"Windows Vista SP %d",
305 						ver.wServicePackMajor);
306 				else
307 					sprintf(sysinfo,"Windows Server 2008 SP %d",
308 						ver.wServicePackMajor);
309 
310 			} else if (ver.dwMajorVersion == 5 && ver.dwMinorVersion == 2) {
311 				// Actually could be Server 2003, Home Server, Server 2003 R2
312 				sprintf(sysinfo,"Windows XP Pro64 SP %d",
313 					ver.wServicePackMajor);
314 
315 			} else if (ver.dwMajorVersion == 5 && ver.dwMinorVersion == 1) {
316 				sprintf(sysinfo,"Windows XP SP %d",
317 						ver.wServicePackMajor);
318 
319 			} else if (ver.dwMajorVersion == 5 && ver.dwMinorVersion == 0) {
320 				sprintf(sysinfo,"Windows XP SP %d",
321 						ver.wServicePackMajor);
322 
323 			} else {
324 				sprintf(sysinfo,"Windows Maj %d Min %d SP %d",
325 					ver.dwMajorVersion,ver.dwMinorVersion,
326 					ver.wServicePackMajor);
327 			}
328 		}
329 	}
330 	return sysinfo;
331 }
332 
333 
334 # define A1LOG_LOCK(log, deb)								\
335 	if (g_log_init == 0) {									\
336 	    InitializeCriticalSection(&log->lock);				\
337 		EnterCriticalSection(&log->lock);					\
338 		g_log_init = 1;										\
339 	} else {												\
340 		EnterCriticalSection(&log->lock);					\
341 	}														\
342 	if (deb && !g_deb_init) {								\
343 		va_loge(log, "Argyll 'V%s' Build '%s' System '%s'\n",ARGYLL_VERSION_STR,ARGYLL_BUILD_STR, get_sys_info());	\
344 		g_deb_init = 1;										\
345 	}
346 # define A1LOG_UNLOCK(log) LeaveCriticalSection(&log->lock)
347 #endif
348 #ifdef UNIX
349 
get_sys_info()350 static char *get_sys_info() {
351 	static char sysinfo[200] = { "Unknown" };
352 	struct utsname ver;
353 
354 	if (uname(&ver) == 0)
355 		sprintf(sysinfo,"%s %s %s %s",ver.sysname, ver.version, ver.release, ver.machine);
356 	return sysinfo;
357 }
358 
359 # define A1LOG_LOCK(log, deb)								\
360 	if (g_log_init == 0) {									\
361 	    pthread_mutex_init(&log->lock, NULL);				\
362 		pthread_mutex_lock(&log->lock);						\
363 		g_log_init = 1;										\
364 	} else {												\
365 		pthread_mutex_lock(&log->lock);						\
366 	}														\
367 	if (deb && !g_deb_init) {								\
368 		va_loge(log, "Argyll 'V%s' Build '%s' System '%s'\n",ARGYLL_VERSION_STR,ARGYLL_BUILD_STR, get_sys_info());	\
369 		g_deb_init = 1;										\
370 	}
371 # define A1LOG_UNLOCK(log) pthread_mutex_unlock(&log->lock)
372 #endif
373 
374 
375 
376 /* Default verbose logging function - print to stdtout */
a1_default_v_log(void * cntx,a1log * p,char * fmt,va_list args)377 static void a1_default_v_log(void *cntx, a1log *p, char *fmt, va_list args) {
378 	vfprintf(stdout, fmt, args);
379 	fflush(stdout);
380 }
381 
382 /* Default debug & error logging function - print to stderr */
a1_default_de_log(void * cntx,a1log * p,char * fmt,va_list args)383 static void a1_default_de_log(void *cntx, a1log *p, char *fmt, va_list args) {
384 	vfprintf(stderr, fmt, args);
385 	fflush(stderr);
386 }
387 
388 #define a1_default_d_log a1_default_de_log
389 #define a1_default_e_log a1_default_de_log
390 
391 
392 /* Call log->loge() with variags */
va_loge(a1log * p,char * fmt,...)393 static void va_loge(a1log *p, char *fmt, ...) {
394 	va_list args;
395 	va_start(args, fmt);
396 	p->loge(p->cntx, p, fmt, args);
397 	va_end(args);
398 }
399 
400 /* Global log */
401 a1log default_log = {
402 	1,			/* Refcount of 1 because this is not allocated or free'd */
403 	"argyll",	/* Default tag */
404 	0,			/* Vebose off */
405 	0,			/* Debug off */
406 	NULL,		/* Context */
407 	&a1_default_v_log,	/* Default verbose to stdout */
408 	&a1_default_d_log,	/* Default debug to stderr */
409 	&a1_default_e_log,	/* Default error to stderr */
410 	0,					/* error code 0 */
411 	{ '\000' }			/* No error message */
412 };
413 a1log *g_log = &default_log;
414 
415 /* If log NULL, allocate a new log and return it, */
416 /* otherwise increment reference count and return existing log, */
417 /* exit() if malloc fails. */
new_a1log(a1log * log,int verb,int debug,void * cntx,void (* logv)(void * cntx,a1log * p,char * fmt,va_list args),void (* logd)(void * cntx,a1log * p,char * fmt,va_list args),void (* loge)(void * cntx,a1log * p,char * fmt,va_list args))418 a1log *new_a1log(
419 	a1log *log,						/* Existing log to reference, NULL if none */
420 	int verb,						/* Verbose level to set */
421 	int debug,						/* Debug level to set */
422 	void *cntx,						/* Function context value */
423 		/* Vebose log function to call - stdout if NULL */
424 	void (*logv)(void *cntx, a1log *p, char *fmt, va_list args),
425 		/* Debug log function to call - stderr if NULL */
426 	void (*logd)(void *cntx, a1log *p, char *fmt, va_list args),
427 		/* Warning/error Log function to call - stderr if NULL */
428 	void (*loge)(void *cntx, a1log *p, char *fmt, va_list args)
429 ) {
430 	if (log != NULL) {
431 		log->refc++;
432 		return log;
433 	}
434 	if ((log = (a1log *)calloc(sizeof(a1log), 1)) == NULL) {
435 		a1loge(g_log, 1, "new_a1log: malloc of a1log failed, calling exit(1)\n");
436 		exit(1);
437 	}
438 	log->refc = 1;
439 	log->verb = verb;
440 	log->debug = debug;
441 
442 	log->cntx = cntx;
443 	if (logv != NULL)
444 		log->logv = logv;
445 	else
446 		log->logv = a1_default_v_log;
447 
448 	if (logd != NULL)
449 		log->logd = logd;
450 	else
451 		log->logd = a1_default_d_log;
452 
453 	if (loge != NULL)
454 		log->loge = loge;
455 	else
456 		log->loge = a1_default_e_log;
457 
458 	log->errc = 0;
459 	log->errm[0] = '\000';
460 
461 	return log;
462 }
463 
464 /* Same as above but set default functions */
new_a1log_d(a1log * log)465 a1log *new_a1log_d(a1log *log) {
466 	return new_a1log(log, 0, 0, NULL, NULL, NULL, NULL);
467 }
468 
469 /* Decrement reference count and free log. */
470 /* Returns NULL */
del_a1log(a1log * log)471 a1log *del_a1log(a1log *log) {
472 	if (log != NULL) {
473 		if (--log->refc <= 0) {
474 #ifdef NT
475 			DeleteCriticalSection(&log->lock);
476 #endif
477 #ifdef UNIX
478 			pthread_mutex_destroy(&log->lock);
479 #endif
480 			free(log);
481 		}
482 	}
483 	return NULL;
484 }
485 
486 /* Set the tag. Note that the tage string is NOT copied, just referenced */
a1log_tag(a1log * log,char * tag)487 void a1log_tag(a1log *log, char *tag) {
488 	log->tag = tag;
489 }
490 
491 /* Log a verbose message if level >= verb */
a1logv(a1log * log,int level,char * fmt,...)492 void a1logv(a1log *log, int level, char *fmt, ...) {
493 	if (log != NULL) {
494 		if (log->verb >= level) {
495 			va_list args;
496 
497 			A1LOG_LOCK(log, 0);
498 			va_start(args, fmt);
499 			log->logv(log->cntx, log, fmt, args);
500 			va_end(args);
501 			A1LOG_UNLOCK(log);
502 		}
503 	}
504 }
505 
506 /* Log a debug message if level >= debug */
a1logd(a1log * log,int level,char * fmt,...)507 void a1logd(a1log *log, int level, char *fmt, ...) {
508 	if (log != NULL) {
509 		if (log->debug >= level) {
510 			va_list args;
511 
512 			A1LOG_LOCK(log, 1);
513 			va_start(args, fmt);
514 			log->loge(log->cntx, log, fmt, args);
515 			va_end(args);
516 			A1LOG_UNLOCK(log);
517 		}
518 	}
519 }
520 
521 /* log a warning message to the verbose, debug and error output, */
a1logw(a1log * log,char * fmt,...)522 void a1logw(a1log *log, char *fmt, ...) {
523 	if (log != NULL) {
524 		va_list args;
525 
526 		/* log to all the outputs, but only log once */
527 		A1LOG_LOCK(log, 0);
528 		va_start(args, fmt);
529 		log->loge(log->cntx, log, fmt, args);
530 		va_end(args);
531 		A1LOG_UNLOCK(log);
532 		if (log->logd != log->loge) {
533 			A1LOG_LOCK(log, 1);
534 			va_start(args, fmt);
535 			log->logd(log->cntx, log, fmt, args);
536 			va_end(args);
537 			A1LOG_UNLOCK(log);
538 		}
539 		if (log->logv != log->loge && log->logv != log->logd) {
540 			A1LOG_LOCK(log, 0);
541 			va_start(args, fmt);
542 			log->logv(log->cntx, log, fmt, args);
543 			va_end(args);
544 			A1LOG_UNLOCK(log);
545 		}
546 	}
547 }
548 
549 /* log an error message to the verbose, debug and error output, */
550 /* and latch the error if it is the first. */
551 /* ecode = system, icoms or instrument error */
a1loge(a1log * log,int ecode,char * fmt,...)552 void a1loge(a1log *log, int ecode, char *fmt, ...) {
553 	if (log != NULL) {
554 		va_list args;
555 
556 		if (log->errc == 0) {
557 			A1LOG_LOCK(log, 0);
558 			log->errc = ecode;
559 			va_start(args, fmt);
560 			vsnprintf(log->errm, A1_LOG_BUFSIZE, fmt, args);
561 			va_end(args);
562 			A1LOG_UNLOCK(log);
563 		}
564 		va_start(args, fmt);
565 		/* log to all the outputs, but only log once */
566 		A1LOG_LOCK(log, 0);
567 		va_start(args, fmt);
568 		log->loge(log->cntx, log, fmt, args);
569 		va_end(args);
570 		A1LOG_UNLOCK(log);
571 		if (log->logd != log->loge) {
572 			A1LOG_LOCK(log, 1);
573 			va_start(args, fmt);
574 			log->logd(log->cntx, log, fmt, args);
575 			va_end(args);
576 			A1LOG_UNLOCK(log);
577 		}
578 		if (log->logv != log->loge && log->logv != log->logd) {
579 			A1LOG_LOCK(log, 0);
580 			va_start(args, fmt);
581 			log->logv(log->cntx, log, fmt, args);
582 			va_end(args);
583 			A1LOG_UNLOCK(log);
584 		}
585 	}
586 }
587 
588 /* Unlatch an error message. */
589 /* This just resets errc and errm */
a1logue(a1log * log)590 void a1logue(a1log *log) {
591 	if (log != NULL) {
592 		log->errc = 0;
593 		log->errm[0] = '\000';
594 	}
595 }
596 
597 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
598 
599 /* Print bytes as hex to debug log */
600 /* base is the base of the displayed offset */
adump_bytes(a1log * log,char * pfx,unsigned char * buf,int base,int len)601 void adump_bytes(a1log *log, char *pfx, unsigned char *buf, int base, int len) {
602 	int i, j, ii;
603 	char oline[200] = { '\000' }, *bp = oline;
604 	for (i = j = 0; i < len; i++) {
605 		if ((i % 16) == 0)
606 			bp += sprintf(bp,"%s%04x:",pfx,base+i);
607 		bp += sprintf(bp," %02x",buf[i]);
608 		if ((i+1) >= len || ((i+1) % 16) == 0) {
609 			for (ii = i; ((ii+1) % 16) != 0; ii++)
610 				bp += sprintf(bp,"   ");
611 			bp += sprintf(bp,"  ");
612 			for (; j <= i; j++) {
613 				if (!(buf[j] & 0x80) && isprint(buf[j]))
614 					bp += sprintf(bp,"%c",buf[j]);
615 				else
616 					bp += sprintf(bp,".");
617 			}
618 			bp += sprintf(bp,"\n");
619 			a1logd(log,0,"%s",oline);
620 			bp = oline;
621 		}
622 	}
623 }
624 
625 /******************************************************************/
626 /* Default verbose/warning/error output routines                  */
627 /* These fall through to, and can be re-director using the        */
628 /* above log class.                                               */
629 /******************************************************************/
630 
631 /* Some utilities to allow us to format output to log functions */
632 /* (Caller aquires lock) */
g_logv(char * fmt,...)633 static void g_logv(char *fmt, ...) {
634 	va_list args;
635 	va_start(args, fmt);
636 	g_log->logv(g_log->cntx, g_log, fmt, args);
637 	va_end(args);
638 }
639 
g_loge(char * fmt,...)640 static void g_loge(char *fmt, ...) {
641 	va_list args;
642 	va_start(args, fmt);
643 	g_log->loge(g_log->cntx, g_log, fmt, args);
644 	va_end(args);
645 }
646 
647 void
verbose(int level,char * fmt,...)648 verbose(int level, char *fmt, ...) {
649 	if (g_log->verb >= level) {
650 		va_list args;
651 
652 		A1LOG_LOCK(g_log, 0);
653 		g_logv("%s: ",g_log->tag);
654 		va_start(args, fmt);
655 		g_log->logv(g_log->cntx, g_log, fmt, args);
656 		va_end(args);
657 		g_logv("\n");
658 		A1LOG_UNLOCK(g_log);
659 	}
660 }
661 
662 void
warning(char * fmt,...)663 warning(char *fmt, ...) {
664 	va_list args;
665 
666 	A1LOG_LOCK(g_log, 0);
667 	g_loge("%s: Warning - ",g_log->tag);
668 	va_start(args, fmt);
669 	g_log->loge(g_log->cntx, g_log, fmt, args);
670 	va_end(args);
671 	g_loge("\n");
672 	A1LOG_UNLOCK(g_log);
673 }
674 
675 ATTRIBUTE_NORETURN void
error(char * fmt,...)676 error(char *fmt, ...) {
677 	va_list args;
678 
679 	A1LOG_LOCK(g_log, 0);
680 	g_loge("%s: Error - ",g_log->tag);
681 	va_start(args, fmt);
682 	g_log->loge(g_log->cntx, g_log, fmt, args);
683 	va_end(args);
684 	g_loge("\n");
685 	A1LOG_UNLOCK(g_log);
686 
687 	exit(1);
688 }
689 
690 
691 /******************************************************************/
692 /* Suplimental allcation functions */
693 /******************************************************************/
694 
695 #ifndef SIZE_MAX
696 # define SIZE_MAX ((size_t)(-1))
697 #endif
698 
699 /* a * b */
ssat_mul(size_t a,size_t b)700 static size_t ssat_mul(size_t a, size_t b) {
701 	size_t c;
702 
703 	if (a == 0 || b == 0)
704 		return 0;
705 
706 	if (a > (SIZE_MAX/b))
707 		return SIZE_MAX;
708 	else
709 		return a * b;
710 }
711 
712 /* reallocate and clear new allocation */
recalloc(void * ptr,size_t cnum,size_t csize,size_t nnum,size_t nsize)713 void *recalloc(		/* Return new address */
714 void *ptr,					/* Current address */
715 size_t cnum,				/* Current number and unit size */
716 size_t csize,
717 size_t nnum,				/* New number and unit size */
718 size_t nsize
719 ) {
720 	int ind = 0;
721 	size_t ctot, ntot;
722 
723 	if (ptr == NULL)
724 		return calloc(nnum, nsize);
725 
726 	if ((ntot = ssat_mul(nnum, nsize)) == SIZE_MAX)
727 		return NULL;			/* Overflow */
728 
729 	if ((ctot = ssat_mul(cnum, csize)) == SIZE_MAX)
730 		return NULL;			/* Overflow */
731 
732 	ptr = realloc(ptr, ntot);
733 
734 	if (ptr != NULL && ntot > ctot)
735 		memset((char *)ptr + ctot, 0, ntot - ctot);			/* Clear the new region */
736 
737 	return ptr;
738 }
739 
740 /******************************************************************/
741 /* OS X App Nap fixes                                             */
742 /******************************************************************/
743 
744 #if defined(__APPLE__)
745 
746 #if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
747 # include <objc/runtime.h>
748 # include <objc/message.h>
749 #else
750 # include <objc/objc-runtime.h>
751 #endif
752 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
753 # include <objc/objc-auto.h>
754 #endif
755 
756 /*
757 	OS X 10.9+ App Nap problems bug:
758 
759 	<http://stackoverflow.com/questions/22784886/what-can-make-nanosleep-drift-with-exactly-10-sec-on-mac-os-x-10-9>
760 
761 	NSProcessInfo variables:
762 
763 	<https://developer.apple.com/library/prerelease/ios/documentation/Cocoa/Reference/Foundation/Classes/NSProcessInfo_Class/#//apple_ref/c/tdef/NSActivityOptions>
764 
765 	 typedef enum : uint64_t { NSActivityIdleDisplaySleepDisabled = (1ULL << 40),
766 		NSActivityIdleSystemSleepDisabled = (1ULL << 20),
767 		NSActivitySuddenTerminationDisabled = (1ULL << 14),
768 		NSActivityAutomaticTerminationDisabled = (1ULL << 15),
769 		NSActivityUserInitiated = (0x00FFFFFFULL | NSActivityIdleSystemSleepDisabled ),
770 		NSActivityUserInitiatedAllowingIdleSystemSleep =
771 		           (NSActivityUserInitiated & ~NSActivityIdleSystemSleepDisabled ),
772 		NSActivityBackground = 0x000000FFULL,
773 		NSActivityLatencyCritical = 0xFF00000000ULL,
774 	} NSActivityOptions;
775 
776 	See <http://stackoverflow.com/questions/19847293/disable-app-nap-in-macos-10-9-mavericks-application>:
777 
778 	@property (strong) id activity;
779 
780 	if ([[NSProcessInfo processInfo] respondsToSelector:@selector(beginActivityWithOptions:reason:)]) {
781     self.activity = [[NSProcessInfo processInfo] beginActivityWithOptions:0x00FFFFFF reason:@"receiving OSC messages"];
782 }
783 
784 	<http://stackoverflow.com/questions/19671197/disabling-app-nap-with-beginactivitywithoptions>
785 
786 	NSProcessInfo = interface(NSObject)['{B96935F6-3809-4A49-AD4F-CBBAB0F2C961}']
787 	function beginActivityWithOptions(options: NSActivityOptions; reason: NSString): NSObject; cdecl;
788 
789 	<http://stackoverflow.com/questions/22164571/weird-behaviour-of-dispatch-after>
790 
791 */
792 
793 static int osx_userinitiated_cnt = 0;
794 static id osx_userinitiated_activity = nil;
795 
796 /* Tell App Nap that this is user initiated */
osx_userinitiated_start()797 void osx_userinitiated_start() {
798 	Class pic;		/* Process info class */
799 	SEL pis;		/* Process info selector */
800 	SEL bawo;		/* Begin Activity With Options selector */
801 	id pi;			/* Process info */
802 	id str;
803 
804 	if (osx_userinitiated_cnt++ != 0)
805 		return;
806 
807 	a1logd(g_log, 7, "OS X - User Initiated Activity start\n");
808 
809 	/* We have to be conservative to avoid triggering an exception when run on older OS X, */
810 	/* since beginActivityWithOptions is only available in >= 10.9 */
811 	if ((pic = (Class)objc_getClass("NSProcessInfo")) == nil) {
812 		return;
813 	}
814 
815 	if (class_getClassMethod(pic, (pis = sel_getUid("processInfo"))) == NULL) {
816 		return;
817 	}
818 
819 	if (class_getInstanceMethod(pic, (bawo = sel_getUid("beginActivityWithOptions:reason:"))) == NULL) {
820 		a1logd(g_log, 7, "OS X - beginActivityWithOptions not supported\n");
821 		return;
822 	}
823 
824 	/* Get the process instance */
825 	if ((pi = objc_msgSend((id)pic, pis)) == nil) {
826 		return;
827 	}
828 
829 	/* Create a reason string */
830 	str = objc_msgSend(objc_getClass("NSString"), sel_getUid("alloc"));
831 	str = objc_msgSend(str, sel_getUid("initWithUTF8String:"), "ArgyllCMS");
832 
833 	/* Start activity that tells App Nap to mind its own business. */
834 	/* NSActivityUserInitiatedAllowingIdleSystemSleep */
835 	osx_userinitiated_activity = objc_msgSend(pi, bawo, 0x00FFFFFFULL, str);
836 }
837 
838 /* Done with user initiated */
osx_userinitiated_end()839 void osx_userinitiated_end() {
840 	if (osx_userinitiated_cnt > 0) {
841 		osx_userinitiated_cnt--;
842 		if (osx_userinitiated_cnt == 0 && osx_userinitiated_activity != nil) {
843 			a1logd(g_log, 7, "OS X - User Initiated Activity end");
844 			objc_msgSend(
845 			             objc_msgSend(objc_getClass("NSProcessInfo"), sel_getUid("processInfo")),
846 			             sel_getUid("endActivity:"), osx_userinitiated_activity);
847 			osx_userinitiated_activity = nil;
848 		}
849 	}
850 }
851 
852 static int osx_latencycritical_cnt = 0;
853 static id osx_latencycritical_activity = nil;
854 
855 /* Tell App Nap that this is latency critical */
osx_latencycritical_start()856 void osx_latencycritical_start() {
857 	Class pic;		/* Process info class */
858 	SEL pis;		/* Process info selector */
859 	SEL bawo;		/* Begin Activity With Options selector */
860 	id pi;		/* Process info */
861 	id str;
862 
863 	if (osx_latencycritical_cnt++ != 0)
864 		return;
865 
866 	a1logd(g_log, 7, "OS X - Latency Critical Activity start\n");
867 
868 	/* We have to be conservative to avoid triggering an exception when run on older OS X */
869 	if ((pic = (Class)objc_getClass("NSProcessInfo")) == nil) {
870 		return;
871 	}
872 
873 	if (class_getClassMethod(pic, (pis = sel_getUid("processInfo"))) == NULL) {
874 		return;
875 	}
876 
877 	if (class_getInstanceMethod(pic, (bawo = sel_getUid("beginActivityWithOptions:reason:"))) == NULL) {
878 		a1logd(g_log, 7, "OS X - beginActivityWithOptions not supported\n");
879 		return;
880 	}
881 
882 	/* Get the process instance */
883 	if ((pi = objc_msgSend((id)pic, pis)) == nil) {
884 		return;
885 	}
886 
887 	/* Create a reason string */
888 	str = objc_msgSend(objc_getClass("NSString"), sel_getUid("alloc"));
889 	str = objc_msgSend(str, sel_getUid("initWithUTF8String:"), "Measuring Color");
890 
891 	/* Start activity that tells App Nap to mind its own business. */
892 	/* NSActivityUserInitiatedAllowingIdleSystemSleep | NSActivityLatencyCritical */
893 	osx_latencycritical_activity = objc_msgSend(pi, bawo, 0x00FFFFFFULL | 0xFF00000000ULL, str);
894 }
895 
896 /* Done with latency critical */
osx_latencycritical_end()897 void osx_latencycritical_end() {
898 	if (osx_latencycritical_cnt > 0) {
899 		osx_latencycritical_cnt--;
900 		if (osx_latencycritical_cnt == 0 && osx_latencycritical_activity != nil) {
901 			a1logd(g_log, 7, "OS X - Latency Critical Activity end");
902 			objc_msgSend(
903 			             objc_msgSend(objc_getClass("NSProcessInfo"), sel_getUid("processInfo")),
904 			             sel_getUid("endActivity:"), osx_latencycritical_activity);
905 			osx_latencycritical_activity = nil;
906 		}
907 	}
908 }
909 
910 #endif	/* __APPLE__ */
911 
912 /******************************************************************/
913 /* Numerical Recipes Vector/Matrix Support functions              */
914 /******************************************************************/
915 /* Note the z suffix versions return zero'd vectors/matricies */
916 
917 /* Double Vector malloc/free */
dvector(int nl,int nh)918 double *dvector(
919 int nl,		/* Lowest index */
920 int nh		/* Highest index */
921 )	{
922 	double *v;
923 
924 	if ((v = (double *) malloc((nh-nl+1) * sizeof(double))) == NULL) {
925 		if (ret_null_on_malloc_fail)
926 			return NULL;
927 		else
928 			error("Malloc failure in dvector()");
929 	}
930 	return v-nl;
931 }
932 
dvectorz(int nl,int nh)933 double *dvectorz(
934 int nl,		/* Lowest index */
935 int nh		/* Highest index */
936 ) {
937 	double *v;
938 
939 	if ((v = (double *) calloc(nh-nl+1, sizeof(double))) == NULL) {
940 		if (ret_null_on_malloc_fail)
941 			return NULL;
942 		else
943 			error("Malloc failure in dvector()");
944 	}
945 	return v-nl;
946 }
947 
free_dvector(double * v,int nl,int nh)948 void free_dvector(
949 double *v,
950 int nl,		/* Lowest index */
951 int nh		/* Highest index */
952 ) {
953 	if (v == NULL)
954 		return;
955 
956 	free((char *) (v+nl));
957 }
958 
959 /* --------------------- */
960 /* 2D Double vector malloc/free */
dmatrix(int nrl,int nrh,int ncl,int nch)961 double **dmatrix(
962 int nrl,	/* Row low index */
963 int nrh,	/* Row high index */
964 int ncl,	/* Col low index */
965 int nch		/* Col high index */
966 ) {
967 	int i;
968 	int rows, cols;
969 	double **m;
970 
971 	if (nrh < nrl)	/* Prevent failure for 0 dimension */
972 		nrh = nrl;
973 	if (nch < ncl)
974 		nch = ncl;
975 
976 	rows = nrh - nrl + 1;
977 	cols = nch - ncl + 1;
978 
979 	if ((m = (double **) malloc((rows + 1) * sizeof(double *))) == NULL) {
980 		if (ret_null_on_malloc_fail)
981 			return NULL;
982 		else
983 			error("Malloc failure in dmatrix(), pointers");
984 	}
985 	m -= nrl;	/* Offset to nrl */
986 	m += 1;		/* Make nrl-1 pointer to main allocation, in case rows get swaped */
987 
988 	if ((m[nrl-1] = (double *) malloc(rows * cols * sizeof(double))) == NULL) {
989 		if (ret_null_on_malloc_fail)
990 			return NULL;
991 		else
992 			error("Malloc failure in dmatrix(), array");
993 	}
994 
995 	m[nrl] = m[nrl-1] - ncl;		/* Set first row address, offset to ncl */
996 	for(i = nrl+1; i <= nrh; i++)	/* Set subsequent row addresses */
997 		m[i] = m[i-1] + cols;
998 
999 	return m;
1000 }
1001 
dmatrixz(int nrl,int nrh,int ncl,int nch)1002 double **dmatrixz(
1003 int nrl,	/* Row low index */
1004 int nrh,	/* Row high index */
1005 int ncl,	/* Col low index */
1006 int nch		/* Col high index */
1007 ) {
1008 	int i;
1009 	int rows, cols;
1010 	double **m;
1011 
1012 	if (nrh < nrl)	/* Prevent failure for 0 dimension */
1013 		nrh = nrl;
1014 	if (nch < ncl)
1015 		nch = ncl;
1016 
1017 	rows = nrh - nrl + 1;
1018 	cols = nch - ncl + 1;
1019 
1020 	if ((m = (double **) malloc((rows + 1) * sizeof(double *))) == NULL) {
1021 		if (ret_null_on_malloc_fail)
1022 			return NULL;
1023 		else
1024 			error("Malloc failure in dmatrix(), pointers");
1025 	}
1026 	m -= nrl;	/* Offset to nrl */
1027 	m += 1;		/* Make nrl-1 pointer to main allocation, in case rows get swaped */
1028 
1029 	if ((m[nrl-1] = (double *) calloc(rows * cols, sizeof(double))) == NULL) {
1030 		if (ret_null_on_malloc_fail)
1031 			return NULL;
1032 		else
1033 			error("Malloc failure in dmatrix(), array");
1034 	}
1035 
1036 	m[nrl] = m[nrl-1] - ncl;		/* Set first row address, offset to ncl */
1037 	for(i = nrl+1; i <= nrh; i++)	/* Set subsequent row addresses */
1038 		m[i] = m[i-1] + cols;
1039 
1040 	return m;
1041 }
1042 
free_dmatrix(double ** m,int nrl,int nrh,int ncl,int nch)1043 void free_dmatrix(
1044 double **m,
1045 int nrl,
1046 int nrh,
1047 int ncl,
1048 int nch
1049 ) {
1050 	if (m == NULL)
1051 		return;
1052 
1053 	if (nrh < nrl)	/* Prevent failure for 0 dimension */
1054 		nrh = nrl;
1055 	if (nch < ncl)
1056 		nch = ncl;
1057 
1058 	free((char *)(m[nrl-1]));
1059 	free((char *)(m+nrl-1));
1060 }
1061 
1062 /* --------------------- */
1063 /* 2D diagonal half matrix vector malloc/free */
1064 /* A half matrix must have equal rows and columns, */
1065 /* and the column address must always be >= than the row. */
dhmatrix(int nrl,int nrh,int ncl,int nch)1066 double **dhmatrix(
1067 int nrl,	/* Row low index */
1068 int nrh,	/* Row high index */
1069 int ncl,	/* Col low index */
1070 int nch		/* Col high index */
1071 ) {
1072 	int i, j;
1073 	int rows, cols;
1074 	double **m;
1075 
1076 	if (nrh < nrl)	/* Prevent failure for 0 dimension */
1077 		nrh = nrl;
1078 	if (nch < ncl)
1079 		nch = ncl;
1080 
1081 	rows = nrh - nrl + 1;
1082 	cols = nch - ncl + 1;
1083 
1084 	if (rows != cols) {
1085 		if (ret_null_on_malloc_fail)
1086 			return NULL;
1087 		else
1088 			error("dhmatrix() given unequal rows and columns");
1089 	}
1090 
1091 	if ((m = (double **) malloc((rows + 1) * sizeof(double *))) == NULL) {
1092 		if (ret_null_on_malloc_fail)
1093 			return NULL;
1094 		else
1095 			error("Malloc failure in dhmatrix(), pointers");
1096 	}
1097 	m -= nrl;	/* Offset to nrl */
1098 	m += 1;		/* Make nrl-1 pointer to main allocation, in case rows get swaped */
1099 
1100 	if ((m[nrl-1] = (double *) malloc((rows * rows + rows)/2 * sizeof(double))) == NULL) {
1101 		if (ret_null_on_malloc_fail)
1102 			return NULL;
1103 		else
1104 			error("Malloc failure in dhmatrix(), array");
1105 	}
1106 
1107 	m[nrl] = m[nrl-1] - ncl;		/* Set first row address, offset to ncl */
1108 	for(i = nrl+1, j = 1; i <= nrh; i++, j++) /* Set subsequent row addresses */
1109 		m[i] = m[i-1] + j;			/* Start with 1 entry and increment */
1110 
1111 	return m;
1112 }
1113 
dhmatrixz(int nrl,int nrh,int ncl,int nch)1114 double **dhmatrixz(
1115 int nrl,	/* Row low index */
1116 int nrh,	/* Row high index */
1117 int ncl,	/* Col low index */
1118 int nch		/* Col high index */
1119 ) {
1120 	int i, j;
1121 	int rows, cols;
1122 	double **m;
1123 
1124 	if (nrh < nrl)	/* Prevent failure for 0 dimension */
1125 		nrh = nrl;
1126 	if (nch < ncl)
1127 		nch = ncl;
1128 
1129 	rows = nrh - nrl + 1;
1130 	cols = nch - ncl + 1;
1131 
1132 	if (rows != cols) {
1133 		if (ret_null_on_malloc_fail)
1134 			return NULL;
1135 		else
1136 			error("dhmatrix() given unequal rows and columns");
1137 	}
1138 
1139 	if ((m = (double **) malloc((rows + 1) * sizeof(double *))) == NULL) {
1140 		if (ret_null_on_malloc_fail)
1141 			return NULL;
1142 		else
1143 			error("Malloc failure in dhmatrix(), pointers");
1144 	}
1145 	m -= nrl;	/* Offset to nrl */
1146 	m += 1;		/* Make nrl-1 pointer to main allocation, in case rows get swaped */
1147 
1148 	if ((m[nrl-1] = (double *) calloc((rows * rows + rows)/2, sizeof(double))) == NULL) {
1149 		if (ret_null_on_malloc_fail)
1150 			return NULL;
1151 		else
1152 			error("Malloc failure in dhmatrix(), array");
1153 	}
1154 
1155 	m[nrl] = m[nrl-1] - ncl;		/* Set first row address, offset to ncl */
1156 	for(i = nrl+1, j = 1; i <= nrh; i++, j++) /* Set subsequent row addresses */
1157 		m[i] = m[i-1] + j;			/* Start with 1 entry and increment */
1158 
1159 	return m;
1160 }
1161 
free_dhmatrix(double ** m,int nrl,int nrh,int ncl,int nch)1162 void free_dhmatrix(
1163 double **m,
1164 int nrl,
1165 int nrh,
1166 int ncl,
1167 int nch
1168 ) {
1169 	if (m == NULL)
1170 		return;
1171 
1172 	if (nrh < nrl)	/* Prevent failure for 0 dimension */
1173 		nrh = nrl;
1174 	if (nch < ncl)
1175 		nch = ncl;
1176 
1177 	free((char *)(m[nrl-1]));
1178 	free((char *)(m+nrl-1));
1179 }
1180 
1181 /* --------------------- */
1182 /* 2D vector copy */
copy_dmatrix(double ** dst,double ** src,int nrl,int nrh,int ncl,int nch)1183 void copy_dmatrix(
1184 double **dst,
1185 double **src,
1186 int nrl,	/* Row low index */
1187 int nrh,	/* Row high index */
1188 int ncl,	/* Col low index */
1189 int nch		/* Col high index */
1190 ) {
1191 	int i, j;
1192 	for (j = nrl; j <= nrh; j++)
1193 		for (i = ncl; i <= nch; i++)
1194 			dst[j][i] = src[j][i];
1195 }
1196 
1197 /* Copy a matrix to a 3x3 standard C array */
copy_dmatrix_to3x3(double dst[3][3],double ** src,int nrl,int nrh,int ncl,int nch)1198 void copy_dmatrix_to3x3(
1199 double dst[3][3],
1200 double **src,
1201 int nrl,	/* Row low index */
1202 int nrh,	/* Row high index */
1203 int ncl,	/* Col low index */
1204 int nch		/* Col high index */
1205 ) {
1206 	int i, j;
1207 	if ((nrh - nrl) > 2)
1208 		nrh = nrl + 2;
1209 	if ((nch - ncl) > 2)
1210 		nch = ncl + 2;
1211 	for (j = nrl; j <= nrh; j++)
1212 		for (i = ncl; i <= nch; i++)
1213 			dst[j][i] = src[j][i];
1214 }
1215 
1216 /* -------------------------------------------------------------- */
1217 /* Convert standard C type 2D array into an indirect referenced array */
convert_dmatrix(double * a,int nrl,int nrh,int ncl,int nch)1218 double **convert_dmatrix(
1219 double *a,	/* base address of normal C array, ie &a[0][0] */
1220 int nrl,	/* Row low index */
1221 int nrh,	/* Row high index */
1222 int ncl,	/* Col low index */
1223 int nch		/* Col high index */
1224 ) {
1225 	int i, j, nrow = nrh-nrl+1, ncol = nch-ncl+1;
1226 	double **m;
1227 
1228 	/* Allocate pointers to rows */
1229 	if ((m = (double **) malloc(nrow * sizeof(double*))) == NULL) {
1230 		if (ret_null_on_malloc_fail)
1231 			return NULL;
1232 		else
1233 			error("Malloc failure in convert_dmatrix()");
1234 	}
1235 
1236 	m -= nrl;
1237 
1238 	m[nrl] = a - ncl;
1239 	for(i=1, j = nrl+1; i < nrow; i++, j++)
1240 		m[j] = m[j-1] + ncol;
1241 	/* return pointer to array of pointers */
1242 	return m;
1243 }
1244 
1245 /* Free the indirect array reference (but not array) */
free_convert_dmatrix(double ** m,int nrl,int nrh,int ncl,int nch)1246 void free_convert_dmatrix(
1247 double **m,
1248 int nrl,
1249 int nrh,
1250 int ncl,
1251 int nch
1252 ) {
1253 	if (m == NULL)
1254 		return;
1255 
1256 	free((char*) (m+nrl));
1257 }
1258 
1259 /* -------------------------- */
1260 /* Float vector malloc/free */
fvector(int nl,int nh)1261 float *fvector(
1262 int nl,		/* Lowest index */
1263 int nh		/* Highest index */
1264 )	{
1265 	float *v;
1266 
1267 	if ((v = (float *) malloc((nh-nl+1) * sizeof(float))) == NULL) {
1268 		if (ret_null_on_malloc_fail)
1269 			return NULL;
1270 		else
1271 			error("Malloc failure in fvector()");
1272 	}
1273 	return v-nl;
1274 }
1275 
fvectorz(int nl,int nh)1276 float *fvectorz(
1277 int nl,		/* Lowest index */
1278 int nh		/* Highest index */
1279 ) {
1280 	float *v;
1281 
1282 	if ((v = (float *) calloc(nh-nl+1, sizeof(float))) == NULL) {
1283 		if (ret_null_on_malloc_fail)
1284 			return NULL;
1285 		else
1286 			error("Malloc failure in fvector()");
1287 	}
1288 	return v-nl;
1289 }
1290 
free_fvector(float * v,int nl,int nh)1291 void free_fvector(
1292 float *v,
1293 int nl,		/* Lowest index */
1294 int nh		/* Highest index */
1295 ) {
1296 	if (v == NULL)
1297 		return;
1298 
1299 	free((char *) (v+nl));
1300 }
1301 
1302 /* --------------------- */
1303 /* 2D Float matrix malloc/free */
fmatrix(int nrl,int nrh,int ncl,int nch)1304 float **fmatrix(
1305 int nrl,	/* Row low index */
1306 int nrh,	/* Row high index */
1307 int ncl,	/* Col low index */
1308 int nch		/* Col high index */
1309 ) {
1310 	int i;
1311 	int rows, cols;
1312 	float **m;
1313 
1314 	if (nrh < nrl)	/* Prevent failure for 0 dimension */
1315 		nrh = nrl;
1316 	if (nch < ncl)
1317 		nch = ncl;
1318 
1319 	rows = nrh - nrl + 1;
1320 	cols = nch - ncl + 1;
1321 
1322 	if ((m = (float **) malloc((rows + 1) * sizeof(float *))) == NULL) {
1323 		if (ret_null_on_malloc_fail)
1324 			return NULL;
1325 		else
1326 			error("Malloc failure in dmatrix(), pointers");
1327 	}
1328 	m -= nrl;	/* Offset to nrl */
1329 	m += 1;		/* Make nrl-1 pointer to main allocation, in case rows get swaped */
1330 
1331 	if ((m[nrl-1] = (float *) malloc(rows * cols * sizeof(float))) == NULL) {
1332 		if (ret_null_on_malloc_fail)
1333 			return NULL;
1334 		else
1335 			error("Malloc failure in dmatrix(), array");
1336 	}
1337 
1338 	m[nrl] = m[nrl-1] - ncl;		/* Set first row address, offset to ncl */
1339 	for(i = nrl+1; i <= nrh; i++)	/* Set subsequent row addresses */
1340 		m[i] = m[i-1] + cols;
1341 
1342 	return m;
1343 }
1344 
fmatrixz(int nrl,int nrh,int ncl,int nch)1345 float **fmatrixz(
1346 int nrl,	/* Row low index */
1347 int nrh,	/* Row high index */
1348 int ncl,	/* Col low index */
1349 int nch		/* Col high index */
1350 ) {
1351 	int i;
1352 	int rows, cols;
1353 	float **m;
1354 
1355 	if (nrh < nrl)	/* Prevent failure for 0 dimension */
1356 		nrh = nrl;
1357 	if (nch < ncl)
1358 		nch = ncl;
1359 
1360 	rows = nrh - nrl + 1;
1361 	cols = nch - ncl + 1;
1362 
1363 	if ((m = (float **) malloc((rows + 1) * sizeof(float *))) == NULL) {
1364 		if (ret_null_on_malloc_fail)
1365 			return NULL;
1366 		else
1367 			error("Malloc failure in dmatrix(), pointers");
1368 	}
1369 	m -= nrl;	/* Offset to nrl */
1370 	m += 1;		/* Make nrl-1 pointer to main allocation, in case rows get swaped */
1371 
1372 	if ((m[nrl-1] = (float *) calloc(rows * cols, sizeof(float))) == NULL) {
1373 		if (ret_null_on_malloc_fail)
1374 			return NULL;
1375 		else
1376 			error("Malloc failure in dmatrix(), array");
1377 	}
1378 
1379 	m[nrl] = m[nrl-1] - ncl;		/* Set first row address, offset to ncl */
1380 	for(i = nrl+1; i <= nrh; i++)	/* Set subsequent row addresses */
1381 		m[i] = m[i-1] + cols;
1382 
1383 	return m;
1384 }
1385 
free_fmatrix(float ** m,int nrl,int nrh,int ncl,int nch)1386 void free_fmatrix(
1387 float **m,
1388 int nrl,
1389 int nrh,
1390 int ncl,
1391 int nch
1392 ) {
1393 	if (m == NULL)
1394 		return;
1395 
1396 	if (nrh < nrl)	/* Prevent failure for 0 dimension */
1397 		nrh = nrl;
1398 	if (nch < ncl)
1399 		nch = ncl;
1400 
1401 	free((char *)(m[nrl-1]));
1402 	free((char *)(m+nrl-1));
1403 }
1404 
1405 /* ------------------ */
1406 /* Integer vector malloc/free */
ivector(int nl,int nh)1407 int *ivector(
1408 int nl,		/* Lowest index */
1409 int nh		/* Highest index */
1410 ) {
1411 	int *v;
1412 
1413 	if ((v = (int *) malloc((nh-nl+1) * sizeof(int))) == NULL) {
1414 		if (ret_null_on_malloc_fail)
1415 			return NULL;
1416 		else
1417 			error("Malloc failure in ivector()");
1418 	}
1419 	return v-nl;
1420 }
1421 
ivectorz(int nl,int nh)1422 int *ivectorz(
1423 int nl,		/* Lowest index */
1424 int nh		/* Highest index */
1425 ) {
1426 	int *v;
1427 
1428 	if ((v = (int *) calloc(nh-nl+1, sizeof(int))) == NULL) {
1429 		if (ret_null_on_malloc_fail)
1430 			return NULL;
1431 		else
1432 			error("Malloc failure in ivector()");
1433 	}
1434 	return v-nl;
1435 }
1436 
free_ivector(int * v,int nl,int nh)1437 void free_ivector(
1438 int *v,
1439 int nl,		/* Lowest index */
1440 int nh		/* Highest index */
1441 ) {
1442 	if (v == NULL)
1443 		return;
1444 
1445 	free((char *) (v+nl));
1446 }
1447 
1448 
1449 /* ------------------------------ */
1450 /* 2D integer matrix malloc/free */
1451 
imatrix(int nrl,int nrh,int ncl,int nch)1452 int **imatrix(
1453 int nrl,	/* Row low index */
1454 int nrh,	/* Row high index */
1455 int ncl,	/* Col low index */
1456 int nch		/* Col high index */
1457 ) {
1458 	int i;
1459 	int rows, cols;
1460 	int **m;
1461 
1462 	if (nrh < nrl)	/* Prevent failure for 0 dimension */
1463 		nrh = nrl;
1464 	if (nch < ncl)
1465 		nch = ncl;
1466 
1467 	rows = nrh - nrl + 1;
1468 	cols = nch - ncl + 1;
1469 
1470 	if ((m = (int **) malloc((rows + 1) * sizeof(int *))) == NULL) {
1471 		if (ret_null_on_malloc_fail)
1472 			return NULL;
1473 		else
1474 			error("Malloc failure in imatrix(), pointers");
1475 	}
1476 	m -= nrl;	/* Offset to nrl */
1477 	m += 1;		/* Make nrl-1 pointer to main allocation, in case rows get swaped */
1478 
1479 	if ((m[nrl-1] = (int *) malloc(rows * cols * sizeof(int))) == NULL) {
1480 		if (ret_null_on_malloc_fail)
1481 			return NULL;
1482 		else
1483 			error("Malloc failure in imatrix(), array");
1484 	}
1485 
1486 	m[nrl] = m[nrl-1] - ncl;		/* Set first row address, offset to ncl */
1487 	for(i = nrl+1; i <= nrh; i++)	/* Set subsequent row addresses */
1488 		m[i] = m[i-1] + cols;
1489 
1490 	return m;
1491 }
1492 
imatrixz(int nrl,int nrh,int ncl,int nch)1493 int **imatrixz(
1494 int nrl,	/* Row low index */
1495 int nrh,	/* Row high index */
1496 int ncl,	/* Col low index */
1497 int nch		/* Col high index */
1498 ) {
1499 	int i;
1500 	int rows, cols;
1501 	int **m;
1502 
1503 	if (nrh < nrl)	/* Prevent failure for 0 dimension */
1504 		nrh = nrl;
1505 	if (nch < ncl)
1506 		nch = ncl;
1507 
1508 	rows = nrh - nrl + 1;
1509 	cols = nch - ncl + 1;
1510 
1511 	if ((m = (int **) malloc((rows + 1) * sizeof(int *))) == NULL) {
1512 		if (ret_null_on_malloc_fail)
1513 			return NULL;
1514 		else
1515 			error("Malloc failure in imatrix(), pointers");
1516 	}
1517 	m -= nrl;	/* Offset to nrl */
1518 	m += 1;		/* Make nrl-1 pointer to main allocation, in case rows get swaped */
1519 
1520 	if ((m[nrl-1] = (int *) calloc(rows * cols, sizeof(int))) == NULL) {
1521 		if (ret_null_on_malloc_fail)
1522 			return NULL;
1523 		else
1524 			error("Malloc failure in imatrix(), array");
1525 	}
1526 
1527 	m[nrl] = m[nrl-1] - ncl;		/* Set first row address, offset to ncl */
1528 	for(i = nrl+1; i <= nrh; i++)	/* Set subsequent row addresses */
1529 		m[i] = m[i-1] + cols;
1530 
1531 	return m;
1532 }
1533 
free_imatrix(int ** m,int nrl,int nrh,int ncl,int nch)1534 void free_imatrix(
1535 int **m,
1536 int nrl,
1537 int nrh,
1538 int ncl,
1539 int nch
1540 ) {
1541 	if (m == NULL)
1542 		return;
1543 
1544 	if (nrh < nrl)	/* Prevent failure for 0 dimension */
1545 		nrh = nrl;
1546 	if (nch < ncl)
1547 		nch = ncl;
1548 
1549 	free((char *)(m[nrl-1]));
1550 	free((char *)(m+nrl-1));
1551 }
1552 
1553 /* ------------------ */
1554 /* Short vector malloc/free */
svector(int nl,int nh)1555 short *svector(
1556 int nl,		/* Lowest index */
1557 int nh		/* Highest index */
1558 ) {
1559 	short *v;
1560 
1561 	if ((v = (short *) malloc((nh-nl+1) * sizeof(short))) == NULL) {
1562 		if (ret_null_on_malloc_fail)
1563 			return NULL;
1564 		else
1565 			error("Malloc failure in svector()");
1566 	}
1567 	return v-nl;
1568 }
1569 
svectorz(int nl,int nh)1570 short *svectorz(
1571 int nl,		/* Lowest index */
1572 int nh		/* Highest index */
1573 ) {
1574 	short *v;
1575 
1576 	if ((v = (short *) calloc(nh-nl+1, sizeof(short))) == NULL) {
1577 		if (ret_null_on_malloc_fail)
1578 			return NULL;
1579 		else
1580 			error("Malloc failure in svector()");
1581 	}
1582 	return v-nl;
1583 }
1584 
free_svector(short * v,int nl,int nh)1585 void free_svector(
1586 short *v,
1587 int nl,		/* Lowest index */
1588 int nh		/* Highest index */
1589 ) {
1590 	if (v == NULL)
1591 		return;
1592 
1593 	free((char *) (v+nl));
1594 }
1595 
1596 
1597 /* ------------------------------ */
1598 /* 2D short vector malloc/free */
1599 
smatrix(int nrl,int nrh,int ncl,int nch)1600 short **smatrix(
1601 int nrl,	/* Row low index */
1602 int nrh,	/* Row high index */
1603 int ncl,	/* Col low index */
1604 int nch		/* Col high index */
1605 ) {
1606 	int i;
1607 	int rows, cols;
1608 	short **m;
1609 
1610 	if (nrh < nrl)	/* Prevent failure for 0 dimension */
1611 		nrh = nrl;
1612 	if (nch < ncl)
1613 		nch = ncl;
1614 
1615 	rows = nrh - nrl + 1;
1616 	cols = nch - ncl + 1;
1617 
1618 	if ((m = (short **) malloc((rows + 1) * sizeof(short *))) == NULL) {
1619 		if (ret_null_on_malloc_fail)
1620 			return NULL;
1621 		else
1622 			error("Malloc failure in smatrix(), pointers");
1623 	}
1624 	m -= nrl;	/* Offset to nrl */
1625 	m += 1;		/* Make nrl-1 pointer to main allocation, in case rows get swaped */
1626 
1627 	if ((m[nrl-1] = (short *) malloc(rows * cols * sizeof(short))) == NULL) {
1628 		if (ret_null_on_malloc_fail)
1629 			return NULL;
1630 		else
1631 			error("Malloc failure in smatrix(), array");
1632 	}
1633 
1634 	m[nrl] = m[nrl-1] - ncl;		/* Set first row address, offset to ncl */
1635 	for(i = nrl+1; i <= nrh; i++)	/* Set subsequent row addresses */
1636 		m[i] = m[i-1] + cols;
1637 
1638 	return m;
1639 }
1640 
smatrixz(int nrl,int nrh,int ncl,int nch)1641 short **smatrixz(
1642 int nrl,	/* Row low index */
1643 int nrh,	/* Row high index */
1644 int ncl,	/* Col low index */
1645 int nch		/* Col high index */
1646 ) {
1647 	int i;
1648 	int rows, cols;
1649 	short **m;
1650 
1651 	if (nrh < nrl)	/* Prevent failure for 0 dimension */
1652 		nrh = nrl;
1653 	if (nch < ncl)
1654 		nch = ncl;
1655 
1656 	rows = nrh - nrl + 1;
1657 	cols = nch - ncl + 1;
1658 
1659 	if ((m = (short **) malloc((rows + 1) * sizeof(short *))) == NULL) {
1660 		if (ret_null_on_malloc_fail)
1661 			return NULL;
1662 		else
1663 			error("Malloc failure in smatrix(), pointers");
1664 	}
1665 	m -= nrl;	/* Offset to nrl */
1666 	m += 1;		/* Make nrl-1 pointer to main allocation, in case rows get swaped */
1667 
1668 	if ((m[nrl-1] = (short *) calloc(rows * cols, sizeof(short))) == NULL) {
1669 		if (ret_null_on_malloc_fail)
1670 			return NULL;
1671 		else
1672 			error("Malloc failure in smatrix(), array");
1673 	}
1674 
1675 	m[nrl] = m[nrl-1] - ncl;		/* Set first row address, offset to ncl */
1676 	for(i = nrl+1; i <= nrh; i++)	/* Set subsequent row addresses */
1677 		m[i] = m[i-1] + cols;
1678 
1679 	return m;
1680 }
1681 
free_smatrix(short ** m,int nrl,int nrh,int ncl,int nch)1682 void free_smatrix(
1683 short **m,
1684 int nrl,
1685 int nrh,
1686 int ncl,
1687 int nch
1688 ) {
1689 	if (m == NULL)
1690 		return;
1691 
1692 	if (nrh < nrl)	/* Prevent failure for 0 dimension */
1693 		nrh = nrl;
1694 	if (nch < ncl)
1695 		nch = ncl;
1696 
1697 	free((char *)(m[nrl-1]));
1698 	free((char *)(m+nrl-1));
1699 }
1700 
1701 /***************************/
1702 /* Basic matrix operations */
1703 /***************************/
1704 
1705 /* Transpose a 0 base matrix */
matrix_trans(double ** d,double ** s,int nr,int nc)1706 void matrix_trans(double **d, double **s, int nr,  int nc) {
1707 	int i, j;
1708 
1709 	for (i = 0; i < nr; i++) {
1710 		for (j = 0; j < nc; j++) {
1711 			d[j][i] = s[i][j];
1712 		}
1713 	}
1714 }
1715 
1716 /* Multiply two 0 based matricies */
1717 /* Return nz on matching error */
matrix_mult(double ** d,int nr,int nc,double ** s1,int nr1,int nc1,double ** s2,int nr2,int nc2)1718 int matrix_mult(
1719 	double **d,  int nr,  int nc,
1720 	double **s1, int nr1, int nc1,
1721 	double **s2, int nr2, int nc2
1722 ) {
1723 	int i, j, k;
1724 
1725 	/* s1 and s2 must mesh */
1726 	if (nc1 != nr2)
1727 		return 1;
1728 
1729 	/* Output rows = s1 rows */
1730 	if (nr != nr1)
1731 		return 2;
1732 
1733 	/* Output colums = s2 columns */
1734 	if (nc != nc2)
1735 		return 2;
1736 
1737 	for (i = 0; i < nr1; i++) {
1738 		for (j = 0; j < nc2; j++) {
1739 			d[i][j] = 0.0;
1740 			for (k = 0; k < nc1; k++) {
1741 				d[i][j] += s1[i][k] * s2[k][j];
1742 			}
1743 		}
1744 	}
1745 
1746 	return 0;
1747 }
1748 
1749 /* Diagnostic - print to g_log debug */
matrix_print(char * c,double ** a,int nr,int nc)1750 void matrix_print(char *c, double **a, int nr,  int nc) {
1751 	int i, j;
1752 	a1logd(g_log, 0, "%s, %d x %d\n",c,nr,nc);
1753 
1754 	for (j = 0; j < nr; j++) {
1755 		a1logd(g_log, 0, " ");
1756 		for (i = 0; i < nc; i++) {
1757 			a1logd(g_log, 0, " %.2f",a[j][i]);
1758 		}
1759 		a1logd(g_log, 0, "\n");
1760 	}
1761 }
1762 
1763 
1764 /*******************************************/
1765 /* Platform independent IEE754 conversions */
1766 /*******************************************/
1767 
1768 /* Convert a native double to an IEEE754 encoded single precision value, */
1769 /* in a platform independent fashion. (ie. This works even */
1770 /* on the rare platforms that don't use IEEE 754 floating */
1771 /* point for their C implementation) */
doubletoIEEE754(double d)1772 ORD32 doubletoIEEE754(double d) {
1773 	ORD32 sn = 0, ep = 0, ma;
1774 	ORD32 id;
1775 
1776 	/* Convert double to IEEE754 single precision. */
1777 	/* This would be easy if we're running on an IEEE754 architecture, */
1778 	/* but isn't generally portable, so we use ugly code: */
1779 
1780 	if (d < 0.0) {
1781 		sn = 1;
1782 		d = -d;
1783 	}
1784 	if (d != 0.0) {
1785 		int ee;
1786 		ee = (int)floor(log(d)/log(2.0));
1787 		if (ee < -126)			/* Allow for denormalized */
1788 			ee = -126;
1789 		d *= pow(0.5, (double)(ee - 23));
1790 		ee += 127;
1791 		if (ee < 1)				/* Too small */
1792 			ee = 0;				/* Zero or denormalised */
1793 		else if (ee > 254) {	/* Too large */
1794 			ee = 255;			/* Infinity */
1795 			d = 0.0;
1796 		}
1797 		ep = ee;
1798 	} else {
1799 		ep = 0;					/* Zero */
1800 	}
1801 	ma = ((ORD32)d) & ((1 << 23)-1);
1802 	id = (sn << 31) | (ep << 23) | ma;
1803 
1804 	return id;
1805 }
1806 
1807 /* Convert a an IEEE754 encoded single precision value to a native double, */
1808 /* in a platform independent fashion. (ie. This works even */
1809 /* on the rare platforms that don't use IEEE 754 floating */
1810 /* point for their C implementation) */
IEEE754todouble(ORD32 ip)1811 double IEEE754todouble(ORD32 ip) {
1812 	double op;
1813 	ORD32 sn = 0, ep = 0, ma;
1814 
1815 	sn = (ip >> 31) & 0x1;
1816 	ep = (ip >> 23) & 0xff;
1817 	ma = ip & 0x7fffff;
1818 
1819 	if (ep == 0) { 		/* Zero or denormalised */
1820 		op = (double)ma/(double)(1 << 23);
1821 		op *= pow(2.0, (-126.0));
1822 	} else {
1823 		op = (double)(ma | (1 << 23))/(double)(1 << 23);
1824 		op *= pow(2.0, (((int)ep)-127.0));
1825 	}
1826 	if (sn)
1827 		op = -op;
1828 	return op;
1829 }
1830 
1831 /* Convert a native double to an IEEE754 encoded double precision value, */
1832 /* in a platform independent fashion. (ie. This works even */
1833 /* on the rare platforms that don't use IEEE 754 floating */
1834 /* point for their C implementation) */
doubletoIEEE754_64(double d)1835 ORD64 doubletoIEEE754_64(double d) {
1836 	ORD32 sn = 0, ep = 0;
1837 	ORD64 ma, id;
1838 
1839 	/* Convert double to IEEE754 double precision. */
1840 	/* This would be easy if we know we're running on an IEEE754 architecture, */
1841 	/* but isn't generally portable, so we use ugly code: */
1842 
1843 	if (d < 0.0) {
1844 		sn = 1;
1845 		d = -d;
1846 	}
1847 	if (d != 0.0) {
1848 		int ee;
1849 		ee = (int)floor(log(d)/log(2.0));
1850 		if (ee < -1022)			/* Allow for denormalized */
1851 			ee = -1022;
1852 		d *= pow(0.5, (double)(ee - 52));
1853 		ee += 1023;				/* Exponent bias */
1854 		if (ee < 1)				/* Too small */
1855 			ee = 0;				/* Zero or denormalised */
1856 		else if (ee > 2046) {	/* Too large */
1857 			ee = 2047;			/* Infinity */
1858 			d = 0.0;
1859 		}
1860 		ep = ee;
1861 	} else {
1862 		ep = 0;					/* Zero */
1863 	}
1864 	ma = ((ORD64)d) & (((ORD64)1 << 52)-1);
1865 	id = ((ORD64)sn << 63) | ((ORD64)ep << 52) | ma;
1866 
1867 	return id;
1868 }
1869 
1870 /* Convert a an IEEE754 encode double precision value to a native double, */
1871 /* in a platform independent fashion. (ie. This works even */
1872 /* on the rare platforms that don't use IEEE 754 floating */
1873 /* point for their C implementation) */
IEEE754_64todouble(ORD64 ip)1874 double IEEE754_64todouble(ORD64 ip) {
1875 	double op;
1876 	ORD32 sn = 0, ep = 0;
1877 	INR64 ma;
1878 
1879 	sn = (ip >> 63) & 0x1;
1880 	ep = (ip >> 52) & 0x7ff;
1881 	ma = ip & (((INR64)1 << 52)-1);
1882 
1883 	if (ep == 0) { 		/* Zero or denormalised */
1884 		op = (double)ma/(double)((INR64)1 << 52);
1885 		op *= pow(2.0, -1022.0);
1886 	} else {
1887 		op = (double)(ma | ((INR64)1 << 52))/(double)((INR64)1 << 52);
1888 		op *= pow(2.0, (((int)ep)-1023.0));
1889 	}
1890 	if (sn)
1891 		op = -op;
1892 	return op;
1893 }
1894 
1895 /* Return a string representation of a 32 bit ctime. */
1896 /* A static buffer is used. There is no \n at the end */
ctime_32(const INR32 * timer)1897 char *ctime_32(const INR32 *timer) {
1898 	char *rv;
1899 #if defined(_MSC_VER) && __MSVCRT_VERSION__ >= 0x0601
1900 	rv = _ctime32((const __time32_t *)timer);
1901 #else
1902 	time_t timerv = (time_t) *timer;		/* May case to 64 bit */
1903 	rv = ctime(&timerv);
1904 #endif
1905 
1906 	if (rv != NULL)
1907 		rv[strlen(rv)-1] = '\000';
1908 
1909 	return rv;
1910 }
1911 
1912 /* Return a string representation of a 64 bit ctime. */
1913 /* A static buffer is used. There is no \n at the end */
ctime_64(const INR64 * timer)1914 char *ctime_64(const INR64 *timer) {
1915 	char *rv;
1916 #if defined(_MSC_VER) && __MSVCRT_VERSION__ >= 0x0601
1917 	rv = _ctime64((const __time64_t *)timer);
1918 #else
1919 	time_t timerv;
1920 
1921 	if (sizeof(time_t) == 4 && *timer > 0x7fffffff)
1922 		return NULL;
1923 	timerv = (time_t) *timer;			/* May truncate to 32 bits */
1924 	rv = ctime(&timerv);
1925 #endif
1926 
1927 	if (rv != NULL)
1928 		rv[strlen(rv)-1] = '\000';
1929 
1930 	return rv;
1931 }
1932 
1933 /*******************************************/
1934 /* Native to/from byte buffer functions    */
1935 /*******************************************/
1936 
1937 /* No overflow detection is done - */
1938 /* numbers are clipped or truncated. */
1939 
1940 /* be = Big Endian */
1941 /* le = Little Endian */
1942 
1943 /* - - - - - - - - */
1944 /* Unsigned 8 bit */
1945 
read_ORD8(ORD8 * p)1946 unsigned int read_ORD8(ORD8 *p) {
1947 	unsigned int rv;
1948 	rv = ((unsigned int)p[0]);
1949 	return rv;
1950 }
1951 
write_ORD8(ORD8 * p,unsigned int d)1952 void write_ORD8(ORD8 *p, unsigned int d) {
1953 	if (d > 0xff)
1954 		d = 0xff;
1955 	p[0] = (ORD8)(d);
1956 }
1957 
1958 /* - - - - - - - - */
1959 /* Signed 8 bit */
1960 
read_INR8(ORD8 * p)1961 int read_INR8(ORD8 *p) {
1962 	int rv;
1963 	rv = (int)(INR8)p[0];
1964 	return rv;
1965 }
1966 
write_INR8(ORD8 * p,int d)1967 void write_INR8(ORD8 *p, int d) {
1968 	if (d > 0x7f)
1969 		d = 0x7f;
1970 	else if (d < -0x80)
1971 		d = -0x80;
1972 	p[0] = (ORD8)(d);
1973 }
1974 
1975 /* - - - - - - - - */
1976 /* Unsigned 16 bit */
1977 
read_ORD16_be(ORD8 * p)1978 unsigned int read_ORD16_be(ORD8 *p) {
1979 	unsigned int rv;
1980 	rv = (((unsigned int)p[0]) << 8)
1981 	   + (((unsigned int)p[1]));
1982 	return rv;
1983 }
1984 
read_ORD16_le(ORD8 * p)1985 unsigned int read_ORD16_le(ORD8 *p) {
1986 	unsigned int rv;
1987 	rv = (((unsigned int)p[0]))
1988 	   + (((unsigned int)p[1]) << 8);
1989 	return rv;
1990 }
1991 
write_ORD16_be(ORD8 * p,unsigned int d)1992 void write_ORD16_be(ORD8 *p, unsigned int d) {
1993 	if (d > 0xffff)
1994 		d = 0xffff;
1995 	p[0] = (ORD8)(d >> 8);
1996 	p[1] = (ORD8)(d);
1997 }
1998 
write_ORD16_le(ORD8 * p,unsigned int d)1999 void write_ORD16_le(ORD8 *p, unsigned int d) {
2000 	if (d > 0xffff)
2001 		d = 0xffff;
2002 	p[0] = (ORD8)(d);
2003 	p[1] = (ORD8)(d >> 8);
2004 }
2005 
2006 /* - - - - - - - - */
2007 /* Signed 16 bit */
2008 
read_INR16_be(ORD8 * p)2009 int read_INR16_be(ORD8 *p) {
2010 	int rv;
2011 	rv = (((int)(INR8)p[0]) << 8)
2012 	   + (((int)p[1]));
2013 	return rv;
2014 }
2015 
read_INR16_le(ORD8 * p)2016 int read_INR16_le(ORD8 *p) {
2017 	int rv;
2018 	rv = (((int)p[0]))
2019 	   + (((int)(INR8)p[1]) << 8);
2020 	return rv;
2021 }
2022 
write_INR16_be(ORD8 * p,int d)2023 void write_INR16_be(ORD8 *p, int d) {
2024 	if (d > 0x7fff)
2025 		d = 0x7fff;
2026 	else if (d < -0x8000)
2027 		d = -0x8000;
2028 	p[0] = (ORD8)(d >> 8);
2029 	p[1] = (ORD8)(d);
2030 }
2031 
write_INR16_le(ORD8 * p,int d)2032 void write_INR16_le(ORD8 *p, int d) {
2033 	if (d > 0x7fff)
2034 		d = 0x7fff;
2035 	else if (d < -0x8000)
2036 		d = -0x8000;
2037 	p[0] = (ORD8)(d);
2038 	p[1] = (ORD8)(d >> 8);
2039 }
2040 
2041 /* - - - - - - - - */
2042 /* Unsigned 32 bit */
2043 
read_ORD32_be(ORD8 * p)2044 unsigned int read_ORD32_be(ORD8 *p) {
2045 	unsigned int rv;
2046 	rv = (((unsigned int)p[0]) << 24)
2047 	   + (((unsigned int)p[1]) << 16)
2048 	   + (((unsigned int)p[2]) << 8)
2049 	   + (((unsigned int)p[3]));
2050 	return rv;
2051 }
2052 
read_ORD32_le(ORD8 * p)2053 unsigned int read_ORD32_le(ORD8 *p) {
2054 	unsigned int rv;
2055 	rv = (((unsigned int)p[0]))
2056 	   + (((unsigned int)p[1]) << 8)
2057 	   + (((unsigned int)p[2]) << 16)
2058 	   + (((unsigned int)p[3]) << 24);
2059 	return rv;
2060 }
2061 
write_ORD32_be(ORD8 * p,unsigned int d)2062 void write_ORD32_be(ORD8 *p, unsigned int d) {
2063 	p[0] = (ORD8)(d >> 24);
2064 	p[1] = (ORD8)(d >> 16);
2065 	p[2] = (ORD8)(d >> 8);
2066 	p[3] = (ORD8)(d);
2067 }
2068 
write_ORD32_le(ORD8 * p,unsigned int d)2069 void write_ORD32_le(ORD8 *p, unsigned int d) {
2070 	p[0] = (ORD8)(d);
2071 	p[1] = (ORD8)(d >> 8);
2072 	p[2] = (ORD8)(d >> 16);
2073 	p[3] = (ORD8)(d >> 24);
2074 }
2075 
2076 /* - - - - - - - - */
2077 /* Signed 32 bit */
2078 
read_INR32_be(ORD8 * p)2079 int read_INR32_be(ORD8 *p) {
2080 	int rv;
2081 	rv = (((int)(INR8)p[0]) << 24)
2082 	   + (((int)p[1]) << 16)
2083 	   + (((int)p[2]) << 8)
2084 	   + (((int)p[3]));
2085 	return rv;
2086 }
2087 
read_INR32_le(ORD8 * p)2088 int read_INR32_le(ORD8 *p) {
2089 	int rv;
2090 	rv = (((int)p[0]))
2091 	   + (((int)p[1]) << 8)
2092 	   + (((int)p[2]) << 16)
2093 	   + (((int)(INR8)p[3]) << 24);
2094 	return rv;
2095 }
2096 
write_INR32_be(ORD8 * p,int d)2097 void write_INR32_be(ORD8 *p, int d) {
2098 	p[0] = (ORD8)(d >> 24);
2099 	p[1] = (ORD8)(d >> 16);
2100 	p[2] = (ORD8)(d >> 8);
2101 	p[3] = (ORD8)(d);
2102 }
2103 
write_INR32_le(ORD8 * p,int d)2104 void write_INR32_le(ORD8 *p, int d) {
2105 	p[0] = (ORD8)(d);
2106 	p[1] = (ORD8)(d >> 8);
2107 	p[2] = (ORD8)(d >> 16);
2108 	p[3] = (ORD8)(d >> 24);
2109 }
2110 
2111 /* - - - - - - - - */
2112 /* Unsigned 64 bit */
2113 
read_ORD64_be(ORD8 * p)2114 ORD64 read_ORD64_be(ORD8 *p) {
2115 	ORD64 rv;
2116 	rv = (((ORD64)p[0]) << 56)
2117 	   + (((ORD64)p[1]) << 48)
2118 	   + (((ORD64)p[2]) << 40)
2119 	   + (((ORD64)p[3]) << 32)
2120 	   + (((ORD64)p[4]) << 24)
2121 	   + (((ORD64)p[5]) << 16)
2122 	   + (((ORD64)p[6]) << 8)
2123 	   + (((ORD64)p[7]));
2124 	return rv;
2125 }
2126 
read_ORD64_le(ORD8 * p)2127 ORD64 read_ORD64_le(ORD8 *p) {
2128 	ORD64 rv;
2129 	rv = (((ORD64)p[0]))
2130 	   + (((ORD64)p[1]) << 8)
2131 	   + (((ORD64)p[2]) << 16)
2132 	   + (((ORD64)p[3]) << 24)
2133 	   + (((ORD64)p[4]) << 32)
2134 	   + (((ORD64)p[5]) << 40)
2135 	   + (((ORD64)p[6]) << 48)
2136 	   + (((ORD64)p[7]) << 56);
2137 	return rv;
2138 }
2139 
write_ORD64_be(ORD8 * p,ORD64 d)2140 void write_ORD64_be(ORD8 *p, ORD64 d) {
2141 	p[0] = (ORD8)(d >> 56);
2142 	p[1] = (ORD8)(d >> 48);
2143 	p[2] = (ORD8)(d >> 40);
2144 	p[3] = (ORD8)(d >> 32);
2145 	p[4] = (ORD8)(d >> 24);
2146 	p[5] = (ORD8)(d >> 16);
2147 	p[6] = (ORD8)(d >> 8);
2148 	p[7] = (ORD8)(d);
2149 }
2150 
write_ORD64_le(ORD8 * p,ORD64 d)2151 void write_ORD64_le(ORD8 *p, ORD64 d) {
2152 	p[0] = (ORD8)(d);
2153 	p[1] = (ORD8)(d >> 8);
2154 	p[2] = (ORD8)(d >> 16);
2155 	p[3] = (ORD8)(d >> 24);
2156 	p[4] = (ORD8)(d >> 32);
2157 	p[5] = (ORD8)(d >> 40);
2158 	p[6] = (ORD8)(d >> 48);
2159 	p[7] = (ORD8)(d >> 56);
2160 }
2161 
2162 /* - - - - - - - - */
2163 /* Signed 64 bit */
2164 
read_INR64_be(ORD8 * p)2165 INR64 read_INR64_be(ORD8 *p) {
2166 	INR64 rv;
2167 	rv = (((INR64)(INR8)p[0]) << 56)
2168 	   + (((INR64)p[1]) << 48)
2169 	   + (((INR64)p[2]) << 40)
2170 	   + (((INR64)p[3]) << 32)
2171 	   + (((INR64)p[4]) << 24)
2172 	   + (((INR64)p[5]) << 16)
2173 	   + (((INR64)p[6]) << 8)
2174 	   + (((INR64)p[7]));
2175 	return rv;
2176 }
2177 
read_INR64_le(ORD8 * p)2178 INR64 read_INR64_le(ORD8 *p) {
2179 	INR64 rv;
2180 	rv = (((INR64)p[0]))
2181 	   + (((INR64)p[1]) << 8)
2182 	   + (((INR64)p[2]) << 16)
2183 	   + (((INR64)p[3]) << 24)
2184 	   + (((INR64)p[4]) << 32)
2185 	   + (((INR64)p[5]) << 40)
2186 	   + (((INR64)p[6]) << 48)
2187 	   + (((INR64)(INR8)p[7]) << 56);
2188 	return rv;
2189 }
2190 
write_INR64_be(ORD8 * p,INR64 d)2191 void write_INR64_be(ORD8 *p, INR64 d) {
2192 	p[0] = (ORD8)(d >> 56);
2193 	p[1] = (ORD8)(d >> 48);
2194 	p[2] = (ORD8)(d >> 40);
2195 	p[3] = (ORD8)(d >> 32);
2196 	p[4] = (ORD8)(d >> 24);
2197 	p[5] = (ORD8)(d >> 16);
2198 	p[6] = (ORD8)(d >> 8);
2199 	p[7] = (ORD8)(d);
2200 }
2201 
write_INR64_le(ORD8 * p,INR64 d)2202 void write_INR64_le(ORD8 *p, INR64 d) {
2203 	p[0] = (ORD8)(d);
2204 	p[1] = (ORD8)(d >> 8);
2205 	p[2] = (ORD8)(d >> 16);
2206 	p[3] = (ORD8)(d >> 24);
2207 	p[4] = (ORD8)(d >> 32);
2208 	p[5] = (ORD8)(d >> 40);
2209 	p[6] = (ORD8)(d >> 48);
2210 	p[7] = (ORD8)(d >> 56);
2211 }
2212 
2213 /*******************************/
2214 /* System independent timing */
2215 
2216 #ifdef NT
2217 
2218 /* Sleep for the given number of msec */
msec_sleep(unsigned int msec)2219 void msec_sleep(unsigned int msec) {
2220 	Sleep(msec);
2221 }
2222 
2223 /* Return the current time in msec since */
2224 /* the first invokation of msec_time() */
2225 /* (Is this based on timeGetTime() ? ) */
msec_time()2226 unsigned int msec_time() {
2227 	unsigned int rv;
2228 	static unsigned int startup = 0;
2229 
2230 	rv =  GetTickCount();
2231 	if (startup == 0)
2232 		startup = rv;
2233 
2234 	return rv - startup;
2235 }
2236 
2237 /* Return the current time in usec */
2238 /* since the first invokation of usec_time() */
2239 /* Return -1.0 if not available */
usec_time()2240 double usec_time() {
2241 	double rv;
2242 	LARGE_INTEGER val;
2243 	static double scale = 0.0;
2244 	static LARGE_INTEGER startup;
2245 
2246 	if (scale == 0.0) {
2247 		if (QueryPerformanceFrequency(&val) == 0)
2248 			return -1.0;
2249 		scale = 1000000.0/val.QuadPart;
2250 		QueryPerformanceCounter(&val);
2251 		startup.QuadPart = val.QuadPart;
2252 
2253 	} else {
2254 		QueryPerformanceCounter(&val);
2255 	}
2256 	val.QuadPart -= startup.QuadPart;
2257 
2258 	rv = val.QuadPart * scale;
2259 
2260 	return rv;
2261 }
2262 
2263 #endif /* NT */
2264 
2265 #if defined(UNIX)
2266 
2267 /* Sleep for the given number of msec */
2268 /* (Note that OS X 10.9+ App Nap can wreck this, unless */
2269 /*  it is turned off.) */
msec_sleep(unsigned int msec)2270 void msec_sleep(unsigned int msec) {
2271 #ifdef NEVER
2272 	if (msec > 1000) {
2273 		unsigned int secs;
2274 		secs = msec / 1000;
2275 		msec = msec % 1000;
2276 		sleep(secs);
2277 	}
2278 	usleep(msec * 1000);
2279 #else
2280 	struct timespec ts;
2281 
2282 	ts.tv_sec = msec / 1000;
2283 	ts.tv_nsec = (msec % 1000) * 1000000;
2284 	nanosleep(&ts, NULL);
2285 #endif
2286 }
2287 
2288 
2289 #if defined(__APPLE__) && !defined(CLOCK_MONOTONIC)
2290 
2291 #include <mach/mach_time.h>
2292 
msec_time()2293 unsigned int msec_time() {
2294     mach_timebase_info_data_t timebase;
2295     static uint64_t startup = 0;
2296     uint64_t time;
2297 	double msec;
2298 
2299     time = mach_absolute_time();
2300 	if (startup == 0)
2301 		startup = time;
2302 
2303     mach_timebase_info(&timebase);
2304 	time -= startup;
2305     msec = ((double)time * (double)timebase.numer)/((double)timebase.denom * 1e6);
2306 
2307     return (unsigned int)floor(msec + 0.5);
2308 }
2309 
2310 /* Return the current time in usec */
2311 /* since the first invokation of usec_time() */
usec_time()2312 double usec_time() {
2313     mach_timebase_info_data_t timebase;
2314     static uint64_t startup = 0;
2315     uint64_t time;
2316 	double usec;
2317 
2318     time = mach_absolute_time();
2319 	if (startup == 0)
2320 		startup = time;
2321 
2322     mach_timebase_info(&timebase);
2323 	time -= startup;
2324     usec = ((double)time * (double)timebase.numer)/((double)timebase.denom * 1e3);
2325 
2326     return usec;
2327 }
2328 
2329 #else
2330 
2331 /* Return the current time in msec */
2332 /* since the first invokation of msec_time() */
msec_time()2333 unsigned int msec_time() {
2334 	unsigned int rv;
2335 	static struct timespec startup = { 0, 0 };
2336 	struct timespec cv;
2337 
2338 	clock_gettime(CLOCK_MONOTONIC, &cv);
2339 
2340 	/* Set time to 0 on first invocation */
2341 	if (startup.tv_sec == 0 && startup.tv_nsec == 0)
2342 		startup = cv;
2343 
2344 	/* Subtract, taking care of carry */
2345 	cv.tv_sec -= startup.tv_sec;
2346 	if (startup.tv_nsec > cv.tv_nsec) {
2347 		cv.tv_sec--;
2348 		cv.tv_nsec += 1000000000;
2349 	}
2350 	cv.tv_nsec -= startup.tv_nsec;
2351 
2352 	/* Convert nsec to msec */
2353 	rv = cv.tv_sec * 1000 + cv.tv_nsec / 1000000;
2354 
2355 	return rv;
2356 }
2357 
2358 /* Return the current time in usec */
2359 /* since the first invokation of usec_time() */
usec_time()2360 double usec_time() {
2361 	double rv;
2362 	static struct timespec startup = { 0, 0 };
2363 	struct timespec cv;
2364 
2365 	clock_gettime(CLOCK_MONOTONIC, &cv);
2366 
2367 	/* Set time to 0 on first invocation */
2368 	if (startup.tv_sec == 0 && startup.tv_nsec == 0)
2369 		startup = cv;
2370 
2371 	/* Subtract, taking care of carry */
2372 	cv.tv_sec -= startup.tv_sec;
2373 	if (startup.tv_nsec > cv.tv_nsec) {
2374 		cv.tv_sec--;
2375 		cv.tv_nsec += 1000000000;
2376 	}
2377 	cv.tv_nsec -= startup.tv_nsec;
2378 
2379 	/* Convert to usec */
2380 	rv = cv.tv_sec * 1000000.0 + cv.tv_nsec/1000;
2381 
2382 	return rv;
2383 }
2384 
2385 #endif
2386 
2387 #endif /* UNIX */
2388 
2389 /*******************************/
2390 /* Debug convenience functions */
2391 /*******************************/
2392 
2393 #define DEB_MAX_CHAN 15
2394 
2395 /* Print an int vector to a string. */
2396 /* Returned static buffer is re-used every 5 calls. */
debPiv(int di,int * p)2397 char *debPiv(int di, int *p) {
2398 	static char buf[5][DEB_MAX_CHAN * 16];
2399 	static int ix = 0;
2400 	int e;
2401 	char *bp;
2402 
2403 	if (++ix >= 5)
2404 		ix = 0;
2405 	bp = buf[ix];
2406 
2407 	if (di > DEB_MAX_CHAN)
2408 		di = DEB_MAX_CHAN;		/* Make sure that buf isn't overrun */
2409 
2410 	for (e = 0; e < di; e++) {
2411 		if (e > 0)
2412 			*bp++ = ' ';
2413 		sprintf(bp, "%d", p[e]); bp += strlen(bp);
2414 	}
2415 	return buf[ix];
2416 }
2417 
2418 /* Print a double color vector to a string. */
2419 /* Returned static buffer is re-used every 5 calls. */
debPdv(int di,double * p)2420 char *debPdv(int di, double *p) {
2421 	static char buf[5][DEB_MAX_CHAN * 16];
2422 	static int ix = 0;
2423 	int e;
2424 	char *bp;
2425 
2426 	if (++ix >= 5)
2427 		ix = 0;
2428 	bp = buf[ix];
2429 
2430 	if (di > DEB_MAX_CHAN)
2431 		di = DEB_MAX_CHAN;		/* Make sure that buf isn't overrun */
2432 
2433 	for (e = 0; e < di; e++) {
2434 		if (e > 0)
2435 			*bp++ = ' ';
2436 		sprintf(bp, "%.8f", p[e]); bp += strlen(bp);
2437 	}
2438 	return buf[ix];
2439 }
2440 
2441 /* Print a float color vector to a string. */
2442 /* Returned static buffer is re-used every 5 calls. */
debPfv(int di,float * p)2443 char *debPfv(int di, float *p) {
2444 	static char buf[5][DEB_MAX_CHAN * 16];
2445 	static int ix = 0;
2446 	int e;
2447 	char *bp;
2448 
2449 	if (++ix >= 5)
2450 		ix = 0;
2451 	bp = buf[ix];
2452 
2453 	if (di > DEB_MAX_CHAN)
2454 		di = DEB_MAX_CHAN;		/* Make sure that buf isn't overrun */
2455 
2456 	for (e = 0; e < di; e++) {
2457 		if (e > 0)
2458 			*bp++ = ' ';
2459 		sprintf(bp, "%.8f", p[e]); bp += strlen(bp);
2460 	}
2461 	return buf[ix];
2462 }
2463 
2464 #undef DEB_MAX_CHAN
2465