00001 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
00034 
00035 
00036 
00037 
00038 
00039 
00040 
00041 
00042 #include "config.h"
00043 
00044 #include <assert.h>
00045 #include <ctype.h>
00046 #include <stdio.h>
00047 #include <stdlib.h>
00048 #include <string.h>
00049 
00050 #include <discover/discover.h>
00051 
00052 #include <discover/utils.h>
00053 
00055 #define MAXBUFLEN 256
00056 
00058 typedef enum range_states {
00059     START,
00060     OPEN,
00061     VERSION1,
00062     VERSEP1,
00063     PAUSE1,
00064     SEPARATOR,
00065     I, N, F,
00066     VERSION2,
00067     VERSEP2,
00068     PAUSE2,
00069     CLOSE,
00070     ERROR
00071 }
00073 range_state;
00074 
00075 
00076 
00077 
00078 
00079 static int
00080 is_versep_char(char c)
00081 {
00082     return c == '.';
00083 }
00084 
00085 
00086 
00087 
00088 
00089 static int
00090 is_version_char(char c)
00091 {
00092     return isdigit(c);
00093 }
00094 
00095 
00096 
00097 
00098 
00099 
00100 
00101 
00102 
00103 
00104 
00105 
00106 
00107 static int
00108 version_compare(const char *const v1, const char *const v2)
00109 {
00110     int int1, int2;
00111     char *word1, *word2;
00112     char *version1, *version2;
00113     char *buffer1;
00114     char *buffer2;
00115 
00116     if (strcmp(v1, v2) == 0) {
00117         return -1;
00118     }
00119 
00120     if (strcmp(v1, "inf") == 0) {
00121         return 1;
00122     }
00123 
00124     if (strcmp(v2, "inf") == 0) {
00125         return 0;
00126     }
00127 
00128     buffer1 = _discover_xmalloc(MAXBUFLEN);
00129     buffer2 = _discover_xmalloc(MAXBUFLEN);
00130 
00131     version1 = _discover_xstrdup(v1);
00132     version2 = _discover_xstrdup(v2);
00133 
00134     word1 = strtok_r(version1, ".", &buffer1);
00135     word2 = strtok_r(version2, ".", &buffer2);
00136 
00137     do {
00138         sscanf(word1, "%d", &int1);
00139         sscanf(word2, "%d", &int2);
00140 
00141         if (int1 != int2) {
00142             return int1 > int2;
00143         }
00144 
00145         word1 = strtok_r(NULL, ".", &buffer1);
00146         word2 = strtok_r(NULL, ".", &buffer2);
00147 
00148     } while(word1 != NULL && word2 != NULL);
00149 
00150     free(version1);
00151     free(version2);
00152 
00153     if (word2 == NULL && word1 == NULL) {
00154         return -1;
00155     }
00156     if (word2 == NULL) {
00157         return 1;
00158     }
00159     return -0;
00160 }
00161 
00162 
00163 static int
00164 determine_range(char * range_text, char **upper,
00165                 int *upper_inclusive, char **lower, int *lower_inclusive,
00166                 char **next)
00167 {
00168     char *current = range_text;
00169     char c;
00170     char last_char = '\0';
00171 
00172     char buffer1[MAXBUFLEN];
00173     char *bufptr1 = buffer1;
00174 
00175     char buffer2[MAXBUFLEN];
00176     char *bufptr2 = buffer2;
00177 
00178     range_state state = START;
00179     range_state last_good_state = START;
00180     int first_inclusive = -1, second_inclusive = -1;
00181 
00182     while(1) {
00183         c = *current;
00184 
00185         switch(state) {
00186         case START:
00187             if (isspace(c)) {
00188                 state = START;
00189             } else if (c == '(' || c == '[') {
00190                 state = OPEN;
00191             } else {
00192                 last_good_state = state;
00193                 state = ERROR;
00194             }
00195             break;
00196 
00197         case OPEN:
00198             if (last_char == '[') {
00199                 first_inclusive = 1;
00200             } else {
00201                 first_inclusive = 0;
00202             }
00203 
00204             if (isspace(c)) {
00205                 state = OPEN;
00206             } else if (is_version_char(c)) {
00207                 state = VERSION1;
00208             } else {
00209                 last_good_state = state;
00210                 state = ERROR;
00211             }
00212             break;
00213 
00214         case VERSION1:
00215             if (bufptr1 - buffer1 > 254) {
00216                 last_good_state = state;
00217                 state = ERROR;
00218                 break;
00219             }
00220 
00221             *bufptr1 = last_char;
00222             bufptr1++;
00223 
00224             if (isspace(c) || c == ',') {
00225                 *bufptr1 = '\0';
00226 
00227                 if (c == ',') {
00228                     state = SEPARATOR;
00229                 } else {
00230                     state = PAUSE1;
00231                 }
00232             } else if (is_version_char(c)) {
00233                 state = VERSION1;
00234             } else if (is_versep_char(c)) {
00235                 state = VERSEP1;
00236             } else {
00237                 last_good_state = VERSION1;
00238                 state = ERROR;
00239             }
00240             break;
00241 
00242         case VERSEP1:
00243             if (bufptr1 - buffer1 > 254) {
00244                 last_good_state = state;
00245                 state = ERROR;
00246                 break;
00247             }
00248 
00249             *bufptr1 = last_char;
00250             bufptr1++;
00251 
00252             if (is_version_char(c)) {
00253                 state = VERSION1;
00254             } else {
00255                 last_good_state = VERSION1;
00256                 state = ERROR;
00257             }
00258             break;
00259 
00260         case PAUSE1:
00261             if (isspace(c)) {
00262                 state = PAUSE1;
00263             } else if (c == ',') {
00264                 state = SEPARATOR;
00265             } else {
00266                 last_good_state = PAUSE1;
00267                 state = ERROR;
00268             }
00269             break;
00270 
00271         case SEPARATOR:
00272             if (isspace(c)) {
00273                 state = SEPARATOR;
00274             } else if (is_version_char(c)) {
00275                 state = VERSION2;
00276             } else if (c == 'i') {
00277                 state = I;
00278             } else {
00279                 last_good_state = SEPARATOR;
00280                 state = ERROR;
00281             }
00282             break;
00283 
00284         case I:
00285             if (c == 'n') {
00286                 state = N;
00287             } else {
00288                 last_good_state = state;
00289                 state = ERROR;
00290             }
00291             break;
00292 
00293         case N:
00294             if (c == 'f') {
00295                 state = F;
00296             } else {
00297                 last_good_state = state;
00298                 state = ERROR;
00299             }
00300             break;
00301 
00302         case F:
00303             strcpy(bufptr2, "inf");
00304             if (isspace(c)) {
00305                 state = PAUSE2;
00306             } else if (c == ')' || c == ']') {
00307                 state = CLOSE;
00308             } else {
00309                 last_good_state = state;
00310                 state = ERROR;
00311             }
00312             break;
00313 
00314         case VERSION2:
00315             if (bufptr2 - buffer2 > 254) {
00316                 last_good_state = state;
00317                 state = ERROR;
00318                 break;
00319             }
00320 
00321             *bufptr2 = last_char;
00322             bufptr2++;
00323 
00324             if (isspace(c) || c == ')' || c == ']') {
00325                 *bufptr2 = '\0';
00326 
00327                 if (c == ')' || c == ']') {
00328                     state = CLOSE;
00329                 } else {
00330                     state = PAUSE2;
00331                 }
00332             } else if (is_version_char(c)) {
00333                 state = VERSION2;
00334             } else if (is_versep_char(c)) {
00335                 state = VERSEP2;
00336             } else {
00337                 last_good_state = VERSION2;
00338                 state = ERROR;
00339             }
00340             break;
00341 
00342         case VERSEP2:
00343             if (bufptr2 - buffer2 > 254) {
00344                 last_good_state = state;
00345                 state = ERROR;
00346                 break;
00347             }
00348 
00349             *bufptr2 = last_char;
00350             bufptr2++;
00351 
00352             if (is_version_char(c)) {
00353                 state = VERSION2;
00354             } else {
00355                 last_good_state = VERSION2;
00356                 state = ERROR;
00357             }
00358             break;
00359 
00360         case PAUSE2:
00361             if (isspace(c)) {
00362                 state = PAUSE2;
00363             } else if (c == ')' || c == ']') {
00364                 state = CLOSE;
00365             } else {
00366                 last_good_state = PAUSE2;
00367                 state = ERROR;
00368             }
00369             break;
00370 
00371         case CLOSE:
00372             *next = current;
00373 
00374             if (last_char == ')') {
00375                 second_inclusive = 0;
00376             } else if (last_char == ']') {
00377                 second_inclusive = 1;
00378             }
00379 
00380             if (version_compare(buffer1, buffer2) == 1) {
00381                 *upper = _discover_xmalloc(bufptr1 - buffer1 + 1);
00382                 strcpy(*upper, buffer1);
00383                 *upper_inclusive = first_inclusive;
00384 
00385                 *lower = _discover_xmalloc(bufptr2 - buffer2 + 1);
00386                 strcpy(*lower, buffer2);
00387                 *lower_inclusive = second_inclusive;
00388             } else {
00389                 *lower = _discover_xmalloc(bufptr1 - buffer1 + 1);
00390                 strcpy(*lower, buffer1);
00391                 *lower_inclusive = first_inclusive;
00392 
00393                 *upper = _discover_xmalloc(bufptr2 - buffer2 + 1);
00394                 strcpy(*upper, buffer2);
00395                 *upper_inclusive = second_inclusive;
00396             }
00397 
00398             
00399             return 1;
00400 
00401         default:
00402             state = ERROR;
00403             last_good_state = -1;
00404             break;
00405         }
00406 
00407         if (state == ERROR) {
00408             
00409             return 0;
00410         }
00411 
00412         
00413 
00414 
00415 
00416         if (!isspace(*current)) {
00417             last_char = *current;
00418         }
00419 
00420         current++;
00421     }
00422 }
00423 
00437 int
00438 discover_xml_version_cmp(char *range, char *version, discover_error_t *status)
00439 {
00440     char *upper, *lower;
00441     int upper_inclusive, lower_inclusive;
00442     char *next_range;
00443     int range_count = 0;
00444 
00445     assert(range != NULL);
00446     assert(version != NULL);
00447     assert(status != NULL);
00448 
00449     next_range = range;
00450 
00451     while(*next_range != '\0') {
00452         range_count++;
00453         if (determine_range(next_range, &upper, &upper_inclusive,
00454                             &lower, &lower_inclusive, &next_range)) {
00455             
00456 
00457 
00458 
00459 
00460 
00461 
00462 
00463 
00464 
00465 
00466             if (version_compare(version, upper) == -1
00467                 && upper_inclusive) {
00468                 return range_count;
00469             } else if (version_compare(version, lower) == -1
00470                        && lower_inclusive) {
00471                 return range_count;
00472             } else if (version_compare(version, lower) > 0 &&
00473                        version_compare(upper, version) > 0) {
00474                 return range_count;
00475             }
00476 
00477         } else {
00478             status->code = DISCOVER_EBADVERSION;
00479             return -1;
00480         }
00481     }
00482 
00483     return 0;
00484 }
00485