目录
  1. 1. redis源码阅读-util(类型转换工具)
    1. 1.1. util介绍
    2. 1.2. util.h
    3. 1.3. util.c
redis源码阅读-util(类型转换工具)

redis源码阅读-util(类型转换工具)

util介绍

util中主要放置的是一些常用的类型转换函数,比如字符串转换为整型,也包含模式匹配,时间时区获取等工具函数。

util.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
/*
* Copyright (c) 2009-2012, Salvatore Sanfilippo <antirez at gmail dot com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Redis nor the names of its contributors may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef __REDIS_UTIL_H
#define __REDIS_UTIL_H

#include <stdint.h>
#include "sds.h"

/* The maximum number of characters needed to represent a long double
* as a string (long double has a huge range).
* This should be the size of the buffer given to ld2string */
// 一个long double作为一个字符串
#define MAX_LONG_DOUBLE_CHARS 5*1024

// 模式匹配,确定了需要匹配的字符串的长度
int stringmatchlen(const char *p, int plen, const char *s, int slen, int nocase);
// 包装上面那个函数
int stringmatch(const char *p, const char *s, int nocase);
// 测试模式匹配用的
int stringmatchlen_fuzz_test(void);
// 将1Gb转换为字节
long long memtoll(const char *p, int *err);
//获取十进制数的位数
uint32_t digits10(uint64_t v);
// 无符号值的位数
uint32_t sdigits10(int64_t v);
// long long 转string
int ll2string(char *s, size_t len, long long value);
// string转long long
int string2ll(const char *s, size_t slen, long long *value);
// string 转long
int string2l(const char *s, size_t slen, long *value);
// string 转long double
int string2ld(const char *s, size_t slen, long double *dp);
// double转string
int d2string(char *buf, size_t len, double value);
// long double 转string
int ld2string(char *buf, size_t len, long double value, int humanfriendly);
// 获取绝对路径
sds getAbsolutePath(char *filename);
// 获取时区
unsigned long getTimeZone(void);
// 获取路径的第一个目录
int pathIsBaseName(char *path);

#ifdef REDIS_TEST
int utilTest(int argc, char **argv);
#endif

#endif

util.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
/*
* Copyright (c) 2009-2012, Salvatore Sanfilippo <antirez at gmail dot com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Redis nor the names of its contributors may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/

#include "fmacros.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <math.h>
#include <unistd.h>
#include <sys/time.h>
#include <float.h>
#include <stdint.h>
#include <errno.h>
#include <time.h>

#include "util.h"
#include "sha1.h" /*提供加密算法原型*/

