LCOV - code coverage report
Current view: top level - libpkg - yuarel.c (source / functions) Hit Total Coverage
Test: plop Lines: 0 113 0.0 %
Date: 2024-12-30 07:09:03 Functions: 0 10 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 74 0.0 %

           Branch data     Line data    Source code
       1                 :            : /**
       2                 :            :  * Copyright (C) 2016,2017 Jack Engqvist Johansson
       3                 :            :  *
       4                 :            :  * Permission is hereby granted, free of charge, to any person obtaining a copy
       5                 :            :  * of this software and associated documentation files (the "Software"), to deal
       6                 :            :  * in the Software without restriction, including without limitation the rights
       7                 :            :  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       8                 :            :  * copies of the Software, and to permit persons to whom the Software is
       9                 :            :  * furnished to do so, subject to the following conditions:
      10                 :            :  *
      11                 :            :  * The above copyright notice and this permission notice shall be included in all
      12                 :            :  * copies or substantial portions of the Software.
      13                 :            :  *
      14                 :            :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      15                 :            :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      16                 :            :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      17                 :            :  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      18                 :            :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      19                 :            :  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
      20                 :            :  * SOFTWARE.
      21                 :            :  */
      22                 :            : #include <stdlib.h>
      23                 :            : #include <stdio.h>
      24                 :            : #include <string.h>
      25                 :            : #include "yuarel.h"
      26                 :            : 
      27                 :            : /**
      28                 :            :  * Parse a non null terminated string into an integer.
      29                 :            :  *
      30                 :            :  * str: the string containing the number.
      31                 :            :  * len: Number of characters to parse.
      32                 :            :  */
      33                 :            : static inline int
      34                 :          0 : natoi(const char *str, size_t len)
      35                 :            : {
      36                 :          0 :         int i, r = 0;
      37         [ #  # ]:          0 :         for (i = 0; i < len; i++) {
      38                 :          0 :                 r *= 10;
      39                 :          0 :                 r += str[i] - '0';
      40                 :          0 :         }
      41                 :            : 
      42                 :          0 :         return r;
      43                 :            : }
      44                 :            : 
      45                 :            : /**
      46                 :            :  * Check if a URL is relative (no scheme and hostname).
      47                 :            :  *
      48                 :            :  * url: the string containing the URL to check.
      49                 :            :  *
      50                 :            :  * Returns 1 if relative, otherwise 0.
      51                 :            :  */
      52                 :            : static inline int
      53                 :          0 : is_relative(const char *url)
      54                 :            : {
      55                 :          0 :         return (*url == '/') ? 1 : 0;
      56                 :            : }
      57                 :            : 
      58                 :            : /**
      59                 :            :  * Parse the scheme of a URL by inserting a null terminator after the scheme.
      60                 :            :  *
      61                 :            :  * str: the string containing the URL to parse. Will be modified.
      62                 :            :  *
      63                 :            :  * Returns a pointer to the hostname on success, otherwise NULL.
      64                 :            :  */
      65                 :            : static inline char *
      66                 :          0 : parse_scheme(char *str)
      67                 :            : {
      68                 :            :         char *s;
      69                 :            : 
      70                 :            :         /* If not found or first in string, return error */
      71                 :          0 :         s = strchr(str, ':');
      72   [ #  #  #  # ]:          0 :         if (s == NULL || s == str) {
      73                 :          0 :                 return NULL;
      74                 :            :         }
      75                 :            : 
      76                 :            :         /* If not followed by two slashes, return error */
      77   [ #  #  #  #  :          0 :         if (s[1] == '\0' || s[1] != '/' || s[2] == '\0' || s[2] != '/') {
             #  #  #  # ]
      78                 :          0 :                 return NULL;
      79                 :            :         }
      80                 :            : 
      81                 :          0 :         *s = '\0'; // Replace ':' with NULL
      82                 :            : 
      83                 :          0 :         return s + 3;
      84                 :          0 : }
      85                 :            : 
      86                 :            : /**
      87                 :            :  * Find a character in a string, replace it with '\0' and return the next
      88                 :            :  * character in the string.
      89                 :            :  *
      90                 :            :  * str: the string to search in.
      91                 :            :  * find: the character to search for.
      92                 :            :  *
      93                 :            :  * Returns a pointer to the character after the one to search for. If not
      94                 :            :  * found, NULL is returned.
      95                 :            :  */
      96                 :            : static inline char *
      97                 :          0 : find_and_terminate(char *str, char find)
      98                 :            : {
      99                 :          0 :         str = strchr(str, find);
     100         [ #  # ]:          0 :         if (NULL == str) {
     101                 :          0 :                 return NULL;
     102                 :            :         }
     103                 :            : 
     104                 :          0 :         *str = '\0';
     105                 :          0 :         return str + 1;
     106                 :          0 : }
     107                 :            : 
     108                 :            : /* Yes, the following functions could be implemented as preprocessor macros
     109                 :            :      instead of inline functions, but I think that this approach will be more
     110                 :            :      clean in this case. */
     111                 :            : static inline char *
     112                 :          0 : find_fragment(char *str)
     113                 :            : {
     114                 :          0 :         return find_and_terminate(str, '#');
     115                 :            : }
     116                 :            : 
     117                 :            : static inline char *
     118                 :          0 : find_query(char *str)
     119                 :            : {
     120                 :          0 :         return find_and_terminate(str, '?');
     121                 :            : }
     122                 :            : 
     123                 :            : static inline char *
     124                 :          0 : find_path(char *str)
     125                 :            : {
     126                 :          0 :         return find_and_terminate(str, '/');
     127                 :            : }
     128                 :            : 
     129                 :            : /**
     130                 :            :  * Parse a URL string to a struct.
     131                 :            :  *
     132                 :            :  * url: pointer to the struct where to store the parsed URL parts.
     133                 :            :  * u:   the string containing the URL to be parsed.
     134                 :            :  *
     135                 :            :  * Returns 0 on success, otherwise -1.
     136                 :            :  */
     137                 :            : int
     138                 :          0 : yuarel_parse(struct yuarel *url, char *u)
     139                 :            : {
     140   [ #  #  #  # ]:          0 :         if (NULL == url || NULL == u) {
     141                 :          0 :                 return -1;
     142                 :            :         }
     143                 :            : 
     144                 :          0 :         memset(url, 0, sizeof (struct yuarel));
     145                 :            : 
     146                 :            :         /* (Fragment) */
     147                 :          0 :         url->fragment = find_fragment(u);
     148                 :            : 
     149                 :            :         /* (Query) */
     150                 :          0 :         url->query = find_query(u);
     151                 :            : 
     152                 :            :         /* Relative URL? Parse scheme and hostname */
     153         [ #  # ]:          0 :         if (!is_relative(u)) {
     154                 :            :                 /* Scheme */
     155                 :          0 :                 url->scheme = u;
     156                 :          0 :                 u = parse_scheme(u);
     157         [ #  # ]:          0 :                 if (u == NULL) {
     158                 :          0 :                         return -1;
     159                 :            :                 }
     160                 :            : 
     161                 :            :                 /* Host */
     162         [ #  # ]:          0 :                 if ('\0' == *u) {
     163                 :          0 :                         return -1;
     164                 :            :                 }
     165                 :          0 :                 url->host = u;
     166                 :            : 
     167                 :            :                 /* (Path) */
     168                 :          0 :                 url->path = find_path(u);
     169                 :            : 
     170                 :            :                 /* (Credentials) */
     171                 :          0 :                 u = strchr(url->host, '@');
     172         [ #  # ]:          0 :                 if (NULL != u) {
     173                 :            :                         /* Missing credentials? */
     174         [ #  # ]:          0 :                         if (u == url->host) {
     175                 :          0 :                                 return -1;
     176                 :            :                         }
     177                 :            : 
     178                 :          0 :                         url->username = url->host;
     179                 :          0 :                         url->host = u + 1;
     180                 :          0 :                         *u = '\0';
     181                 :            : 
     182                 :          0 :                         u = strchr(url->username, ':');
     183         [ #  # ]:          0 :                         if (NULL != u) {
     184                 :          0 :                                 url->password = u + 1;
     185                 :          0 :                                 *u = '\0';
     186                 :          0 :                         }
     187                 :          0 :                 }
     188                 :            : 
     189                 :            :                 /* Missing hostname? */
     190         [ #  # ]:          0 :                 if ('\0' == *url->host) {
     191                 :          0 :                         return -1;
     192                 :            :                 }
     193                 :            : 
     194                 :            :                 /* (Port) */
     195                 :          0 :                 u = strchr(url->host, ':');
     196   [ #  #  #  #  :          0 :                 if (NULL != u && (NULL == url->path || u < url->path)) {
                   #  # ]
     197                 :          0 :                         *(u++) = '\0';
     198         [ #  # ]:          0 :                         if ('\0' == *u) {
     199                 :          0 :                                 return -1;
     200                 :            :                         }
     201                 :            : 
     202         [ #  # ]:          0 :                         if (url->path) {
     203                 :          0 :                                 url->port = natoi(u, url->path - u - 1);
     204                 :          0 :                         } else {
     205                 :          0 :                                 url->port = atoi(u);
     206                 :            :                         }
     207                 :          0 :                 }
     208                 :            : 
     209                 :            :                 /* Missing hostname? */
     210         [ #  # ]:          0 :                 if ('\0' == *url->host) {
     211                 :          0 :                         return -1;
     212                 :            :                 }
     213                 :          0 :         } else {
     214                 :            :                 /* (Path) */
     215                 :          0 :                 url->path = find_path(u);
     216                 :            :         }
     217                 :            : 
     218                 :          0 :         return 0;
     219                 :          0 : }
     220                 :            : 
     221                 :            : /**
     222                 :            :  * Split a path into several strings.
     223                 :            :  *
     224                 :            :  * No data is copied, the slashed are used as null terminators and then
     225                 :            :  * pointers to each path part will be stored in **parts. Double slashes will be
     226                 :            :  * treated as one.
     227                 :            :  *
     228                 :            :  * path: the path to split.
     229                 :            :  * parts: a pointer to an array of (char *) where to store the result.
     230                 :            :  * max_parts: max number of parts to parse.
     231                 :            :  */
     232                 :            : int
     233                 :          0 : yuarel_split_path(char *path, char **parts, int max_parts)
     234                 :            : {
     235                 :          0 :         int i = 0;
     236                 :            : 
     237   [ #  #  #  # ]:          0 :         if (NULL == path || '\0' == *path) {
     238                 :          0 :                 return -1;
     239                 :            :         }
     240                 :            : 
     241                 :          0 :         do {
     242                 :            :                 /* Forward to after slashes */
     243         [ #  # ]:          0 :                 while (*path == '/') path++;
     244                 :            : 
     245         [ #  # ]:          0 :                 if ('\0' == *path) {
     246                 :          0 :                         break;
     247                 :            :                 }
     248                 :            : 
     249                 :          0 :                 parts[i++] = path;
     250                 :            : 
     251                 :          0 :                 path = strchr(path, '/');
     252         [ #  # ]:          0 :                 if (NULL == path) {
     253                 :          0 :                         break;
     254                 :            :                 }
     255                 :            : 
     256                 :          0 :                 *(path++) = '\0';
     257         [ #  # ]:          0 :         } while (i < max_parts);
     258                 :            : 
     259                 :          0 :         return i;
     260                 :          0 : }
     261                 :            : 
     262                 :            : int
     263                 :          0 : yuarel_parse_query(char *query, char delimiter, struct yuarel_param *params, int max_params)
     264                 :            : {
     265                 :          0 :         int i = 0;
     266                 :            : 
     267   [ #  #  #  # ]:          0 :         if (NULL == query || '\0' == *query) {
     268                 :          0 :                 return -1;
     269                 :            :         }
     270                 :            : 
     271                 :          0 :         params[i++].key = query;
     272   [ #  #  #  #  :          0 :         while (i < max_params && NULL != (query = strchr(query, delimiter))) {
                   #  # ]
     273                 :          0 :                 *query = '\0';
     274                 :          0 :                 params[i].key = ++query;
     275                 :          0 :                 params[i].val = NULL;
     276                 :            : 
     277                 :            :                 /* Go back and split previous param */
     278         [ #  # ]:          0 :                 if (i > 0) {
     279         [ #  # ]:          0 :                         if ((params[i - 1].val = strchr(params[i - 1].key, '=')) != NULL) {
     280                 :          0 :                                 *(params[i - 1].val)++ = '\0';
     281                 :          0 :                         }
     282                 :          0 :                 }
     283                 :          0 :                 i++;
     284                 :            :         }
     285                 :            : 
     286                 :            :         /* Go back and split last param */
     287         [ #  # ]:          0 :         if ((params[i - 1].val = strchr(params[i - 1].key, '=')) != NULL) {
     288                 :          0 :                 *(params[i - 1].val)++ = '\0';
     289                 :          0 :         }
     290                 :            : 
     291                 :          0 :         return i;
     292                 :          0 : }

Generated by: LCOV version 1.15