/* Copyright (C) 1988, 1991-2008 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include "system.h" #include "filevercmp.h" #define xisalnum(c) isalnum ((unsigned char) c) #define xisdigit(c) isdigit ((unsigned char) c) #define xisalpha(c) isalpha ((unsigned char) c) int verrevcmp (const char *s1, size_t s1_len, const char *s2, size_t s2_len); const char * match_suffix (const char **str); /* proposed new function to compare version strings (and files with version) This function is supposed to be replacement for STRVERSCMP function. Same parameters and return value as standard STRCMP function. It is based on verrevcmp function from dpkg and improved to deal better with file suffixes. */ int filevercmp (const char *s1, const char *s2) { const char *s1_pos, *s2_pos; const char *s1_suffix, *s2_suffix; int s1_len, s2_len; /* easy comparison to see if versions are identical */ if (!strcmp (s1, s2)) return 0; /* "cut" file suffixes */ s1_pos = s1; s2_pos = s2; s1_suffix = match_suffix (&s1_pos); s2_suffix = match_suffix (&s2_pos); s1_len = (s1_suffix ? s1_suffix : s1_pos) - s1; s2_len = (s2_suffix ? s2_suffix : s2_pos) - s2; /* restore file suffixes if strings are identical after "cut" */ if ((s1_suffix || s2_suffix) && (s1_len == s2_len) && 0 == strncmp (s1, s2, s1_len)) { s1_len = s1_pos - s1; s2_len = s2_pos - s2; } return verrevcmp (s1, s1_len, s2, s2_len); } /* match file suffix defined as RE (\.[A-Za-z][A-Za-z0-9]*)*$ Scan string pointed by *str and return pointer to suffix begin or NULL if not found. Pointer *str points to ending zero of scanned string after return. */ const char * match_suffix (const char **str) { const char *match = NULL; bool read_alpha = false; while (**str) { if (read_alpha) { read_alpha = false; if (!xisalpha (**str)) match = NULL; } else if ('.'==**str) { read_alpha = true; if (!match) match = *str; } else if (!xisalnum (**str)) match = NULL; (*str)++; } return match; } /* verrevcmp helper function */ inline int order (unsigned char c) { if (c == '~') return -1; else if (xisdigit (c)) return 0; else if (xisalpha (c)) return c; else return c + 256; } /* slightly modified ververcmp function from dpkg S1, S2 - compared string S1_LEN, S2_LEN - length of strings to be scanned */ int verrevcmp (const char *s1, size_t s1_len, const char *s2, size_t s2_len) { int s1_pos = 0; int s2_pos = 0; while (s1_pos < s1_len || s2_pos < s2_len) { int first_diff= 0; while ((s1_pos < s1_len && !xisdigit (s1[s1_pos])) || (s2_pos < s2_len && !xisdigit (s2[s2_pos]))) { int s1_c = (s1_pos == s1_len) ? 0 : order (s1[s1_pos]); int s2_c = (s2_pos == s2_len) ? 0 : order (s2[s2_pos]); if (s1_c != s2_c) return s1_c - s2_c; s1_pos++; s2_pos++; } while (s1[s1_pos] == '0') s1_pos++; while (s2[s2_pos] == '0') s2_pos++; while (xisdigit (s1[s1_pos]) && xisdigit (s2[s2_pos])) { if (!first_diff) first_diff = s1[s1_pos] - s2[s2_pos]; s1_pos++; s2_pos++; } if (xisdigit (s1[s1_pos])) return 1; if (xisdigit (s2[s2_pos])) return -1; if (first_diff) return first_diff; } return 0; }