/* Glob-style pattern matching. */
/* 模式匹配
const char *pattern : 模式字符串
int patternLen : 模式字符串长度
const char *string : 需要匹配的字符串
int stringLen : 需要匹配的字符串的长度
int nocase :
*/
int stringmatchlen(const char *pattern, int patternLen,
const char *string, int stringLen, int nocase)
{
// 当两个长度都不为0时循环
while(patternLen && stringLen) {
// pattern是一个指针,其中游标位置表示其当前起始位置,而pattern[0]表示当前游标指向的位置的内容
switch(pattern[0]) {
case '*': // 表示匹配0个或多个,这里直接匹配所有
while (pattern[1] == '*') { // 如果第二个字符还是"*",就直接匹配
pattern++;
patternLen--;
}
if (patternLen == 1) // 如果模式匹配字符串长度为1,就表名只有"*"一个字符,表示已经匹配,直接返回1,表示匹配
return 1; /* match */
while(stringLen) { // 如果default块匹配成功,就直接返回匹配成功
if (stringmatchlen(pattern+1, patternLen-1,
string, stringLen, nocase))
return 1; /* match */
// 如果匹配失败,就再向后匹配
string++;
stringLen--;
}
return 0; /* no match */
break;
case '?': // 匹配一个或0个
if (stringLen == 0)
return 0; /* no match */
string++;
stringLen--;
break;
case '[': // 匹配[],用来匹配一个字符,这个字符在这个区间之内
{
int not, match;

pattern++; // 先将"["忽略
patternLen--; // 需要匹配的长度减1
not = pattern[0] == '^'; // 如果第一个字符是'^'表示取反
if (not) {
pattern++;
patternLen--;
}
match = 0;
while(1) {
// 如果找到转义字符,并且后面需要的长度大于2,也就是\\%
if (pattern[0] == '\\' && patternLen >= 2) {
pattern++; // 先让指针跳过'\\'
patternLen--;
if (pattern[0] == string[0]) // 如果转义后的字符等于字符串中的字符
match = 1;
} else if (pattern[0] == ']') { // 遇到闭合符,跳出循环
break;
} else if (patternLen == 0) { // 如果模式匹配字符串需要匹配的长度为0了
pattern--;
patternLen++;
break;
} else if (pattern[1] == '-' && patternLen >= 3) { // 当前项的后一个字符是'-',并且长度大于等于3,相当于1-9这样
int start = pattern[0]; // 第一个就是1,是开始字符
int end = pattern[2]; // 第三个就是9,是结束字符
int c = string[0]; // 需要匹配的字符
if (start > end) { // 如果开始值大于结尾值,就让start=end
int t = start;
start = end;
end = t;
}
if (nocase) { // 如果大小写不敏感,就将字符都转小写
start = tolower(start);
end = tolower(end);
c = tolower(c);
}
pattern += 2; // 然后模式匹配位置向后偏移,到范围区间之后
patternLen -= 2; // 长度同样减去
if (c >= start && c <= end) // 判断字符是否在区间之内
match = 1;
} else { // 如果不是特殊字符,就一个字符一个字符的比较
if (!nocase) { // 大小写敏感
if (pattern[0] == string[0])
match = 1;
} else { // 大小写不敏感
if (tolower((int)pattern[0]) == tolower((int)string[0]))
match = 1;
}
}
pattern++; // 跳过']'
patternLen--;
}
if (not) // 如果not='^'
match = !match; //给匹配结果取反
if (!match) //
return 0; /* no match */
string++; // 最终需要匹配的字符串向后面移动
stringLen--;
break;
}
case '\\': // 如果是转义字符
if (patternLen >= 2) {
pattern++;
patternLen--;
}
/* fall through */
default: // 这里只有"*"使用了递归,因此这里主要是用来处理"*"后面的字符串
// 这里用来匹配中"*"后面的模式匹配的第一个字符匹配的需要匹配的第一个字符在哪,如果没有匹配到就直接
if (!nocase) { // 是否大小写敏感
if (pattern[0] != string[0])
return 0; /* no match */
} else {
if (tolower((int)pattern[0]) != tolower((int)string[0]))
return 0; /* no match */
}
string++;
stringLen--;
break;
}
pattern++; //到达模式匹配结尾
patternLen--;
if (stringLen == 0) {
while(*pattern == '*') {
pattern++;
patternLen--;
}
break;
}
}
// 如果模式匹配长度和字符串长度都为0,表示都匹配成功
if (patternLen == 0 && stringLen == 0)
return 1;
return 0;
}

// 将上面的模式匹配函数包装了一下,只是将长度变量隐藏了,给了一个指定值
int stringmatch(const char *pattern, const char *string, int nocase) {
return stringmatchlen(pattern,strlen(pattern),string,strlen(string),nocase);
}

/* Fuzz stringmatchlen() trying to crash it with bad input. */
int stringmatchlen_fuzz_test(void) {
char str[32];
char pat[32];
int cycles = 10000000;
int total_matches = 0;
while(cycles--) {
int strlen = rand() % sizeof(str);
int patlen = rand() % sizeof(pat);
for (int j = 0; j < strlen; j++) str[j] = rand() % 128;
for (int j = 0; j < patlen; j++) pat[j] = rand() % 128;
total_matches += stringmatchlen(pat, patlen, str, strlen, 0);
}
return total_matches;
}

