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 <stdio.h>
 #include <setjmp.h>
@@ -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 <hipster / xs4all.nl> 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 <hipster / xs4all.nl>       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 */