Home | History | Annotate | Download | only in lib
      1 /***************************************************************************
      2  *                                  _   _ ____  _
      3  *  Project                     ___| | | |  _ \| |
      4  *                             / __| | | | |_) | |
      5  *                            | (__| |_| |  _ <| |___
      6  *                             \___|\___/|_| \_\_____|
      7  *
      8  * Copyright (C) 1998 - 2017, 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_strcasecompare() is for doing "raw" case insensitive strings. This is
     98  * meant to be locale independent and only compare strings we know are safe
     99  * for this.  See
    100  * https://daniel.haxx.se/blog/2008/10/15/strcasecmp-in-turkish/ for some
    101  * further explanation to why this function is necessary.
    102  *
    103  * The function is capable of comparing a-z case insensitively even for
    104  * non-ascii.
    105  *
    106  * @unittest: 1301
    107  */
    108 
    109 int Curl_strcasecompare(const char *first, const char *second)
    110 {
    111   while(*first && *second) {
    112     if(Curl_raw_toupper(*first) != Curl_raw_toupper(*second))
    113       /* get out of the loop as soon as they don't match */
    114       break;
    115     first++;
    116     second++;
    117   }
    118   /* we do the comparison here (possibly again), just to make sure that if the
    119      loop above is skipped because one of the strings reached zero, we must not
    120      return this as a successful match */
    121   return (Curl_raw_toupper(*first) == Curl_raw_toupper(*second));
    122 }
    123 
    124 int Curl_safe_strcasecompare(const char *first, const char *second)
    125 {
    126   if(first && second)
    127     /* both pointers point to something then compare them */
    128     return Curl_strcasecompare(first, second);
    129 
    130   /* if both pointers are NULL then treat them as equal */
    131   return (NULL == first && NULL == second);
    132 }
    133 
    134 /*
    135  * @unittest: 1301
    136  */
    137 int Curl_strncasecompare(const char *first, const char *second, size_t max)
    138 {
    139   while(*first && *second && max) {
    140     if(Curl_raw_toupper(*first) != Curl_raw_toupper(*second)) {
    141       break;
    142     }
    143     max--;
    144     first++;
    145     second++;
    146   }
    147   if(0 == max)
    148     return 1; /* they are equal this far */
    149 
    150   return Curl_raw_toupper(*first) == Curl_raw_toupper(*second);
    151 }
    152 
    153 /* Copy an upper case version of the string from src to dest.  The
    154  * strings may overlap.  No more than n characters of the string are copied
    155  * (including any NUL) and the destination string will NOT be
    156  * NUL-terminated if that limit is reached.
    157  */
    158 void Curl_strntoupper(char *dest, const char *src, size_t n)
    159 {
    160   if(n < 1)
    161     return;
    162 
    163   do {
    164     *dest++ = Curl_raw_toupper(*src);
    165   } while(*src++ && --n);
    166 }
    167 
    168 /* --- public functions --- */
    169 
    170 int curl_strequal(const char *first, const char *second)
    171 {
    172   return Curl_strcasecompare(first, second);
    173 }
    174 int curl_strnequal(const char *first, const char *second, size_t max)
    175 {
    176   return Curl_strncasecompare(first, second, max);
    177 }
    178