/* Convert a string representing an amount of memory into the number of
* bytes, so for instance memtoll("1Gb") will return 1073741824 that is
* (1024*1024*1024).
*
* On parsing error, if *err is not NULL, it's set to 1, otherwise it's
* set to 0. On error the function return value is 0, regardless of the
* fact 'err' is NULL or not. */
// 将"1GB"转换为字节数,如果解析错误返回0,err=1
long long memtoll(const char *p, int *err) {
const char *u;
char buf[128];
long mul; /* unit multiplier */
long long val;
unsigned int digits;

if (err) *err = 0;

/* Search the first non digit character. */
u = p;
// 如果是"-",表示负数,游标向后移
if (*u == '-') u++;
// 如果是数字,游标向后移
while(*u && isdigit(*u)) u++;
// 搜索第一个不是数字的字符,都大小写不敏感
// 如果没有字符,就默认该数字是字节
if (*u == '\0' || !strcasecmp(u,"b")) {
mul = 1;
// 如果是k,就转为1000b
} else if (!strcasecmp(u,"k")) {
mul = 1000;
// 如果是kb,就转为1024b
} else if (!strcasecmp(u,"kb")) {
mul = 1024;
// 如果是m,转为1000*1000b
} else if (!strcasecmp(u,"m")) {
mul = 1000*1000;
// 如果是mb,转为1024*1024b
} else if (!strcasecmp(u,"mb")) {
mul = 1024*1024;
// 如果是g,转为1000L*1000*1000b
} else if (!strcasecmp(u,"g")) {
mul = 1000L*1000*1000;
// 如果是gb,转为1024L*1024*1024b
} else if (!strcasecmp(u,"gb")) {
mul = 1024L*1024*1024;
} else { // 否则就是其他字符,表示输入的是错误的字符,返回错误码
if (err) *err = 1;
return 0;
}

/* Copy the digits into a buffer, we'll use strtoll() to convert
* the digit (without the unit) into a number. */
digits = u-p; // u的游标移动到第一个字符处,p是起始位置,这样就能得到数字所占内存偏移量
if (digits >= sizeof(buf)) { // 如果字符所占内存大小大于缓存区,也输出错误码
if (err) *err = 1;
return 0;
}
memcpy(buf,p,digits); // 将从开始位置开始到数字所占内存的长度结束位置的内存区域复制给buf
buf[digits] = '\0';//将其作为一个字符串,以空字符结尾

char *endptr;
errno = 0;
val = strtoll(buf,&endptr,10); // 将字符串转换为long long
if ((val == 0 && errno == EINVAL) || *endptr != '\0') { // 如果转换出的值有问题
if (err) *err = 1;
return 0;
}
return val*mul; // 转换处的数字*字节数,就是总的内存字节数
}

/* Return the number of digits of 'v' when converted to string in radix 10.
* See ll2string() for more information. */
// 返回数值v的数字数量,就是表示数值是几位数,这是无符号值,也就是正数
uint32_t digits10(uint64_t v) {
if (v < 10) return 1; //个位数
if (v < 100) return 2; // 十位数
if (v < 1000) return 3; // 百位数
if (v < 1000000000000UL) {
if (v < 100000000UL) {
if (v < 1000000) {
if (v < 10000) return 4;
return 5 + (v >= 100000);
}
return 7 + (v >= 10000000UL);
}
if (v < 10000000000UL) {
return 9 + (v >= 1000000000UL);
}
return 11 + (v >= 100000000000UL);
}
return 12 + digits10(v / 1000000000000UL);
}

/* Like digits10() but for signed values. */
// 计算无符号值是几位数
uint32_t sdigits10(int64_t v) {
if (v < 0) {
/* Abs value of LLONG_MIN requires special handling. */
uint64_t uv = (v != LLONG_MIN) ?
(uint64_t)-v : ((uint64_t) LLONG_MAX)+1;
return digits10(uv)+1; /* +1 for the minus. */
} else {
return digits10(v);
}
}

