From: hipster Date: 2000-10-05T21:40:50+09:00 Subject: [ruby-talk:5307] Re: [PATCH] version test using require On Thu, 05 Oct 2000 04:33:43 +0900, hipster wrote: > The following patch allows testing for a minimal Ruby version using the > `require' statement, like This fixes the problem noted by Guy. I took the logic from Debian dpkg/apt, cut it down and added it to util.c. It's still a bit too generic but it works like a charm. - Michel --- eval.c.orig Thu Oct 5 09:28:07 2000 +++ eval.c Thu Oct 5 14:30:26 2000 @@ -16,6 +16,8 @@ #include "node.h" #include "env.h" #include "rubysig.h" +#include "util.h" +#include "version.h" #include #include @@ -5107,7 +5109,7 @@ rb_f_require(obj, fname) VALUE obj, fname; { - char *ext, *file, *feature, *buf; /* OK */ + char *ext, *file, *feature, *buf, *version; /* OK */ volatile VALUE load; int state; volatile int safe = ruby_safe_level; @@ -5182,6 +5184,24 @@ goto load_dyna; } #endif + + /* check for Ruby version */ + /* Michel van de Ven 20001005 */ + version = "^\\d+(\\.\\d+)*$"; + if(rb_reg_match(rb_reg_new(version, strlen(version), 0), + rb_str_new2(RSTRING(fname)->ptr)) != Qnil) + { + if(version_compare(RSTRING(fname)->ptr, RUBY_VERSION) > 0) + { + fprintf(stderr, + "Ruby %s or later is required to run this script.\n", + RSTRING(fname)->ptr); + rb_exit(1); + } + else + return Qtrue; + } + rb_raise(rb_eLoadError, "No such file to load -- %s", RSTRING(fname)->ptr); --- util.c.orig Thu Jul 27 11:49:24 2000 +++ util.c Thu Oct 5 14:25:44 2000 @@ -770,3 +770,108 @@ return tmp; } + +/* version comparison functions for require, see eval.c */ +/* glarked from apt-0.3.19::version.cc */ +/* Michel van de Ven 20001005 */ +static unsigned long version_str_to_long(const char *begin, const char *end) +{ + char s[40]; + char *i = s; + for (; begin != end && i < s + 40;) + *i++ = *begin++; + *i = 0; + return strtoul(s, 0, 10); +} + +int version_compare(const char *a, const char *b) +{ + const char *aend = a, *bend = b; + const char *lhs = a, *rhs = b; + + aend += strlen(a); + bend += strlen(b); + + if (a >= aend && b >= bend) + return 0; + if (a >= aend) + return -1; + if (b >= bend) + return 1; + + /* Iterate over the whole string + What this does is to spilt the whole string into groups of + numeric and non numeric portions. For instance: + a67bhgs89 + Has 4 portions 'a', '67', 'bhgs', '89'. A more normal: + 2.7.2-linux-1 + Has '2', '.', '7', '.' ,'-linux-','1' */ + while (lhs != aend && rhs != bend){ + /* Starting points */ + const char *slhs = lhs; + const char *srhs = rhs; + int digit; + + /* Compute ending points were we have passed over the portion */ + digit = (isdigit(*lhs) > 0 ? 1 : 0); + for (;lhs != aend && (isdigit(*lhs) > 0 ? 1 : 0) == digit; lhs++); + for (;rhs != bend && (isdigit(*rhs) > 0 ? 1 : 0) == digit; rhs++); + + if (digit == 1){ + unsigned long ilhs, irhs; + /* If the lhs has a digit and the rhs does not then < */ + if (rhs - srhs == 0) + return -1; + + /* Generate integers from the strings. */ + ilhs = version_str_to_long(slhs,lhs); + irhs = version_str_to_long(srhs,rhs); + if (ilhs != irhs){ + if (ilhs > irhs) + return 1; + return -1; + } + } + else{ + /* They are equal length so do a straight text compare */ + for (;slhs != lhs && srhs != rhs; slhs++, srhs++) + { + if (*slhs != *srhs) + { + /* We need to compare non alpha chars as higher than alpha + chars (a < !) */ + int lc = *slhs; + int rc = *srhs; + if (isalpha(lc) == 0) lc += 256; + if (isalpha(rc) == 0) rc += 256; + if (lc > rc) + return 1; + return -1; + } + } + + /* If the lhs is shorter than the right it is 'less' */ + if (lhs - slhs < rhs - srhs) + return -1; + + /* If the lhs is longer than the right it is 'more' */ + if (lhs - slhs > rhs - srhs) + return 1; + } + } + + /* The strings must be equal */ + if (lhs == aend && rhs == bend) + return 0; + + /* lhs is shorter */ + if (lhs == aend) + return -1; + + /* rhs is shorter */ + if (rhs == bend) + return 1; + + /* Shouldnt happen */ + return 1; +} --- util.h.orig Thu Jul 27 11:49:24 2000 +++ util.h Thu Oct 5 12:16:26 2000 @@ -50,4 +50,6 @@ #undef strdup #define strdup(s) ruby_strdup((s)) +int version_compare _((const char*, const char*)); + #endif /* UTIL_H */