LCOV - code coverage report
Current view: top level - mutt - atoi.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 56 56 100.0 %
Date: 2022-03-09 12:17:43 Functions: 9 9 100.0 %

          Line data    Source code
       1             : /**
       2             :  * @file
       3             :  * Parse a number in a string
       4             :  *
       5             :  * @authors
       6             :  * Copyright (C) 2021 Pietro Cerutti <gahr@gahr.ch>
       7             :  *
       8             :  * @copyright
       9             :  * This program is free software: you can redistribute it and/or modify it under
      10             :  * the terms of the GNU General Public License as published by the Free Software
      11             :  * Foundation, either version 2 of the License, or (at your option) any later
      12             :  * version.
      13             :  *
      14             :  * This program is distributed in the hope that it will be useful, but WITHOUT
      15             :  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
      16             :  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
      17             :  * details.
      18             :  *
      19             :  * You should have received a copy of the GNU General Public License along with
      20             :  * this program.  If not, see <http://www.gnu.org/licenses/>.
      21             :  */
      22             : 
      23             : /**
      24             :  * @page mutt_atoi Parse a number in a string
      25             :  *
      26             :  * Parse a number in a string.
      27             :  */
      28             : 
      29             : #include "config.h"
      30             : #include <errno.h>
      31             : #include <limits.h>
      32             : #include <stdio.h>
      33             : #include <stdlib.h>
      34             : 
      35             : /**
      36             :  * str_atol_clamp - Convert ASCII string to a long and clamp
      37             :  * @param[in]  str String to read
      38             :  * @param[in]  lmin Lower bound
      39             :  * @param[in]  lmax Upper bound
      40             :  * @param[out] dst Store the result
      41             :  * @retval endptr
      42             :  *
      43             :  * endptr    == NULL -> no conversion happened, or overflow
      44             :  * endptr[0] == '\0' -> str was fully converted
      45             :  * endptr[0] != '\0' -> endptr points to first non converted char in str
      46             :  *
      47             :  * This is a strtol() wrapper with range checking.
      48             :  * errno may be set on error, e.g. ERANGE
      49             :  */
      50         424 : static const char *str_atol_clamp(const char *str, long *dst, long lmin, long lmax)
      51             : {
      52         424 :   if (dst)
      53             :   {
      54         422 :     *dst = 0;
      55             :   }
      56             : 
      57         424 :   if (!str || (*str == '\0'))
      58             :   {
      59          22 :     return NULL;
      60             :   }
      61             : 
      62         402 :   char *e = NULL;
      63         402 :   errno = 0;
      64         402 :   long res = strtol(str, &e, 10);
      65         402 :   if ((e == str) || (((res == LONG_MIN) || (res == LONG_MAX)) && (errno == ERANGE)) ||
      66         326 :       (res < lmin) || (res > lmax))
      67             :   {
      68          88 :     return NULL;
      69             :   }
      70             : 
      71         314 :   if (dst)
      72             :   {
      73         312 :     *dst = res;
      74             :   }
      75             : 
      76         314 :   return e;
      77             : }
      78             : 
      79             : /**
      80             :  * str_atoull_clamp - Convert ASCII string to an unsigned long long and clamp
      81             :  * @param[in]  str String to read
      82             :  * @param[in]  ullmax Upper bound
      83             :  * @param[out] dst Store the result
      84             :  * @retval endptr
      85             :  *
      86             :  * endptr    == NULL -> no conversion happened, or overflow
      87             :  * endptr[0] == '\0' -> str was fully converted
      88             :  * endptr[0] != '\0' -> endptr points to first non converted char in str
      89             :  *
      90             :  * This is a strtoull() wrapper with range checking.
      91             :  * errno may be set on error, e.g. ERANGE
      92             :  */
      93         406 : static const char *str_atoull_clamp(const char *str, unsigned long long *dst,
      94             :                                     unsigned long long ullmax)
      95             : {
      96         406 :   if (dst)
      97             :   {
      98         404 :     *dst = 0;
      99             :   }
     100             : 
     101         406 :   if (!str || (*str == '\0'))
     102             :   {
     103           6 :     return str;
     104             :   }
     105             : 
     106         400 :   char *e = NULL;
     107         400 :   errno = 0;
     108         400 :   unsigned long long res = strtoull(str, &e, 10);
     109         400 :   if ((e == str) || ((res == ULLONG_MAX) && (errno == ERANGE)) || (res > ullmax))
     110             :   {
     111          50 :     return NULL;
     112             :   }
     113             : 
     114         350 :   if (dst)
     115             :   {
     116         348 :     *dst = res;
     117             :   }
     118             : 
     119         350 :   return e;
     120             : }
     121             : 
     122             : /**
     123             :  * mutt_str_atol - Convert ASCII string to a long
     124             :  * @param[in]  str String to read
     125             :  * @param[out] dst Store the result
     126             :  * @retval endptr
     127             :  *
     128             :  * endptr    == NULL -> no conversion happened, or overflow
     129             :  * endptr[0] == '\0' -> str was fully converted
     130             :  * endptr[0] != '\0' -> endptr points to first non converted char in str
     131             :  *
     132             :  * This is a strtol() wrapper with range checking.
     133             :  * errno may be set on error, e.g. ERANGE
     134             :  */
     135         158 : const char *mutt_str_atol(const char *str, long *dst)
     136             : {
     137         158 :   return str_atol_clamp(str, dst, LONG_MIN, LONG_MAX);
     138             : }
     139             : 
     140             : /**
     141             :  * mutt_str_atos - Convert ASCII string to a short
     142             :  * @param[in]  str String to read
     143             :  * @param[out] dst Store the result
     144             :  * @retval  0 Success
     145             :  * @retval -1 Error
     146             :  * @retval -2 Error, overflow
     147             :  *
     148             :  * This is a strtol() wrapper with range checking.
     149             :  * If @a dst is NULL, the string will be tested only (without conversion).
     150             :  *
     151             :  * errno may be set on error, e.g. ERANGE
     152             :  */
     153          78 : const char *mutt_str_atos(const char *str, short *dst)
     154             : {
     155             :   long l;
     156          78 :   const char *res = str_atol_clamp(str, &l, SHRT_MIN, SHRT_MAX);
     157          78 :   if (dst)
     158             :   {
     159          76 :     *dst = res ? l : 0;
     160             :   }
     161          78 :   return res;
     162             : }
     163             : 
     164             : /**
     165             :  * mutt_str_atoi - Convert ASCII string to an integer
     166             :  * @param[in]  str String to read
     167             :  * @param[out] dst Store the result
     168             :  * @retval endptr
     169             :  *
     170             :  * endptr    == NULL -> no conversion happened, or overflow
     171             :  * endptr[0] == '\0' -> str was fully converted
     172             :  * endptr[0] != '\0' -> endptr points to first non converted char in str
     173             :  *
     174             :  * This is a strtol() wrapper with range checking.
     175             :  * If @a dst is NULL, the string will be tested only (without conversion).
     176             :  * errno may be set on error, e.g. ERANGE
     177             :  */
     178         188 : const char *mutt_str_atoi(const char *str, int *dst)
     179             : {
     180             :   long l;
     181         188 :   const char *res = str_atol_clamp(str, &l, INT_MIN, INT_MAX);
     182         188 :   if (dst)
     183             :   {
     184         186 :     *dst = res ? l : 0;
     185             :   }
     186         188 :   return res;
     187             : }
     188             : 
     189             : /**
     190             :  * mutt_str_atoui - Convert ASCII string to an unsigned integer
     191             :  * @param[in]  str String to read
     192             :  * @param[out] dst Store the result
     193             :  * @retval endptr
     194             :  *
     195             :  * endptr    == NULL -> no conversion happened, or overflow
     196             :  * endptr[0] == '\0' -> str was fully converted
     197             :  * endptr[0] != '\0' -> endptr points to first non converted char in str
     198             :  *
     199             :  * @note This function's return value differs from the other functions.
     200             :  *       They return -1 if there is input beyond the number.
     201             :  */
     202          54 : const char *mutt_str_atoui(const char *str, unsigned int *dst)
     203             : {
     204             :   unsigned long long l;
     205          54 :   const char *res = str_atoull_clamp(str, &l, UINT_MAX);
     206          54 :   if (dst)
     207             :   {
     208          52 :     *dst = res ? l : 0;
     209             :   }
     210          54 :   return res;
     211             : }
     212             : 
     213             : /**
     214             :  * mutt_str_atoul - Convert ASCII string to an unsigned long
     215             :  * @param[in]  str String to read
     216             :  * @param[out] dst Store the result
     217             :  * @retval endptr
     218             :  *
     219             :  * endptr    == NULL -> no conversion happened, or overflow
     220             :  * endptr[0] == '\0' -> str was fully converted
     221             :  * endptr[0] != '\0' -> endptr points to first non converted char in str
     222             :  *
     223             :  * @note This function's return value differs from the other functions.
     224             :  *       They return -1 if there is input beyond the number.
     225             :  */
     226          52 : const char *mutt_str_atoul(const char *str, unsigned long *dst)
     227             : {
     228             :   unsigned long long l;
     229          52 :   const char *res = str_atoull_clamp(str, &l, ULONG_MAX);
     230          52 :   if (dst)
     231             :   {
     232          50 :     *dst = res ? l : 0;
     233             :   }
     234          52 :   return res;
     235             : }
     236             : 
     237             : /**
     238             :  * mutt_str_atous - Convert ASCII string to an unsigned short
     239             :  * @param[in]  str String to read
     240             :  * @param[out] dst Store the result
     241             :  * @retval endptr
     242             :  *
     243             :  * endptr    == NULL -> no conversion happened, or overflow
     244             :  * endptr[0] == '\0' -> str was fully converted
     245             :  * endptr[0] != '\0' -> endptr points to first non converted char in str
     246             :  *
     247             :  * @note This function's return value differs from the other functions.
     248             :  *       They return -1 if there is input beyond the number.
     249             :  */
     250         248 : const char *mutt_str_atous(const char *str, unsigned short *dst)
     251             : {
     252             :   unsigned long long l;
     253         248 :   const char *res = str_atoull_clamp(str, &l, USHRT_MAX);
     254         248 :   if (dst)
     255             :   {
     256         248 :     *dst = res ? l : 0;
     257             :   }
     258         248 :   return res;
     259             : }
     260             : 
     261             : /**
     262             :  * mutt_str_atoull - Convert ASCII string to an unsigned long long
     263             :  * @param[in]  str String to read
     264             :  * @param[out] dst Store the result
     265             :  * @retval endptr
     266             :  *
     267             :  * endptr    == NULL -> no conversion happened, or overflow
     268             :  * endptr[0] == '\0' -> str was fully converted
     269             :  * endptr[0] != '\0' -> endptr points to first non converted char in str
     270             :  *
     271             :  * @note This function's return value differs from the other functions.
     272             :  *       They return -1 if there is input beyond the number.
     273             :  */
     274          52 : const char *mutt_str_atoull(const char *str, unsigned long long *dst)
     275             : {
     276          52 :   return str_atoull_clamp(str, dst, ULLONG_MAX);
     277             : }

Generated by: LCOV version 1.14