/* Convert a long long into a string. Returns the number of
* characters needed to represent the number.
* If the buffer is not big enough to store the string, 0 is returned.
*
* Based on the following article (that apparently does not provide a
* novel approach but only publicizes an already used technique):
*
* https://www.facebook.com/notes/facebook-engineering/three-optimization-tips-for-c/10151361643253920
*
* Modified in order to handle signed integers since the original code was
* designed for unsigned integers. */
// long long转string,返回的是字符数量,将输入的数值svalue转换为字符串,保存到dst中
int ll2string(char *dst, size_t dstlen, long long svalue) {
static const char digits[201] =
"0001020304050607080910111213141516171819"
"2021222324252627282930313233343536373839"
"4041424344454647484950515253545556575859"
"6061626364656667686970717273747576777879"
"8081828384858687888990919293949596979899";
int negative;
unsigned long long value;

/* The main loop works with 64bit unsigned integers for simplicity, so
* we convert the number here and remember if it is negative. */
// 如果输入的是负数,就将其转换为正数
if (svalue < 0) {
// 如果负数在long的范围之内
if (svalue != LLONG_MIN) {
value = -svalue;
} else { // 如果没有在long范围之内,就是long long的最大值+1,因为value是unsigned long long,其最大值大于long long的最大值,所以在范围之内
value = ((unsigned long long) LLONG_MAX)+1;
}
negative = 1;
} else {
value = svalue;
negative = 0;
}

/* Check length. */
uint32_t const length = digits10(value)+negative; // 检查数字长度,negative表示符号(正号或者负号)
if (length >= dstlen) return 0;// 如果需要转换值的字符长度比目标长度还大,就表明转换失败

/* Null term. */
uint32_t next = length;
dst[next] = '\0'; // 给字符串设置结尾空字符
next--; // 减一个长度
while (value >= 100) { // 乘以2是因为一个二位数是由两个数字组成,在digits数组中,想定位对应数字,需要乘以2
int const i = (value % 100) * 2;
value /= 100;
// 获得两位数字,放入数组中;这个数组是由末尾向前填充,因为value值也是从数值的后面位向前获取
dst[next] = digits[i + 1];
dst[next - 1] = digits[i];
next -= 2;
}

/* Handle last 1-2 digits. */
if (value < 10) { // 如果得到的值是自然数,直接补0转换为字符串;如果不是自然数,也就是两位数,不需要补0,和上面一样
dst[next] = '0' + (uint32_t) value;
} else {
int i = (uint32_t) value * 2;
dst[next] = digits[i + 1];
dst[next - 1] = digits[i];
}

/* Add sign. */
if (negative) dst[0] = '-'; // 如果是负数,就将负号加入最前面
return length; // 这里就是总长度
}

/* Convert a string into a long long. Returns 1 if the string could be parsed
* into a (non-overflowing) long long, 0 otherwise. The value will be set to
* the parsed value when appropriate.
*
* Note that this function demands that the string strictly represents
* a long long: no spaces or other characters before or after the string
* representing the number are accepted, nor zeroes at the start if not
* for the string "0" representing the zero number.
*
* Because of its strictness, it is safe to use this function to check if
* you can convert a string into a long long, and obtain back the string
* from the number without any loss in the string representation. */
// 与上面的函数反过来,string转long long,输入字符串s转long long,保存到value中
int string2ll(const char *s, size_t slen, long long *value) {
const char *p = s;
size_t plen = 0;
int negative = 0;
unsigned long long v;

/* A zero length string is not a valid number. */
if (plen == slen) // 如果字符串长度为0
return 0;

/* Special case: first and only digit is 0. */
if (slen == 1 && p[0] == '0') { // 如果字符串长度为1,并且字符串是"0"
if (value != NULL) *value = 0;
return 1;
}

/* Handle negative numbers: just set a flag and continue like if it
* was a positive number. Later convert into negative. */
if (p[0] == '-') { // 如果字符串的第一位是"-",表示负数
negative = 1;
p++; plen++;

/* Abort on only a negative sign. */
if (plen == slen) // 如果仅有一个负号
return 0;
}

/* First digit should be 1-9, otherwise the string should just be 0. */
if (p[0] >= '1' && p[0] <= '9') { // 如果第一个字符是1到9
v = p[0]-'0'; // 那么就转为数字
p++; plen++;
} else {
return 0;
}

/* Parse all the other digits, checking for overflow at every step. */
// 解析其他所有字符串,检查是否溢出
while (plen < slen && p[0] >= '0' && p[0] <= '9') {
if (v > (ULLONG_MAX / 10)) /* Overflow. */
return 0;
v *= 10; // 正常情况就*10

if (v > (ULLONG_MAX - (p[0]-'0'))) /* Overflow. */
return 0;
v += p[0]-'0'; // 将个位数补齐

p++; plen++; // 一位一位的进行
}

/* Return if not all bytes were used. */
if (plen < slen)
return 0;

/* Convert to negative if needed, and do the final overflow check when
* converting from unsigned long long to long long. */
if (negative) { // 如果有负号,就让其成为负数
if (v > ((unsigned long long)(-(LLONG_MIN+1))+1)) /* Overflow. */
return 0;
if (value != NULL) *value = -v;
} else {
if (v > LLONG_MAX) /* Overflow. */
return 0;
if (value != NULL) *value = v;
}
return 1; // 转换成功返回1
}

