Home | History | Annotate | Download | only in lib
      1 /***************************************************************************
      2  *                                  _   _ ____  _
      3  *  Project                     ___| | | |  _ \| |
      4  *                             / __| | | | |_) | |
      5  *                            | (__| |_| |  _ <| |___
      6  *                             \___|\___/|_| \_\_____|
      7  *
      8  * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel (at) haxx.se>, et al.
      9  *
     10  * This software is licensed as described in the file COPYING, which
     11  * you should have received as part of this distribution. The terms
     12  * are also available at https://curl.haxx.se/docs/copyright.html.
     13  *
     14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
     15  * copies of the Software, and permit persons to whom the Software is
     16  * furnished to do so, under the terms of the COPYING file.
     17  *
     18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
     19  * KIND, either express or implied.
     20  *
     21  ***************************************************************************/
     22 
     23 #include "curl_setup.h"
     24 
     25 #include <curl/curl.h>
     26 
     27 #include "strcase.h"
     28 
     29 /* Portable, consistent toupper (remember EBCDIC). Do not use toupper() because
     30    its behavior is altered by the current locale. */
     31 char Curl_raw_toupper(char in)
     32 {
     33 #if !defined(CURL_DOES_CONVERSIONS)
     34   if(in >= 'a' && in <= 'z')
     35     return (char)('A' + in - 'a');
     36 #else
     37   switch (in) {
     38   case 'a':
     39     return 'A';
     40   case 'b':
     41     return 'B';
     42   case 'c':
     43     return 'C';
     44   case 'd':
     45     return 'D';
     46   case 'e':
     47     return 'E';
     48   case 'f':
     49     return 'F';
     50   case 'g':
     51     return 'G';
     52   case 'h':
     53     return 'H';
     54   case 'i':
     55     return 'I';
     56   case 'j':
     57     return 'J';
     58   case 'k':
     59     return 'K';
     60   case 'l':
     61     return 'L';
     62   case 'm':
     63     return 'M';
     64   case 'n':
     65     return 'N';
     66   case 'o':
     67     return 'O';
     68   case 'p':
     69     return 'P';
     70   case 'q':
     71     return 'Q';
     72   case 'r':
     73     return 'R';
     74   case 's':
     75     return 'S';
     76   case 't':
     77     return 'T';
     78   case 'u':
     79     return 'U';
     80   case 'v':
     81     return 'V';
     82   case 'w':
     83     return 'W';
     84   case 'x':
     85     return 'X';
     86   case 'y':
     87     return 'Y';
     88   case 'z':
     89     return 'Z';
     90   }
     91 #endif
     92 
     93   return in;
     94 }
     95 
     96 /*
     97  * Curl_raw_equal() is for doing "raw" case insensitive strings. This is meant
     98  * to be locale independent and only compare strings we know are safe for
     99  * this.  See https://daniel.haxx.se/blog/2008/10/15/strcasecmp-in-turkish/ for
    100  * some further explanation to why this function is necessary.
    101  *
    102  * The function is capable of comparing a-z case insensitively even for
    103  * non-ascii.
    104  *
    105  * @unittest: 1301
    106  */
    107 
    108 int Curl_strcasecompare(const char *first, const char *second)
    109 {
    110   while(*first && *second) {
    111     if(Curl_raw_toupper(*first) != Curl_raw_toupper(*second))
    112       /* get out of the loop as soon as they don't match */
    113       break;
    114     first++;
    115     second++;
    116   }
    117   /* we do the comparison here (possibly again), just to make sure that if the
    118      loop above is skipped because one of the strings reached zero, we must not
    119      return this as a successful match */
    120   return (Curl_raw_toupper(*first) == Curl_raw_toupper(*second));
    121 }
    122 
    123 int Curl_safe_strcasecompare(const char *first, const char *second)
    124 {
    125   if(first && second)
    126     /* both pointers point to something then compare them */
    127     return Curl_strcasecompare(first, second);
    128   else
    129     /* if both pointers are NULL then treat them as equal */
    130     return (NULL == first && NULL == second);
    131 }
    132 
    133 /*
    134  * @unittest: 1301
    135  */
    136 int Curl_strncasecompare(const char *first, const char *second, size_t max)
    137 {
    138   while(*first && *second && max) {
    139     if(Curl_raw_toupper(*first) != Curl_raw_toupper(*second)) {
    140       break;
    141     }
    142     max--;
    143     first++;
    144     second++;
    145   }
    146   if(0 == max)
    147     return 1; /* they are equal this far */
    148 
    149   return Curl_raw_toupper(*first) == Curl_raw_toupper(*second);
    150 }
    151 
    152 /* Copy an upper case version of the string from src to dest.  The
    153  * strings may overlap.  No more than n characters of the string are copied
    154  * (including any NUL) and the destination string will NOT be
    155  * NUL-terminated if that limit is reached.
    156  */
    157 void Curl_strntoupper(char *dest, const char *src, size_t n)
    158 {
    159   if(n < 1)
    160     return;
    161 
    162   do {
    163     *dest++ = Curl_raw_toupper(*src);
    164   } while(*src++ && --n);
    165 }
    166 
    167 /* --- public functions --- */
    168 
    169 int curl_strequal(const char *first, const char *second)
    170 {
    171   return Curl_strcasecompare(first, second);
    172 }
    173 int curl_strnequal(const char *first, const char *second, size_t max)
    174 {
    175   return Curl_strncasecompare(first, second, max);
    176 }
    177