Changeset 46c20c8 in mainline for uspace/lib/c/generic/str.c
- Timestamp:
- 2010-11-26T20:08:10Z (14 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 45df59a
- Parents:
- fb150d78 (diff), ffdd2b9 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - File:
-
- 1 moved
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/c/generic/str.c
rfb150d78 r46c20c8 34 34 */ 35 35 36 #include <str ing.h>36 #include <str.h> 37 37 #include <stdlib.h> 38 38 #include <assert.h> 39 #include < limits.h>39 #include <stdint.h> 40 40 #include <ctype.h> 41 41 #include <malloc.h> … … 43 43 #include <align.h> 44 44 #include <mem.h> 45 #include <str ing.h>45 #include <str.h> 46 46 47 47 /** Byte mask consisting of lowest @n bits (out of 8) */ … … 471 471 * null-terminated and containing only complete characters. 472 472 * 473 * @param dest 473 * @param dest Destination buffer. 474 474 * @param count Size of the destination buffer (must be > 0). 475 475 * @param src Source string. … … 477 477 void str_cpy(char *dest, size_t size, const char *src) 478 478 { 479 wchar_t ch;480 size_t src_off;481 size_t dest_off;482 483 479 /* There must be space for a null terminator in the buffer. */ 484 480 assert(size > 0); 485 481 486 src_off = 0; 487 dest_off = 0; 488 482 size_t src_off = 0; 483 size_t dest_off = 0; 484 485 wchar_t ch; 489 486 while ((ch = str_decode(src, &src_off, STR_NO_LIMIT)) != 0) { 490 487 if (chr_encode(ch, dest, &dest_off, size - 1) != EOK) 491 488 break; 492 489 } 493 490 494 491 dest[dest_off] = '\0'; 495 492 } … … 505 502 * have to be null-terminated. 506 503 * 507 * @param dest 504 * @param dest Destination buffer. 508 505 * @param count Size of the destination buffer (must be > 0). 509 506 * @param src Source string. 510 * @param n 507 * @param n Maximum number of bytes to read from @a src. 511 508 */ 512 509 void str_ncpy(char *dest, size_t size, const char *src, size_t n) 513 510 { 514 wchar_t ch;515 size_t src_off;516 size_t dest_off;517 518 511 /* There must be space for a null terminator in the buffer. */ 519 512 assert(size > 0); 520 513 521 src_off = 0; 522 dest_off = 0; 523 514 size_t src_off = 0; 515 size_t dest_off = 0; 516 517 wchar_t ch; 524 518 while ((ch = str_decode(src, &src_off, n)) != 0) { 525 519 if (chr_encode(ch, dest, &dest_off, size - 1) != EOK) 526 520 break; 527 521 } 528 522 529 523 dest[dest_off] = '\0'; 530 524 } … … 896 890 } 897 891 892 /** Duplicate string. 893 * 894 * Allocate a new string and copy characters from the source 895 * string into it. The duplicate string is allocated via sleeping 896 * malloc(), thus this function can sleep in no memory conditions. 897 * 898 * The allocation cannot fail and the return value is always 899 * a valid pointer. The duplicate string is always a well-formed 900 * null-terminated UTF-8 string, but it can differ from the source 901 * string on the byte level. 902 * 903 * @param src Source string. 904 * 905 * @return Duplicate string. 906 * 907 */ 898 908 char *str_dup(const char *src) 899 909 { 900 size_t size = str_size(src); 901 void *dest = malloc(size + 1); 902 910 size_t size = str_size(src) + 1; 911 char *dest = (char *) malloc(size); 903 912 if (dest == NULL) 904 913 return (char *) NULL; 905 914 906 return (char *) memcpy(dest, src, size + 1); 907 } 908 909 char *str_ndup(const char *src, size_t max_size) 915 str_cpy(dest, size, src); 916 return dest; 917 } 918 919 /** Duplicate string with size limit. 920 * 921 * Allocate a new string and copy up to @max_size bytes from the source 922 * string into it. The duplicate string is allocated via sleeping 923 * malloc(), thus this function can sleep in no memory conditions. 924 * No more than @max_size + 1 bytes is allocated, but if the size 925 * occupied by the source string is smaller than @max_size + 1, 926 * less is allocated. 927 * 928 * The allocation cannot fail and the return value is always 929 * a valid pointer. The duplicate string is always a well-formed 930 * null-terminated UTF-8 string, but it can differ from the source 931 * string on the byte level. 932 * 933 * @param src Source string. 934 * @param n Maximum number of bytes to duplicate. 935 * 936 * @return Duplicate string. 937 * 938 */ 939 char *str_ndup(const char *src, size_t n) 910 940 { 911 941 size_t size = str_size(src); 912 if (size > max_size)913 size = max_size;942 if (size > n) 943 size = n; 914 944 915 945 char *dest = (char *) malloc(size + 1); 916 917 946 if (dest == NULL) 918 947 return (char *) NULL; 919 948 920 memcpy(dest, src, size); 921 dest[size] = 0; 949 str_ncpy(dest, size + 1, src, size); 922 950 return dest; 923 951 } … … 979 1007 } 980 1008 1009 /** Convert string to uint64_t (internal variant). 1010 * 1011 * @param nptr Pointer to string. 1012 * @param endptr Pointer to the first invalid character is stored here. 1013 * @param base Zero or number between 2 and 36 inclusive. 1014 * @param neg Indication of unary minus is stored here. 1015 * @apram result Result of the conversion. 1016 * 1017 * @return EOK if conversion was successful. 1018 * 1019 */ 1020 static int str_uint(const char *nptr, char **endptr, unsigned int base, 1021 bool *neg, uint64_t *result) 1022 { 1023 assert(endptr != NULL); 1024 assert(neg != NULL); 1025 assert(result != NULL); 1026 1027 *neg = false; 1028 const char *str = nptr; 1029 1030 /* Ignore leading whitespace */ 1031 while (isspace(*str)) 1032 str++; 1033 1034 if (*str == '-') { 1035 *neg = true; 1036 str++; 1037 } else if (*str == '+') 1038 str++; 1039 1040 if (base == 0) { 1041 /* Decode base if not specified */ 1042 base = 10; 1043 1044 if (*str == '0') { 1045 base = 8; 1046 str++; 1047 1048 switch (*str) { 1049 case 'b': 1050 case 'B': 1051 base = 2; 1052 str++; 1053 break; 1054 case 'o': 1055 case 'O': 1056 base = 8; 1057 str++; 1058 break; 1059 case 'd': 1060 case 'D': 1061 case 't': 1062 case 'T': 1063 base = 10; 1064 str++; 1065 break; 1066 case 'x': 1067 case 'X': 1068 base = 16; 1069 str++; 1070 break; 1071 default: 1072 str--; 1073 } 1074 } 1075 } else { 1076 /* Check base range */ 1077 if ((base < 2) || (base > 36)) { 1078 *endptr = (char *) str; 1079 return EINVAL; 1080 } 1081 } 1082 1083 *result = 0; 1084 const char *startstr = str; 1085 1086 while (*str != 0) { 1087 unsigned int digit; 1088 1089 if ((*str >= 'a') && (*str <= 'z')) 1090 digit = *str - 'a' + 10; 1091 else if ((*str >= 'A') && (*str <= 'Z')) 1092 digit = *str - 'A' + 10; 1093 else if ((*str >= '0') && (*str <= '9')) 1094 digit = *str - '0'; 1095 else 1096 break; 1097 1098 if (digit >= base) 1099 break; 1100 1101 uint64_t prev = *result; 1102 *result = (*result) * base + digit; 1103 1104 if (*result < prev) { 1105 /* Overflow */ 1106 *endptr = (char *) str; 1107 return EOVERFLOW; 1108 } 1109 1110 str++; 1111 } 1112 1113 if (str == startstr) { 1114 /* 1115 * No digits were decoded => first invalid character is 1116 * the first character of the string. 1117 */ 1118 str = nptr; 1119 } 1120 1121 *endptr = (char *) str; 1122 1123 if (str == nptr) 1124 return EINVAL; 1125 1126 return EOK; 1127 } 1128 1129 /** Convert string to uint64_t. 1130 * 1131 * @param nptr Pointer to string. 1132 * @param endptr If not NULL, pointer to the first invalid character 1133 * is stored here. 1134 * @param base Zero or number between 2 and 36 inclusive. 1135 * @param strict Do not allow any trailing characters. 1136 * @param result Result of the conversion. 1137 * 1138 * @return EOK if conversion was successful. 1139 * 1140 */ 1141 int str_uint64(const char *nptr, char **endptr, unsigned int base, 1142 bool strict, uint64_t *result) 1143 { 1144 assert(result != NULL); 1145 1146 bool neg; 1147 char *lendptr; 1148 int ret = str_uint(nptr, &lendptr, base, &neg, result); 1149 1150 if (endptr != NULL) 1151 *endptr = (char *) lendptr; 1152 1153 if (ret != EOK) 1154 return ret; 1155 1156 /* Do not allow negative values */ 1157 if (neg) 1158 return EINVAL; 1159 1160 /* Check whether we are at the end of 1161 the string in strict mode */ 1162 if ((strict) && (*lendptr != 0)) 1163 return EINVAL; 1164 1165 return EOK; 1166 } 1167 1168 /** Convert string to size_t. 1169 * 1170 * @param nptr Pointer to string. 1171 * @param endptr If not NULL, pointer to the first invalid character 1172 * is stored here. 1173 * @param base Zero or number between 2 and 36 inclusive. 1174 * @param strict Do not allow any trailing characters. 1175 * @param result Result of the conversion. 1176 * 1177 * @return EOK if conversion was successful. 1178 * 1179 */ 1180 int str_size_t(const char *nptr, char **endptr, unsigned int base, 1181 bool strict, size_t *result) 1182 { 1183 assert(result != NULL); 1184 1185 bool neg; 1186 char *lendptr; 1187 uint64_t res; 1188 int ret = str_uint(nptr, &lendptr, base, &neg, &res); 1189 1190 if (endptr != NULL) 1191 *endptr = (char *) lendptr; 1192 1193 if (ret != EOK) 1194 return ret; 1195 1196 /* Do not allow negative values */ 1197 if (neg) 1198 return EINVAL; 1199 1200 /* Check whether we are at the end of 1201 the string in strict mode */ 1202 if ((strict) && (*lendptr != 0)) 1203 return EINVAL; 1204 1205 /* Check for overflow */ 1206 size_t _res = (size_t) res; 1207 if (_res != res) 1208 return EOVERFLOW; 1209 1210 *result = _res; 1211 1212 return EOK; 1213 } 1214 1215 void order_suffix(const uint64_t val, uint64_t *rv, char *suffix) 1216 { 1217 if (val > 10000000000000000000ULL) { 1218 *rv = val / 1000000000000000000ULL; 1219 *suffix = 'Z'; 1220 } else if (val > 1000000000000000000ULL) { 1221 *rv = val / 1000000000000000ULL; 1222 *suffix = 'E'; 1223 } else if (val > 1000000000000000ULL) { 1224 *rv = val / 1000000000000ULL; 1225 *suffix = 'T'; 1226 } else if (val > 1000000000000ULL) { 1227 *rv = val / 1000000000ULL; 1228 *suffix = 'G'; 1229 } else if (val > 1000000000ULL) { 1230 *rv = val / 1000000ULL; 1231 *suffix = 'M'; 1232 } else if (val > 1000000ULL) { 1233 *rv = val / 1000ULL; 1234 *suffix = 'k'; 1235 } else { 1236 *rv = val; 1237 *suffix = ' '; 1238 } 1239 } 1240 981 1241 /** @} 982 1242 */
Note:
See TracChangeset
for help on using the changeset viewer.