/* Convert a string into a long. Returns 1 if the string could be parsed into a
* (non-overflowing) long, 0 otherwise. The value will be set to the parsed
* value when appropriate. */
// string转换为long , 基本上是调用string2ll,只是转换后的值强制转换为long
int string2l(const char *s, size_t slen, long *lval) {
long long llval;

if (!string2ll(s,slen,&llval))
return 0;

if (llval < LONG_MIN || llval > LONG_MAX)
return 0;

*lval = (long)llval;
return 1;
}

/* Convert a string into a double. Returns 1 if the string could be parsed
* into a (non-overflowing) double, 0 otherwise. The value will be set to
* the parsed value when appropriate.
*
* Note that this function demands that the string strictly represents
* a double: no spaces or other characters before or after the string
* representing the number are accepted. */
// string 转换为 long double,主要使用stdlib库函数strtold
int string2ld(const char *s, size_t slen, long double *dp) {
char buf[MAX_LONG_DOUBLE_CHARS];
long double value;
char *eptr;

if (slen >= sizeof(buf)) return 0;
memcpy(buf,s,slen);
buf[slen] = '\0';

errno = 0;
value = strtold(buf, &eptr); // 调用stdlib中的库函数
// 判断是否合法
if (isspace(buf[0]) || eptr[0] != '\0' ||
(errno == ERANGE &&
(value == HUGE_VAL || value == -HUGE_VAL || value == 0)) ||
errno == EINVAL ||
isnan(value))
return 0;

if (dp) *dp = value;
return 1;
}

/* Convert a double to a string representation. Returns the number of bytes
* required. The representation should always be parsable by strtod(3).
* This function does not support human-friendly formatting like ld2string
* does. It is intended mainly to be used inside t_zset.c when writing scores
* into a ziplist representing a sorted set. */
// double转换为string,通过调用ll2string进行转换
int d2string(char *buf, size_t len, double value) {
if (isnan(value)) { // 判断value是否是一个数值
len = snprintf(buf,len,"nan");
} else if (isinf(value)) { // 判断value是否是一个无理数
if (value < 0)
len = snprintf(buf,len,"-inf");
else
len = snprintf(buf,len,"inf");
} else if (value == 0) { // 如果value为0
/* See: http://en.wikipedia.org/wiki/Signed_zero, "Comparisons". */
if (1.0/value < 0)
len = snprintf(buf,len,"-0");
else
len = snprintf(buf,len,"0");
} else {
#if (DBL_MANT_DIG >= 52) && (LLONG_MAX == 0x7fffffffffffffffLL)
/* Check if the float is in a safe range to be casted into a
* long long. We are assuming that long long is 64 bit here.
* Also we are assuming that there are no implementations around where
* double has precision < 52 bit.
*
* Under this assumptions we test if a double is inside an interval
* where casting to long long is safe. Then using two castings we
* make sure the decimal part is zero. If all this is true we use
* integer printing function that is much faster. */
double min = -4503599627370495; /* (2^52)-1 */
double max = 4503599627370496; /* -(2^52) */
if (value > min && value < max && value == ((double)((long long)value)))
len = ll2string(buf,len,(long long)value);
else
#endif
len = snprintf(buf,len,"%.17g",value);
}

return len;
}

