From e21c7a116e2e26158f5a79ab35f3ac0ec94280ce Mon Sep 17 00:00:00 2001 From: Anders Lindh Olsson <anders.lindholsson@ess.eu> Date: Thu, 2 Dec 2021 17:43:42 +0100 Subject: [PATCH] Apply pre-commit --- require-ess/src/asprintf.c | 56 +- require-ess/src/asprintf.h | 6 +- require-ess/src/dbLoadTemplate.h | 4 +- require-ess/src/expr.c | 816 +++++----- require-ess/src/expr.h | 17 +- require-ess/src/require.c | 2443 +++++++++++++++--------------- require-ess/src/require.h | 19 +- require-ess/src/runScript.c | 541 +++---- require-ess/src/strdup.c | 32 +- require-ess/src/version.c | 100 +- require-ess/src/version.h | 12 +- 11 files changed, 2044 insertions(+), 2002 deletions(-) diff --git a/require-ess/src/asprintf.c b/require-ess/src/asprintf.c index 68495340..7290e021 100644 --- a/require-ess/src/asprintf.c +++ b/require-ess/src/asprintf.c @@ -1,52 +1,50 @@ +#include "asprintf.h" +#include <stdarg.h> #include <stdio.h> #include <stdlib.h> -#include <stdarg.h> -#include "asprintf.h" /* some implementations have __va_copy instead of va_copy */ -#if !defined(va_copy) && defined (__va_copy) +#if !defined(va_copy) && defined(__va_copy) #define va_copy __va_copy #endif -int vasprintf(char** pbuffer, const char* format, va_list ap) -{ - int len = -1; +int vasprintf(char **pbuffer, const char *format, va_list ap) { + int len = -1; #ifdef va_copy - va_list ap2; - va_copy(ap2, ap); + va_list ap2; + va_copy(ap2, ap); #else - /* if we have no va_copy, we probably don't need one */ - #define ap2 ap +/* if we have no va_copy, we probably don't need one */ +#define ap2 ap #endif #if defined(_WIN32) - len = _vscprintf(format, ap2); + len = _vscprintf(format, ap2); #else - len = vsnprintf(NULL, 0, format, ap2); + len = vsnprintf(NULL, 0, format, ap2); #endif #ifdef va_copy - va_end(ap2); + va_end(ap2); #endif - if (len <= 0) - { - fprintf(stderr, "vasprintf: error calculating needed size\n"); - return -1; - } - *pbuffer = malloc(len+1); - if (*pbuffer == NULL) return -1; - return vsprintf(*pbuffer, format, ap); + if (len <= 0) { + fprintf(stderr, "vasprintf: error calculating needed size\n"); + return -1; + } + *pbuffer = malloc(len + 1); + if (*pbuffer == NULL) + return -1; + return vsprintf(*pbuffer, format, ap); } -int asprintf(char** pbuffer, const char* format, ...) -{ - va_list ap; - int len; +int asprintf(char **pbuffer, const char *format, ...) { + va_list ap; + int len; - va_start(ap, format); - len = vasprintf(pbuffer, format, ap); - va_end(ap); - return len; + va_start(ap, format); + len = vasprintf(pbuffer, format, ap); + va_end(ap); + return len; } diff --git a/require-ess/src/asprintf.h b/require-ess/src/asprintf.h index d28f3544..d2e232e1 100644 --- a/require-ess/src/asprintf.h +++ b/require-ess/src/asprintf.h @@ -8,8 +8,10 @@ extern "C" { #define __attribute__(arg) #endif -int asprintf(char** pbuffer, const char* format, ...) __attribute__((__format__(__printf__,2,3))); -int vasprintf(char** pbuffer, const char* format, va_list ap) __attribute__((__format__(__printf__,2,0))); +int asprintf(char **pbuffer, const char *format, ...) + __attribute__((__format__(__printf__, 2, 3))); +int vasprintf(char **pbuffer, const char *format, va_list ap) + __attribute__((__format__(__printf__, 2, 0))); #ifdef __cplusplus } #endif diff --git a/require-ess/src/dbLoadTemplate.h b/require-ess/src/dbLoadTemplate.h index 509047b8..1894a929 100644 --- a/require-ess/src/dbLoadTemplate.h +++ b/require-ess/src/dbLoadTemplate.h @@ -12,7 +12,7 @@ #define INCdbLoadTemplateh #include "shareLib.h" -epicsShareFunc int dbLoadTemplate( - const char *sub_file, const char *cmd_collect, const char *path); +epicsShareFunc int dbLoadTemplate(const char *sub_file, const char *cmd_collect, + const char *path); #endif /*INCdbLoadTemplateh*/ diff --git a/require-ess/src/expr.c b/require-ess/src/expr.c index 9c8ac42d..9ec91aa3 100644 --- a/require-ess/src/expr.c +++ b/require-ess/src/expr.c @@ -1,7 +1,7 @@ #include <ctype.h> -#include <string.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> #include "expr.h" @@ -9,419 +9,495 @@ int exprDebug; static int parseSubExpr(const char **pp, long *v, int pr, int op); static long parseString(const char **pp, const char **pstart); -#define parseExpr(pp,v) parseSubExpr(pp, v, 0, 0) -#define skipSpace(p) while (isspace((unsigned char)*p)) p++ +#define parseExpr(pp, v) parseSubExpr(pp, v, 0, 0) +#define skipSpace(p) \ + while (isspace((unsigned char)*p)) \ + p++ -static int parseValue(const char **pp, long *v) -{ - long val; - const char *p = *pp; - char o; +static int parseValue(const char **pp, long *v) { + long val; + const char *p = *pp; + char o; - /* A value is optionally prefixed with an unary operator + - ! ~. - * It is either a number (decimal, octal or hex) - * or an expression in (). - * Allowed chars after a number: operators, closing parenthesis, whitespace, quotes, end of string - */ + /* A value is optionally prefixed with an unary operator + - ! ~. + * It is either a number (decimal, octal or hex) + * or an expression in (). + * Allowed chars after a number: operators, closing parenthesis, whitespace, + * quotes, end of string + */ - /* first look for value */ + /* first look for value */ + skipSpace(p); + o = *p; + if (memchr("+-~!", o, 4)) { + /* unary operators */ + p++; + if (!parseValue(&p, &val)) + return 0; /* no valid value */ + if (exprDebug) + printf("parseValue: %c %ld\n", o, val); + if (o == '-') + val = -val; + else if (o == '~') + val = ~val; + else if (o == '!') + val = !val; + } else if (o == '(') { + /* sub-expression */ + p++; + if (parseExpr(&p, &val) < 0) + return 0; /* no valid expression */ skipSpace(p); - o = *p; - if (memchr("+-~!", o, 4)) - { - /* unary operators */ - p++; - if (!parseValue(&p, &val)) return 0; /* no valid value */ - if (exprDebug) printf("parseValue: %c %ld\n", o, val); - if (o == '-') val=-val; - else if (o == '~') val=~val; - else if (o == '!') val=!val; - } - else if (o == '(') - { - /* sub-expression */ - p++; - if (parseExpr(&p, &val) < 0) return 0; /* no valid expression */ - skipSpace(p); - if (*p++ != ')') return 0; /* missing ) */ - } - else if (o == '#') - { - /* string length operator */ - p++; - if (exprDebug) printf("parseValue: string length of %s\n", p); - if (*p == '"' || *p == '\'') - val = parseString(&p, NULL); - else return 0; - } + if (*p++ != ')') + return 0; /* missing ) */ + } else if (o == '#') { + /* string length operator */ + p++; + if (exprDebug) + printf("parseValue: string length of %s\n", p); + if (*p == '"' || *p == '\'') + val = parseString(&p, NULL); else - { - /* number */ - char *e; - val = strtol(p, &e, 0); - if (e == p) return 0; /* no number */ + return 0; + } else { + /* number */ + char *e; + val = strtol(p, &e, 0); + if (e == p) + return 0; /* no number */ - if (isalpha((unsigned char)*e)||*e=='.') - { - /* part of plain word or floating point number */ - return 0; - } - p = e; + if (isalpha((unsigned char)*e) || *e == '.') { + /* part of plain word or floating point number */ + return 0; } - *pp = p; - *v = val; - return 1; + p = e; + } + *pp = p; + *v = val; + return 1; } -static long ipow(long base, long exp) -{ - long val; - if (exp == 2) return base*base; - if (exp == 3) return base*base*base; - if (exp == 1) return base; - if (exp == 0) return 1; - if (exp < 0) return 0; - val = ipow(base,exp>>1); - val *= val; - if (exp&1) val *= base; - return val; +static long ipow(long base, long exp) { + long val; + if (exp == 2) + return base * base; + if (exp == 3) + return base * base * base; + if (exp == 1) + return base; + if (exp == 0) + return 1; + if (exp < 0) + return 0; + val = ipow(base, exp >> 1); + val *= val; + if (exp & 1) + val *= base; + return val; } -static char parseSep(const char **pp, const char *seps) -{ - const char *p = *pp; +static char parseSep(const char **pp, const char *seps) { + const char *p = *pp; - skipSpace(p); - if (!*p || !strchr(seps, *p)) return 0; - *pp = p+1; - return *p; + skipSpace(p); + if (!*p || !strchr(seps, *p)) + return 0; + *pp = p + 1; + return *p; } -struct {char str[4]; int pr;} ops[] = { - {":=",0}, - {"**",14}, - {"*", 13},{"/",13},{"%",13}, - {"+",12},{"-",12}, - {"<<",11},{">>>",11},{">>",11}, - {"<?",10},{">?",10}, - {"<=>",9}, - {"<=",8},{">=",8},{"<",8},{">",8}, - {"==",7},{"!=",7}, - {"&&",3},{"||",2}, - {"&",6},{"^",5},{"|",4}, - {"?:",1},{"?",1} -}; +struct { + char str[4]; + int pr; +} ops[] = {{":=", 0}, {"**", 14}, {"*", 13}, {"/", 13}, {"%", 13}, + {"+", 12}, {"-", 12}, {"<<", 11}, {">>>", 11}, {">>", 11}, + {"<?", 10}, {">?", 10}, {"<=>", 9}, {"<=", 8}, {">=", 8}, + {"<", 8}, {">", 8}, {"==", 7}, {"!=", 7}, {"&&", 3}, + {"||", 2}, {"&", 6}, {"^", 5}, {"|", 4}, {"?:", 1}, + {"?", 1}}; enum op { - op_none, - op_pow, - op_mul,op_div,op_mod, - op_plus,op_minus, - op_lshift,op_urshift,op_rshift, - op_min,op_max, - op_cmp, - op_lteq,op_gteq,op_lt,op_gt, - op_eq,op_neq, - op_logicand,op_logicor, - op_bitand,op_bitxor,op_bitor, - op_alt,op_if + op_none, + op_pow, + op_mul, + op_div, + op_mod, + op_plus, + op_minus, + op_lshift, + op_urshift, + op_rshift, + op_min, + op_max, + op_cmp, + op_lteq, + op_gteq, + op_lt, + op_gt, + op_eq, + op_neq, + op_logicand, + op_logicor, + op_bitand, + op_bitxor, + op_bitor, + op_alt, + op_if }; -static int startsWith(const char *p, const char *s) -{ - int i = 0; - while (*s) { i++; if (*p++ != *s++) return 0; } - return i; +static int startsWith(const char *p, const char *s) { + int i = 0; + while (*s) { + i++; + if (*p++ != *s++) + return 0; + } + return i; } -static int parseOp(const char **pp) -{ - const char *p = *pp; - int o, l; +static int parseOp(const char **pp) { + const char *p = *pp; + int o, l; - skipSpace(p); - if (ispunct((unsigned char)*p)) - { - for (o = 1; o < (int)(sizeof(ops)/sizeof(ops[0])); o++) - { - if ((l = startsWith(p, ops[o].str))) - { - /* operator found */ - *pp = p+l; - return o; - } - } + skipSpace(p); + if (ispunct((unsigned char)*p)) { + for (o = 1; o < (int)(sizeof(ops) / sizeof(ops[0])); o++) { + if ((l = startsWith(p, ops[o].str))) { + /* operator found */ + *pp = p + l; + return o; + } } - return 0; + } + return 0; } -static int parseSubExpr(const char **pp, long *v, int pr, int o) -{ - const char *p = *pp; - long val = o ? *v : 0; - long val2; - int o2 = o; +static int parseSubExpr(const char **pp, long *v, int pr, int o) { + const char *p = *pp; + long val = o ? *v : 0; + long val2; + int o2 = o; - if (exprDebug) printf("parseExpr(%d): start %ld %s \"%s\"\n", pr, val, ops[o].str, p); - do { - if (!parseValue(&p, &val2)) - { - if (exprDebug) printf("parseExpr(%d): no value after %ld %s\n", pr, val, ops[o].str); - return -1; - } -nextop: - if ((o2 = parseOp(&p))) - { - if (exprDebug) printf("parseExpr(%d): %ld %s %ld %s \"%s\"\n", pr, val, ops[o].str, val2, ops[o2].str, p); - if (o && ops[o2].pr > ops[o].pr) - { - if ((o2 = parseSubExpr(&p, &val2, ops[o].pr, o2)) < 0) - { - if (exprDebug) printf("parseExpr(%d): parse failed after %ld %s %ld\n", pr, val, ops[o].str, val2); - return -1; - } - } - } - if (exprDebug) printf("parseExpr(%d): calc %ld %s %ld\n", pr, val, ops[o].str, val2); - switch (o) - { - case op_none: val = val2; break; - case op_pow: val = ipow(val, val2); break; - case op_mul: val *= val2; break; - case op_div: val /= val2; break; - case op_mod: val %= val2; break; - case op_plus: val += val2; break; - case op_minus: val -= val2; break; - case op_lshift: val <<= val2; break; - case op_urshift: val = (unsigned long)val >> val2; break; - case op_rshift: val >>= val2; break; - case op_min: if (val2 < val) val = val2; break; - case op_max: if (val2 > val) val = val2; break; - case op_cmp: val = val < val2 ? -1 : val == val2 ? 0 : 1; break; - case op_lteq: val = val <= val2; break; - case op_gteq: val = val >= val2; break; - case op_lt: val = val < val2; break; - case op_gt: val = val > val2; break; - case op_eq: val = val == val2; break; - case op_neq: val = val != val2; break; - case op_logicand: val = val && val2; break; - case op_logicor: val = val || val2; break; - case op_bitand: val &= val2; break; - case op_bitxor: val ^= val2; break; - case op_bitor: val |= val2; break; - case op_alt: if (!val) val = val2; break; + if (exprDebug) + printf("parseExpr(%d): start %ld %s \"%s\"\n", pr, val, ops[o].str, p); + do { + if (!parseValue(&p, &val2)) { + if (exprDebug) + printf("parseExpr(%d): no value after %ld %s\n", pr, val, ops[o].str); + return -1; + } + nextop: + if ((o2 = parseOp(&p))) { + if (exprDebug) + printf("parseExpr(%d): %ld %s %ld %s \"%s\"\n", pr, val, ops[o].str, + val2, ops[o2].str, p); + if (o && ops[o2].pr > ops[o].pr) { + if ((o2 = parseSubExpr(&p, &val2, ops[o].pr, o2)) < 0) { + if (exprDebug) + printf("parseExpr(%d): parse failed after %ld %s %ld\n", pr, val, + ops[o].str, val2); + return -1; } - if (exprDebug) printf("parseExpr(%d): result %ld\n", pr, val); - if (o2 == op_if) - { - long val3 = 0; - val2 = 1; - if (exprDebug) printf("parseExpr(%d) if %ld\n", pr, val); - if ((o2 = parseExpr(&p, &val2)) >= 0) - { - if (exprDebug) printf("parseExpr(%d) then %ld\n", pr, val2); - if (parseSep(&p, ":")) - { - parseExpr(&p, &val3); - if (exprDebug) printf("parseExpr(%d) else %ld\n", pr, val3); - } - } - if (exprDebug) printf("parseExpr(%d) if %ld then %ld else %ld\n", pr, val, val2, val3); - val = val ? val2 : val3; - if (exprDebug) printf("parseExpr(%d): result %ld, o2=%d, rest \"%s\" \n", pr, val, o2, p); - if (o2 == -1) goto nextop; + } + } + if (exprDebug) + printf("parseExpr(%d): calc %ld %s %ld\n", pr, val, ops[o].str, val2); + switch (o) { + case op_none: + val = val2; + break; + case op_pow: + val = ipow(val, val2); + break; + case op_mul: + val *= val2; + break; + case op_div: + val /= val2; + break; + case op_mod: + val %= val2; + break; + case op_plus: + val += val2; + break; + case op_minus: + val -= val2; + break; + case op_lshift: + val <<= val2; + break; + case op_urshift: + val = (unsigned long)val >> val2; + break; + case op_rshift: + val >>= val2; + break; + case op_min: + if (val2 < val) + val = val2; + break; + case op_max: + if (val2 > val) + val = val2; + break; + case op_cmp: + val = val < val2 ? -1 : val == val2 ? 0 : 1; + break; + case op_lteq: + val = val <= val2; + break; + case op_gteq: + val = val >= val2; + break; + case op_lt: + val = val < val2; + break; + case op_gt: + val = val > val2; + break; + case op_eq: + val = val == val2; + break; + case op_neq: + val = val != val2; + break; + case op_logicand: + val = val && val2; + break; + case op_logicor: + val = val || val2; + break; + case op_bitand: + val &= val2; + break; + case op_bitxor: + val ^= val2; + break; + case op_bitor: + val |= val2; + break; + case op_alt: + if (!val) + val = val2; + break; + } + if (exprDebug) + printf("parseExpr(%d): result %ld\n", pr, val); + if (o2 == op_if) { + long val3 = 0; + val2 = 1; + if (exprDebug) + printf("parseExpr(%d) if %ld\n", pr, val); + if ((o2 = parseExpr(&p, &val2)) >= 0) { + if (exprDebug) + printf("parseExpr(%d) then %ld\n", pr, val2); + if (parseSep(&p, ":")) { + parseExpr(&p, &val3); + if (exprDebug) + printf("parseExpr(%d) else %ld\n", pr, val3); } - o = o2; - } while (ops[o].pr && pr <= ops[o].pr); - if (exprDebug) printf("parseExpr(%d): value = %ld return %d %s\n", pr, val, o, ops[o].str); - *pp = p; - *v = val; - return o; + } + if (exprDebug) + printf("parseExpr(%d) if %ld then %ld else %ld\n", pr, val, val2, val3); + val = val ? val2 : val3; + if (exprDebug) + printf("parseExpr(%d): result %ld, o2=%d, rest \"%s\" \n", pr, val, o2, + p); + if (o2 == -1) + goto nextop; + } + o = o2; + } while (ops[o].pr && pr <= ops[o].pr); + if (exprDebug) + printf("parseExpr(%d): value = %ld return %d %s\n", pr, val, o, ops[o].str); + *pp = p; + *v = val; + return o; } -static const char *getFormat(const char **pp) -{ - static char format [20]; - const char *p = *pp; - unsigned int i = 1; - if (exprDebug) printf("getFormat %s\n", p); - if ((format[0] = *p++) == '%') - { - while (i < sizeof(format) && memchr(" #-+0", *p, 5)) - format[i++] = *p++; - while (i < sizeof(format) && *p >= '0' && *p <= '9') - format[i++] = *p++; - if (i < sizeof(format)) - format[i++] = 'l'; - if (i < sizeof(format) && memchr("diouxXc", *p, 7)) - { - format[i++] = *p++; - format[i] = 0; - *pp = p; - if (exprDebug) printf("format = '%s'\n", format); - return format; - } +static const char *getFormat(const char **pp) { + static char format[20]; + const char *p = *pp; + unsigned int i = 1; + if (exprDebug) + printf("getFormat %s\n", p); + if ((format[0] = *p++) == '%') { + while (i < sizeof(format) && memchr(" #-+0", *p, 5)) + format[i++] = *p++; + while (i < sizeof(format) && *p >= '0' && *p <= '9') + format[i++] = *p++; + if (i < sizeof(format)) + format[i++] = 'l'; + if (i < sizeof(format) && memchr("diouxXc", *p, 7)) { + format[i++] = *p++; + format[i] = 0; + *pp = p; + if (exprDebug) + printf("format = '%s'\n", format); + return format; } - if (exprDebug) printf("no format\n"); - return NULL; + } + if (exprDebug) + printf("no format\n"); + return NULL; } -static int parseSlice(const char **pp, long* pstart, long* plength) -{ - const char *p = *pp; - long slice_start = 0; - long slice_length = 0; - long string_length = *plength; - char o; +static int parseSlice(const char **pp, long *pstart, long *plength) { + const char *p = *pp; + long slice_start = 0; + long slice_length = 0; + long string_length = *plength; + char o; - if (*p++ != '[') return 0; - parseExpr(&p, &slice_start); - if (slice_start < 0) slice_start += string_length; - if ((o = parseSep(&p, ":,"))) /* [start,length] or [start:end] */ - { - parseExpr(&p, &slice_length); - if (o == ':') - { - if (slice_length < 0) slice_length += string_length; - slice_length -= slice_start; - } - } - else slice_length = 1; - if (slice_start < 0) - { - slice_length += slice_start; - slice_start = 0; + if (*p++ != '[') + return 0; + parseExpr(&p, &slice_start); + if (slice_start < 0) + slice_start += string_length; + if ((o = parseSep(&p, ":,"))) /* [start,length] or [start:end] */ + { + parseExpr(&p, &slice_length); + if (o == ':') { + if (slice_length < 0) + slice_length += string_length; + slice_length -= slice_start; } - if (slice_start > string_length) - slice_length = 0; - if (slice_length > string_length - slice_start) - slice_length = string_length - slice_start; - if (slice_length < 0) - slice_length = 0; - skipSpace(p); - if (*p++ != ']') return 0; - *pstart += slice_start; - *plength = slice_length; - *pp = p; - return 1; + } else + slice_length = 1; + if (slice_start < 0) { + slice_length += slice_start; + slice_start = 0; + } + if (slice_start > string_length) + slice_length = 0; + if (slice_length > string_length - slice_start) + slice_length = string_length - slice_start; + if (slice_length < 0) + slice_length = 0; + skipSpace(p); + if (*p++ != ']') + return 0; + *pstart += slice_start; + *plength = slice_length; + *pp = p; + return 1; } -static long parseString(const char **pp, const char **pstart) -{ - const char *p = *pp; - const char *string_start = p; - long slice_start = 0; - long length = 0; - char q; +static long parseString(const char **pp, const char **pstart) { + const char *p = *pp; + const char *string_start = p; + long slice_start = 0; + long length = 0; + char q; - q = *p++; - while (*p) /* string length with escapes */ - { - if (*p == '\\') - if (*++p == 0) break; - if (*p++ == q) break; - length++; + q = *p++; + while (*p) /* string length with escapes */ + { + if (*p == '\\') + if (*++p == 0) + break; + if (*p++ == q) + break; + length++; + } + while (parseSlice(&p, &slice_start, &length)) + ; + if (exprDebug) + printf("parseString %.*s[%ld,%ld]\n", (int)(p - string_start), string_start, + slice_start, length); + if (length && pstart) { + while (slice_start-- > 0) { + if (*string_start++ == '\\') + string_start++; } - while (parseSlice(&p, &slice_start, &length)); - if (exprDebug) printf("parseString %.*s[%ld,%ld]\n", (int)(p-string_start), string_start, slice_start, length); - if (length && pstart) - { - while (slice_start-- > 0) - { - if (*string_start++ == '\\') string_start++; - } - *pstart = ++string_start; - } - *pp = p; - return length; + *pstart = ++string_start; + } + *pp = p; + return length; } -static void writeString(char** pw, const char* r, long length, char q) -{ - char* w = *pw; - *w++ = q; - while (length-- > 0) - { - if (*r == '\\') *w++ = *r++; - *w++ = *r++; - } - *w++ = q; - *w++ = 0; - *pw = w; +static void writeString(char **pw, const char *r, long length, char q) { + char *w = *pw; + *w++ = q; + while (length-- > 0) { + if (*r == '\\') + *w++ = *r++; + *w++ = *r++; + } + *w++ = q; + *w++ = 0; + *pw = w; } -size_t replaceExpressions(const char *r, char *buffer, size_t buffersize) -{ - long val, string_length; - char *w = buffer; - char *s; - const char *string_start = r; - char q; +size_t replaceExpressions(const char *r, char *buffer, size_t buffersize) { + long val, string_length; + char *w = buffer; + char *s; + const char *string_start = r; + char q; - *w = 0; - while (*r) - { - s = w; - if (*r == '"' || *r == '\'') - { - /* quoted strings */ - q = *r; - string_length = parseString(&r, &string_start); - writeString(&w, string_start, string_length, q); - if (exprDebug) printf("quoted string %s\n", s); + *w = 0; + while (*r) { + s = w; + if (*r == '"' || *r == '\'') { + /* quoted strings */ + q = *r; + string_length = parseString(&r, &string_start); + writeString(&w, string_start, string_length, q); + if (exprDebug) + printf("quoted string %s\n", s); + } else if (*r == '%') { + /* formatted expression */ + const char *r2 = r; + const char *f; + if (exprDebug) + printf("formatted expression after '%s'\n", s); + if ((f = getFormat(&r2)) && parseExpr(&r2, &val) >= 0) { + r = r2; + if (w > buffer && w[-1] == '(' && *r2++ == ')') { + w--; + r = r2; } - else if (*r == '%') - { - /* formatted expression */ - const char *r2 = r; - const char *f; - if (exprDebug) printf("formatted expression after '%s'\n", s); - if ((f = getFormat(&r2)) && parseExpr(&r2, &val) >= 0) - { - r = r2; - if (w > buffer && w[-1] == '(' && *r2++ == ')') - { - w--; - r = r2; - } - w += sprintf(w, f , val); - if (exprDebug) printf("formatted expression %s\n", s); - } - } - else if (parseExpr(&r, &val) >= 0) - { - /* unformatted expression */ - if (r[-1] == '?' && (q = parseSep(&r, "\"'"))) - { - /* handle expression ? "string1" : "string2" */ - w = s; - r--; - string_length = parseString(&r, &string_start); - if (val) writeString(&w, string_start, string_length, q); - if (parseSep(&r, ":")) - { - string_length = parseString(&r, &string_start); - if (!val) writeString(&w, string_start, string_length, q); - } - } - else - { - w += sprintf(w, "%ld", val); - } - if (exprDebug) printf("expression %s\n", s); - } - else { - /* unquoted string (i.e plain word) */ - do { - if ((*w++ = *r++) == '\\') if (*r) *w++ = *r++; - } while (*r && !strchr("%(\"', \t\n", *r)); - *w = 0; - if (exprDebug) printf("plain word '%s'\n", s); + w += sprintf(w, f, val); + if (exprDebug) + printf("formatted expression %s\n", s); + } + } else if (parseExpr(&r, &val) >= 0) { + /* unformatted expression */ + if (r[-1] == '?' && (q = parseSep(&r, "\"'"))) { + /* handle expression ? "string1" : "string2" */ + w = s; + r--; + string_length = parseString(&r, &string_start); + if (val) + writeString(&w, string_start, string_length, q); + if (parseSep(&r, ":")) { + string_length = parseString(&r, &string_start); + if (!val) + writeString(&w, string_start, string_length, q); } - /* copy space */ - while (isspace((unsigned char)*r) || *r == ',') *w++ = *r++; - /* terminate */ - *w = 0; + } else { + w += sprintf(w, "%ld", val); + } + if (exprDebug) + printf("expression %s\n", s); + } else { + /* unquoted string (i.e plain word) */ + do { + if ((*w++ = *r++) == '\\') + if (*r) + *w++ = *r++; + } while (*r && !strchr("%(\"', \t\n", *r)); + *w = 0; + if (exprDebug) + printf("plain word '%s'\n", s); } - return w - buffer; + /* copy space */ + while (isspace((unsigned char)*r) || *r == ',') + *w++ = *r++; + /* terminate */ + *w = 0; + } + return w - buffer; } diff --git a/require-ess/src/expr.h b/require-ess/src/expr.h index d3ee4eda..3924c3fd 100644 --- a/require-ess/src/expr.h +++ b/require-ess/src/expr.h @@ -5,15 +5,16 @@ extern { #endif -extern int exprDebug; + extern int exprDebug; -size_t replaceExpressions(const char* source, char* buffer, size_t buffersize); -/* Resolve integer expressions that are either free standing - * or in parentheses () embedded in an unquoted word. - * Do not resolve expressions in single or double quoted strings. - * An expression optionally starts with a integer format such as %x. - * It consists of integer numbers, operators and parentheses (). - */ + size_t replaceExpressions(const char *source, char *buffer, + size_t buffersize); + /* Resolve integer expressions that are either free standing + * or in parentheses () embedded in an unquoted word. + * Do not resolve expressions in single or double quoted strings. + * An expression optionally starts with a integer format such as %x. + * It consists of integer numbers, operators and parentheses (). + */ #ifdef __cplusplus } diff --git a/require-ess/src/require.c b/require-ess/src/require.c index 1156c2d1..14787804 100644 --- a/require-ess/src/require.c +++ b/require-ess/src/require.c @@ -18,28 +18,28 @@ /* for 64 bit (NFS) file systems */ #define _FILE_OFFSET_BITS 64 -#include <sys/stat.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> #include <ctype.h> +#include <epicsVersion.h> #include <errno.h> -#include <recSup.h> #include <initHooks.h> #include <osiFileName.h> -#include <epicsVersion.h> +#include <recSup.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> -#include <iocsh.h> #include <dbAccess.h> +#include <iocsh.h> /* This prototype is missing in older EPICS versions */ epicsShareFunc int epicsShareAPI iocshCmd(const char *cmd); #include <epicsExit.h> +#include <epicsExport.h> #include <epicsStdio.h> #include <osiFileName.h> -#include <epicsExport.h> -#include "version.h" #include "require.h" +#include "version.h" int requireDebug; @@ -96,8 +96,8 @@ int requireDebug; #define OS_CLASS "WIN32" #endif -#include <windows.h> #include <Psapi.h> +#include <windows.h> #pragma comment(lib, "kernel32.lib") #pragma comment(lib, "psapi.lib") #include "asprintf.h" @@ -111,20 +111,18 @@ int requireDebug; #define getAddress(module, name) GetProcAddress(module, name) -static char *realpath(const char *path, char *buffer) -{ - int len = MAX_PATH; +static char *realpath(const char *path, char *buffer) { + int len = MAX_PATH; + if (buffer == NULL) { + len = GetFullPathName(path, 0, NULL, NULL); + if (len == 0) + return NULL; + buffer = malloc(len); if (buffer == NULL) - { - len = GetFullPathName(path, 0, NULL, NULL); - if (len == 0) - return NULL; - buffer = malloc(len); - if (buffer == NULL) - return NULL; - } - GetFullPathName(path, len, buffer, NULL); - return buffer; + return NULL; + } + GetFullPathName(path, len, buffer, NULL); + return buffer; } #else @@ -141,15 +139,19 @@ static char *realpath(const char *path, char *buffer) #if defined(_WIN32) #define DIR_HANDLE HANDLE #define DIR_ENTRY WIN32_FIND_DATA -#define IF_OPEN_DIR(f) if (snprintf(f + modulediroffs, sizeof(f) - modulediroffs, "\\*.*"), (dir = FindFirstFile(filename, &direntry)) != INVALID_HANDLE_VALUE || (FindClose(dir), 0)) +#define IF_OPEN_DIR(f) \ + if (snprintf(f + modulediroffs, sizeof(f) - modulediroffs, "\\*.*"), \ + (dir = FindFirstFile(filename, &direntry)) != INVALID_HANDLE_VALUE || \ + (FindClose(dir), 0)) #define START_DIR_LOOP do -#define END_DIR_LOOP \ - while (FindNextFile(dir, &direntry)) \ - ; \ - FindClose(dir); -#define SKIP_NON_DIR(e) \ - if (!(e.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) || (e.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)) \ - continue; +#define END_DIR_LOOP \ + while (FindNextFile(dir, &direntry)) \ + ; \ + FindClose(dir); +#define SKIP_NON_DIR(e) \ + if (!(e.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) || \ + (e.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)) \ + continue; #define FILENAME(e) e.cFileName #else @@ -158,15 +160,16 @@ static char *realpath(const char *path, char *buffer) #define IF_OPEN_DIR(f) if ((dir = opendir(f))) #define DIR_ENTRY struct dirent * #define START_DIR_LOOP while ((errno = 0, direntry = readdir(dir)) != NULL) -#define END_DIR_LOOP \ - if (!direntry && errno) \ - fprintf(stderr, "error reading directory %s: %s\n", filename, strerror(errno)); \ - if (dir) \ - closedir(dir); +#define END_DIR_LOOP \ + if (!direntry && errno) \ + fprintf(stderr, "error reading directory %s: %s\n", filename, \ + strerror(errno)); \ + if (dir) \ + closedir(dir); #ifdef _DIRENT_HAVE_D_TYPE -#define SKIP_NON_DIR(e) \ - if (e->d_type != DT_DIR && e->d_type != DT_UNKNOWN) \ - continue; +#define SKIP_NON_DIR(e) \ + if (e->d_type != DT_DIR && e->d_type != DT_UNKNOWN) \ + continue; #else #define SKIP_NON_DIR(e) #endif @@ -180,7 +183,8 @@ static char *realpath(const char *path, char *buffer) /* #define TOSTR(s) TOSTR2(s) #define TOSTR2(s) #s -const char epicsRelease[] = TOSTR(EPICS_VERSION)"."TOSTR(EPICS_REVISION)"."TOSTR(EPICS_MODIFICATION); +const char epicsRelease[] = +TOSTR(EPICS_VERSION)"."TOSTR(EPICS_REVISION)"."TOSTR(EPICS_MODIFICATION); #ifndef T_A #error T_A not defined: Compile with USR_CFLAGS += -DT_A='"${T_A}"' @@ -201,60 +205,49 @@ Find a loadable library by name and load it. char epicsRelease[80]; char *targetArch; -void set_require_env() -{ - char *epics_version_major = getenv("EPICS_VERSION_MAJOR"); - char *epics_version_middle = getenv("EPICS_VERSION_MIDDLE"); - char *epics_version_minor = getenv("EPICS_VERSION_MINOR"); +void set_require_env() { + char *epics_version_major = getenv("EPICS_VERSION_MAJOR"); + char *epics_version_middle = getenv("EPICS_VERSION_MIDDLE"); + char *epics_version_minor = getenv("EPICS_VERSION_MINOR"); - sprintf(epicsRelease, "%s.%s.%s", epics_version_major, epics_version_middle, epics_version_minor); - targetArch = getenv("EPICS_HOST_ARCH"); - return; + sprintf(epicsRelease, "%s.%s.%s", epics_version_major, epics_version_middle, + epics_version_minor); + targetArch = getenv("EPICS_HOST_ARCH"); + return; } -static HMODULE loadlib(const char *libname) -{ - HMODULE libhandle = NULL; +static HMODULE loadlib(const char *libname) { + HMODULE libhandle = NULL; - if (libname == NULL) - { - fprintf(stderr, "missing library name\n"); - return NULL; - } + if (libname == NULL) { + fprintf(stderr, "missing library name\n"); + return NULL; + } #if defined(__unix) - if ((libhandle = dlopen(libname, RTLD_NOW | RTLD_GLOBAL)) == NULL) - { - fprintf(stderr, "Loading %s library failed: %s\n", - libname, dlerror()); - } + if ((libhandle = dlopen(libname, RTLD_NOW | RTLD_GLOBAL)) == NULL) { + fprintf(stderr, "Loading %s library failed: %s\n", libname, dlerror()); + } #elif defined(_WIN32) - if ((libhandle = LoadLibrary(libname)) == NULL) - { - LPVOID lpMsgBuf; - - FormatMessage( - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM, - NULL, - GetLastError(), - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPTSTR)&lpMsgBuf, - 0, NULL); - fprintf(stderr, "Loading %s library failed: %s\n", - libname, lpMsgBuf); - LocalFree(lpMsgBuf); - } + if ((libhandle = LoadLibrary(libname)) == NULL) { + LPVOID lpMsgBuf; + + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, + 0, NULL); + fprintf(stderr, "Loading %s library failed: %s\n", libname, lpMsgBuf); + LocalFree(lpMsgBuf); + } #else - fprintf(stderr, "cannot load libraries on this OS.\n"); + fprintf(stderr, "cannot load libraries on this OS.\n"); #endif - return libhandle; + return libhandle; } -typedef struct moduleitem -{ - struct moduleitem *next; - char content[0]; +typedef struct moduleitem { + struct moduleitem *next; + char content[0]; } moduleitem; static moduleitem *loadedModules = NULL; @@ -262,546 +255,504 @@ static unsigned long moduleCount = 0; static unsigned long moduleListBufferSize = 1; static unsigned long maxModuleNameLength = 0; -int putenvprintf(const char *format, ...) -{ - va_list ap; - char *var; - char *val; - int status = 0; - - if (!format) - return -1; - va_start(ap, format); - if (vasprintf(&var, format, ap) < 0) - { - perror("require putenvprintf"); - return errno; - } - va_end(ap); - - if (requireDebug) - printf("require: putenv(\"%s\")\n", var); - - val = strchr(var, '='); - if (!val) - { - fprintf(stderr, "putenvprintf: string contains no =: %s\n", var); - status = -1; +int putenvprintf(const char *format, ...) { + va_list ap; + char *var; + char *val; + int status = 0; + + if (!format) + return -1; + va_start(ap, format); + if (vasprintf(&var, format, ap) < 0) { + perror("require putenvprintf"); + return errno; + } + va_end(ap); + + if (requireDebug) + printf("require: putenv(\"%s\")\n", var); + + val = strchr(var, '='); + if (!val) { + fprintf(stderr, "putenvprintf: string contains no =: %s\n", var); + status = -1; + } else { + *val++ = 0; + if (setenv(var, val, 1) != 0) { + perror("require putenvprintf: setenv failed"); + status = errno; } - else - { - *val++ = 0; - if (setenv(var, val, 1) != 0) - { - perror("require putenvprintf: setenv failed"); - status = errno; - } - } - free(var); - return status; + } + free(var); + return status; } -void pathAdd(const char *varname, const char *dirname) -{ - char *old_path; +void pathAdd(const char *varname, const char *dirname) { + char *old_path; - if (!varname || !dirname) - { - fprintf(stderr, "usage: pathAdd \"ENVIRONMENT_VARIABLE\",\"directory\"\n"); - fprintf(stderr, " Adds or moves the directory to the front of the ENVIRONMENT_VARIABLE\n"); - fprintf(stderr, " but after a leading \".\".\n"); - return; - } - - /* add directory to front */ - old_path = getenv(varname); - if (old_path == NULL) - putenvprintf("%s=." OSI_PATH_LIST_SEPARATOR "%s", varname, dirname); - else - { - size_t len = strlen(dirname); - char *p; - - /* skip over "." at the beginning */ - if (old_path[0] == '.' && old_path[1] == OSI_PATH_LIST_SEPARATOR[0]) - old_path += 2; - - /* If directory is already in path, move it to front */ - p = old_path; - while ((p = strstr(p, dirname)) != NULL) - { - if ((p == old_path || *(p - 1) == OSI_PATH_LIST_SEPARATOR[0]) && - (p[len] == 0 || p[len] == OSI_PATH_LIST_SEPARATOR[0])) - { - if (p == old_path) - break; /* already at front, nothing to do */ - memmove(old_path + len + 1, old_path, p - old_path - 1); - strcpy(old_path, dirname); - old_path[len] = OSI_PATH_LIST_SEPARATOR[0]; - if (requireDebug) - printf("require: modified %s=%s\n", varname, old_path); - break; - } - p += len; - } - if (p == NULL) - /* add new directory to the front (after "." )*/ - putenvprintf("%s=." OSI_PATH_LIST_SEPARATOR "%s" OSI_PATH_LIST_SEPARATOR "%s", - varname, dirname, old_path); - } -} + if (!varname || !dirname) { + fprintf(stderr, "usage: pathAdd \"ENVIRONMENT_VARIABLE\",\"directory\"\n"); + fprintf(stderr, " Adds or moves the directory to the front of the " + "ENVIRONMENT_VARIABLE\n"); + fprintf(stderr, " but after a leading \".\".\n"); + return; + } + + /* add directory to front */ + old_path = getenv(varname); + if (old_path == NULL) + putenvprintf("%s=." OSI_PATH_LIST_SEPARATOR "%s", varname, dirname); + else { + size_t len = strlen(dirname); + char *p; -char *realpathSeparator(const char *location) -{ - size_t ll; - char *buffer = malloc(PATH_MAX + strlen(OSI_PATH_SEPARATOR)); - buffer = realpath(location, buffer); - if (!buffer) - { + /* skip over "." at the beginning */ + if (old_path[0] == '.' && old_path[1] == OSI_PATH_LIST_SEPARATOR[0]) + old_path += 2; + + /* If directory is already in path, move it to front */ + p = old_path; + while ((p = strstr(p, dirname)) != NULL) { + if ((p == old_path || *(p - 1) == OSI_PATH_LIST_SEPARATOR[0]) && + (p[len] == 0 || p[len] == OSI_PATH_LIST_SEPARATOR[0])) { + if (p == old_path) + break; /* already at front, nothing to do */ + memmove(old_path + len + 1, old_path, p - old_path - 1); + strcpy(old_path, dirname); + old_path[len] = OSI_PATH_LIST_SEPARATOR[0]; if (requireDebug) - printf("require: realpath(%s) failed\n", location); - return NULL; + printf("require: modified %s=%s\n", varname, old_path); + break; + } + p += len; } - ll = strlen(buffer); - /* linux realpath removes trailing slash */ - if (buffer[ll - strlen(OSI_PATH_SEPARATOR)] != OSI_PATH_SEPARATOR[0]) - { - strcpy(buffer + ll + 1 - strlen(OSI_PATH_SEPARATOR), OSI_PATH_SEPARATOR); - } - return buffer; + if (p == NULL) + /* add new directory to the front (after "." )*/ + putenvprintf("%s=." OSI_PATH_LIST_SEPARATOR "%s" OSI_PATH_LIST_SEPARATOR + "%s", + varname, dirname, old_path); + } } -static int setupDbPath(const char *module, const char *dbdir) -{ - char *absdir = realpathSeparator(dbdir); /* so we can change directory later safely */ - if (absdir == NULL) - { - if (requireDebug) - printf("require: cannot resolve %s\n", dbdir); - return -1; - } - +char *realpathSeparator(const char *location) { + size_t ll; + char *buffer = malloc(PATH_MAX + strlen(OSI_PATH_SEPARATOR)); + buffer = realpath(location, buffer); + if (!buffer) { if (requireDebug) - printf("require: found template directory %s\n", absdir); - - /* set up db search path environment variables - <module>_DB template path of <module> - TEMPLATES template path of the current module (overwritten) - EPICS_DB_INCLUDE_PATH template path of all loaded modules (last in front after ".") - */ - - putenvprintf("%s_DB=%s", module, absdir); - putenvprintf("TEMPLATES=%s", absdir); - pathAdd("EPICS_DB_INCLUDE_PATH", absdir); - free(absdir); - return 0; + printf("require: realpath(%s) failed\n", location); + return NULL; + } + ll = strlen(buffer); + /* linux realpath removes trailing slash */ + if (buffer[ll - strlen(OSI_PATH_SEPARATOR)] != OSI_PATH_SEPARATOR[0]) { + strcpy(buffer + ll + 1 - strlen(OSI_PATH_SEPARATOR), OSI_PATH_SEPARATOR); + } + return buffer; } -static int getRecordHandle(const char *namepart, short type, long minsize, DBADDR *paddr) -{ - /* - #define PVNAME_STRINGSZ 61 - defined in EPICS_BASE/include/dbDefs.h - */ - char recordname[PVNAME_STRINGSZ] = ""; - long dummy = 0L; - long offset = 0L; - - sprintf(recordname, "%.*s%s", (int)(PVNAME_STRINGSZ - strlen(namepart) - 1), getenv("REQUIRE_IOC"), namepart); - - if (dbNameToAddr(recordname, paddr) != 0) - { - fprintf(stderr, - "require:getRecordHandle : record %s not found\n", - recordname); - return -1; - } - if (paddr->field_type != type) - { - fprintf(stderr, - "require:getRecordHandle : record %s has wrong type %s instead of %s\n", - recordname, - pamapdbfType[paddr->field_type].strvalue, - pamapdbfType[type].strvalue); - return -1; - } - if (paddr->no_elements < minsize) - { - fprintf(stderr, - "require:getRecordHandle : record %s has not enough elements: %lu instead of %lu\n", - recordname, - paddr->no_elements, - minsize); - return -1; - } - if (paddr->pfield == NULL) - { - fprintf(stderr, "require:getRecordHandle : record %s has not yet allocated memory\n", - recordname); - return -1; - } - - /* update array information */ - dbGetRset(paddr)->get_array_info(paddr, &dummy, &offset); +static int setupDbPath(const char *module, const char *dbdir) { + char *absdir = + realpathSeparator(dbdir); /* so we can change directory later safely */ + if (absdir == NULL) { + if (requireDebug) + printf("require: cannot resolve %s\n", dbdir); + return -1; + } + + if (requireDebug) + printf("require: found template directory %s\n", absdir); + + /* set up db search path environment variables + <module>_DB template path of <module> + TEMPLATES template path of the current module (overwritten) + EPICS_DB_INCLUDE_PATH template path of all loaded modules (last in front + after ".") + */ + + putenvprintf("%s_DB=%s", module, absdir); + putenvprintf("TEMPLATES=%s", absdir); + pathAdd("EPICS_DB_INCLUDE_PATH", absdir); + free(absdir); + return 0; +} - return 0; +static int getRecordHandle(const char *namepart, short type, long minsize, + DBADDR *paddr) { + /* + #define PVNAME_STRINGSZ 61 + defined in EPICS_BASE/include/dbDefs.h + */ + char recordname[PVNAME_STRINGSZ] = ""; + long dummy = 0L; + long offset = 0L; + + sprintf(recordname, "%.*s%s", (int)(PVNAME_STRINGSZ - strlen(namepart) - 1), + getenv("REQUIRE_IOC"), namepart); + + if (dbNameToAddr(recordname, paddr) != 0) { + fprintf(stderr, "require:getRecordHandle : record %s not found\n", + recordname); + return -1; + } + if (paddr->field_type != type) { + fprintf( + stderr, + "require:getRecordHandle : record %s has wrong type %s instead of %s\n", + recordname, pamapdbfType[paddr->field_type].strvalue, + pamapdbfType[type].strvalue); + return -1; + } + if (paddr->no_elements < minsize) { + fprintf(stderr, + "require:getRecordHandle : record %s has not enough elements: %lu " + "instead of %lu\n", + recordname, paddr->no_elements, minsize); + return -1; + } + if (paddr->pfield == NULL) { + fprintf( + stderr, + "require:getRecordHandle : record %s has not yet allocated memory\n", + recordname); + return -1; + } + + /* update array information */ + dbGetRset(paddr)->get_array_info(paddr, &dummy, &offset); + + return 0; } /* -We can fill the records only after they have been initialized, at initHookAfterFinishDevSup. -But use double indirection here because in 3.13 we must -wait until initHooks is loaded before we can register the hook. +We can fill the records only after they have been initialized, at +initHookAfterFinishDevSup. But use double indirection here because in 3.13 we +must wait until initHooks is loaded before we can register the hook. */ -static void fillModuleListRecord(initHookState state) -{ - if (state == initHookAfterFinishDevSup) /* MODULES record exists and has allocated memory */ - { - DBADDR modules, versions, modver; - int have_modules, have_versions, have_modver; - moduleitem *m; - int i = 0; - long c = 0; +static void fillModuleListRecord(initHookState state) { + if (state == initHookAfterFinishDevSup) /* MODULES record exists and has + allocated memory */ + { + DBADDR modules, versions, modver; + int have_modules, have_versions, have_modver; + moduleitem *m; + int i = 0; + long c = 0; - if (requireDebug) - printf("require: fillModuleListRecord\n"); + if (requireDebug) + printf("require: fillModuleListRecord\n"); - have_modules = (getRecordHandle(":MODULES", DBF_STRING, moduleCount, &modules) == 0); - have_versions = (getRecordHandle(":VERSIONS", DBF_STRING, moduleCount, &versions) == 0); + have_modules = + (getRecordHandle(":MODULES", DBF_STRING, moduleCount, &modules) == 0); + have_versions = + (getRecordHandle(":VERSIONS", DBF_STRING, moduleCount, &versions) == 0); - moduleListBufferSize += moduleCount * maxModuleNameLength; - have_modver = (getRecordHandle(":MOD_VER", DBF_CHAR, moduleListBufferSize, &modver) == 0); + moduleListBufferSize += moduleCount * maxModuleNameLength; + have_modver = (getRecordHandle(":MOD_VER", DBF_CHAR, moduleListBufferSize, + &modver) == 0); - for (m = loadedModules, i = 0; m; m = m->next, i++) - { - size_t lm = strlen(m->content) + 1; - if (have_modules) - { - if (requireDebug) - printf("require: %s[%d] = \"%.*s\"\n", - modules.precord->name, i, - MAX_STRING_SIZE - 1, m->content); - sprintf((char *)(modules.pfield) + i * MAX_STRING_SIZE, "%.*s", - MAX_STRING_SIZE - 1, m->content); - } - if (have_versions) - { - if (requireDebug) - printf("require: %s[%d] = \"%.*s\"\n", - versions.precord->name, i, - MAX_STRING_SIZE - 1, m->content + lm); - sprintf((char *)(versions.pfield) + i * MAX_STRING_SIZE, "%.*s", - MAX_STRING_SIZE - 1, m->content + lm); - } - if (have_modver) - { - if (requireDebug) - printf("require: %s+=\"%-*s%s\"\n", - modver.precord->name, - (int)maxModuleNameLength, m->content, m->content + lm); - c += sprintf((char *)(modver.pfield) + c, "%-*s%s\n", - (int)maxModuleNameLength, m->content, m->content + lm); - } - } - if (have_modules) - dbGetRset(&modules)->put_array_info(&modules, i); - if (have_versions) - dbGetRset(&versions)->put_array_info(&versions, i); - if (have_modver) - dbGetRset(&modver)->put_array_info(&modver, c + 1); + for (m = loadedModules, i = 0; m; m = m->next, i++) { + size_t lm = strlen(m->content) + 1; + if (have_modules) { + if (requireDebug) + printf("require: %s[%d] = \"%.*s\"\n", modules.precord->name, i, + MAX_STRING_SIZE - 1, m->content); + sprintf((char *)(modules.pfield) + i * MAX_STRING_SIZE, "%.*s", + MAX_STRING_SIZE - 1, m->content); + } + if (have_versions) { + if (requireDebug) + printf("require: %s[%d] = \"%.*s\"\n", versions.precord->name, i, + MAX_STRING_SIZE - 1, m->content + lm); + sprintf((char *)(versions.pfield) + i * MAX_STRING_SIZE, "%.*s", + MAX_STRING_SIZE - 1, m->content + lm); + } + if (have_modver) { + if (requireDebug) + printf("require: %s+=\"%-*s%s\"\n", modver.precord->name, + (int)maxModuleNameLength, m->content, m->content + lm); + c += sprintf((char *)(modver.pfield) + c, "%-*s%s\n", + (int)maxModuleNameLength, m->content, m->content + lm); + } } + if (have_modules) + dbGetRset(&modules)->put_array_info(&modules, i); + if (have_versions) + dbGetRset(&versions)->put_array_info(&versions, i); + if (have_modver) + dbGetRset(&modver)->put_array_info(&modver, c + 1); + } } -void registerModule(const char *module, const char *version, const char *location) -{ - moduleitem *m, **pm; - size_t lm = strlen(module) + 1; - size_t lv = (version ? strlen(version) : 0) + 1; - size_t ll = 1; - char *absLocation = NULL; - char *absLocationRequire = NULL; - char *argstring = NULL; - const char *mylocation; - static int firstTime = 1; - +void registerModule(const char *module, const char *version, + const char *location) { + moduleitem *m, **pm; + size_t lm = strlen(module) + 1; + size_t lv = (version ? strlen(version) : 0) + 1; + size_t ll = 1; + char *absLocation = NULL; + char *absLocationRequire = NULL; + char *argstring = NULL; + const char *mylocation; + static int firstTime = 1; + + if (requireDebug) + printf("require: registerModule(%s,%s,%s)\n", module, version, location); + + if (firstTime) { + initHookRegister(fillModuleListRecord); if (requireDebug) - printf("require: registerModule(%s,%s,%s)\n", module, version, location); - - if (firstTime) - { - initHookRegister(fillModuleListRecord); - if (requireDebug) - printf("require: initHookRegister\n"); - firstTime = 0; - } - - if (!version) - version = ""; - - if (location) - { - absLocation = realpathSeparator(location); - ll = strlen(absLocation) + 1; - } - m = (moduleitem *)malloc(sizeof(moduleitem) + lm + lv + ll); - if (m == NULL) - { - fprintf(stderr, "require: out of memory\n"); - return; - } - - m->next = NULL; + printf("require: initHookRegister\n"); + firstTime = 0; + } + + if (!version) + version = ""; + + if (location) { + absLocation = realpathSeparator(location); + ll = strlen(absLocation) + 1; + } + m = (moduleitem *)malloc(sizeof(moduleitem) + lm + lv + ll); + if (m == NULL) { + fprintf(stderr, "require: out of memory\n"); + return; + } - strcpy(m->content, module); - strcpy(m->content + lm, version); - strcpy(m->content + lm + lv, absLocation ? absLocation : ""); + m->next = NULL; - free(absLocation); - for (pm = &loadedModules; *pm != NULL; pm = &(*pm)->next) - ; - *pm = m; - if (lm > maxModuleNameLength) - maxModuleNameLength = lm; - moduleListBufferSize += lv; - moduleCount++; + strcpy(m->content, module); + strcpy(m->content + lm, version); + strcpy(m->content + lm + lv, absLocation ? absLocation : ""); - putenvprintf("MODULE=%s", module); - putenvprintf("%s_VERSION=%s", module, version); - if (location) - { - putenvprintf("%s_DIR=%s", module, m->content + lm + lv); - pathAdd("SCRIPT_PATH", m->content + lm + lv); - } + free(absLocation); + for (pm = &loadedModules; *pm != NULL; pm = &(*pm)->next) + ; + *pm = m; + if (lm > maxModuleNameLength) + maxModuleNameLength = lm; + moduleListBufferSize += lv; + moduleCount++; + + putenvprintf("MODULE=%s", module); + putenvprintf("%s_VERSION=%s", module, version); + if (location) { + putenvprintf("%s_DIR=%s", module, m->content + lm + lv); + pathAdd("SCRIPT_PATH", m->content + lm + lv); + } + + /* only do registration register stuff at init */ + if (interruptAccept) + return; - /* only do registration register stuff at init */ - if (interruptAccept) - return; - - /* create a record with the version string */ - mylocation = getenv("require_DIR"); - if (mylocation == NULL) - return; - if (asprintf(&absLocationRequire, "%s" OSI_PATH_SEPARATOR "db" OSI_PATH_SEPARATOR "moduleversion.template", mylocation) < 0) - return; - /* - Require DB has the following four PVs: - - $(REQUIRE_IOC):$(MODULE)_VER - - $(REQUIRE_IOC):MOD_VER - - $(REQUIRE_IOC):VERSIONS - - $(REQUIRE_IOC):MODULES - We reserved 30 chars for :$(MODULE)_VER, so MODULE has the maximum 24 chars. - And we've reserved for 30 chars for $(REQUIRE_IOC). - So, the whole PV and record name in moduleversion.template has 59 + 1. - */ - if (asprintf(&argstring, "REQUIRE_IOC=%.30s, MODULE=%.24s, VERSION=%.39s, MODULE_COUNT=%lu, BUFFER_SIZE=%lu", - getenv("REQUIRE_IOC"), module, version, moduleCount, - moduleListBufferSize + maxModuleNameLength * moduleCount) < 0) - return; - printf("Loading module info records for %s\n", module); - dbLoadRecords(absLocationRequire, argstring); - free(argstring); - free(absLocationRequire); + /* create a record with the version string */ + mylocation = getenv("require_DIR"); + if (mylocation == NULL) + return; + if (asprintf(&absLocationRequire, + "%s" OSI_PATH_SEPARATOR "db" OSI_PATH_SEPARATOR + "moduleversion.template", + mylocation) < 0) + return; + /* + Require DB has the following four PVs: + - $(REQUIRE_IOC):$(MODULE)_VER + - $(REQUIRE_IOC):MOD_VER + - $(REQUIRE_IOC):VERSIONS + - $(REQUIRE_IOC):MODULES + We reserved 30 chars for :$(MODULE)_VER, so MODULE has the maximum 24 + chars. And we've reserved for 30 chars for $(REQUIRE_IOC). So, the whole PV + and record name in moduleversion.template has 59 + 1. + */ + if (asprintf(&argstring, + "REQUIRE_IOC=%.30s, MODULE=%.24s, VERSION=%.39s, " + "MODULE_COUNT=%lu, BUFFER_SIZE=%lu", + getenv("REQUIRE_IOC"), module, version, moduleCount, + moduleListBufferSize + maxModuleNameLength * moduleCount) < 0) + return; + printf("Loading module info records for %s\n", module); + dbLoadRecords(absLocationRequire, argstring); + free(argstring); + free(absLocationRequire); } #if defined(__linux) /* This is the Linux link.h, not the EPICS link.h ! */ #include <link.h> -static int findLibRelease( - struct dl_phdr_info *info, /* shared library info */ - size_t size, /* size of info structure */ - void *data /* user-supplied arg */ -) -{ - void *handle; - char *location = NULL; - char *p; - char *version; - char *symname; - char name[PATH_MAX + 11]; /* get space for library path + "LibRelease" */ - - (void)data; /* unused */ - if (size < sizeof(struct dl_phdr_info)) - return 0; /* wrong version of struct dl_phdr_info */ - /* find a symbol with a name like "_<module>LibRelease" - where <module> is from the library name "<location>/lib<module>.so" */ - if (info->dlpi_name == NULL || info->dlpi_name[0] == 0) - return 0; /* no library name */ - strcpy(name, info->dlpi_name); /* get a modifiable copy of the library name */ - handle = dlopen(info->dlpi_name, RTLD_LAZY); /* re-open already loaded library */ - p = strrchr(name, '/'); /* find file name part in "<location>/lib<module>.so" */ - if (p) - { - location = name; - *++p = 0; - } - else - p = name; /* terminate "<location>/" (if exists) */ - *(symname = p + 2) = '_'; /* replace "lib" with "_" */ - p = strchr(symname, '.'); /* find ".so" extension */ - if (p == NULL) - p = symname + strlen(symname); /* no file extension ? */ - strcpy(p, "LibRelease"); /* append "LibRelease" to module name */ - version = dlsym(handle, symname); /* find symbol "_<module>LibRelease" */ - if (version) - { - *p = 0; - symname++; /* get "<module>" from "_<module>LibRelease" */ - if ((p = strstr(name, "/" LIBDIR)) != NULL) - p[1] = 0; /* cut "<location>" before LIBDIR */ - if (getLibVersion(symname) == NULL) - registerModule(symname, version, location); - } - dlclose(handle); - return 0; +static int findLibRelease(struct dl_phdr_info *info, /* shared library info */ + size_t size, /* size of info structure */ + void *data /* user-supplied arg */ +) { + void *handle; + char *location = NULL; + char *p; + char *version; + char *symname; + char name[PATH_MAX + 11]; /* get space for library path + "LibRelease" */ + + (void)data; /* unused */ + if (size < sizeof(struct dl_phdr_info)) + return 0; /* wrong version of struct dl_phdr_info */ + /* find a symbol with a name like "_<module>LibRelease" + where <module> is from the library name "<location>/lib<module>.so" */ + if (info->dlpi_name == NULL || info->dlpi_name[0] == 0) + return 0; /* no library name */ + strcpy(name, info->dlpi_name); /* get a modifiable copy of the library name */ + handle = + dlopen(info->dlpi_name, RTLD_LAZY); /* re-open already loaded library */ + p = strrchr(name, + '/'); /* find file name part in "<location>/lib<module>.so" */ + if (p) { + location = name; + *++p = 0; + } else + p = name; /* terminate "<location>/" (if exists) */ + *(symname = p + 2) = '_'; /* replace "lib" with "_" */ + p = strchr(symname, '.'); /* find ".so" extension */ + if (p == NULL) + p = symname + strlen(symname); /* no file extension ? */ + strcpy(p, "LibRelease"); /* append "LibRelease" to module name */ + version = dlsym(handle, symname); /* find symbol "_<module>LibRelease" */ + if (version) { + *p = 0; + symname++; /* get "<module>" from "_<module>LibRelease" */ + if ((p = strstr(name, "/" LIBDIR)) != NULL) + p[1] = 0; /* cut "<location>" before LIBDIR */ + if (getLibVersion(symname) == NULL) + registerModule(symname, version, location); + } + dlclose(handle); + return 0; } -static void registerExternalModules() -{ - /* iterate over all loaded libraries */ - dl_iterate_phdr(findLibRelease, NULL); +static void registerExternalModules() { + /* iterate over all loaded libraries */ + dl_iterate_phdr(findLibRelease, NULL); } #elif defined(_WIN32) -static void registerExternalModules() -{ - HMODULE hMods[100]; - HANDLE hProcess = GetCurrentProcess(); - DWORD cbNeeded; - char *location = NULL; - char *p; - char *version; - char *symname; - unsigned int i; - char name[MAX_PATH + 11]; /* get space for library path + "LibRelease" */ - - /* iterate over all loaded libraries */ - if (!EnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded)) - return; - for (i = 0; i < (cbNeeded / sizeof(HMODULE)); i++) - { - /* Get the full path to the module's file. */ - if (!GetModuleFileName(hMods[i], name, MAX_PATH)) - continue; /* no library name */ - name[sizeof(name) - 1] = 0; /* WinXP may not terminate the string */ - p = strrchr(name, '\\'); /* find file name part in "<location>/<module>.dll" */ - if (p) - { - location = name; - } - else - p = name; /* find end of "<location>\\" (if exists) */ - symname = p; - p = strchr(symname, '.'); /* find ".dll" */ - if (p == NULL) - p = symname + strlen(symname); /* no file extension ? */ - memmove(symname + 2, symname, p - symname); /* make room for 0 and '_' */ - *symname++ = 0; /* terminate "<location>/" */ - *symname = '_'; /* prefix module name with '_' */ - strcpy((p += 2), "LibRelease"); /* append "LibRelease" to module name */ - - version = (char *)GetProcAddress(hMods[i], symname); /* find symbol "_<module>LibRelease" */ - if (version) - { - *p = 0; - symname++; /* get "<module>" from "_<module>LibRelease" */ - if ((p = strstr(name, "\\" LIBDIR)) != NULL) - p[1] = 0; /* cut "<location>" before LIBDIR */ - if (getLibVersion(symname) == NULL) - registerModule(symname, version, location); - } +static void registerExternalModules() { + HMODULE hMods[100]; + HANDLE hProcess = GetCurrentProcess(); + DWORD cbNeeded; + char *location = NULL; + char *p; + char *version; + char *symname; + unsigned int i; + char name[MAX_PATH + 11]; /* get space for library path + "LibRelease" */ + + /* iterate over all loaded libraries */ + if (!EnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded)) + return; + for (i = 0; i < (cbNeeded / sizeof(HMODULE)); i++) { + /* Get the full path to the module's file. */ + if (!GetModuleFileName(hMods[i], name, MAX_PATH)) + continue; /* no library name */ + name[sizeof(name) - 1] = 0; /* WinXP may not terminate the string */ + p = strrchr(name, + '\\'); /* find file name part in "<location>/<module>.dll" */ + if (p) { + location = name; + } else + p = name; /* find end of "<location>\\" (if exists) */ + symname = p; + p = strchr(symname, '.'); /* find ".dll" */ + if (p == NULL) + p = symname + strlen(symname); /* no file extension ? */ + memmove(symname + 2, symname, p - symname); /* make room for 0 and '_' */ + *symname++ = 0; /* terminate "<location>/" */ + *symname = '_'; /* prefix module name with '_' */ + strcpy((p += 2), "LibRelease"); /* append "LibRelease" to module name */ + + version = (char *)GetProcAddress( + hMods[i], symname); /* find symbol "_<module>LibRelease" */ + if (version) { + *p = 0; + symname++; /* get "<module>" from "_<module>LibRelease" */ + if ((p = strstr(name, "\\" LIBDIR)) != NULL) + p[1] = 0; /* cut "<location>" before LIBDIR */ + if (getLibVersion(symname) == NULL) + registerModule(symname, version, location); } + } } #else -static void registerExternalModules() -{ - ; -} +static void registerExternalModules() { ; } #endif -size_t foreachLoadedLib(size_t (*func)(const char *name, const char *version, const char *path, void *arg), void *arg) -{ - moduleitem *m; - int result; - - for (m = loadedModules; m; m = m->next) - { - const char *name = m->content; - const char *version = name + strlen(name) + 1; - const char *path = version + strlen(version) + 1; - result = func(name, version, path, arg); - if (result) - return result; - } - return 0; +size_t foreachLoadedLib(size_t (*func)(const char *name, const char *version, + const char *path, void *arg), + void *arg) { + moduleitem *m; + int result; + + for (m = loadedModules; m; m = m->next) { + const char *name = m->content; + const char *version = name + strlen(name) + 1; + const char *path = version + strlen(version) + 1; + result = func(name, version, path, arg); + if (result) + return result; + } + return 0; } -const char *getLibVersion(const char *libname) -{ - moduleitem *m; +const char *getLibVersion(const char *libname) { + moduleitem *m; - for (m = loadedModules; m; m = m->next) - { - if (strcmp(m->content, libname) == 0) - { - return m->content + strlen(m->content) + 1; - } + for (m = loadedModules; m; m = m->next) { + if (strcmp(m->content, libname) == 0) { + return m->content + strlen(m->content) + 1; } - return NULL; + } + return NULL; } -const char *getLibLocation(const char *libname) -{ - moduleitem *m; - char *v; +const char *getLibLocation(const char *libname) { + moduleitem *m; + char *v; - for (m = loadedModules; m; m = m->next) - { - if (strcmp(m->content, libname) == 0) - { - v = m->content + strlen(m->content) + 1; - return v + strlen(v) + 1; - } + for (m = loadedModules; m; m = m->next) { + if (strcmp(m->content, libname) == 0) { + v = m->content + strlen(m->content) + 1; + return v + strlen(v) + 1; } - return NULL; + } + return NULL; } -int libversionShow(const char *outfile) -{ - moduleitem *m; - size_t lm, lv; +int libversionShow(const char *outfile) { + moduleitem *m; + size_t lm, lv; - FILE *out = epicsGetStdout(); + FILE *out = epicsGetStdout(); - if (outfile) - { - out = fopen(outfile, "w"); - if (out == NULL) - { - fprintf(stderr, "can't open %s: %s\n", - outfile, strerror(errno)); - return -1; - } + if (outfile) { + out = fopen(outfile, "w"); + if (out == NULL) { + fprintf(stderr, "can't open %s: %s\n", outfile, strerror(errno)); + return -1; } - for (m = loadedModules; m; m = m->next) - { - lm = strlen(m->content) + 1; - lv = strlen(m->content + lm) + 1; - fprintf(out, "%-*s%-20s %s\n", - (int)maxModuleNameLength, m->content, - m->content + lm, m->content + lm + lv); - } - if (fflush(out) < 0 && outfile) - { - fprintf(stderr, "can't write to %s: %s\n", - outfile, strerror(errno)); - return -1; - } - if (outfile) - fclose(out); - return 0; + } + for (m = loadedModules; m; m = m->next) { + lm = strlen(m->content) + 1; + lv = strlen(m->content + lm) + 1; + fprintf(out, "%-*s%-20s %s\n", (int)maxModuleNameLength, m->content, + m->content + lm, m->content + lm + lv); + } + if (fflush(out) < 0 && outfile) { + fprintf(stderr, "can't write to %s: %s\n", outfile, strerror(errno)); + return -1; + } + if (outfile) + fclose(out); + return 0; } #define MISMATCH -1 @@ -810,121 +761,106 @@ int libversionShow(const char *outfile) #define TESTVERS 2 #define HIGHER 3 -#define debug(...) \ - if (requireDebug) \ - printf(__VA_ARGS__) - -static int compareDigit(int found, int requested, const char *name) -{ - debug("require: compareDigit: found %d, requested %d for digit %s\n", found, requested, name); - if (found < requested) - { - debug("require: compareVersions: MISMATCH too low %s number\n", name); - return MISMATCH; - } - if (found > requested) - { - debug("require: compareVersions: HIGHER %s number\n", name); - return HIGHER; - } - - return MATCH; +#define debug(...) \ + if (requireDebug) \ + printf(__VA_ARGS__) + +static int compareDigit(int found, int requested, const char *name) { + debug("require: compareDigit: found %d, requested %d for digit %s\n", found, + requested, name); + if (found < requested) { + debug("require: compareVersions: MISMATCH too low %s number\n", name); + return MISMATCH; + } + if (found > requested) { + debug("require: compareVersions: HIGHER %s number\n", name); + return HIGHER; + } + + return MATCH; } -static int compareNumericVersion(semver_t *sv_found, semver_t *sv_request, int already_matched) -{ - int match; - - match = compareDigit(sv_found->major, sv_request->major, "major"); - if (match != MATCH) - { - return match; - } - match = compareDigit(sv_found->minor, sv_request->minor, "minor"); - if (match != MATCH) - { - return match; - } - match = compareDigit(sv_found->patch, sv_request->patch, "patch"); - if (match != MATCH) - { - return match; - } +static int compareNumericVersion(semver_t *sv_found, semver_t *sv_request, + int already_matched) { + int match; - if (sv_request->build == -1) - { - if (already_matched) - { - debug("require: compareVersions: No build number requested. Returning HIGHER\n"); - return HIGHER; - } - else - { - debug("require: compareVersions: No build number requested. Returning MATCH\n"); - return MATCH; - } + match = compareDigit(sv_found->major, sv_request->major, "major"); + if (match != MATCH) { + return match; + } + match = compareDigit(sv_found->minor, sv_request->minor, "minor"); + if (match != MATCH) { + return match; + } + match = compareDigit(sv_found->patch, sv_request->patch, "patch"); + if (match != MATCH) { + return match; + } + + if (sv_request->build == -1) { + if (already_matched) { + debug("require: compareVersions: No build number requested. Returning " + "HIGHER\n"); + return HIGHER; + } else { + debug("require: compareVersions: No build number requested. Returning " + "MATCH\n"); + return MATCH; } - return compareDigit(sv_found->build, sv_request->build, "build"); + } + return compareDigit(sv_found->build, sv_request->build, "build"); } /* * Returns if the version <found> is higher than <request>. */ -static int compareVersions(const char *found, const char *request, int already_matched) -{ - semver_t *sv_found, *sv_request; - int match; - - debug("require: compareVersions(found=%s, request=%s)\n", found, request); - - if (request == NULL || request[0] == 0) - { - debug("require: compareVersions: MATCH empty version requested\n"); - return MATCH; - } - if (found == NULL || found[0] == 0) - { - debug("require: compareVersions: MISMATCH empty version found\n"); - return MISMATCH; - } +static int compareVersions(const char *found, const char *request, + int already_matched) { + semver_t *sv_found, *sv_request; + int match; - sv_found = (semver_t *)calloc(1, sizeof(semver_t)); - sv_request = (semver_t *)calloc(1, sizeof(semver_t)); + debug("require: compareVersions(found=%s, request=%s)\n", found, request); - parse_semver(found, sv_found); - parse_semver(request, sv_request); - - // test version, look for exact. - if (strlen(sv_request->test_str) > 0) - { - if (strcmp(found, request) == 0) - { - debug("require: compareVersions: Test version requested and found, matches exactly\n"); - match = EXACT; - } - else if (strlen(sv_found->test_str) > 0) - { - debug("require: compareVersions: Test versions requested and found, no match\n"); - match = MISMATCH; - } - else - { - debug("require: compareVersions: found numeric version, higher than test\n"); - match = HIGHER; - } - } - else if (strlen(sv_found->test_str) > 0) - { - debug("require: compareVersions: Numeric version requested, test version found\n"); - match = MISMATCH; - } - else - { - match = compareNumericVersion(sv_found, sv_request, already_matched); + if (request == NULL || request[0] == 0) { + debug("require: compareVersions: MATCH empty version requested\n"); + return MATCH; + } + if (found == NULL || found[0] == 0) { + debug("require: compareVersions: MISMATCH empty version found\n"); + return MISMATCH; + } + + sv_found = (semver_t *)calloc(1, sizeof(semver_t)); + sv_request = (semver_t *)calloc(1, sizeof(semver_t)); + + parse_semver(found, sv_found); + parse_semver(request, sv_request); + + // test version, look for exact. + if (strlen(sv_request->test_str) > 0) { + if (strcmp(found, request) == 0) { + debug("require: compareVersions: Test version requested and found, " + "matches exactly\n"); + match = EXACT; + } else if (strlen(sv_found->test_str) > 0) { + debug("require: compareVersions: Test versions requested and found, no " + "match\n"); + match = MISMATCH; + } else { + debug("require: compareVersions: found numeric version, higher than " + "test\n"); + match = HIGHER; } - cleanup_semver(sv_found); - cleanup_semver(sv_request); - return match; + } else if (strlen(sv_found->test_str) > 0) { + debug("require: compareVersions: Numeric version requested, test version " + "found\n"); + match = MISMATCH; + } else { + match = compareNumericVersion(sv_found, sv_request, already_matched); + } + cleanup_semver(sv_found); + cleanup_semver(sv_request); + return match; } /* require (module) @@ -939,664 +875,675 @@ it calls epicsExit to abort the application. */ /* wrapper to abort statup script */ -static int require_priv(const char *module, const char *version, const char *args, const char *versionstr); - -int require(const char *module, const char *version, const char *args) -{ - int status; - char *versionstr; - static int firstTime = 1; - - if (firstTime) - { - firstTime = 0; - - set_require_env(); - - putenvprintf("T_A=%s", targetArch); - putenvprintf("EPICS_HOST_ARCH=%s", targetArch); - putenvprintf("EPICS_RELEASE=%s", epicsRelease); - putenvprintf("OS_CLASS=%s", osClass); - } - - if (module == NULL) - { - printf("Usage: require \"<module>\" [, \"<version>\" | \"ifexists\"] [, \"<args>\"]\n"); - printf("Loads " PREFIX "<module>" INFIX EXT " and <libname>.dbd\n"); - printf("And calls <module>_registerRecordDeviceDriver\n"); - printf("If available, runs startup script snippet (only before iocInit)\n"); - return -1; - } - - /* either order for version and args, either may be empty or NULL */ - if (version && strchr(version, '=')) - { - const char *v = version; - version = args; - args = v; - if (requireDebug) - printf("require: swap version and args\n"); - } - - if (version && version[0] == 0) - version = NULL; +static int require_priv(const char *module, const char *version, + const char *args, const char *versionstr); + +int require(const char *module, const char *version, const char *args) { + int status; + char *versionstr; + static int firstTime = 1; + + if (firstTime) { + firstTime = 0; + + set_require_env(); + + putenvprintf("T_A=%s", targetArch); + putenvprintf("EPICS_HOST_ARCH=%s", targetArch); + putenvprintf("EPICS_RELEASE=%s", epicsRelease); + putenvprintf("OS_CLASS=%s", osClass); + } + + if (module == NULL) { + printf("Usage: require \"<module>\" [, \"<version>\" | \"ifexists\"] [, " + "\"<args>\"]\n"); + printf("Loads " PREFIX "<module>" INFIX EXT " and <libname>.dbd\n"); + printf("And calls <module>_registerRecordDeviceDriver\n"); + printf("If available, runs startup script snippet (only before iocInit)\n"); + return -1; + } + + /* either order for version and args, either may be empty or NULL */ + if (version && strchr(version, '=')) { + const char *v = version; + version = args; + args = v; + if (requireDebug) + printf("require: swap version and args\n"); + } - if (version && strcmp(version, "none") == 0) - { - if (requireDebug) - printf("require: skip version=none\n"); - return 0; - } + if (version && version[0] == 0) + version = NULL; - if (version) - { - /* needed for old style only: */ - if (asprintf(&versionstr, "-%s", version) < 0) - return errno; - if (isdigit((unsigned char)version[0]) && version[strlen(version) - 1] == '+') - { - /* - user may give a minimal version (e.g. "1.2.4+") - load highest matching version (here "1.2") and check later - */ - char *p = strrchr(versionstr, '.'); - if (p == NULL) - p = versionstr; - *p = 0; - } - } - else - versionstr = ""; + if (version && strcmp(version, "none") == 0) { if (requireDebug) - printf("require: versionstr = \"%s\"\n", versionstr); - - status = require_priv(module, version, args, versionstr); + printf("require: skip version=none\n"); + return 0; + } + + if (version) { + /* needed for old style only: */ + if (asprintf(&versionstr, "-%s", version) < 0) + return errno; + if (isdigit((unsigned char)version[0]) && + version[strlen(version) - 1] == '+') { + /* + user may give a minimal version (e.g. "1.2.4+") + load highest matching version (here "1.2") and check later + */ + char *p = strrchr(versionstr, '.'); + if (p == NULL) + p = versionstr; + *p = 0; + } + } else + versionstr = ""; + if (requireDebug) + printf("require: versionstr = \"%s\"\n", versionstr); - if (version) - free(versionstr); + status = require_priv(module, version, args, versionstr); - if (status == 0) - return 0; - if (status != -1) - perror("require"); - if (interruptAccept) - return status; + if (version) + free(versionstr); - /* require failed in startup script before iocInit */ - fprintf(stderr, "Aborting startup script\n"); - epicsExit(1); + if (status == 0) + return 0; + if (status != -1) + perror("require"); + if (interruptAccept) return status; + + /* require failed in startup script before iocInit */ + fprintf(stderr, "Aborting startup script\n"); + epicsExit(1); + return status; } -static off_t fileSize(const char *filename) -{ - struct stat filestat; - if (stat(filename, &filestat) != 0) - { - if (requireDebug) - printf("require: %s does not exist\n", filename); - return -1; - } - switch (filestat.st_mode & S_IFMT) - { - case S_IFREG: - if (requireDebug) - printf("require: file %s exists, size %lld bytes\n", - filename, (unsigned long long)filestat.st_size); - return filestat.st_size; - case S_IFDIR: - if (requireDebug) - printf("require: directory %s exists\n", - filename); - return 0; +static off_t fileSize(const char *filename) { + struct stat filestat; + if (stat(filename, &filestat) != 0) { + if (requireDebug) + printf("require: %s does not exist\n", filename); + return -1; + } + switch (filestat.st_mode & S_IFMT) { + case S_IFREG: + if (requireDebug) + printf("require: file %s exists, size %lld bytes\n", filename, + (unsigned long long)filestat.st_size); + return filestat.st_size; + case S_IFDIR: + if (requireDebug) + printf("require: directory %s exists\n", filename); + return 0; #ifdef S_IFBLK - case S_IFBLK: - if (requireDebug) - printf("require: %s is a block device\n", - filename); - return -1; + case S_IFBLK: + if (requireDebug) + printf("require: %s is a block device\n", filename); + return -1; #endif #ifdef S_IFCHR - case S_IFCHR: - if (requireDebug) - printf("require: %s is a character device\n", - filename); - return -1; + case S_IFCHR: + if (requireDebug) + printf("require: %s is a character device\n", filename); + return -1; #endif #ifdef S_IFIFO - case S_IFIFO: - if (requireDebug) - printf("require: %s is a FIFO/pipe\n", - filename); - return -1; + case S_IFIFO: + if (requireDebug) + printf("require: %s is a FIFO/pipe\n", filename); + return -1; #endif #ifdef S_IFSOCK - case S_IFSOCK: - if (requireDebug) - printf("require: %s is a socket\n", - filename); - return -1; + case S_IFSOCK: + if (requireDebug) + printf("require: %s is a socket\n", filename); + return -1; #endif - default: - if (requireDebug) - printf("require: %s is an unknown type of special file\n", - filename); - return -1; - } + default: + if (requireDebug) + printf("require: %s is an unknown type of special file\n", filename); + return -1; + } } #define fileExists(filename) (fileSize(filename) >= 0) #define fileNotEmpty(filename) (fileSize(filename) > 0) -static int handleDependencies(const char *module, char *depfilename) -{ - FILE *depfile; - char buffer[40]; - char *end; /* end of string */ - char *rmodule; /* required module */ - char *rversion; /* required version */ - - if (requireDebug) - printf("require: parsing dependency file %s\n", depfilename); - depfile = fopen(depfilename, "r"); - while (fgets(buffer, sizeof(buffer) - 1, depfile)) - { - rmodule = buffer; - /* ignore leading spaces */ - while (isspace((unsigned char)*rmodule)) - rmodule++; - /* ignore empty lines and comment lines */ - if (*rmodule == 0 || *rmodule == '#') - continue; - /* rmodule at start of module name */ - rversion = rmodule; - /* find end of module name */ - while (*rversion && !isspace((unsigned char)*rversion)) - rversion++; - /* terminate module name */ - *rversion++ = 0; - /* ignore spaces */ - while (isspace((unsigned char)*rversion)) - rversion++; - /* rversion at start of version */ - - if (*rversion) - { - end = rversion; - /* find end of version */ - while (*end && !isspace((unsigned char)*end)) - end++; - - /* add + to numerial versions if not yet there */ - /* - ESS would like to use the MATCH version only, not HIGHER. - In order to touch the PSI code mininaly, disable add + from VERSION from Dep file. - At the same time, ESS use the X.X.X instead of X.X. - Wednesday, May 2 00:12:18 CEST 2018, jhlee - */ - /* - if (*(end-1) != '+' && strspn(rversion, "0123456789.") == (size_t)(end-rversion)) *end++ = '+'; - */ - /* terminate version */ - *end = 0; - } - printf("Module %s depends on %s %s\n", module, rmodule, rversion); - if (require(rmodule, rversion, NULL) != 0) - { - fclose(depfile); - return -1; - } +static int handleDependencies(const char *module, char *depfilename) { + FILE *depfile; + char buffer[40]; + char *end; /* end of string */ + char *rmodule; /* required module */ + char *rversion; /* required version */ + + if (requireDebug) + printf("require: parsing dependency file %s\n", depfilename); + depfile = fopen(depfilename, "r"); + while (fgets(buffer, sizeof(buffer) - 1, depfile)) { + rmodule = buffer; + /* ignore leading spaces */ + while (isspace((unsigned char)*rmodule)) + rmodule++; + /* ignore empty lines and comment lines */ + if (*rmodule == 0 || *rmodule == '#') + continue; + /* rmodule at start of module name */ + rversion = rmodule; + /* find end of module name */ + while (*rversion && !isspace((unsigned char)*rversion)) + rversion++; + /* terminate module name */ + *rversion++ = 0; + /* ignore spaces */ + while (isspace((unsigned char)*rversion)) + rversion++; + /* rversion at start of version */ + + if (*rversion) { + end = rversion; + /* find end of version */ + while (*end && !isspace((unsigned char)*end)) + end++; + + /* add + to numerial versions if not yet there */ + /* + ESS would like to use the MATCH version only, not HIGHER. + In order to touch the PSI code mininaly, disable add + from VERSION from Dep + file. At the same time, ESS use the X.X.X instead of X.X. Wednesday, May 2 + 00:12:18 CEST 2018, jhlee + */ + /* + if (*(end-1) != '+' && strspn(rversion, "0123456789.") == + (size_t)(end-rversion)) *end++ = '+'; +*/ + /* terminate version */ + *end = 0; } - fclose(depfile); - return 0; + printf("Module %s depends on %s %s\n", module, rmodule, rversion); + if (require(rmodule, rversion, NULL) != 0) { + fclose(depfile); + return -1; + } + } + fclose(depfile); + return 0; } static int -require_priv(const char *module, - const char *version, - const char *args, +require_priv(const char *module, const char *version, const char *args, const char *versionstr /* "-<version>" or "" (for old style only */ -) -{ - int status; - const char *loaded = NULL; - const char *found = NULL; - HMODULE libhandle; - int ifexists = 0; - const char *driverpath; - const char *dirname; - const char *end; - - int releasediroffs; - int libdiroffs; - int extoffs; - char *founddir = NULL; - char *symbolname; - char filename[PATH_MAX]; - - int someVersionFound = 0; - int someArchFound = 0; - - static char *globalTemplates = NULL; - - if (requireDebug) - printf("require: module=\"%s\" version=\"%s\" args=\"%s\"\n", module, version, args); +) { + int status; + const char *loaded = NULL; + const char *found = NULL; + HMODULE libhandle; + int ifexists = 0; + const char *driverpath; + const char *dirname; + const char *end; + + int releasediroffs; + int libdiroffs; + int extoffs; + char *founddir = NULL; + char *symbolname; + char filename[PATH_MAX]; + + int someVersionFound = 0; + int someArchFound = 0; + + static char *globalTemplates = NULL; + + if (requireDebug) + printf("require: module=\"%s\" version=\"%s\" args=\"%s\"\n", module, + version, args); #if defined __GNUC__ && __GNUC__ < 3 -#define TRY_FILE(offs, args...) \ - (snprintf(filename + offs, sizeof(filename) - offs, args) && fileExists(filename)) +#define TRY_FILE(offs, args...) \ + (snprintf(filename + offs, sizeof(filename) - offs, args) && \ + fileExists(filename)) -#define TRY_NONEMPTY_FILE(offs, args...) \ - (snprintf(filename + offs, sizeof(filename) - offs, args) && fileNotEmpty(filename)) +#define TRY_NONEMPTY_FILE(offs, args...) \ + (snprintf(filename + offs, sizeof(filename) - offs, args) && \ + fileNotEmpty(filename)) #else -#define TRY_FILE(offs, ...) \ - (snprintf(filename + offs, sizeof(filename) - offs, __VA_ARGS__) && fileExists(filename)) +#define TRY_FILE(offs, ...) \ + (snprintf(filename + offs, sizeof(filename) - offs, __VA_ARGS__) && \ + fileExists(filename)) -#define TRY_NONEMPTY_FILE(offs, ...) \ - (snprintf(filename + offs, sizeof(filename) - offs, __VA_ARGS__) && fileNotEmpty(filename)) +#define TRY_NONEMPTY_FILE(offs, ...) \ + (snprintf(filename + offs, sizeof(filename) - offs, __VA_ARGS__) && \ + fileNotEmpty(filename)) #endif #if defined(_WIN32) - /* enable %n in printf */ - _set_printf_count_output(1); + /* enable %n in printf */ + _set_printf_count_output(1); #endif - driverpath = getenv("EPICS_DRIVER_PATH"); - if (!globalTemplates) - { - char *t = getenv("TEMPLATES"); - if (t) - globalTemplates = strdup(t); + driverpath = getenv("EPICS_DRIVER_PATH"); + if (!globalTemplates) { + char *t = getenv("TEMPLATES"); + if (t) + globalTemplates = strdup(t); + } + + if (driverpath == NULL) + driverpath = "."; + if (requireDebug) + printf("require: searchpath=%s\n", driverpath); + + if (version && strcmp(version, "ifexists") == 0) { + ifexists = 1; + version = NULL; + versionstr = ""; + } + + /* check already loaded verion */ + loaded = getLibVersion(module); + if (loaded) { + /* Library already loaded. Check Version. */ + switch (compareVersions(loaded, version, FALSE)) { + case TESTVERS: + if (version) + printf("Warning: Module %s test version %s already loaded where %s was " + "requested\n", + module, loaded, version); + case EXACT: + case MATCH: + printf("Module %s version %s already loaded\n", module, loaded); + break; + default: + printf("Conflict between requested %s version %s and already loaded " + "version %s.\n", + module, version, loaded); + return -1; } - - if (driverpath == NULL) - driverpath = "."; + dirname = getLibLocation(module); + if (dirname[0] == 0) + return 0; if (requireDebug) - printf("require: searchpath=%s\n", driverpath); - - if (version && strcmp(version, "ifexists") == 0) - { - ifexists = 1; - version = NULL; - versionstr = ""; - } - - /* check already loaded verion */ - loaded = getLibVersion(module); - if (loaded) - { - /* Library already loaded. Check Version. */ - switch (compareVersions(loaded, version, FALSE)) - { - case TESTVERS: - if (version) - printf("Warning: Module %s test version %s already loaded where %s was requested\n", - module, loaded, version); - case EXACT: - case MATCH: - printf("Module %s version %s already loaded\n", module, loaded); - break; - default: - printf("Conflict between requested %s version %s and already loaded version %s.\n", - module, version, loaded); - return -1; - } - dirname = getLibLocation(module); - if (dirname[0] == 0) - return 0; - if (requireDebug) - printf("require: library found in %s\n", dirname); - snprintf(filename, sizeof(filename), "%s%n", dirname, &releasediroffs); - putenvprintf("MODULE=%s", module); - pathAdd("SCRIPT_PATH", dirname); - } - else - { + printf("require: library found in %s\n", dirname); + snprintf(filename, sizeof(filename), "%s%n", dirname, &releasediroffs); + putenvprintf("MODULE=%s", module); + pathAdd("SCRIPT_PATH", dirname); + } else { + if (requireDebug) + printf("require: no %s version loaded yet\n", module); + + /* Search for module in driverpath */ + for (dirname = driverpath; dirname != NULL; dirname = end) { + /* get one directory from driverpath */ + int dirlen; + int modulediroffs; + DIR_HANDLE dir; + DIR_ENTRY direntry; + + end = strchr(dirname, OSI_PATH_LIST_SEPARATOR[0]); + if (end && end[1] == OSI_PATH_SEPARATOR[0] && + end[2] == OSI_PATH_SEPARATOR[0]) /* "http://..." and friends */ + end = strchr(end + 2, OSI_PATH_LIST_SEPARATOR[0]); + if (end) + dirlen = (int)(end++ - dirname); + else + dirlen = (int)strlen(dirname); + if (dirlen == 0) + continue; /* ignore empty driverpath elements */ + + if (requireDebug) + printf("require: trying %.*s\n", dirlen, dirname); + + snprintf(filename, sizeof(filename), + "%.*s" OSI_PATH_SEPARATOR "%s" OSI_PATH_SEPARATOR "%n", dirlen, + dirname, module, &modulediroffs); + dirlen++; + /* filename = "<dirname>/[dirlen]<module>/[modulediroffs]" */ + + /* Does the module directory exist? */ + IF_OPEN_DIR(filename) { if (requireDebug) - printf("require: no %s version loaded yet\n", module); - - /* Search for module in driverpath */ - for (dirname = driverpath; dirname != NULL; dirname = end) - { - /* get one directory from driverpath */ - int dirlen; - int modulediroffs; - DIR_HANDLE dir; - DIR_ENTRY direntry; - - end = strchr(dirname, OSI_PATH_LIST_SEPARATOR[0]); - if (end && end[1] == OSI_PATH_SEPARATOR[0] && end[2] == OSI_PATH_SEPARATOR[0]) /* "http://..." and friends */ - end = strchr(end + 2, OSI_PATH_LIST_SEPARATOR[0]); - if (end) - dirlen = (int)(end++ - dirname); - else - dirlen = (int)strlen(dirname); - if (dirlen == 0) - continue; /* ignore empty driverpath elements */ + printf("require: found directory %s\n", filename); - if (requireDebug) - printf("require: trying %.*s\n", dirlen, dirname); - - snprintf(filename, sizeof(filename), "%.*s" OSI_PATH_SEPARATOR "%s" OSI_PATH_SEPARATOR "%n", - dirlen, dirname, module, &modulediroffs); - dirlen++; - /* filename = "<dirname>/[dirlen]<module>/[modulediroffs]" */ - - /* Does the module directory exist? */ - IF_OPEN_DIR(filename) - { - if (requireDebug) - printf("require: found directory %s\n", filename); - - /* Now look for versions. */ - START_DIR_LOOP - { - char *currentFilename = FILENAME(direntry); - - SKIP_NON_DIR(direntry) - if (currentFilename[0] == '.') - continue; /* ignore hidden directories */ - - someVersionFound = 1; - - /* Look for highest matching version. */ - if (requireDebug) - printf("require: checking version %s against required %s\n", - currentFilename, version); - - switch ((status = compareVersions(currentFilename, version, FALSE))) - { - case TESTVERS: /* test version found */ - case EXACT: /* exact match found */ - case MATCH: /* all given numbers match. */ - { - someArchFound = 1; - - if (requireDebug) - printf("require: %s %s may match %s\n", - module, currentFilename, version); - - /* Check if it has our EPICS version and architecture. */ - /* Even if it has no library, at least it has a dep file in the lib dir */ - - /* Step 1 : library file location */ - /* filename = "<dirname>/[dirlen]<module>/[modulediroffs]" */ - if (!TRY_FILE(modulediroffs, "%s" OSI_PATH_SEPARATOR LIBDIR "%s" OSI_PATH_SEPARATOR, - currentFilename, targetArch)) - /* filename = "<dirname>/[dirlen]<module>/[modulediroffs]<version>/lib/<targetArch>/" */ - { - if (requireDebug) - printf("require: %s %s has no support for %s %s\n", - module, currentFilename, epicsRelease, targetArch); - continue; - } - - if (status == EXACT) - { - if (requireDebug) - printf("require: %s %s matches %s exactly\n", - module, currentFilename, version); - /* We are done. */ - end = NULL; - break; - } - - /* Is it higher than the one we found before? */ - if (found && requireDebug) - printf("require: %s %s support for %s %s found, compare against previously found %s\n", - module, currentFilename, epicsRelease, targetArch, found); - if (!found || compareVersions(currentFilename, found, TRUE) == HIGHER) - { - if (requireDebug) - printf("require: %s %s looks promising\n", module, currentFilename); - break; - } - if (requireDebug) - printf("require: version %s is lower than %s \n", currentFilename, found); - continue; - } - default: - { - if (requireDebug) - printf("require: %s %s does not match %s\n", - module, currentFilename, version); - continue; - } - } - /* we have found something (EXACT or MATCH) */ - free(founddir); - /* filename = "<dirname>/[dirlen]<module>/[modulediroffs]..." */ - if (asprintf(&founddir, "%.*s%s", modulediroffs, filename, currentFilename) < 0) - return errno; - /* founddir = "<dirname>/[dirlen]<module>/[modulediroffs]<version>" */ - found = founddir + modulediroffs; /* version part in the path */ - if (status == EXACT) - break; - } - END_DIR_LOOP - } - else - { - /* filename = "<dirname>/[dirlen]<module>/" */ - if (requireDebug) - printf("require: no %s directory\n", filename); - - /* try local/old style module only if no new style candidate has been found */ - if (!found) - { - /* look for dep file */ - releasediroffs = libdiroffs = dirlen; - if (TRY_FILE(dirlen, "%s%s.dep", module, versionstr)) - /* filename = "<dirname>/[dirlen][releasediroffs][libdiroffs]<module>(-<version>)?.dep" */ - { - if (requireDebug) - printf("require: found old style %s\n", filename); - printf("Module %s%s found in %.*s\n", module, - versionstr, dirlen, filename); - goto checkdep; - } - - /* look for library file */ - if (TRY_FILE(dirlen, PREFIX "%s" INFIX "%s%n" EXT, module, versionstr, &extoffs) - /* filename = "<dirname>/[dirlen][releasediroffs][libdiroffs]PREFIX<module>INFIX(-<version>)?[extoffs]EXT" */ - ) - { - if (requireDebug) - printf("require: found old style %s\n", filename); - printf("Module %s%s found in %.*s\n", module, - versionstr, dirlen, filename); - goto loadlib; - } - } - } - /* filename = "<dirname>/[dirlen]..." */ - if (!found && requireDebug) - printf("require: no matching version in %.*s\n", dirlen, filename); - } + /* Now look for versions. */ + START_DIR_LOOP { + char *currentFilename = FILENAME(direntry); - if (!found) - { - if (someArchFound) - fprintf(stderr, "Module %s%s%s not available for %s\n(but maybe for other EPICS versions or architectures)\n", - module, version ? " version " : "", version ? version : "", targetArch); - else if (someVersionFound) - fprintf(stderr, "Module %s%s%s not available (but other versions are available)\n", - module, version ? " version " : "", version ? version : ""); - else - fprintf(stderr, "Module %s%s%s not available\n", - module, version ? " version " : "", version ? version : ""); - return ifexists ? 0 : -1; - } + SKIP_NON_DIR(direntry) + if (currentFilename[0] == '.') + continue; /* ignore hidden directories */ - versionstr = ""; + someVersionFound = 1; - /* founddir = "<dirname>/[dirlen]<module>/<version>" */ - printf("Module %s version %s found in %s" OSI_PATH_SEPARATOR "\n", module, found, founddir); + /* Look for highest matching version. */ + if (requireDebug) + printf("require: checking version %s against required %s\n", + currentFilename, version); - /* Step 2 : Looking for Dep file */ - if (requireDebug) - printf("require: looking for dependency file\n"); + switch ((status = compareVersions(currentFilename, version, FALSE))) { + case TESTVERS: /* test version found */ + case EXACT: /* exact match found */ + case MATCH: /* all given numbers match. */ + { + someArchFound = 1; - if (!TRY_FILE(0, "%s" OSI_PATH_SEPARATOR "%n" LIBDIR "%s" OSI_PATH_SEPARATOR "%n%s.dep", - founddir, &releasediroffs, targetArch, &libdiroffs, module)) - /* filename = "<dirname>/[dirlen]<module>/<version>/R<epicsRelease>/[releasediroffs]/lib/<targetArch>/[libdiroffs]/module.dep" */ - { - fprintf(stderr, "Dependency file %s not found\n", filename); - } - else - { - checkdep: - /* filename = "<dirname>/[dirlen]<module>/<version>/R<epicsRelease>/[releasediroffs]/lib/<targetArch>/[libdiroffs]/module.dep" */ - /* or (old) "<dirname>/[dirlen]][releasediroffs][libdiroffs]<module>(-<version>)?.dep" */ - if (handleDependencies(module, filename) == -1) - return -1; - } + if (requireDebug) + printf("require: %s %s may match %s\n", module, currentFilename, + version); - if (requireDebug) - printf("require: looking for library file\n"); + /* Check if it has our EPICS version and architecture. */ + /* Even if it has no library, at least it has a dep file in the lib + * dir */ - if (!(TRY_FILE(libdiroffs, PREFIX "%s" INFIX "%s%n" EXT, module, versionstr, &extoffs))) - /* filename = "<dirname>/[dirlen]<module>/<version>/R<epicsRelease>/[releasediroffs]/lib/<targetArch>/[libdiroffs]/PREFIX<module>INFIX[extoffs](EXT)?" */ - /* or (old) "<dirname>/[dirlen][releasediroffs][libdiroffs]PREFIX<module>INFIX(-<version>)?[extoffs](EXT)?" */ - { - printf("Module %s has no library\n", module); - } - else - { - loadlib: - /* filename = "<dirname>/[dirlen]<module>/<version>/R<epicsRelease>/[releasediroffs]/lib/<targetArch>/[libdiroffs]/PREFIX<module>INFIX[extoffs]EXT" */ - /* or (old) "<dirname>/[dirlen][releasediroffs][libdiroffs]PREFIX<module>INFIX(-<version>)?[extoffs]EXT" */ - printf("Loading library %s\n", filename); - if ((libhandle = loadlib(filename)) == NULL) - return -1; - - /* now check what version we really got (with compiled-in version number) */ - if (asprintf(&symbolname, "_%sLibRelease", module) < 0) - return errno; - - found = (const char *)getAddress(libhandle, symbolname); - free(symbolname); - printf("Loaded %s version %s\n", module, found); - - /* check what we got */ - if (requireDebug) - printf("require: compare requested version %s with loaded version %s\n", version, found); - if (compareVersions(found, version, FALSE) == MISMATCH) + /* Step 1 : library file location */ + /* filename = "<dirname>/[dirlen]<module>/[modulediroffs]" */ + if (!TRY_FILE(modulediroffs, + "%s" OSI_PATH_SEPARATOR LIBDIR + "%s" OSI_PATH_SEPARATOR, + currentFilename, targetArch)) + /* filename = + "<dirname>/[dirlen]<module>/[modulediroffs]<version>/lib/<targetArch>/" + */ { - fprintf(stderr, "Requested %s version %s not available, found only %s.\n", - module, version, found); - return -1; + if (requireDebug) + printf("require: %s %s has no support for %s %s\n", module, + currentFilename, epicsRelease, targetArch); + continue; } - /* load dbd file */ - if (TRY_NONEMPTY_FILE(releasediroffs, "dbd" OSI_PATH_SEPARATOR "%s%s.dbd", module, versionstr) || - TRY_NONEMPTY_FILE(releasediroffs, "%s%s.dbd", module, versionstr) || - TRY_NONEMPTY_FILE(releasediroffs, ".." OSI_PATH_SEPARATOR "dbd" OSI_PATH_SEPARATOR "%s%s.dbd", module, versionstr) || - TRY_NONEMPTY_FILE(releasediroffs, ".." OSI_PATH_SEPARATOR "%s%s.dbd", module, versionstr) || - TRY_NONEMPTY_FILE(releasediroffs, ".." OSI_PATH_SEPARATOR ".." OSI_PATH_SEPARATOR "dbd" OSI_PATH_SEPARATOR "%s.dbd", module)) /* org EPICSbase */ - { - printf("Loading dbd file %s\n", filename); - if (dbLoadDatabase(filename, NULL, NULL) != 0) - { - fprintf(stderr, "Error loading %s\n", filename); - return -1; - } - - /* when dbd is loaded call register function */ - if (asprintf(&symbolname, "%s_registerRecordDeviceDriver", module) < 0) - return errno; - - printf("Calling function %s\n", symbolname); - iocshCmd(symbolname); - free(symbolname); + if (status == EXACT) { + if (requireDebug) + printf("require: %s %s matches %s exactly\n", module, + currentFilename, version); + /* We are done. */ + end = NULL; + break; } - else - { - /* no dbd file, but that might be OK */ - printf("%s has no dbd file\n", module); + + /* Is it higher than the one we found before? */ + if (found && requireDebug) + printf("require: %s %s support for %s %s found, compare against " + "previously found %s\n", + module, currentFilename, epicsRelease, targetArch, found); + if (!found || + compareVersions(currentFilename, found, TRUE) == HIGHER) { + if (requireDebug) + printf("require: %s %s looks promising\n", module, + currentFilename); + break; } + if (requireDebug) + printf("require: version %s is lower than %s \n", currentFilename, + found); + continue; + } + default: { + if (requireDebug) + printf("require: %s %s does not match %s\n", module, + currentFilename, version); + continue; + } + } + /* we have found something (EXACT or MATCH) */ + free(founddir); + /* filename = "<dirname>/[dirlen]<module>/[modulediroffs]..." */ + if (asprintf(&founddir, "%.*s%s", modulediroffs, filename, + currentFilename) < 0) + return errno; + /* founddir = "<dirname>/[dirlen]<module>/[modulediroffs]<version>" */ + found = founddir + modulediroffs; /* version part in the path */ + if (status == EXACT) + break; + } + END_DIR_LOOP + } + else { + /* filename = "<dirname>/[dirlen]<module>/" */ + if (requireDebug) + printf("require: no %s directory\n", filename); + + /* try local/old style module only if no new style candidate has been + * found */ + if (!found) { + /* look for dep file */ + releasediroffs = libdiroffs = dirlen; + if (TRY_FILE(dirlen, "%s%s.dep", module, versionstr)) + /* filename = + "<dirname>/[dirlen][releasediroffs][libdiroffs]<module>(-<version>)?.dep" + */ + { + if (requireDebug) + printf("require: found old style %s\n", filename); + printf("Module %s%s found in %.*s\n", module, versionstr, dirlen, + filename); + goto checkdep; + } + + /* look for library file */ + if (TRY_FILE(dirlen, PREFIX "%s" INFIX "%s%n" EXT, module, versionstr, + &extoffs) + /* filename = + "<dirname>/[dirlen][releasediroffs][libdiroffs]PREFIX<module>INFIX(-<version>)?[extoffs]EXT" + */ + ) { + if (requireDebug) + printf("require: found old style %s\n", filename); + printf("Module %s%s found in %.*s\n", module, versionstr, dirlen, + filename); + goto loadlib; + } } - /* register module with path */ - filename[releasediroffs] = 0; - registerModule(module, found, filename); + } + /* filename = "<dirname>/[dirlen]..." */ + if (!found && requireDebug) + printf("require: no matching version in %.*s\n", dirlen, filename); } - status = 0; + if (!found) { + if (someArchFound) + fprintf(stderr, + "Module %s%s%s not available for %s\n(but maybe for other " + "EPICS versions or architectures)\n", + module, version ? " version " : "", version ? version : "", + targetArch); + else if (someVersionFound) + fprintf( + stderr, + "Module %s%s%s not available (but other versions are available)\n", + module, version ? " version " : "", version ? version : ""); + else + fprintf(stderr, "Module %s%s%s not available\n", module, + version ? " version " : "", version ? version : ""); + return ifexists ? 0 : -1; + } + + versionstr = ""; + + /* founddir = "<dirname>/[dirlen]<module>/<version>" */ + printf("Module %s version %s found in %s" OSI_PATH_SEPARATOR "\n", module, + found, founddir); + /* Step 2 : Looking for Dep file */ if (requireDebug) - printf("require: looking for template directory\n"); - /* filename = "<dirname>/[dirlen]<module>/<version>/R<epicsRelease>/[releasediroffs]..." */ - if (!((TRY_FILE(releasediroffs, TEMPLATEDIR) || - TRY_FILE(releasediroffs, ".." OSI_PATH_SEPARATOR TEMPLATEDIR)) && - setupDbPath(module, filename) == 0)) + printf("require: looking for dependency file\n"); + + if (!TRY_FILE(0, + "%s" OSI_PATH_SEPARATOR "%n" LIBDIR "%s" OSI_PATH_SEPARATOR + "%n%s.dep", + founddir, &releasediroffs, targetArch, &libdiroffs, module)) + /* filename = + "<dirname>/[dirlen]<module>/<version>/R<epicsRelease>/[releasediroffs]/lib/<targetArch>/[libdiroffs]/module.dep" + */ { - /* if no template directory found, restore TEMPLATES to initial value */ - char *t; - t = getenv("TEMPLATES"); - if (globalTemplates && (!t || strcmp(globalTemplates, t) != 0)) - putenvprintf("TEMPLATES=%s", globalTemplates); + fprintf(stderr, "Dependency file %s not found\n", filename); + } else { + checkdep: + /* filename = + * "<dirname>/[dirlen]<module>/<version>/R<epicsRelease>/[releasediroffs]/lib/<targetArch>/[libdiroffs]/module.dep" + */ + /* or (old) + * "<dirname>/[dirlen]][releasediroffs][libdiroffs]<module>(-<version>)?.dep" + */ + if (handleDependencies(module, filename) == -1) + return -1; } - if (loaded && args == NULL) - return 0; /* no need to execute startup script twice if not with new arguments */ + if (requireDebug) + printf("require: looking for library file\n"); - return status; + if (!(TRY_FILE(libdiroffs, PREFIX "%s" INFIX "%s%n" EXT, module, versionstr, + &extoffs))) + /* filename = + "<dirname>/[dirlen]<module>/<version>/R<epicsRelease>/[releasediroffs]/lib/<targetArch>/[libdiroffs]/PREFIX<module>INFIX[extoffs](EXT)?" + */ + /* or (old) + "<dirname>/[dirlen][releasediroffs][libdiroffs]PREFIX<module>INFIX(-<version>)?[extoffs](EXT)?" + */ + { + printf("Module %s has no library\n", module); + } else { + loadlib: + /* filename = + * "<dirname>/[dirlen]<module>/<version>/R<epicsRelease>/[releasediroffs]/lib/<targetArch>/[libdiroffs]/PREFIX<module>INFIX[extoffs]EXT" + */ + /* or (old) + * "<dirname>/[dirlen][releasediroffs][libdiroffs]PREFIX<module>INFIX(-<version>)?[extoffs]EXT" + */ + printf("Loading library %s\n", filename); + if ((libhandle = loadlib(filename)) == NULL) + return -1; + + /* now check what version we really got (with compiled-in version number) + */ + if (asprintf(&symbolname, "_%sLibRelease", module) < 0) + return errno; + + found = (const char *)getAddress(libhandle, symbolname); + free(symbolname); + printf("Loaded %s version %s\n", module, found); + + /* check what we got */ + if (requireDebug) + printf("require: compare requested version %s with loaded version %s\n", + version, found); + if (compareVersions(found, version, FALSE) == MISMATCH) { + fprintf(stderr, + "Requested %s version %s not available, found only %s.\n", + module, version, found); + return -1; + } + + /* load dbd file */ + if (TRY_NONEMPTY_FILE(releasediroffs, "dbd" OSI_PATH_SEPARATOR "%s%s.dbd", + module, versionstr) || + TRY_NONEMPTY_FILE(releasediroffs, "%s%s.dbd", module, versionstr) || + TRY_NONEMPTY_FILE(releasediroffs, + ".." OSI_PATH_SEPARATOR "dbd" OSI_PATH_SEPARATOR + "%s%s.dbd", + module, versionstr) || + TRY_NONEMPTY_FILE(releasediroffs, ".." OSI_PATH_SEPARATOR "%s%s.dbd", + module, versionstr) || + TRY_NONEMPTY_FILE(releasediroffs, + ".." OSI_PATH_SEPARATOR ".." OSI_PATH_SEPARATOR + "dbd" OSI_PATH_SEPARATOR "%s.dbd", + module)) /* org EPICSbase */ + { + printf("Loading dbd file %s\n", filename); + if (dbLoadDatabase(filename, NULL, NULL) != 0) { + fprintf(stderr, "Error loading %s\n", filename); + return -1; + } + + /* when dbd is loaded call register function */ + if (asprintf(&symbolname, "%s_registerRecordDeviceDriver", module) < 0) + return errno; + + printf("Calling function %s\n", symbolname); + iocshCmd(symbolname); + free(symbolname); + } else { + /* no dbd file, but that might be OK */ + printf("%s has no dbd file\n", module); + } + } + /* register module with path */ + filename[releasediroffs] = 0; + registerModule(module, found, filename); + } + + status = 0; + + if (requireDebug) + printf("require: looking for template directory\n"); + /* filename = + * "<dirname>/[dirlen]<module>/<version>/R<epicsRelease>/[releasediroffs]..." + */ + if (!((TRY_FILE(releasediroffs, TEMPLATEDIR) || + TRY_FILE(releasediroffs, ".." OSI_PATH_SEPARATOR TEMPLATEDIR)) && + setupDbPath(module, filename) == 0)) { + /* if no template directory found, restore TEMPLATES to initial value */ + char *t; + t = getenv("TEMPLATES"); + if (globalTemplates && (!t || strcmp(globalTemplates, t) != 0)) + putenvprintf("TEMPLATES=%s", globalTemplates); + } + + if (loaded && args == NULL) + return 0; /* no need to execute startup script twice if not with new + arguments */ + + return status; } static const iocshFuncDef requireDef = { - "require", 3, (const iocshArg *[]){ - &(iocshArg){"module", iocshArgString}, - &(iocshArg){"[version]", iocshArgString}, - &(iocshArg){"[substitutions]", iocshArgString}, - }}; - -static void requireFunc(const iocshArgBuf *args) -{ - require(args[0].sval, args[1].sval, args[2].sval); + "require", 3, + (const iocshArg *[]){ + &(iocshArg){"module", iocshArgString}, + &(iocshArg){"[version]", iocshArgString}, + &(iocshArg){"[substitutions]", iocshArgString}, + }}; + +static void requireFunc(const iocshArgBuf *args) { + require(args[0].sval, args[1].sval, args[2].sval); } static const iocshFuncDef libversionShowDef = { - "libversionShow", 1, (const iocshArg *[]){ - &(iocshArg){"outputfile", iocshArgString}, - }}; + "libversionShow", 1, + (const iocshArg *[]){ + &(iocshArg){"outputfile", iocshArgString}, + }}; -static void libversionShowFunc(const iocshArgBuf *args) -{ - libversionShow(args[0].sval); +static void libversionShowFunc(const iocshArgBuf *args) { + libversionShow(args[0].sval); } -static const iocshFuncDef ldDef = { - "ld", 1, (const iocshArg *[]){ - &(iocshArg){"library", iocshArgString}, - }}; +static const iocshFuncDef ldDef = {"ld", 1, + (const iocshArg *[]){ + &(iocshArg){"library", iocshArgString}, + }}; -static void ldFunc(const iocshArgBuf *args) -{ - loadlib(args[0].sval); -} +static void ldFunc(const iocshArgBuf *args) { loadlib(args[0].sval); } static const iocshFuncDef pathAddDef = { - "pathAdd", 2, (const iocshArg *[]){ - &(iocshArg){"ENV_VARIABLE", iocshArgString}, - &(iocshArg){"directory", iocshArgString}, - }}; - -static void pathAddFunc(const iocshArgBuf *args) -{ - pathAdd(args[0].sval, args[1].sval); + "pathAdd", 2, + (const iocshArg *[]){ + &(iocshArg){"ENV_VARIABLE", iocshArgString}, + &(iocshArg){"directory", iocshArgString}, + }}; + +static void pathAddFunc(const iocshArgBuf *args) { + pathAdd(args[0].sval, args[1].sval); } -static void requireRegister(void) -{ - static int firstTime = 1; - if (firstTime) - { - firstTime = 0; - iocshRegister(&requireDef, requireFunc); - iocshRegister(&libversionShowDef, libversionShowFunc); - iocshRegister(&ldDef, ldFunc); - iocshRegister(&pathAddDef, pathAddFunc); - registerExternalModules(); - } +static void requireRegister(void) { + static int firstTime = 1; + if (firstTime) { + firstTime = 0; + iocshRegister(&requireDef, requireFunc); + iocshRegister(&libversionShowDef, libversionShowFunc); + iocshRegister(&ldDef, ldFunc); + iocshRegister(&pathAddDef, pathAddFunc); + registerExternalModules(); + } } epicsExportRegistrar(requireRegister); diff --git a/require-ess/src/require.h b/require-ess/src/require.h index 59d89b00..59224c9f 100644 --- a/require-ess/src/require.h +++ b/require-ess/src/require.h @@ -9,14 +9,17 @@ extern "C" { #define __attribute__(dummy) #endif -int require(const char* libname, const char* version, const char* args); -size_t foreachLoadedLib(size_t (*func)(const char* name, const char* version, const char* path, void* arg), void* arg); -const char* getLibVersion(const char* libname); -const char* getLibLocation(const char* libname); -int libversionShow(const char* outfile); -int runScript(const char* filename, const char* args); -int putenvprintf(const char* format, ...) __attribute__((__format__(__printf__,1,2))); -void pathAdd(const char* varname, const char* dirname); +int require(const char *libname, const char *version, const char *args); +size_t foreachLoadedLib(size_t (*func)(const char *name, const char *version, + const char *path, void *arg), + void *arg); +const char *getLibVersion(const char *libname); +const char *getLibLocation(const char *libname); +int libversionShow(const char *outfile); +int runScript(const char *filename, const char *args); +int putenvprintf(const char *format, ...) + __attribute__((__format__(__printf__, 1, 2))); +void pathAdd(const char *varname, const char *dirname); #ifdef __cplusplus } diff --git a/require-ess/src/runScript.c b/require-ess/src/runScript.c index e771e2ae..789e28d2 100644 --- a/require-ess/src/runScript.c +++ b/require-ess/src/runScript.c @@ -1,310 +1,331 @@ #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <stdarg.h> #include <ctype.h> -#include <errno.h> -#include <macLib.h> #include <dbAccess.h> -#include <initHooks.h> #include <epicsVersion.h> +#include <errno.h> +#include <initHooks.h> +#include <macLib.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> -#define EPICSVER EPICS_VERSION*10000+EPICS_REVISION*100+EPICS_MODIFICATION +#define EPICSVER \ + EPICS_VERSION * 10000 + EPICS_REVISION * 100 + EPICS_MODIFICATION -#if defined (_WIN32) +#if defined(_WIN32) #include "asprintf.h" #endif -#include <osiFileName.h> #include <iocsh.h> +#include <osiFileName.h> epicsShareFunc int epicsShareAPI iocshCmd(const char *cmd); #include <epicsExport.h> -#define IS_ABS_PATH(filename) (filename[0] == OSI_PATH_SEPARATOR[0]) /* may be different for other OS ? */ +#define IS_ABS_PATH(filename) \ + (filename[0] == OSI_PATH_SEPARATOR[0]) /* may be different for other OS ? */ #include "expr.h" #include "require.h" -#define SAVEENV(var) do { old_##var = getenv(#var); if (old_##var) old_##var=strdup(old_##var); } while(0) -#define RESTOREENV(var) do { if(old_##var) { putenvprintf("%s=%s", #var, old_##var); free(old_##var); }} while(0) - -int runScriptDebug=0; - -int runScript(const char* filename, const char* args) -{ - MAC_HANDLE *mac = NULL; - FILE* file = NULL; - char* line_raw = NULL; - char* line_exp = NULL; - long line_raw_size = 256; - long line_exp_size = line_raw_size; - long len; - char** pairs; - int status = 0; - char* old_MODULE = NULL; - char* old_MODULE_DIR = NULL; - - if (!filename) - { - fprintf(stderr, "Usage: runScript filename [macro=value,...]\n"); - return -1; - } - - if (macCreateHandle(&mac,(const char*[]){ "", "environ", NULL, NULL }) != 0) goto error; - macSuppressWarning(mac, 1); - - if ((line_exp = malloc(line_exp_size)) == NULL) goto error; - if ((line_raw = malloc(line_raw_size)) == NULL) goto error; - - /* add args to macro definitions */ - if (args) - { - if (runScriptDebug) - printf("runScript: macParseDefns \"%s\"\n", args); - macParseDefns(mac, (char*)args, &pairs); - macInstallMacros(mac, pairs); - free(pairs); +#define SAVEENV(var) \ + do { \ + old_##var = getenv(#var); \ + if (old_##var) \ + old_##var = strdup(old_##var); \ + } while (0) +#define RESTOREENV(var) \ + do { \ + if (old_##var) { \ + putenvprintf("%s=%s", #var, old_##var); \ + free(old_##var); \ + } \ + } while (0) + +int runScriptDebug = 0; + +int runScript(const char *filename, const char *args) { + MAC_HANDLE *mac = NULL; + FILE *file = NULL; + char *line_raw = NULL; + char *line_exp = NULL; + long line_raw_size = 256; + long line_exp_size = line_raw_size; + long len; + char **pairs; + int status = 0; + char *old_MODULE = NULL; + char *old_MODULE_DIR = NULL; + + if (!filename) { + fprintf(stderr, "Usage: runScript filename [macro=value,...]\n"); + return -1; + } + + if (macCreateHandle(&mac, (const char *[]){"", "environ", NULL, NULL}) != 0) + goto error; + macSuppressWarning(mac, 1); + + if ((line_exp = malloc(line_exp_size)) == NULL) + goto error; + if ((line_raw = malloc(line_raw_size)) == NULL) + goto error; + + /* add args to macro definitions */ + if (args) { + if (runScriptDebug) + printf("runScript: macParseDefns \"%s\"\n", args); + macParseDefns(mac, (char *)args, &pairs); + macInstallMacros(mac, pairs); + free(pairs); + } + + if (IS_ABS_PATH(filename)) { + file = fopen(filename, "r"); + } else { + const char *dirname; + const char *end; + char *fullname; + const char *path = getenv("SCRIPT_PATH"); + int dirlen; + + for (dirname = path; dirname != NULL; dirname = end) { + end = strchr(dirname, OSI_PATH_LIST_SEPARATOR[0]); + if (end && end[1] == OSI_PATH_SEPARATOR[0] && + end[2] == OSI_PATH_SEPARATOR[0]) /* "http://..." and friends */ + end = strchr(end + 2, OSI_PATH_LIST_SEPARATOR[0]); + if (end) + dirlen = (int)(end++ - dirname); + else + dirlen = (int)strlen(dirname); + if (dirlen == 0) + continue; /* ignore empty path elements */ + if (dirname[dirlen - 1] == OSI_PATH_SEPARATOR[0]) + dirlen--; + asprintf(&fullname, "%.*s" OSI_PATH_SEPARATOR "%s", dirlen, dirname, + filename); + if (runScriptDebug) + printf("runScript: trying %s\n", fullname); + file = fopen(fullname, "r"); + if (!file && (errno & 0xffff) != ENOENT) + perror(fullname); + free(fullname); + if (file) + break; } - - if (IS_ABS_PATH(filename)) - { - file = fopen(filename, "r"); + } + if (file == NULL) { + perror(filename); + return errno; + } + + /* save some environments variables */ + SAVEENV(MODULE); + SAVEENV(MODULE_DIR); + + /* execute script line by line after expanding macros with arguments or + * environment */ + while (fgets(line_raw, line_raw_size, file)) { + char *p, *x; + + /* check if we have a line longer than the buffer size */ + while (line_raw[(len = (long)strlen(line_raw)) - 1] != '\n' && + !feof(file)) { + if (runScriptDebug) + printf("runScript partial line: \"%s\"\n", line_raw); + if ((line_raw = realloc(line_raw, line_raw_size *= 2)) == NULL) + goto error; + if (fgets(line_raw + len, line_raw_size - len, file) == NULL) + break; } - else - { - const char* dirname; - const char* end; - char* fullname; - const char* path = getenv("SCRIPT_PATH"); - int dirlen; - - for (dirname = path; dirname != NULL; dirname = end) - { - end = strchr(dirname, OSI_PATH_LIST_SEPARATOR[0]); - if (end && end[1] == OSI_PATH_SEPARATOR[0] && end[2] == OSI_PATH_SEPARATOR[0]) /* "http://..." and friends */ - end = strchr(end+2, OSI_PATH_LIST_SEPARATOR[0]); - if (end) dirlen = (int)(end++ - dirname); - else dirlen = (int)strlen(dirname); - if (dirlen == 0) continue; /* ignore empty path elements */ - if (dirname[dirlen-1] == OSI_PATH_SEPARATOR[0]) dirlen--; - asprintf(&fullname, "%.*s" OSI_PATH_SEPARATOR "%s", - dirlen, dirname, filename); - if (runScriptDebug) - printf("runScript: trying %s\n", fullname); - file = fopen(fullname, "r"); - if (!file && (errno & 0xffff) != ENOENT) perror(fullname); - free(fullname); - if (file) break; - } + while (len > 0 && isspace((unsigned char)line_raw[len - 1])) + line_raw[--len] = 0; /* get rid of '\n' and friends */ + if (runScriptDebug) + printf("runScript raw line (%ld chars): '%s'\n", len, line_raw); + /* expand and check the buffer size (different epics versions write + * different may number of bytes)*/ + while ((len = labs( + macExpandString(mac, line_raw, line_exp, line_exp_size - 1))) >= + line_exp_size - 2) { + if (runScriptDebug) + printf("runScript: grow expand buffer: len=%ld size=%ld\n", len, + line_exp_size); + free(line_exp); + if ((line_exp = malloc(line_exp_size *= 2)) == NULL) + goto error; } - if (file == NULL) { perror(filename); return errno; } - - /* save some environments variables */ - SAVEENV(MODULE); - SAVEENV(MODULE_DIR); - - /* execute script line by line after expanding macros with arguments or environment */ - while (fgets(line_raw, line_raw_size, file)) - { - char* p, *x; - - /* check if we have a line longer than the buffer size */ - while (line_raw[(len = (long)strlen(line_raw))-1] != '\n' && !feof(file)) - { - if (runScriptDebug) - printf("runScript partial line: \"%s\"\n", line_raw); - if ((line_raw = realloc(line_raw, line_raw_size *= 2)) == NULL) goto error; - if (fgets(line_raw + len, line_raw_size - len, file) == NULL) break; - } - while (len > 0 && isspace((unsigned char)line_raw[len-1])) line_raw[--len] = 0; /* get rid of '\n' and friends */ - if (runScriptDebug) - printf("runScript raw line (%ld chars): '%s'\n", len, line_raw); - /* expand and check the buffer size (different epics versions write different may number of bytes)*/ - while ((len = labs(macExpandString(mac, line_raw, line_exp, line_exp_size-1))) >= line_exp_size-2) - { - if (runScriptDebug) - printf("runScript: grow expand buffer: len=%ld size=%ld\n", len, line_exp_size); - free(line_exp); - if ((line_exp = malloc(line_exp_size *= 2)) == NULL) goto error; - } - if (runScriptDebug) - printf("runScript expanded line (%ld chars): '%s'\n", len, line_exp); - printf("%s\n", line_exp); - p = line_exp; - while (isspace((unsigned char)*p)) p++; - if (*p == 0 || *p == '#') continue; - - /* find local variable assignments */ - if ((x = strpbrk(p, "=(, \t\n\r")) != NULL && *x=='=') - { - *x++ = 0; - replaceExpressions(x, line_raw, line_raw_size); - if (runScriptDebug) - printf("runScript: assign %s=%s\n", p, line_raw); - macPutValue(mac, p, line_raw); - continue; - } - if (runScriptDebug) - printf("runScript: iocshCmd: '%s'\n", line_exp); - status = iocshCmd(line_exp); - if (status != 0) break; + if (runScriptDebug) + printf("runScript expanded line (%ld chars): '%s'\n", len, line_exp); + printf("%s\n", line_exp); + p = line_exp; + while (isspace((unsigned char)*p)) + p++; + if (*p == 0 || *p == '#') + continue; + + /* find local variable assignments */ + if ((x = strpbrk(p, "=(, \t\n\r")) != NULL && *x == '=') { + *x++ = 0; + replaceExpressions(x, line_raw, line_raw_size); + if (runScriptDebug) + printf("runScript: assign %s=%s\n", p, line_raw); + macPutValue(mac, p, line_raw); + continue; } - goto end; + if (runScriptDebug) + printf("runScript: iocshCmd: '%s'\n", line_exp); + status = iocshCmd(line_exp); + if (status != 0) + break; + } + goto end; error: - if (errno) - { - status = errno; - perror("runScript"); - } + if (errno) { + status = errno; + perror("runScript"); + } end: - free(line_raw); - free(line_exp); - if (mac) macDeleteHandle(mac); - if (file) fclose(file); + free(line_raw); + free(line_exp); + if (mac) + macDeleteHandle(mac); + if (file) + fclose(file); + + /* restore environment */ + RESTOREENV(MODULE); + RESTOREENV(MODULE_DIR); + + return status; +} - /* restore environment */ - RESTOREENV(MODULE); - RESTOREENV(MODULE_DIR); +struct cmditem { + struct cmditem *next; + int type; + union { + char *a[12]; + char cmd[256]; + } x; +} * cmdlist, **cmdlast = &cmdlist; - return status; -} +void afterInitHook(initHookState state) { + struct cmditem *item; -struct cmditem -{ - struct cmditem* next; - int type; - union { - char* a[12]; - char cmd[256]; - } x; -} *cmdlist, **cmdlast=&cmdlist; - -void afterInitHook(initHookState state) -{ - struct cmditem *item; - - if (state != + if (state != #ifdef INCinitHooksh - /* old: without iocPause etc */ - initHookAfterInterruptAccept + /* old: without iocPause etc */ + initHookAfterInterruptAccept #else - /* new: with iocPause etc */ - initHookAfterIocRunning + /* new: with iocPause etc */ + initHookAfterIocRunning #endif - ) return; - for (item = cmdlist; item != NULL; item = item->next) - { - if (item->type == 1) - { - printf("%s\n", item->x.cmd); - iocshCmd(item->x.cmd); - } - else - ((void (*)())item->x.a[0])(item->x.a[1], item->x.a[2], item->x.a[3], item->x.a[4], item->x.a[5], - item->x.a[6], item->x.a[7], item->x.a[8], item->x.a[9], item->x.a[10], item->x.a[11]); - } + ) + return; + for (item = cmdlist; item != NULL; item = item->next) { + if (item->type == 1) { + printf("%s\n", item->x.cmd); + iocshCmd(item->x.cmd); + } else + ((void (*)())item->x.a[0])(item->x.a[1], item->x.a[2], item->x.a[3], + item->x.a[4], item->x.a[5], item->x.a[6], + item->x.a[7], item->x.a[8], item->x.a[9], + item->x.a[10], item->x.a[11]); + } } - static int first_time = 1; -static struct cmditem *newItem(char* cmd, int type) -{ - struct cmditem *item; - if (!cmd) - { - fprintf(stderr, "usage: afterInit command, args...\n"); - return NULL; - } - if (interruptAccept) - { - fprintf(stderr, "afterInit can only be used before iocInit\n"); - return NULL; - } - if (first_time) - { - first_time = 0; - initHookRegister(afterInitHook); - } - item = malloc(sizeof(struct cmditem)); - if (item == NULL) - { - perror("afterInit"); - return NULL; - } - item->type = type; - item->next = NULL; - *cmdlast = item; - cmdlast = &item->next; - return item; +static struct cmditem *newItem(char *cmd, int type) { + struct cmditem *item; + if (!cmd) { + fprintf(stderr, "usage: afterInit command, args...\n"); + return NULL; + } + if (interruptAccept) { + fprintf(stderr, "afterInit can only be used before iocInit\n"); + return NULL; + } + if (first_time) { + first_time = 0; + initHookRegister(afterInitHook); + } + item = malloc(sizeof(struct cmditem)); + if (item == NULL) { + perror("afterInit"); + return NULL; + } + item->type = type; + item->next = NULL; + *cmdlast = item; + cmdlast = &item->next; + return item; } -int afterInit(char* cmd, char* a1, char* a2, char* a3, char* a4, char* a5, char* a6, char* a7, char* a8, char* a9, char* a10, char* a11) -{ - struct cmditem *item = newItem(cmd, 0); - if (!item) return -1; - - item->x.a[0] = cmd; - item->x.a[1] = a1; - item->x.a[2] = a2; - item->x.a[3] = a3; - item->x.a[4] = a4; - item->x.a[5] = a5; - item->x.a[6] = a6; - item->x.a[7] = a7; - item->x.a[8] = a8; - item->x.a[9] = a9; - item->x.a[10] = a10; - item->x.a[11] = a11; - - return 0; +int afterInit(char *cmd, char *a1, char *a2, char *a3, char *a4, char *a5, + char *a6, char *a7, char *a8, char *a9, char *a10, char *a11) { + struct cmditem *item = newItem(cmd, 0); + if (!item) + return -1; + + item->x.a[0] = cmd; + item->x.a[1] = a1; + item->x.a[2] = a2; + item->x.a[3] = a3; + item->x.a[4] = a4; + item->x.a[5] = a5; + item->x.a[6] = a6; + item->x.a[7] = a7; + item->x.a[8] = a8; + item->x.a[9] = a9; + item->x.a[10] = a10; + item->x.a[11] = a11; + + return 0; } epicsExportAddress(int, runScriptDebug); epicsExportAddress(int, exprDebug); static const iocshFuncDef runScriptDef = { - "runScript", 2, (const iocshArg *[]) { - &(iocshArg) { "filename", iocshArgString }, - &(iocshArg) { "substitutions", iocshArgString }, -}}; - -static void runScriptFunc(const iocshArgBuf *args) -{ - runScript(args[0].sval, args[1].sval); + "runScript", 2, + (const iocshArg *[]){ + &(iocshArg){"filename", iocshArgString}, + &(iocshArg){"substitutions", iocshArgString}, + }}; + +static void runScriptFunc(const iocshArgBuf *args) { + runScript(args[0].sval, args[1].sval); } static const iocshFuncDef afterInitDef = { - "afterInit", 1, (const iocshArg *[]) { - &(iocshArg) { "commandline", iocshArgArgv }, -}}; - -static void afterInitFunc(const iocshArgBuf *args) -{ - int i, n; - struct cmditem *item = newItem(args[0].aval.av[1], 1); - if (!item) return; - - n = sprintf(item->x.cmd, "%.255s", args[0].aval.av[1]); - for (i = 2; i < args[0].aval.ac; i++) - { - if (strpbrk(args[0].aval.av[i], " ,\"\\")) - n += sprintf(item->x.cmd+n, " '%.*s'", 255-3-n, args[0].aval.av[i]); - else - n += sprintf(item->x.cmd+n, " %.*s", 255-1-n, args[0].aval.av[i]); - } + "afterInit", 1, + (const iocshArg *[]){ + &(iocshArg){"commandline", iocshArgArgv}, + }}; + +static void afterInitFunc(const iocshArgBuf *args) { + int i, n; + struct cmditem *item = newItem(args[0].aval.av[1], 1); + if (!item) + return; + + n = sprintf(item->x.cmd, "%.255s", args[0].aval.av[1]); + for (i = 2; i < args[0].aval.ac; i++) { + if (strpbrk(args[0].aval.av[i], " ,\"\\")) + n += sprintf(item->x.cmd + n, " '%.*s'", 255 - 3 - n, args[0].aval.av[i]); + else + n += sprintf(item->x.cmd + n, " %.*s", 255 - 1 - n, args[0].aval.av[i]); + } } -static void runScriptRegister(void) -{ - static int firstTime = 1; - if (firstTime) { - firstTime = 0; - iocshRegister (&runScriptDef, runScriptFunc); - iocshRegister (&afterInitDef, afterInitFunc); - } +static void runScriptRegister(void) { + static int firstTime = 1; + if (firstTime) { + firstTime = 0; + iocshRegister(&runScriptDef, runScriptFunc); + iocshRegister(&afterInitDef, afterInitFunc); + } } epicsExportRegistrar(runScriptRegister); diff --git a/require-ess/src/strdup.c b/require-ess/src/strdup.c index 310518e4..598c316c 100644 --- a/require-ess/src/strdup.c +++ b/require-ess/src/strdup.c @@ -1,22 +1,22 @@ -#include <string.h> #include <stdlib.h> +#include <string.h> -char *strdup(const char *s) -{ - char *d = malloc(strlen(s)+1); - if (d) strcpy(d,s); - return d; +char *strdup(const char *s) { + char *d = malloc(strlen(s) + 1); + if (d) + strcpy(d, s); + return d; } -char *strndup(const char *s, size_t n) -{ - size_t l; - char *d; +char *strndup(const char *s, size_t n) { + size_t l; + char *d; - l = strlen(s); - if (n > l) n = l; - d = malloc(n+1); - strncpy(d,s,l); - d[n] = 0; - return d; + l = strlen(s); + if (n > l) + n = l; + d = malloc(n + 1); + strncpy(d, s, l); + d[n] = 0; + return d; } diff --git a/require-ess/src/version.c b/require-ess/src/version.c index 9d716c53..9a66e9b7 100644 --- a/require-ess/src/version.c +++ b/require-ess/src/version.c @@ -1,72 +1,66 @@ +#include "version.h" #include <regex.h> +#include <stdio.h> #include <stdlib.h> #include <string.h> -#include <stdio.h> -#include "version.h" -void cleanup_semver(semver_t *s) -{ - free(s->version_str); - free(s); +void cleanup_semver(semver_t *s) { + free(s->version_str); + free(s); } -static void init_semver(const char *version, semver_t *s) -{ - s->version_str = calloc(strlen(version) + 1, sizeof(char)); - strcpy(s->version_str, version); - s->test_str = ""; +static void init_semver(const char *version, semver_t *s) { + s->version_str = calloc(strlen(version) + 1, sizeof(char)); + strcpy(s->version_str, version); + s->test_str = ""; - s->major = 0; - s->minor = 0; - s->patch = 0; - s->build = -1; + s->major = 0; + s->minor = 0; + s->patch = 0; + s->build = -1; } -static void fetch_part(char *version_str, const regmatch_t *groups, unsigned int ix, int *part) -{ - char tmp; +static void fetch_part(char *version_str, const regmatch_t *groups, + unsigned int ix, int *part) { + char tmp; - tmp = version_str[groups[ix].rm_eo]; - version_str[groups[ix].rm_eo] = 0; - *part = atoi(version_str + groups[ix].rm_so); - version_str[groups[ix].rm_eo] = tmp; + tmp = version_str[groups[ix].rm_eo]; + version_str[groups[ix].rm_eo] = 0; + *part = atoi(version_str + groups[ix].rm_so); + version_str[groups[ix].rm_eo] = tmp; } -int parse_semver(const char *version, semver_t *s) -{ - static const char* version_regex = "^(([0-9]+)\\.([0-9]+)\\.([0-9]+)(\\+([0-9]+))?)?(.*)$"; - static const unsigned int max_regex_groups = 7 + 1; - static const unsigned int major_ix = 2; - static const unsigned int minor_ix = 3; - static const unsigned int patch_ix = 4; - static const unsigned int build_ix = 6; - static const unsigned int test_ix = 7; +int parse_semver(const char *version, semver_t *s) { + static const char *version_regex = + "^(([0-9]+)\\.([0-9]+)\\.([0-9]+)(\\+([0-9]+))?)?(.*)$"; + static const unsigned int max_regex_groups = 7 + 1; + static const unsigned int major_ix = 2; + static const unsigned int minor_ix = 3; + static const unsigned int patch_ix = 4; + static const unsigned int build_ix = 6; + static const unsigned int test_ix = 7; - regex_t compiled; - regmatch_t groups[max_regex_groups]; + regex_t compiled; + regmatch_t groups[max_regex_groups]; - init_semver(version, s); + init_semver(version, s); - if (s->version_str == NULL || s->version_str[0] == 0) - { - return 1; - } + if (s->version_str == NULL || s->version_str[0] == 0) { + return 1; + } - if (regcomp(&compiled, version_regex, REG_EXTENDED)) - { - return 1; - } + if (regcomp(&compiled, version_regex, REG_EXTENDED)) { + return 1; + } - if (regexec(&compiled, s->version_str, max_regex_groups, groups, 0) == 0) - { - fetch_part(s->version_str, groups, major_ix, &s->major); - fetch_part(s->version_str, groups, minor_ix, &s->minor); - fetch_part(s->version_str, groups, patch_ix, &s->patch); - if (groups[build_ix].rm_so != (regoff_t)-1) - { - fetch_part(s->version_str, groups, build_ix, &s->build); - } - s->test_str = s->version_str + groups[test_ix].rm_so; + if (regexec(&compiled, s->version_str, max_regex_groups, groups, 0) == 0) { + fetch_part(s->version_str, groups, major_ix, &s->major); + fetch_part(s->version_str, groups, minor_ix, &s->minor); + fetch_part(s->version_str, groups, patch_ix, &s->patch); + if (groups[build_ix].rm_so != (regoff_t)-1) { + fetch_part(s->version_str, groups, build_ix, &s->build); } - return 0; + s->test_str = s->version_str + groups[test_ix].rm_so; + } + return 0; } diff --git a/require-ess/src/version.h b/require-ess/src/version.h index 185c2c53..8f72da6c 100644 --- a/require-ess/src/version.h +++ b/require-ess/src/version.h @@ -1,10 +1,10 @@ typedef struct semver_t { - char *version_str; - int major; - int minor; - int patch; - int build; // can be negative; implies that build has not been specified - char *test_str; + char *version_str; + int major; + int minor; + int patch; + int build; // can be negative; implies that build has not been specified + char *test_str; } semver_t; void cleanup_semver(semver_t *s); -- GitLab