/* Convert a long double into a string. If humanfriendly is non-zero
* it does not use exponential format and trims trailing zeroes at the end,
* however this results in loss of precision. Otherwise exp format is used
* and the output of snprintf() is not modified.
*
* The function returns the length of the string or zero if there was not
* enough buffer room to store it. */
// long double转换为string
int ld2string(char *buf, size_t len, long double value, int humanfriendly) {
size_t l;

if (isinf(value)) { //如果value为无理数
/* Libc in odd systems (Hi Solaris!) will format infinite in a
* different way, so better to handle it in an explicit way. */
if (len < 5) return 0; /* No room. 5 is "-inf\0" */ // 先判断目标字符串长度是否能容纳
if (value > 0) {
memcpy(buf,"inf",3);
l = 3;
} else {
memcpy(buf,"-inf",4);
l = 4;
}
} else if (humanfriendly) { // 如果需要转换为人类可读
/* We use 17 digits precision since with 128 bit floats that precision
* after rounding is able to represent most small decimal numbers in a
* way that is "non surprising" for the user (that is, most small
* decimal numbers will be represented in a way that when converted
* back into a string are exactly the same as what the user typed.) */
l = snprintf(buf,len,"%.17Lf", value); // 将value通过格式化转换为人类可读样式,再存入buf中,返回其长度
if (l+1 > len) return 0; /* No room. */ // 如果转换后的长度大于目标字符串buf的长度
/* Now remove trailing zeroes after the '.' */
if (strchr(buf,'.') != NULL) {// 如果'.'字符在buf中存在,表示它是一个浮点数
char *p = buf+l-1; // 指针p指向最末尾
while(*p == '0') { // 判断第一个不为0的数,然后就在将后面的0都清除 1.2000000 = 1.2
p--;
l--;
}
if (*p == '.') l--; // 如果直接到'.'都没有不为0的数,表示这个数为整数,就把'.'一起去掉
}
} else {
l = snprintf(buf,len,"%.17Lg", value); // 直接将数值打印出来,不考虑是否对人类友好
if (l+1 > len) return 0; /* No room. */
}
buf[l] = '\0'; // 空字符结尾
return l; // 返回字符串长度
}

/* Get random bytes, attempts to get an initial seed from /dev/urandom and
* the uses a one way hash function in counter mode to generate a random
* stream. However if /dev/urandom is not available, a weaker seed is used.
*
* This function is not thread safe, since the state is global. */
// 获取随机的字节
void getRandomBytes(unsigned char *p, size_t len) {
/* Global state. */
static int seed_initialized = 0; // 被初始化的种子
static unsigned char seed[20]; /* The SHA1 seed, from /dev/urandom. */ // 从/dev/urandom中获取随机种子
static uint64_t counter = 0; /* The counter we hash with the seed. */ // 用种子计算hash值

if (!seed_initialized) {
/* Initialize a seed and use SHA1 in counter mode, where we hash
* the same seed with a progressive counter. For the goals of this
* function we just need non-colliding strings, there are no
* cryptographic security needs. */
FILE *fp = fopen("/dev/urandom","r"); // 打开/dev/urandom文件
if (fp == NULL || fread(seed,sizeof(seed),1,fp) != 1) {
/* Revert to a weaker seed, and in this case reseed again
* at every call.*/
// sizeof(seed)获取的随机数数量
for (unsigned int j = 0; j < sizeof(seed); j++) {
struct timeval tv;
gettimeofday(&tv,NULL); // 获取天
pid_t pid = getpid(); // 获取pid号
seed[j] = tv.tv_sec ^ tv.tv_usec ^ pid ^ (long)fp;//秒^微秒^pid号^文件描述符号用来生成种子
}
} else { // 没有获取到随机数
seed_initialized = 1;
}
if (fp) fclose(fp);
}

while(len) {
unsigned char digest[20];
SHA1_CTX ctx;
unsigned int copylen = len > 20 ? 20 : len; // 让copylen长度在20以内

// 使用sha1算法生成hash值digest
SHA1Init(&ctx); // 初始化sha1
SHA1Update(&ctx, seed, sizeof(seed));
SHA1Update(&ctx, (unsigned char*)&counter,sizeof(counter));
SHA1Final(digest, &ctx);
counter++;

memcpy(p,digest,copylen);// 将值放到p处
len -= copylen;
p += copylen;
}
}

/* Generate the Redis "Run ID", a SHA1-sized random number that identifies a
* given execution of Redis, so that if you are talking with an instance
* having run_id == A, and you reconnect and it has run_id == B, you can be
* sure that it is either a different instance or it was restarted. */
// 获取随机的16进制字符
void getRandomHexChars(char *p, size_t len) {
char *charset = "0123456789abcdef";
size_t j;

getRandomBytes((unsigned char*)p,len);
for (j = 0; j < len; j++) p[j] = charset[p[j] & 0x0F];
}

/* Given the filename, return the absolute path as an SDS string, or NULL
* if it fails for some reason. Note that "filename" may be an absolute path
* already, this will be detected and handled correctly.
*
* The function does not try to normalize everything, but only the obvious
* case of one or more "../" appearing at the start of "filename"
* relative path. */
// 获取文件的绝对路径
sds getAbsolutePath(char *filename) {
char cwd[1024];
sds abspath;
sds relpath = sdsnew(filename);

relpath = sdstrim(relpath," \r\n\t"); // 将多余字符去除
if (relpath[0] == '/') return relpath; /* Path is already absolute. */ // 如果第一个字符就是'/',表示就是绝对路径

/* If path is relative, join cwd and relative path. */
if (getcwd(cwd,sizeof(cwd)) == NULL) { // 获取绝对路径
sdsfree(relpath); // 将relpath这个中间变量释放
return NULL;
}
abspath = sdsnew(cwd); // 新创建一个sds字符串
if (sdslen(abspath) && abspath[sdslen(abspath)-1] != '/') // 如果是这样/home/myhome,就转换为/home/myhome/
abspath = sdscat(abspath,"/");

/* At this point we have the current path always ending with "/", and
* the trimmed relative path. Try to normalize the obvious case of
* trailing ../ elements at the start of the path.
*
* For every "../" we find in the filename, we remove it and also remove
* the last element of the cwd, unless the current cwd is "/". */
while (sdslen(relpath) >= 3 &&
relpath[0] == '.' && relpath[1] == '.' && relpath[2] == '/')
{
sdsrange(relpath,3,-1);
if (sdslen(abspath) > 1) {
char *p = abspath + sdslen(abspath)-2;
int trimlen = 1;

while(*p != '/') {
p--;
trimlen++;
}
sdsrange(abspath,0,-(trimlen+1));
}
}

/* Finally glue the two parts together. */
abspath = sdscatsds(abspath,relpath);
sdsfree(relpath);
return abspath;
}

/*
* Gets the proper timezone in a more portable fashion
* i.e timezone variables are linux specific.
*/
// 获取时区
unsigned long getTimeZone(void) {
#ifdef __linux__
return timezone;
#else
struct timeval tv;
struct timezone tz;

gettimeofday(&tv, &tz);

return tz.tz_minuteswest * 60UL;
#endif
}

/* Return true if the specified path is just a file basename without any
* relative or absolute path. This function just checks that no / or \
* character exists inside the specified path, that's enough in the
* environments where Redis runs. */
// 判断路径的根目录名
int pathIsBaseName(char *path) {
return strchr(path,'/') == NULL && strchr(path,'\\') == NULL;
}

#ifdef REDIS_TEST
#include <assert.h>

static void test_string2ll(void) {
char buf[32];
long long v;

/* May not start with +. */
strcpy(buf,"+1");
assert(string2ll(buf,strlen(buf),&v) == 0);

/* Leading space. */
strcpy(buf," 1");
assert(string2ll(buf,strlen(buf),&v) == 0);

/* Trailing space. */
strcpy(buf,"1 ");
assert(string2ll(buf,strlen(buf),&v) == 0);

/* May not start with 0. */
strcpy(buf,"01");
assert(string2ll(buf,strlen(buf),&v) == 0);

strcpy(buf,"-1");
assert(string2ll(buf,strlen(buf),&v) == 1);
assert(v == -1);

strcpy(buf,"0");
assert(string2ll(buf,strlen(buf),&v) == 1);
assert(v == 0);

strcpy(buf,"1");
assert(string2ll(buf,strlen(buf),&v) == 1);
assert(v == 1);

strcpy(buf,"99");
assert(string2ll(buf,strlen(buf),&v) == 1);
assert(v == 99);

strcpy(buf,"-99");
assert(string2ll(buf,strlen(buf),&v) == 1);
assert(v == -99);

strcpy(buf,"-9223372036854775808");
assert(string2ll(buf,strlen(buf),&v) == 1);
assert(v == LLONG_MIN);

strcpy(buf,"-9223372036854775809"); /* overflow */
assert(string2ll(buf,strlen(buf),&v) == 0);

strcpy(buf,"9223372036854775807");
assert(string2ll(buf,strlen(buf),&v) == 1);
assert(v == LLONG_MAX);

strcpy(buf,"9223372036854775808"); /* overflow */
assert(string2ll(buf,strlen(buf),&v) == 0);
}

static void test_string2l(void) {
char buf[32];
long v;

/* May not start with +. */
strcpy(buf,"+1");
assert(string2l(buf,strlen(buf),&v) == 0);

/* May not start with 0. */
strcpy(buf,"01");
assert(string2l(buf,strlen(buf),&v) == 0);

strcpy(buf,"-1");
assert(string2l(buf,strlen(buf),&v) == 1);
assert(v == -1);

strcpy(buf,"0");
assert(string2l(buf,strlen(buf),&v) == 1);
assert(v == 0);

strcpy(buf,"1");
assert(string2l(buf,strlen(buf),&v) == 1);
assert(v == 1);

strcpy(buf,"99");
assert(string2l(buf,strlen(buf),&v) == 1);
assert(v == 99);

strcpy(buf,"-99");
assert(string2l(buf,strlen(buf),&v) == 1);
assert(v == -99);

#if LONG_MAX != LLONG_MAX
strcpy(buf,"-2147483648");
assert(string2l(buf,strlen(buf),&v) == 1);
assert(v == LONG_MIN);

strcpy(buf,"-2147483649"); /* overflow */
assert(string2l(buf,strlen(buf),&v) == 0);

strcpy(buf,"2147483647");
assert(string2l(buf,strlen(buf),&v) == 1);
assert(v == LONG_MAX);

strcpy(buf,"2147483648"); /* overflow */
assert(string2l(buf,strlen(buf),&v) == 0);
#endif
}

static void test_ll2string(void) {
char buf[32];
long long v;
int sz;

v = 0;
sz = ll2string(buf, sizeof buf, v);
assert(sz == 1);
assert(!strcmp(buf, "0"));

v = -1;
sz = ll2string(buf, sizeof buf, v);
assert(sz == 2);
assert(!strcmp(buf, "-1"));

v = 99;
sz = ll2string(buf, sizeof buf, v);
assert(sz == 2);
assert(!strcmp(buf, "99"));

v = -99;
sz = ll2string(buf, sizeof buf, v);
assert(sz == 3);
assert(!strcmp(buf, "-99"));

v = -2147483648;
sz = ll2string(buf, sizeof buf, v);
assert(sz == 11);
assert(!strcmp(buf, "-2147483648"));

v = LLONG_MIN;
sz = ll2string(buf, sizeof buf, v);
assert(sz == 20);
assert(!strcmp(buf, "-9223372036854775808"));

v = LLONG_MAX;
sz = ll2string(buf, sizeof buf, v);
assert(sz == 19);
assert(!strcmp(buf, "9223372036854775807"));
}

#define UNUSED(x) (void)(x)
int utilTest(int argc, char **argv) {
UNUSED(argc);
UNUSED(argv);

test_string2ll();
test_string2l();
test_ll2string();
return 0;
}
#endif
文章作者: rack-leen
文章链接: http://yoursite.com/2019/12/26/%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB/C/redis/redis%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB-util-%E7%B1%BB%E5%9E%8B%E8%BD%AC%E6%8D%A2%E5%B7%A5%E5%85%B7/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 rack-leen's blog
打赏
  • 微信
  • 支付宝

评论