From b01413abb8e6d7880af39d51d2781662faa3e789 Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Tue, 13 Nov 2018 23:57:15 +0800 Subject: [PATCH 001/126] =?UTF-8?q?=E5=85=88=E5=86=99php=E9=83=A8=E5=88=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .editorconfig | 25 +++++++++++++++++++++ README.MD | 6 +++-- spec/Stringy/StringySpec.php | 20 +++++++++++++++++ src/Minbaby/Stringy/Stringy.php | 39 +++++++++++++++++++++++++++++++++ tools/test.sh | 4 ++-- 5 files changed, 90 insertions(+), 4 deletions(-) create mode 100644 .editorconfig create mode 100644 spec/Stringy/StringySpec.php create mode 100644 src/Minbaby/Stringy/Stringy.php diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..1102fc0 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,25 @@ +# EditorConfig is awesome: https://EditorConfig.org + +# top-most EditorConfig file +root = true + +# Unix-style newlines with a newline ending every file +[*] +end_of_line = lf +insert_final_newline = true + +# Matches multiple files with brace expansion notation +# Set default charset +[*.{php,c,h}] +charset = utf-8 +indent_size = 4 +indent_style = space + +# Tab indentation (no size specified) +[Makefile] +indent_style = tab + +# Matches the exact files either package.json or .travis.yml +[*.{json,yml}] +indent_style = space +indent_size = 2 \ No newline at end of file diff --git a/README.MD b/README.MD index a45115e..8f21b79 100644 --- a/README.MD +++ b/README.MD @@ -27,7 +27,9 @@ 2. 查看 `src/Minbaby/` 目录下的 php 实现 3. 查看 `src/ext` 目录下的 c 实现 -## 其他 +## TODO + + - [ ] [stringy](https://github.com/danielstjules/Stringy) ### skip ci @@ -37,4 +39,4 @@ ### 参考 - [phpbook](https://github.com/walu/phpbook) -- [Kahlan](https://kahlan.github.io/docs/index.html) \ No newline at end of file +- [Kahlan](https://kahlan.github.io/docs/index.html) diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php new file mode 100644 index 0000000..2d8f79e --- /dev/null +++ b/spec/Stringy/StringySpec.php @@ -0,0 +1,20 @@ +toBe(true); + \expect((string) $stringy)->toBe('test test2 test3'); + \expect($stringy->getEncoding())->toBe('UTF-8'); + }); + + it("test empty construct", function () { + $stringy = new Stringy(); + + \expect($stringy instanceof Stringy)->toBe(true); + \expect((string) $stringy)->toBe(''); + }); +}); diff --git a/src/Minbaby/Stringy/Stringy.php b/src/Minbaby/Stringy/Stringy.php new file mode 100644 index 0000000..858b14c --- /dev/null +++ b/src/Minbaby/Stringy/Stringy.php @@ -0,0 +1,39 @@ +str = (string) $str; + $this->encoding = $encoding ?: \mb_internal_encoding(); + } + + public function __toString() + { + return $this->str; + } + + public function getEncoding() + { + return $this->encoding; + } +} diff --git a/tools/test.sh b/tools/test.sh index e041d0a..512c8e0 100755 --- a/tools/test.sh +++ b/tools/test.sh @@ -6,11 +6,11 @@ pwd # echo "disable ext startup.so" phpbrew ext disable startup -./vendor/bin/kahlan +./vendor/bin/kahlan --reporter=verbose # echo "enable ext start.so" phpbrew ext enable startup -./vendor/bin/kahlan +./vendor/bin/kahlan --reporter=verbose From 546b310b78860f2ac7a862abb982e92a22a1d38c Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Wed, 14 Nov 2018 21:20:30 +0800 Subject: [PATCH 002/126] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.MD | 3 +-- spec/Stringy/StringySpec.php | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/README.MD b/README.MD index 8f21b79..ed90296 100644 --- a/README.MD +++ b/README.MD @@ -11,7 +11,6 @@ 3. 再用 ext 实现 4. 跑测试 - ## 测试思路 利用 php [自动加载](http://www.php.net/manual/zh/language.oop5.autoload.php)的逻辑。 @@ -29,7 +28,7 @@ ## TODO - - [ ] [stringy](https://github.com/danielstjules/Stringy) +- [ ] [stringy](https://github.com/danielstjules/Stringy) ### skip ci diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index 2d8f79e..af2fd85 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -17,4 +17,20 @@ \expect($stringy instanceof Stringy)->toBe(true); \expect((string) $stringy)->toBe(''); }); + + it("test construct with array", function () { + $closure = function () { + (string) new Stringy([]); + }; + + \expect($closure)->toThrow(new \InvalidArgumentException('Passed value cannot be an array')); + }); + + it("test construct with object", function () { + $closure = function () { + (string) new Stringy(new \stdClass()); + }; + + \expect($closure)->toThrow(new \InvalidArgumentException('Passed object must have a __toString method')); + }); }); From e35dc3c75a522b41fbc83611747f542ec5faf733 Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Thu, 15 Nov 2018 00:20:41 +0800 Subject: [PATCH 003/126] static method create --- spec/Stringy/StringySpec.php | 29 +++++++++++++++++++++++++++-- src/Minbaby/Stringy/Stringy.php | 5 +++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index af2fd85..5cd73f2 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -6,7 +6,7 @@ it("test construct", function () { $stringy = new Stringy('test test2 test3', 'UTF-8'); - \expect($stringy instanceof Stringy)->toBe(true); + \expect($stringy)->toBeAnInstanceOf(Stringy::class); \expect((string) $stringy)->toBe('test test2 test3'); \expect($stringy->getEncoding())->toBe('UTF-8'); }); @@ -26,11 +26,36 @@ \expect($closure)->toThrow(new \InvalidArgumentException('Passed value cannot be an array')); }); - it("test construct with object", function () { + it("test missing to string", function () { $closure = function () { (string) new Stringy(new \stdClass()); }; \expect($closure)->toThrow(new \InvalidArgumentException('Passed object must have a __toString method')); }); + + it("test __toString", function () { + $data = [ + ['', null], + ['', false], + ['1', true], + ['-9', -9], + ['1.18', 1.18], + [' string ', ' string '], + ['❤', '❤'], + ]; + + foreach($data as $v) { + [$key, $value] = $v; + \expect($key)->toBe((string) new Stringy($value)); + } + }); + + it("test create", function () { + $stringy = Stringy::create('foo bar', 'UTF-8'); + + \expect($stringy)->toBeAnInstanceOf(Stringy::class); + \expect('foo bar')->toBe((string) $stringy); + \expect('UTF-8')->toBe($stringy->getEncoding()); + }); }); diff --git a/src/Minbaby/Stringy/Stringy.php b/src/Minbaby/Stringy/Stringy.php index 858b14c..2bf9979 100644 --- a/src/Minbaby/Stringy/Stringy.php +++ b/src/Minbaby/Stringy/Stringy.php @@ -36,4 +36,9 @@ public function getEncoding() { return $this->encoding; } + + public static function create($str, $encoding) + { + return new static($str, $encoding); + } } From d2a64b0e1361deaecc3ec677a5cdfdab3937427f Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Thu, 15 Nov 2018 20:35:39 +0800 Subject: [PATCH 004/126] it test chaining --- spec/Stringy/StringySpec.php | 6 +++ src/Minbaby/Stringy/Stringy.php | 80 +++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+) diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index 5cd73f2..271983e 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -58,4 +58,10 @@ \expect('foo bar')->toBe((string) $stringy); \expect('UTF-8')->toBe($stringy->getEncoding()); }); + + it('test chaining', function () { + $stringy = Stringy::create('Fòô Bàř', 'UTF-8'); + \expect($stringy)->toBeAnInstanceOf(Stringy::class); + \expect('FÒÔ bÀŘ')->toBe((string) $stringy->collapseWhiteSpace()->swapCase()->upperCaseFirst()); + }); }); diff --git a/src/Minbaby/Stringy/Stringy.php b/src/Minbaby/Stringy/Stringy.php index 2bf9979..f737abc 100644 --- a/src/Minbaby/Stringy/Stringy.php +++ b/src/Minbaby/Stringy/Stringy.php @@ -41,4 +41,84 @@ public static function create($str, $encoding) { return new static($str, $encoding); } + + public function collapseWhiteSpace() + { + return $this->regexReplace('[[:space:]]+', ' ')->trim(); + } + + public function regexReplace($pattern, $replacement, $options = 'msr') + { + $regexEncoding = $this->regexEncoding(); + $this->regexEncoding($this->encoding); + + $str = $this->eregReplace($pattern, $replacement, $this->str, $options); + $this->regexEncoding($regexEncoding); + + return static::create($str, $this->encoding); + } + + protected function regexEncoding() + { + static $functionExists; + + if ($functionExists === null) { + $functionExists = function_exists('\mb_regex_encoding'); + } + + if ($functionExists) { + $args = func_get_args(); + return \call_user_func_array('\mb_regex_encoding', $args); + } + } + + protected function eregReplace($pattern, $replacement, $string, $option = 'msr') + { + static $functionExists; + if ($functionExists === null) { + $functionExists = function_exists('\mb_split'); + } + if ($functionExists) { + return \mb_ereg_replace($pattern, $replacement, $string, $option); + } else if ($this->supportsEncoding()) { + $option = str_replace('r', '', $option); + return \preg_replace("/$pattern/u$option", $replacement, $string); + } + } + + public function trim($chars = null) + { + $chars = ($chars) ? preg_quote($chars) : '[:space:]'; + return $this->regexReplace("^[$chars]+|[$chars]+\$", ''); + } + + public function swapCase() + { + $stringy = static::create($this->str, $this->encoding); + $encoding = $stringy->encoding; + $stringy->str = preg_replace_callback( + '/[\S]/u', + function ($match) use ($encoding) { + if ($match[0] == \mb_strtoupper($match[0], $encoding)) { + return \mb_strtolower($match[0], $encoding); + } + return \mb_strtoupper($match[0], $encoding); + }, + $stringy->str + ); + return $stringy; + } + + public function upperCaseFirst() + { + $first = \mb_substr($this->str, 0, 1, $this->encoding); + $rest = \mb_substr($this->str, 1, $this->length() - 1, $this->encoding); + $str = \mb_strtoupper($first, $this->encoding) . $rest; + return static::create($str, $this->encoding); + } + + public function length() + { + return \mb_strlen($this->str, $this->encoding); + } } From 9b5f829ea96b040dabe670f7a0eb9d0427281c21 Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Sat, 17 Nov 2018 01:08:19 +0800 Subject: [PATCH 005/126] update count+iterator+offsetExists+OffsetGet --- spec/Stringy/StringySpec.php | 49 ++++++++++++++++++++++++ src/Minbaby/Stringy/Stringy.php | 67 ++++++++++++++++++++++++++++++++- tools/test.sh | 1 + 3 files changed, 116 insertions(+), 1 deletion(-) diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index 271983e..42e844f 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -64,4 +64,53 @@ \expect($stringy)->toBeAnInstanceOf(Stringy::class); \expect('FÒÔ bÀŘ')->toBe((string) $stringy->collapseWhiteSpace()->swapCase()->upperCaseFirst()); }); + + it('test count', function () { + $stringy = Stringy::create('Fòô', 'UTF-8'); + \expect($stringy->count())->toBe(3); + \expect(count($stringy))->toBe(3); + }); + + it('test GetIterator', function () { + $stringy = Stringy::create('Fòô Bàř', 'UTF-8'); + $valResult = []; + foreach ($stringy as $char) { + $valResult[] = $char; + } + $keyValResult = []; + foreach ($stringy as $pos => $char) { + $keyValResult[$pos] = $char; + } + + \expect($valResult)->toBe(['F', 'ò', 'ô', ' ', 'B', 'à', 'ř']); + \expect($keyValResult)->toBe(['F', 'ò', 'ô', ' ', 'B', 'à', 'ř']); + }); + + it('test offsetExists', function () { + $data = [ + [true, 0], + [true, 2], + [false, 3], + [true, -1], + [true, -3], + [false, -4] + ]; + + $stringy = Stringy::create('fòô', 'UTF-8'); + + foreach ($data as $value) { + [$expected, $offset] = $value; + \expect($stringy->offsetExists($offset))->toBe($expected); + \expect(isset($stringy[$offset]))->toBe($expected); + } + }); + + it('test OffsetGet', function () { + $stringy = Stringy::create('fòô', 'UTF-8'); + + \expect($stringy->offsetGet(0))->toBe('f'); + \expect($stringy->offsetGet(1))->toBe('ò'); + + \expect($stringy[2])->toBe('ô'); + }); }); diff --git a/src/Minbaby/Stringy/Stringy.php b/src/Minbaby/Stringy/Stringy.php index f737abc..7aa4d49 100644 --- a/src/Minbaby/Stringy/Stringy.php +++ b/src/Minbaby/Stringy/Stringy.php @@ -4,7 +4,7 @@ use InvalidArgumentException; -class Stringy +class Stringy implements \Countable, \IteratorAggregate, \ArrayAccess { protected $str; @@ -121,4 +121,69 @@ public function length() { return \mb_strlen($this->str, $this->encoding); } + + public function count() + { + return $this->length(); + } + + public function getIterator() + { + return new \ArrayIterator($this->chars()); + } + + public function chars() + { + $chars = []; + for($i = 0, $l = $this->length(); $i < $l; $i++) + { + $chars[] = $this->at($i)->str; + } + + return $chars; + } + + public function at($index) + { + return $this->substr($index, 1); + } + + public function substr($start, $length = null) + { + $length = $length === null ? $this->length() : $length; + $str = \mb_substr($this->str, $start, $length, $this->encoding); + return static::create($str, $this->encoding); + } + + public function offsetExists($offset) + { + $length = $this->length(); + $offset = (int) $offset; + + if ($offset >= 0) { + return $length > $offset; + } + + return $length >= abs($offset); + } + + public function offsetGet($offset) + { + $offset = (int) $offset; + $length = $this->length(); + if (($offset >= 0 && $length <= $offset) || $length < abs($offset)) { + throw new OutOfBoundsException('No character exists at the index'); + } + return \mb_substr($this->str, $offset, 1, $this->encoding); + } + + public function offsetSet($offset, $value) + { + + } + + public function offsetUnset($offset) + { + + } } diff --git a/tools/test.sh b/tools/test.sh index 512c8e0..fe832e5 100755 --- a/tools/test.sh +++ b/tools/test.sh @@ -1,6 +1,7 @@ #!/usr/bin/env bash set -e +set -x pwd From 18e8962f2e74f24af2e23d70b5ba6471fbda8378 Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Sat, 17 Nov 2018 11:31:15 +0800 Subject: [PATCH 006/126] update offsetSet --- .gitignore | 4 ++-- .vscode/c_cpp_properties.json | 17 +++++++++++++++++ .vscode/settings.json | 10 ++++++++++ .vscode/snnipt.code-snippets | 28 ++++++++++++++++++++++++++++ spec/Stringy/StringySpec.php | 16 ++++++++++++++++ src/Minbaby/Stringy/Stringy.php | 4 ++-- 6 files changed, 75 insertions(+), 4 deletions(-) create mode 100644 .vscode/c_cpp_properties.json create mode 100644 .vscode/settings.json create mode 100644 .vscode/snnipt.code-snippets diff --git a/.gitignore b/.gitignore index 391d310..e422bd6 100644 --- a/.gitignore +++ b/.gitignore @@ -35,7 +35,7 @@ tests/*/*.log tests/*/*.sh # minbaby -.vscode +# .vscode tags GRTAGS GTAGS @@ -43,4 +43,4 @@ GPATH /vendor/ *.loT -/nbproject/private/ \ No newline at end of file +/nbproject/private/ diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..d2ad79e --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,17 @@ +{ + "configurations": [ + { + "name": "Linux", + "includePath": [ + "${workspaceFolder}/**", + "~/.phpbrew/build/php-7.1.23/**" + ], + "defines": [], + "compilerPath": "/usr/bin/gcc", + "cStandard": "c11", + "cppStandard": "c++17", + "intelliSenseMode": "clang-x64" + } + ], + "version": 4 +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..5bbe39f --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,10 @@ +{ + "files.associations": { + "php.h": "c", + "php_ini.h": "c", + "zend.h": "c", + "type_traits": "c", + "typeinfo": "cpp", + "stdarg.h": "c" + } +} \ No newline at end of file diff --git a/.vscode/snnipt.code-snippets b/.vscode/snnipt.code-snippets new file mode 100644 index 0000000..f394eaf --- /dev/null +++ b/.vscode/snnipt.code-snippets @@ -0,0 +1,28 @@ +{ + // Place your global snippets here. Each snippet is defined under a snippet name and has a scope, prefix, body and + // description. Add comma separated ids of the languages where the snippet is applicable in the scope field. If scope + // is left empty or omitted, the snippet gets applied to all languages. The prefix is what is + // used to trigger the snippet and the body will be expanded and inserted. Possible variables are: + // $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders. + // Placeholders with the same ids are connected. + // Example: + // "Print to console": { + // "scope": "javascript,typescript", + // "prefix": "log", + // "body": [ + // "console.log('$1');", + // "$2" + // ], + // "description": "Log output to console" + // } + "itf": { + "prefix": "ift", + "scope": "php", + "body": [ + "it('test $1', function () {", + " $0", + "});" + ], + "description": "it function scope" + } +} diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index 42e844f..1d05e39 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -113,4 +113,20 @@ \expect($stringy[2])->toBe('ô'); }); + + it('test OffsetGet out of bounds', function () { + $stringy = Stringy::create('fòô', 'UTF-8'); + $callable = function () use ($stringy) { + $test = $stringy[3]; + }; + \expect($callable)->toThrow(new \OutOfBoundsException('No character exists at the index')); + }); + + it('test OffsetSet', function () { + $stringy = Stringy::create('fòô', 'UTF-8'); + $callable = function () use ($stringy) { + $stringy[1] = 'invalid'; + }; + \expect($callable)->toThrow(new \Exception('Stringy object is immutable, cannot modify char')); + }); }); diff --git a/src/Minbaby/Stringy/Stringy.php b/src/Minbaby/Stringy/Stringy.php index 7aa4d49..55c6261 100644 --- a/src/Minbaby/Stringy/Stringy.php +++ b/src/Minbaby/Stringy/Stringy.php @@ -172,14 +172,14 @@ public function offsetGet($offset) $offset = (int) $offset; $length = $this->length(); if (($offset >= 0 && $length <= $offset) || $length < abs($offset)) { - throw new OutOfBoundsException('No character exists at the index'); + throw new \OutOfBoundsException('No character exists at the index'); } return \mb_substr($this->str, $offset, 1, $this->encoding); } public function offsetSet($offset, $value) { - + throw new \Exception('Stringy object is immutable, cannot modify char'); } public function offsetUnset($offset) From 7794911379f92aa5f341ef54a8112e80ad8596a7 Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Sat, 17 Nov 2018 13:26:58 +0800 Subject: [PATCH 007/126] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20circleci=20?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=E5=AF=BC=E8=87=B4=E6=97=A0=E6=B3=95=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E9=80=9A=E8=BF=87=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .circleci/config.yml | 5 +++++ .circleci/docker-php-ext-startup.ini | 1 + 2 files changed, 6 insertions(+) create mode 100644 .circleci/docker-php-ext-startup.ini diff --git a/.circleci/config.yml b/.circleci/config.yml index 4cad210..61bc287 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -37,9 +37,14 @@ jobs: name: run test command: ./vendor/bin/kahlan + - run: + name: cp docker-php-ext-start.ini + command: sudo cp .circleci/docker-php-ext-startup.ini /usr/local/etc/php/conf.d/ + - run: name: enable startup command: sudo docker-php-ext-enable startup + - run: name: run test command: ./vendor/bin/kahlan diff --git a/.circleci/docker-php-ext-startup.ini b/.circleci/docker-php-ext-startup.ini new file mode 100644 index 0000000..2e123ed --- /dev/null +++ b/.circleci/docker-php-ext-startup.ini @@ -0,0 +1 @@ +extension=startup.so From 99ed1863f579419b4e43e6906c2bce006d7b0ded Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Sat, 17 Nov 2018 22:09:55 +0800 Subject: [PATCH 008/126] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=EF=BC=8Boffset=20unset=20test?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/keybindings.json | 13 ++++++++++ .vscode/settings.json | 13 +++++++++- .vscode/tasks.json | 48 ++++++++++++++++++++++++++++++++++++ spec/Stringy/StringySpec.php | 8 ++++++ 4 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 .vscode/keybindings.json create mode 100644 .vscode/tasks.json diff --git a/.vscode/keybindings.json b/.vscode/keybindings.json new file mode 100644 index 0000000..52e0481 --- /dev/null +++ b/.vscode/keybindings.json @@ -0,0 +1,13 @@ +// Place your key bindings in this file to overwrite the defaults +[ + { + "key": "ctrl+k ctrl+b", + "command": "workbench.action.tasks.runTask", + "args": "run build" + }, + { + "key": "ctrl+k ctrl+t", + "command": "workbench.action.tasks.runTask", + "args": "run test" + } +] \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 5bbe39f..67a35d7 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -6,5 +6,16 @@ "type_traits": "c", "typeinfo": "cpp", "stdarg.h": "c" + }, + "files.autoSave": "afterDelay", + "editor.fontSize": 18, + "editor.renderWhitespace": "boundary", + "editor.cursorStyle": "line-thin", + "files.exclude": { + "**/.git": true, + "**/.svn": true, + "**/.hg": true, + "**/CVS": true, + "**/.DS_Store": true } -} \ No newline at end of file +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..7388e21 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,48 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "label": "run build", + "type": "shell", + "command": "./tools/build.sh", + "group": { + "kind": "build", + "isDefault": true + }, + "problemMatcher": [ + "$gcc" + ], + "presentation": { + "echo": true, + "reveal": "silent", + "focus": false, + "panel": "shared", + "showReuseMessage": true, + "clear": true + } + }, + { + "label": "run test", + "type": "shell", + "command": "./tools/test.sh", + "group": { + "kind": "test", + "isDefault": true + }, + "presentation": { + "echo": true, + "reveal": "silent", + "focus": true, + "panel": "shared", + "showReuseMessage": true, + "clear": true + } + }, + { + "label": "run build && run test", + "dependsOn":["run build", "run"] + } + ] +} diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index 1d05e39..8d1f0eb 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -129,4 +129,12 @@ }; \expect($callable)->toThrow(new \Exception('Stringy object is immutable, cannot modify char')); }); + + it('test OffsetUnset', function () { + $stringy = Stringy::create('fòô', 'UTF-8'); + $callable = function () use ($stringy) { + unset($stringy[1]); + }; + \expect($callable)->toThrow(new \Exception('Stringy object is immutable, cannot modify char')); + }); }); From 29f6093edebf8531d8ba168651fa3679cbae8c60 Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Sat, 17 Nov 2018 22:35:17 +0800 Subject: [PATCH 009/126] test pass --- spec/Stringy/StringySpec.php | 2 +- src/Minbaby/Stringy/Stringy.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index 8d1f0eb..29abeea 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -135,6 +135,6 @@ $callable = function () use ($stringy) { unset($stringy[1]); }; - \expect($callable)->toThrow(new \Exception('Stringy object is immutable, cannot modify char')); + \expect($callable)->toThrow(new \Exception('Stringy object is immutable, cannot unset char')); }); }); diff --git a/src/Minbaby/Stringy/Stringy.php b/src/Minbaby/Stringy/Stringy.php index 55c6261..6dd0c47 100644 --- a/src/Minbaby/Stringy/Stringy.php +++ b/src/Minbaby/Stringy/Stringy.php @@ -184,6 +184,6 @@ public function offsetSet($offset, $value) public function offsetUnset($offset) { - + throw new \Exception('Stringy object is immutable, cannot unset char'); } } From a241c6de36dd7eae3e1f58e06edf4f1bc2ecfbea Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Sun, 18 Nov 2018 01:54:27 +0800 Subject: [PATCH 010/126] =?UTF-8?q?=E5=87=BA=E6=9D=A5=E4=B8=80=E7=82=B9?= =?UTF-8?q?=E9=97=AE=E9=A2=98=EF=BC=8C=E6=83=B3=E6=83=B3=E6=80=8E=E4=B9=88?= =?UTF-8?q?=E8=A7=A3=E5=86=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/settings.json | 5 +- README.MD | 6 +- composer.json | 3 +- config.m4 | 6 +- kahlan-config.php | 6 +- spec/Stringy/StringySpec.php | 68 ++++++++++++++++++----- src/Minbaby/{ => Ext}/Stringy/Stringy.php | 20 +++++++ src/Minbaby/{ => Ext}/Test.php | 0 src/ext/common.h | 4 -- src/ext/stringy/stringy.c | 2 + src/ext/stringy/stringy.h | 8 +++ src/ext/test.class.c | 2 +- src/ext/test.class.h | 2 + tools/test.sh | 5 +- 14 files changed, 110 insertions(+), 27 deletions(-) rename src/Minbaby/{ => Ext}/Stringy/Stringy.php (92%) rename src/Minbaby/{ => Ext}/Test.php (100%) create mode 100644 src/ext/stringy/stringy.c create mode 100644 src/ext/stringy/stringy.h diff --git a/.vscode/settings.json b/.vscode/settings.json index 67a35d7..7c7dc07 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -5,9 +5,10 @@ "zend.h": "c", "type_traits": "c", "typeinfo": "cpp", - "stdarg.h": "c" + "stdarg.h": "c", + "common.h": "c" }, - "files.autoSave": "afterDelay", + "files.autoSave": "onFocusChange", "editor.fontSize": 18, "editor.renderWhitespace": "boundary", "editor.cursorStyle": "line-thin", diff --git a/README.MD b/README.MD index ed90296..4f106c7 100644 --- a/README.MD +++ b/README.MD @@ -16,7 +16,7 @@ 利用 php [自动加载](http://www.php.net/manual/zh/language.oop5.autoload.php)的逻辑。 1. 默认禁用扩展执行一遍测试,这个时候执行的是 PHP 逻辑 -2. 启用扩展再执行一次扩展, 这个时候执行的是 EXT 逻辑 +2. 启用扩展再执行一次扩展, 这个时候执行的是 EXT 逻辑 (这个地方有个问题,如果 ext 扩展不存在,那么就会降级使用 php 代码) ## 学习方式 @@ -30,6 +30,10 @@ - [ ] [stringy](https://github.com/danielstjules/Stringy) +## 说明 + +- 使用 `@` 抑制符不是一个好习惯,尽量不要使用。 + ### skip ci - `[skip ci]` diff --git a/composer.json b/composer.json index 356b160..a3d4f48 100644 --- a/composer.json +++ b/composer.json @@ -2,6 +2,7 @@ "name": "minbaby/php-ext-startup", "type": "project", "license": "MIT", + "description": "", "authors": [ { "name": "minbaby.zhang", @@ -13,7 +14,7 @@ }, "autoload": { "psr-4": { - "Minbaby\\Ext\\": "src/Minbaby/" + "Minbaby\\Ext\\": "src/Minbaby/Ext" } }, "autoload-dev": { diff --git a/config.m4 b/config.m4 index 195e98c..2c79364 100644 --- a/config.m4 +++ b/config.m4 @@ -59,5 +59,9 @@ if test "$PHP_STARTUP" != "no"; then dnl dnl PHP_SUBST(STARTUP_SHARED_LIBADD) - PHP_NEW_EXTENSION(startup, startup.c src/ext/test.class.c, $ext_shared,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1) + $source = "startup.c \ + src/ext/test.class.c \ + src/ext/stringy/stringy.c"; + + PHP_NEW_EXTENSION(startup, $source, $ext_shared,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1) fi diff --git a/kahlan-config.php b/kahlan-config.php index ba50604..1d57af1 100644 --- a/kahlan-config.php +++ b/kahlan-config.php @@ -1,3 +1,7 @@ commandLine(); +$commandLine->option('reporter', 'default', 'verbose'); +$commandLine->option('ff', 'default', 1); diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index 29abeea..15d2814 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -11,14 +11,14 @@ \expect($stringy->getEncoding())->toBe('UTF-8'); }); - it("test empty construct", function () { + xit("test empty construct", function () { $stringy = new Stringy(); \expect($stringy instanceof Stringy)->toBe(true); \expect((string) $stringy)->toBe(''); }); - it("test construct with array", function () { + xit("test construct with array", function () { $closure = function () { (string) new Stringy([]); }; @@ -26,7 +26,7 @@ \expect($closure)->toThrow(new \InvalidArgumentException('Passed value cannot be an array')); }); - it("test missing to string", function () { + xit("test missing to string", function () { $closure = function () { (string) new Stringy(new \stdClass()); }; @@ -34,7 +34,7 @@ \expect($closure)->toThrow(new \InvalidArgumentException('Passed object must have a __toString method')); }); - it("test __toString", function () { + xit("test __toString", function () { $data = [ ['', null], ['', false], @@ -51,7 +51,7 @@ } }); - it("test create", function () { + xit("test create", function () { $stringy = Stringy::create('foo bar', 'UTF-8'); \expect($stringy)->toBeAnInstanceOf(Stringy::class); @@ -59,19 +59,19 @@ \expect('UTF-8')->toBe($stringy->getEncoding()); }); - it('test chaining', function () { + xit('test chaining', function () { $stringy = Stringy::create('Fòô Bàř', 'UTF-8'); \expect($stringy)->toBeAnInstanceOf(Stringy::class); \expect('FÒÔ bÀŘ')->toBe((string) $stringy->collapseWhiteSpace()->swapCase()->upperCaseFirst()); }); - it('test count', function () { + xit('test count', function () { $stringy = Stringy::create('Fòô', 'UTF-8'); \expect($stringy->count())->toBe(3); \expect(count($stringy))->toBe(3); }); - it('test GetIterator', function () { + xit('test GetIterator', function () { $stringy = Stringy::create('Fòô Bàř', 'UTF-8'); $valResult = []; foreach ($stringy as $char) { @@ -86,7 +86,7 @@ \expect($keyValResult)->toBe(['F', 'ò', 'ô', ' ', 'B', 'à', 'ř']); }); - it('test offsetExists', function () { + xit('test offsetExists', function () { $data = [ [true, 0], [true, 2], @@ -105,7 +105,7 @@ } }); - it('test OffsetGet', function () { + xit('test OffsetGet', function () { $stringy = Stringy::create('fòô', 'UTF-8'); \expect($stringy->offsetGet(0))->toBe('f'); @@ -114,7 +114,7 @@ \expect($stringy[2])->toBe('ô'); }); - it('test OffsetGet out of bounds', function () { + xit('test OffsetGet out of bounds', function () { $stringy = Stringy::create('fòô', 'UTF-8'); $callable = function () use ($stringy) { $test = $stringy[3]; @@ -122,7 +122,7 @@ \expect($callable)->toThrow(new \OutOfBoundsException('No character exists at the index')); }); - it('test OffsetSet', function () { + xit('test OffsetSet', function () { $stringy = Stringy::create('fòô', 'UTF-8'); $callable = function () use ($stringy) { $stringy[1] = 'invalid'; @@ -130,11 +130,53 @@ \expect($callable)->toThrow(new \Exception('Stringy object is immutable, cannot modify char')); }); - it('test OffsetUnset', function () { + xit('test OffsetUnset', function () { $stringy = Stringy::create('fòô', 'UTF-8'); $callable = function () use ($stringy) { unset($stringy[1]); }; \expect($callable)->toThrow(new \Exception('Stringy object is immutable, cannot unset char')); }); + + xit('test IndexOf', function () { + $data = [ + [6, 'foo & bar', 'bar'], + [6, 'foo & bar', 'bar', 0], + [false, 'foo & bar', 'baz'], + [false, 'foo & bar', 'baz', 0], + [0, 'foo & bar & foo', 'foo', 0], + [12, 'foo & bar & foo', 'foo', 5], + [6, 'fòô & bàř', 'bàř', 0, 'UTF-8'], + [false, 'fòô & bàř', 'baz', 0, 'UTF-8'], + [0, 'fòô & bàř & fòô', 'fòô', 0, 'UTF-8'], + [12, 'fòô & bàř & fòô', 'fòô', 5, 'UTF-8'] + ]; + + foreach ($data as $value) { + @list($expectd, $str, $subStr, $offset, $encoding) = $value; + $result = Stringy::create($str, $encoding)->indexOf($subStr, $offset); + \expect($result)->toBe($expectd); + } + }); + + xit('test IndexOfLast', function () { + $data = [ + [6, 'foo & bar', 'bar'], + [6, 'foo & bar', 'bar', 0], + [false, 'foo & bar', 'baz'], + [false, 'foo & bar', 'baz', 0], + [12, 'foo & bar & foo', 'foo', 0], + [0, 'foo & bar & foo', 'foo', -5], + [6, 'fòô & bàř', 'bàř', 0, 'UTF-8'], + [false, 'fòô & bàř', 'baz', 0, 'UTF-8'], + [12, 'fòô & bàř & fòô', 'fòô', 0, 'UTF-8'], + [0, 'fòô & bàř & fòô', 'fòô', -5, 'UTF-8'] + ]; + + foreach ($data as $value) { + @list($expectd, $str, $subStr, $offset, $encoding) = $value; + $result = Stringy::create($str, $encoding)->indexOfLast($subStr, $offset); + \expect($result)->toBe($expectd); + } + }); }); diff --git a/src/Minbaby/Stringy/Stringy.php b/src/Minbaby/Ext/Stringy/Stringy.php similarity index 92% rename from src/Minbaby/Stringy/Stringy.php rename to src/Minbaby/Ext/Stringy/Stringy.php index 6dd0c47..5d0bcf9 100644 --- a/src/Minbaby/Stringy/Stringy.php +++ b/src/Minbaby/Ext/Stringy/Stringy.php @@ -186,4 +186,24 @@ public function offsetUnset($offset) { throw new \Exception('Stringy object is immutable, cannot unset char'); } + + public function indexOf($needle, $offset = 0) + { + return \mb_strpos( + $this->str, + (string) $needle, + (int) $offset, + $this->encoding + ); + } + + public function indexOfLast($needle, $offset = 0) + { + return \mb_strrpos( + $this->str, + (string) $needle, + (int) $offset, + $this->encoding + ); + } } diff --git a/src/Minbaby/Test.php b/src/Minbaby/Ext/Test.php similarity index 100% rename from src/Minbaby/Test.php rename to src/Minbaby/Ext/Test.php diff --git a/src/ext/common.h b/src/ext/common.h index 021c615..43c8c29 100644 --- a/src/ext/common.h +++ b/src/ext/common.h @@ -1,10 +1,6 @@ #ifndef STARTUP_COMMON_H #define STARTUP_COMMON_H -/** - * Default namespace. - */ #define PHP_STARTUP_NS_NAME "Minbaby\\Ext\\" -#define PHP_STARTUP_NS(cls) PHP_STARTUP_NS_NAME #cls #endif diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c new file mode 100644 index 0000000..e0c1ea7 --- /dev/null +++ b/src/ext/stringy/stringy.c @@ -0,0 +1,2 @@ +#include "stringy.h" + diff --git a/src/ext/stringy/stringy.h b/src/ext/stringy/stringy.h new file mode 100644 index 0000000..f8c9887 --- /dev/null +++ b/src/ext/stringy/stringy.h @@ -0,0 +1,8 @@ +#ifndef STARTUP_STRINGY_STRINGY_H +#define STARTUP_STRINGY_STRINGY_H + +#include "../common.h" + +#define PHP_STARTUP_STRINGY_NS(cls) PHP_STARTUP_NS_NAME "Stringy\\" #cls + +#endif diff --git a/src/ext/test.class.c b/src/ext/test.class.c index 404b750..4e78fe9 100644 --- a/src/ext/test.class.c +++ b/src/ext/test.class.c @@ -83,7 +83,7 @@ void php_start_register_test() { zend_class_entry ce; - INIT_CLASS_ENTRY(ce, PHP_STARTUP_NS(Test), methods); + INIT_CLASS_ENTRY(ce, PHP_STARTUP_TEST_NS(Test), methods); test_ce = zend_register_internal_class(&ce); diff --git a/src/ext/test.class.h b/src/ext/test.class.h index 82ebc06..1babbfc 100644 --- a/src/ext/test.class.h +++ b/src/ext/test.class.h @@ -5,6 +5,8 @@ #include "common.h" #include "ext/standard/php_standard.h" +#define PHP_STARTUP_TEST_NS(cls) PHP_STARTUP_NS_NAME "Test\\" #cls + extern zend_class_entry *test_ce; void php_start_register_test(); diff --git a/tools/test.sh b/tools/test.sh index fe832e5..ba0fb1e 100755 --- a/tools/test.sh +++ b/tools/test.sh @@ -7,11 +7,10 @@ pwd # echo "disable ext startup.so" phpbrew ext disable startup -./vendor/bin/kahlan --reporter=verbose +./vendor/bin/kahlan # echo "enable ext start.so" phpbrew ext enable startup -./vendor/bin/kahlan --reporter=verbose - +./vendor/bin/kahlan From 0a3633c8872527eb6ee44734213b99868a5cfe4d Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Sun, 18 Nov 2018 11:29:47 +0800 Subject: [PATCH 011/126] =?UTF-8?q?=E5=8F=AF=E7=BC=96=E8=AF=91=E9=80=9A?= =?UTF-8?q?=E8=BF=87=EF=BC=8C=E6=B5=8B=E8=AF=95=E4=B8=BA=E9=80=9A=E8=BF=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- composer.json | 12 +++++--- config.m4 | 2 +- php_startup.h | 2 +- spec/Stringy/StringySpec.php | 31 ++++++++++++-------- spec/TestSpec.php | 23 +++++++-------- spec/const.php | 9 ++++++ spec/functions.php | 30 +++++++++++++++++++ src/Minbaby/{Ext => Php}/Stringy/Stringy.php | 2 +- src/Minbaby/{Ext => Php}/Test.php | 2 +- src/ext/common.h | 2 +- src/ext/stringy/stringy.c | 27 +++++++++++++++++ src/ext/stringy/stringy.h | 6 ++++ src/ext/test.class.c | 2 +- startup.php | 4 +-- tools/test.sh | 2 ++ 15 files changed, 119 insertions(+), 37 deletions(-) create mode 100644 spec/const.php create mode 100644 spec/functions.php rename src/Minbaby/{Ext => Php}/Stringy/Stringy.php (99%) rename src/Minbaby/{Ext => Php}/Test.php (94%) diff --git a/composer.json b/composer.json index a3d4f48..345a57c 100644 --- a/composer.json +++ b/composer.json @@ -10,17 +10,21 @@ } ], "require": { - + "php": "^7.1" }, "autoload": { "psr-4": { - "Minbaby\\Ext\\": "src/Minbaby/Ext" + "Minbaby\\Startup\\Php\\": "src/Minbaby/Php" } }, "autoload-dev": { "psr-4": { - "Minbaby\\Ext\\Spec\\": "spec/" - } + "Minbaby\\Startup\\Spec\\": "spec/" + }, + "files": [ + "spec/const.php", + "spec/functions.php" + ] }, "require-dev": { "kahlan/kahlan": "^4.3" diff --git a/config.m4 b/config.m4 index 2c79364..fbb00cd 100644 --- a/config.m4 +++ b/config.m4 @@ -59,7 +59,7 @@ if test "$PHP_STARTUP" != "no"; then dnl dnl PHP_SUBST(STARTUP_SHARED_LIBADD) - $source = "startup.c \ + source="startup.c \ src/ext/test.class.c \ src/ext/stringy/stringy.c"; diff --git a/php_startup.h b/php_startup.h index 4ea7092..b768a76 100644 --- a/php_startup.h +++ b/php_startup.h @@ -24,7 +24,7 @@ extern zend_module_entry startup_module_entry; #define phpext_startup_ptr &startup_module_entry -#define PHP_STARTUP_VERSION "0.1.0" /* Replace with version number for your extension */ +#define PHP_STARTUP_VERSION "0.2.0" /* Replace with version number for your extension */ #ifdef PHP_WIN32 # define PHP_STARTUP_API __declspec(dllexport) diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index 15d2814..d349dca 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -1,40 +1,45 @@ class = 'Stringy'; + $this->className = __($this->class); + }); + it("test construct", function () { - $stringy = new Stringy('test test2 test3', 'UTF-8'); + $stringy = _('Stringy', ['test test2 test3', 'UTF-8']); - \expect($stringy)->toBeAnInstanceOf(Stringy::class); + \expect($stringy)->toBeAnInstanceOf(__('Stringy')); \expect((string) $stringy)->toBe('test test2 test3'); \expect($stringy->getEncoding())->toBe('UTF-8'); }); - xit("test empty construct", function () { - $stringy = new Stringy(); + it("test empty construct", function () { + $stringy = _('Stringy'); - \expect($stringy instanceof Stringy)->toBe(true); + \expect($stringy instanceof $this->className)->toBe(true); \expect((string) $stringy)->toBe(''); }); - xit("test construct with array", function () { + it("test construct with array", function () { $closure = function () { - (string) new Stringy([]); + (string)_($this->class, [[]]); }; - \expect($closure)->toThrow(new \InvalidArgumentException('Passed value cannot be an array')); }); - xit("test missing to string", function () { + it("test missing to string", function () { $closure = function () { - (string) new Stringy(new \stdClass()); + (string)_($this->class, [new \stdClass()]); }; \expect($closure)->toThrow(new \InvalidArgumentException('Passed object must have a __toString method')); }); - xit("test __toString", function () { + it("test __toString", function () { $data = [ ['', null], ['', false], @@ -47,7 +52,7 @@ foreach($data as $v) { [$key, $value] = $v; - \expect($key)->toBe((string) new Stringy($value)); + \expect($key)->toBe((string) _($this->class, [$value])); } }); diff --git a/spec/TestSpec.php b/spec/TestSpec.php index 238695d..70075bb 100644 --- a/spec/TestSpec.php +++ b/spec/TestSpec.php @@ -1,34 +1,33 @@ toEcho('hello world!'); + expect([_('Test'), 'helloWorld'])->toEcho('hello world!'); }); it('测试实例化 hello world!!', function() { - $instance = new Test(); - expect([$instance, 'echoHelloWorld'])->toEcho('hello world!!'); + expect([_('Test'), 'echoHelloWorld'])->toEcho('hello world!!'); }); it('测试 public 属性', function () { - $instance = new Test(); - expect($instance->publicProperty)->toBe('hello world +property'); + expect(_('Test')->publicProperty)->toBe('hello world +property'); }); it('测试 public static 属性', function () { - expect(Test::$publicPropertyStatic)->toBe('hello world +property +static'); + expect(__('Test')::$publicPropertyStatic)->toBe('hello world +property +static'); }); it('测试 const 属性', function () { - expect(Test::PUBLIC_CONST)->toBe('hello world +const'); + expect(__('Test')::PUBLIC_CONST)->toBe('hello world +const'); }); it('测试方法不存在的逻辑', function () { - $instance = new Test(); + $instance = _('Test'); $params = [ 'a21212' => [1, 2, 3, 4], '😊☺😀' => ['abab', 'cdcd', 'efef'], diff --git a/spec/const.php b/spec/const.php new file mode 100644 index 0000000..2b14203 --- /dev/null +++ b/spec/const.php @@ -0,0 +1,9 @@ +xab(); + var_dump(extension_loaded('startup')); + var_dump(get_declared_classes()); } diff --git a/tools/test.sh b/tools/test.sh index ba0fb1e..c6b5130 100755 --- a/tools/test.sh +++ b/tools/test.sh @@ -7,10 +7,12 @@ pwd # echo "disable ext startup.so" phpbrew ext disable startup +export MINBABY_TEST_EXT=0 ./vendor/bin/kahlan # echo "enable ext start.so" phpbrew ext enable startup +export MINBABY_TEST_EXT=1 ./vendor/bin/kahlan From c23a20fd59a69d187ca29af44619e4523c2f301a Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Sun, 18 Nov 2018 11:33:05 +0800 Subject: [PATCH 012/126] =?UTF-8?q?=E5=90=8C=E4=B8=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/settings.json | 4 +++- src/ext/stringy/stringy.c | 5 +++-- src/ext/test.class.h | 4 ++-- startup.c | 4 +++- tools/build.sh | 3 ++- 5 files changed, 13 insertions(+), 7 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 7c7dc07..18306d5 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -6,7 +6,9 @@ "type_traits": "c", "typeinfo": "cpp", "stdarg.h": "c", - "common.h": "c" + "common.h": "c", + "config.h": "c", + "stringy.h": "c" }, "files.autoSave": "onFocusChange", "editor.fontSize": 18, diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index f4fcf93..557f6f1 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -13,6 +13,7 @@ PHP_METHOD(Stringy, __toString) static zend_function_entry methods[] = { + PHP_ME(Stringy, __toString, NULL, ZEND_ACC_PUBLIC) PHP_FE_END }; @@ -24,6 +25,6 @@ void php_startup_register_stringy() stringy_ce = zend_register_internal_class(&ce); - zend_declare_property_string(&ce, "str", sizeof("str"), "", ZEND_ACC_PROTECTED); - zend_declare_property_string(&ce, "encoding", sizeof("encoding"), "", ZEND_ACC_PROTECTED); + zend_declare_property_string(stringy_ce, "str", sizeof("str"), "", ZEND_ACC_PROTECTED); + zend_declare_property_string(stringy_ce, "encoding", sizeof("encoding"), "", ZEND_ACC_PROTECTED); } diff --git a/src/ext/test.class.h b/src/ext/test.class.h index 1babbfc..cb6742f 100644 --- a/src/ext/test.class.h +++ b/src/ext/test.class.h @@ -5,10 +5,10 @@ #include "common.h" #include "ext/standard/php_standard.h" -#define PHP_STARTUP_TEST_NS(cls) PHP_STARTUP_NS_NAME "Test\\" #cls +#define PHP_STARTUP_TEST_NS(cls) PHP_STARTUP_NS_NAME #cls extern zend_class_entry *test_ce; -void php_start_register_test(); +void php_startup_register_test(); #endif diff --git a/startup.c b/startup.c index 1e88961..555c8ea 100644 --- a/startup.c +++ b/startup.c @@ -28,6 +28,7 @@ #include "zend_types.h" #include "php_startup.h" #include "src/ext/test.class.h" +#include "src/ext/stringy/stringy.h" /* If you declare any globals in php_startup.h uncomment this: ZEND_DECLARE_MODULE_GLOBALS(startup) @@ -115,7 +116,8 @@ PHP_MINIT_FUNCTION(startup) zend_declare_property_null(myclass_ce, "pub_var", strlen("pub_var"), ZEND_ACC_PUBLIC TSRMLS_CC); - php_start_register_test(); + php_startup_register_test(); + php_startup_register_stringy(); return SUCCESS; } diff --git a/tools/build.sh b/tools/build.sh index f9ce3c6..c2f49a0 100755 --- a/tools/build.sh +++ b/tools/build.sh @@ -6,7 +6,8 @@ set -x pwd echo "disabled startup" -phpbrew ext disable startup +# phpbrew ext disable startup +rm -f $PHPBREW_ROOT/php/$PHPBREW_PHP/var/db/start.ini echo "go..." phpize && ./configure && make && make install && make clean && phpize --clean From 80887ddc45fd12570c5718c03b07ae8154ff9388 Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Sun, 18 Nov 2018 15:25:18 +0800 Subject: [PATCH 013/126] =?UTF-8?q?=E6=B3=A8=E9=87=8A=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E4=B8=8D=E9=80=9A=E8=BF=87=E7=9A=84=E7=94=A8=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- spec/Stringy/StringySpec.php | 6 ++--- src/ext/stringy/stringy.c | 52 +++++++++++++++++++++++++++++++----- src/ext/test.class.c | 2 +- startup.php | 21 +++++++++++++-- tools/build.sh | 2 +- 5 files changed, 69 insertions(+), 14 deletions(-) diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index d349dca..4131a9f 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -24,14 +24,14 @@ \expect((string) $stringy)->toBe(''); }); - it("test construct with array", function () { + xit("test construct with array", function () { $closure = function () { (string)_($this->class, [[]]); }; \expect($closure)->toThrow(new \InvalidArgumentException('Passed value cannot be an array')); }); - it("test missing to string", function () { + xit("test missing to string", function () { $closure = function () { (string)_($this->class, [new \stdClass()]); }; @@ -39,7 +39,7 @@ \expect($closure)->toThrow(new \InvalidArgumentException('Passed object must have a __toString method')); }); - it("test __toString", function () { + xit("test __toString", function () { $data = [ ['', null], ['', false], diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index 557f6f1..3ae8c3e 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -4,16 +4,54 @@ zend_class_entry *stringy_ce; PHP_METHOD(Stringy, __toString) { - // zval rv; - // zend_read_property(stringy_ce, getThis(), "str", sizeof("str") - 1, 0, &rv); - // php_var_dump(&rv, 1); - // RETURN_STRING(Z_STRVAL_P(rv)); - RETURN_EMPTY_STRING(); + zval rv, *value; + value = zend_read_property(stringy_ce, getThis(), "str", strlen("str"), 0, &rv); + RETURN_STRING(Z_STRVAL_P(value)); +} + +PHP_METHOD(Stringy, __construct) +{ + char *str, *encoding; + size_t str_len, encoding_len; + + if (EX_NUM_ARGS() == 0) { + RETURN_NULL(); + } + + ZEND_PARSE_PARAMETERS_START(0, 2) + Z_PARAM_OPTIONAL + Z_PARAM_STRING(str, str_len) + Z_PARAM_STRING(encoding, encoding_len) + ZEND_PARSE_PARAMETERS_END(); + + if (str == NULL) { + str = ""; + } + + if (encoding == NULL) { + encoding = ""; + } + + zend_update_property_string(stringy_ce, getThis(), "str", strlen("str"), str); + zend_update_property_string(stringy_ce, getThis(), "encoding", strlen("encoding"), encoding); +} +ZEND_BEGIN_ARG_INFO_EX(arginfo_construct, 0, 0, 2) + ZEND_ARG_INFO(0, str) + ZEND_ARG_INFO(0, encoding) +ZEND_END_ARG_INFO() + +PHP_METHOD(Stringy, getEncoding) +{ + zval rv, *value; + value = zend_read_property(stringy_ce, getThis(), "encoding", strlen("encoding"), 0, &rv); + RETURN_STRING(Z_STRVAL_P(value)); } static zend_function_entry methods[] = { + PHP_ME(Stringy, __construct, arginfo_construct, ZEND_ACC_PUBLIC) PHP_ME(Stringy, __toString, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, getEncoding, NULL, ZEND_ACC_PUBLIC) PHP_FE_END }; @@ -25,6 +63,6 @@ void php_startup_register_stringy() stringy_ce = zend_register_internal_class(&ce); - zend_declare_property_string(stringy_ce, "str", sizeof("str"), "", ZEND_ACC_PROTECTED); - zend_declare_property_string(stringy_ce, "encoding", sizeof("encoding"), "", ZEND_ACC_PROTECTED); + zend_declare_property_string(stringy_ce, "str", strlen("str"), "", ZEND_ACC_PROTECTED); + zend_declare_property_string(stringy_ce, "encoding", strlen("encoding"), "", ZEND_ACC_PROTECTED); } diff --git a/src/ext/test.class.c b/src/ext/test.class.c index 954edf5..fe25815 100644 --- a/src/ext/test.class.c +++ b/src/ext/test.class.c @@ -20,7 +20,7 @@ PHP_METHOD(Test, echoHelloWorld) php_printf("hello world!!"); - RETVAL_NULL(); + RETURN_NULL(); } PHP_METHOD(Test, __call) diff --git a/startup.php b/startup.php index bf346cf..2c8820a 100644 --- a/startup.php +++ b/startup.php @@ -43,9 +43,26 @@ function checkExt() echo "$br\n"; } +include __DIR__ . "/spec/const.php"; +include __DIR__ . "/spec/functions.php"; + +class X +{ + public function __construct() + { + var_dump(func_get_args(), func_num_args()); + } +} + function main() { - var_dump(extension_loaded('startup')); - var_dump(get_declared_classes()); + _ns(NS_STRINGY); + $x = _('Stringy'); + $i = __('Stringy'); + var_dump($x instanceof $i, $i); + + // _ns('\\'); + // $xy = _('X'); + // $xyz = new X(); } diff --git a/tools/build.sh b/tools/build.sh index c2f49a0..0389446 100755 --- a/tools/build.sh +++ b/tools/build.sh @@ -6,7 +6,7 @@ set -x pwd echo "disabled startup" -# phpbrew ext disable startup +# phpbrew ext disable startup # 如果 ext 出问题了,这个命令就无法执行了 rm -f $PHPBREW_ROOT/php/$PHPBREW_PHP/var/db/start.ini echo "go..." From ba7485141cea20a9c1c08971507f1a4ad9d70668 Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Sun, 18 Nov 2018 16:03:13 +0800 Subject: [PATCH 014/126] update ci config --- .circleci/config.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 61bc287..bc17063 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -25,10 +25,6 @@ jobs: steps: - checkout - - run: - name: startup install - command: phpize && ./configure && make && sudo make install - - run: name: composer install command: composer install @@ -37,6 +33,10 @@ jobs: name: run test command: ./vendor/bin/kahlan + - run: + name: startup install + command: phpize && ./configure && make && sudo make install + - run: name: cp docker-php-ext-start.ini command: sudo cp .circleci/docker-php-ext-startup.ini /usr/local/etc/php/conf.d/ From b30b0affee7323e94f56f1c3c0c4f12028615ac8 Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Sun, 18 Nov 2018 19:05:53 +0800 Subject: [PATCH 015/126] update --- .circleci/config.yml | 6 +----- .vscode/c_cpp_properties.json | 2 +- .vscode/settings.json | 8 +++++++- spec/Stringy/StringySpec.php | 10 +++++----- src/ext/stringy/stringy.c | 26 +++++++++++++++++++++----- src/ext/stringy/stringy.h | 2 ++ startup.php | 16 ++-------------- 7 files changed, 39 insertions(+), 31 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index bc17063..19cba95 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -37,13 +37,9 @@ jobs: name: startup install command: phpize && ./configure && make && sudo make install - - run: - name: cp docker-php-ext-start.ini - command: sudo cp .circleci/docker-php-ext-startup.ini /usr/local/etc/php/conf.d/ - - run: name: enable startup - command: sudo docker-php-ext-enable startup + command: sudo cp .circleci/docker-php-ext-startup.ini /usr/local/etc/php/conf.d/ - run: name: run test diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index d2ad79e..83500c2 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -14,4 +14,4 @@ } ], "version": 4 -} \ No newline at end of file +} diff --git a/.vscode/settings.json b/.vscode/settings.json index 18306d5..bc86f28 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -8,7 +8,13 @@ "stdarg.h": "c", "common.h": "c", "config.h": "c", - "stringy.h": "c" + "stringy.h": "c", + "php_standard.h": "c", + "spl_exceptions.h": "c", + "php_spl.h": "c", + "zend_exceptions.h": "c", + "zend_interfaces.h": "c", + "php_mt_rand.h": "c" }, "files.autoSave": "onFocusChange", "editor.fontSize": 18, diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index 4131a9f..926252f 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -24,14 +24,14 @@ \expect((string) $stringy)->toBe(''); }); - xit("test construct with array", function () { + it("test construct with array", function () { $closure = function () { (string)_($this->class, [[]]); }; \expect($closure)->toThrow(new \InvalidArgumentException('Passed value cannot be an array')); }); - xit("test missing to string", function () { + it("test missing to string", function () { $closure = function () { (string)_($this->class, [new \stdClass()]); }; @@ -39,7 +39,7 @@ \expect($closure)->toThrow(new \InvalidArgumentException('Passed object must have a __toString method')); }); - xit("test __toString", function () { + it("test __toString", function () { $data = [ ['', null], ['', false], @@ -57,9 +57,9 @@ }); xit("test create", function () { - $stringy = Stringy::create('foo bar', 'UTF-8'); + $stringy = __('Stringy')::create('foo bar', 'UTF-8'); - \expect($stringy)->toBeAnInstanceOf(Stringy::class); + \expect($stringy)->toBeAnInstanceOf(__('Stringy')); \expect('foo bar')->toBe((string) $stringy); \expect('UTF-8')->toBe($stringy->getEncoding()); }); diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index 3ae8c3e..e484019 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -12,17 +12,33 @@ PHP_METHOD(Stringy, __toString) PHP_METHOD(Stringy, __construct) { char *str, *encoding; + zval *val; size_t str_len, encoding_len; if (EX_NUM_ARGS() == 0) { RETURN_NULL(); } - ZEND_PARSE_PARAMETERS_START(0, 2) - Z_PARAM_OPTIONAL - Z_PARAM_STRING(str, str_len) - Z_PARAM_STRING(encoding, encoding_len) - ZEND_PARSE_PARAMETERS_END(); + ZEND_PARSE_PARAMETERS_START(0, 2) + Z_PARAM_OPTIONAL + // Z_PARAM_STRING(str, str_len) + Z_PARAM_ZVAL(val) + Z_PARAM_STRING(encoding, encoding_len) + ZEND_PARSE_PARAMETERS_END(); + + if (Z_TYPE_P(val) == IS_ARRAY) { + zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0, "%s", "Passed value cannot be an array"); + return; + } + + if (Z_TYPE_P(val) == IS_OBJECT) { + zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0, "%s", "Passed object must have a __toString method"); + return; + } + + convert_to_string(val) + + str = Z_STRVAL_P(val); if (str == NULL) { str = ""; diff --git a/src/ext/stringy/stringy.h b/src/ext/stringy/stringy.h index 6c6de7b..fafdfa8 100644 --- a/src/ext/stringy/stringy.h +++ b/src/ext/stringy/stringy.h @@ -4,6 +4,8 @@ #include "php.h" #include "../common.h" #include "ext/standard/php_standard.h" +#include "Zend/zend_exceptions.h" +#include "ext/spl/spl_exceptions.h" #define PHP_STARTUP_STRINGY_NS(cls) PHP_STARTUP_NS_NAME "Stringy\\" #cls diff --git a/startup.php b/startup.php index 2c8820a..3e12b54 100644 --- a/startup.php +++ b/startup.php @@ -46,23 +46,11 @@ function checkExt() include __DIR__ . "/spec/const.php"; include __DIR__ . "/spec/functions.php"; -class X -{ - public function __construct() - { - var_dump(func_get_args(), func_num_args()); - } -} - function main() { _ns(NS_STRINGY); - $x = _('Stringy'); + $x = _('Stringy', [new stdClass()]); $i = __('Stringy'); - var_dump($x instanceof $i, $i); - - // _ns('\\'); - // $xy = _('X'); - // $xyz = new X(); + var_dump($x instanceof $i, (string) $x); } From b0d8f52e83cb6fcf7bdb4003b4c46a7af5006efe Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Sun, 18 Nov 2018 21:14:03 +0800 Subject: [PATCH 016/126] build test create --- src/ext/stringy/stringy.c | 44 ++++++++++++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index e484019..8aa8dc7 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -11,8 +11,8 @@ PHP_METHOD(Stringy, __toString) PHP_METHOD(Stringy, __construct) { - char *str, *encoding; - zval *val; + char *encoding; + zval *str; size_t str_len, encoding_len; if (EX_NUM_ARGS() == 0) { @@ -21,24 +21,23 @@ PHP_METHOD(Stringy, __construct) ZEND_PARSE_PARAMETERS_START(0, 2) Z_PARAM_OPTIONAL - // Z_PARAM_STRING(str, str_len) - Z_PARAM_ZVAL(val) + Z_PARAM_ZVAL(str) Z_PARAM_STRING(encoding, encoding_len) ZEND_PARSE_PARAMETERS_END(); - if (Z_TYPE_P(val) == IS_ARRAY) { + if (Z_TYPE_P(str) == IS_ARRAY) { zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0, "%s", "Passed value cannot be an array"); return; } - if (Z_TYPE_P(val) == IS_OBJECT) { + if (Z_TYPE_P(str) == IS_OBJECT) { zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0, "%s", "Passed object must have a __toString method"); return; } - convert_to_string(val) + convert_to_string(str) - str = Z_STRVAL_P(val); + str = Z_STRVAL_P(str); if (str == NULL) { str = ""; @@ -51,6 +50,7 @@ PHP_METHOD(Stringy, __construct) zend_update_property_string(stringy_ce, getThis(), "str", strlen("str"), str); zend_update_property_string(stringy_ce, getThis(), "encoding", strlen("encoding"), encoding); } + ZEND_BEGIN_ARG_INFO_EX(arginfo_construct, 0, 0, 2) ZEND_ARG_INFO(0, str) ZEND_ARG_INFO(0, encoding) @@ -63,11 +63,39 @@ PHP_METHOD(Stringy, getEncoding) RETURN_STRING(Z_STRVAL_P(value)); } +PHP_METHOD(Stringy, create) +{ + zval instance = {}; + zval *retval, *str, *encoding; + + ZEND_PARSE_PARAMETERS_START(0, 2) + Z_PARAM_OPTIONAL + Z_PARAM_ZVAL(str) + Z_PARAM_ZVAL(encoding) + ZEND_PARSE_PARAMETERS_END(); + + object_init_ex(&instance, stringy_ce); + + zval func, args[2]; + ZVAL_ZVAL(args, str, 0, 1); + ZVAL_ZVAL(args, encoding, 0, 1); + + ZVAL_STRING(&func, "__construct"); + + call_user_function(EG(function_table), &instance, &func, retval, 2, args); + + RETURN_ZVAL(retval, 0, 1); +} +ZEND_BEGIN_ARG_INFO_EX(arginfo_create, 0, 0, 2) + ZEND_ARG_INFO(0, str) + ZEND_ARG_INFO(0, encoding) +ZEND_END_ARG_INFO() static zend_function_entry methods[] = { PHP_ME(Stringy, __construct, arginfo_construct, ZEND_ACC_PUBLIC) PHP_ME(Stringy, __toString, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, getEncoding, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, create, arginfo_create, ZEND_ACC_PUBLIC) PHP_FE_END }; From fe844e613af69f09a046facea8f4e8f50c2d6724 Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Mon, 19 Nov 2018 00:18:10 +0800 Subject: [PATCH 017/126] static create method --- spec/Stringy/StringySpec.php | 2 +- src/ext/stringy/stringy.c | 34 +++++++++++++++++----------------- startup.php | 4 +--- 3 files changed, 19 insertions(+), 21 deletions(-) diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index 926252f..82ef4e0 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -56,7 +56,7 @@ } }); - xit("test create", function () { + it("test create", function () { $stringy = __('Stringy')::create('foo bar', 'UTF-8'); \expect($stringy)->toBeAnInstanceOf(__('Stringy')); diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index 8aa8dc7..acdd73c 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -13,6 +13,7 @@ PHP_METHOD(Stringy, __construct) { char *encoding; zval *str; + char *string; size_t str_len, encoding_len; if (EX_NUM_ARGS() == 0) { @@ -37,17 +38,17 @@ PHP_METHOD(Stringy, __construct) convert_to_string(str) - str = Z_STRVAL_P(str); + string = Z_STRVAL_P(str); - if (str == NULL) { - str = ""; + if (string == NULL) { + string = ""; } if (encoding == NULL) { encoding = ""; } - zend_update_property_string(stringy_ce, getThis(), "str", strlen("str"), str); + zend_update_property_string(stringy_ce, getThis(), "str", strlen("str"), string); zend_update_property_string(stringy_ce, getThis(), "encoding", strlen("encoding"), encoding); } @@ -65,26 +66,25 @@ PHP_METHOD(Stringy, getEncoding) PHP_METHOD(Stringy, create) { - zval instance = {}; - zval *retval, *str, *encoding; + zval instance = {}, retval = {}, func = {}, args[2] = {}; + zval *str, *encoding; ZEND_PARSE_PARAMETERS_START(0, 2) - Z_PARAM_OPTIONAL - Z_PARAM_ZVAL(str) - Z_PARAM_ZVAL(encoding) + Z_PARAM_OPTIONAL + Z_PARAM_ZVAL(str) + Z_PARAM_ZVAL(encoding) ZEND_PARSE_PARAMETERS_END(); object_init_ex(&instance, stringy_ce); - - zval func, args[2]; - ZVAL_ZVAL(args, str, 0, 1); - ZVAL_ZVAL(args, encoding, 0, 1); + + args[0] = *str; + args[1] = *encoding; ZVAL_STRING(&func, "__construct"); - call_user_function(EG(function_table), &instance, &func, retval, 2, args); + call_user_function_ex(NULL, &instance, &func, &retval, 2, args, 0, NULL); - RETURN_ZVAL(retval, 0, 1); + RETURN_ZVAL(&instance, 0, 1); } ZEND_BEGIN_ARG_INFO_EX(arginfo_create, 0, 0, 2) ZEND_ARG_INFO(0, str) @@ -92,10 +92,10 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_create, 0, 0, 2) ZEND_END_ARG_INFO() static zend_function_entry methods[] = { - PHP_ME(Stringy, __construct, arginfo_construct, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, __construct, arginfo_construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) PHP_ME(Stringy, __toString, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, getEncoding, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Stringy, create, arginfo_create, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, create, arginfo_create, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) PHP_FE_END }; diff --git a/startup.php b/startup.php index 3e12b54..a556049 100644 --- a/startup.php +++ b/startup.php @@ -48,9 +48,7 @@ function checkExt() function main() { _ns(NS_STRINGY); - $x = _('Stringy', [new stdClass()]); - $i = __('Stringy'); - var_dump($x instanceof $i, (string) $x); + $i = __('Stringy')::create(1, 'UTF-8'); } From d692f699dac2da774be6a2d162cdb0a2061be980 Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Mon, 19 Nov 2018 19:35:48 +0800 Subject: [PATCH 018/126] =?UTF-8?q?=E5=8F=91=E7=8E=B0=E5=BC=80=E5=90=AFxde?= =?UTF-8?q?bug=20=E7=A8=8B=E5=BA=8F=E4=BC=9A=E5=B4=A9=E6=BA=83=EF=BC=8C?= =?UTF-8?q?=E6=9C=80=E7=BB=88=E4=B9=9F=E6=B2=A1=E6=9C=89=E8=A7=A3=E5=86=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/c_cpp_properties.json | 12 ++++++++++++ .vscode/keybindings.json | 2 +- README.MD | 4 ++++ config.m4 | 7 +++++++ spec/Stringy/StringySpec.php | 2 +- src/ext/stringy/stringy.c | 8 ++++---- tools/build.sh | 2 +- 7 files changed, 30 insertions(+), 7 deletions(-) diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index 83500c2..dafe320 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -11,6 +11,18 @@ "cStandard": "c11", "cppStandard": "c++17", "intelliSenseMode": "clang-x64" + }, + { + "name": "Mac", + "includePath": [ + "${workspaceFolder}/**", + "~/.phpbrew/build/php-7.1.17/**" + ], + "defines": [], + "compilerPath": "/usr/bin/gcc", + "cStandard": "c11", + "cppStandard": "c++17", + "intelliSenseMode": "clang-x64" } ], "version": 4 diff --git a/.vscode/keybindings.json b/.vscode/keybindings.json index 52e0481..55f5301 100644 --- a/.vscode/keybindings.json +++ b/.vscode/keybindings.json @@ -10,4 +10,4 @@ "command": "workbench.action.tasks.runTask", "args": "run test" } -] \ No newline at end of file +] diff --git a/README.MD b/README.MD index 4f106c7..1ea77aa 100644 --- a/README.MD +++ b/README.MD @@ -34,6 +34,10 @@ - 使用 `@` 抑制符不是一个好习惯,尽量不要使用。 +## 已知问题 + +- 和 xdebug 不兼容,开启 xdebug 会出现崩溃现象,原因未知(能力有限 😅) + ### skip ci - `[skip ci]` diff --git a/config.m4 b/config.m4 index fbb00cd..5abc715 100644 --- a/config.m4 +++ b/config.m4 @@ -65,3 +65,10 @@ if test "$PHP_STARTUP" != "no"; then PHP_NEW_EXTENSION(startup, $source, $ext_shared,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1) fi + +if test -z "$PHP_DEBUG"; then + AC_ARG_ENABLE(debug, + [--enable-debg compile with debugging system], + [PHP_DEBUG=$enableval], [PHP_DEBUG=no] + ) +fi diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index 82ef4e0..145830c 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -31,7 +31,7 @@ \expect($closure)->toThrow(new \InvalidArgumentException('Passed value cannot be an array')); }); - it("test missing to string", function () { + xit("test missing __toString", function () { $closure = function () { (string)_($this->class, [new \stdClass()]); }; diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index acdd73c..3c3709b 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -4,7 +4,7 @@ zend_class_entry *stringy_ce; PHP_METHOD(Stringy, __toString) { - zval rv, *value; + zval rv = {}, *value; value = zend_read_property(stringy_ce, getThis(), "str", strlen("str"), 0, &rv); RETURN_STRING(Z_STRVAL_P(value)); } @@ -21,9 +21,9 @@ PHP_METHOD(Stringy, __construct) } ZEND_PARSE_PARAMETERS_START(0, 2) - Z_PARAM_OPTIONAL - Z_PARAM_ZVAL(str) - Z_PARAM_STRING(encoding, encoding_len) + Z_PARAM_OPTIONAL + Z_PARAM_ZVAL(str) + Z_PARAM_STRING(encoding, encoding_len) ZEND_PARSE_PARAMETERS_END(); if (Z_TYPE_P(str) == IS_ARRAY) { diff --git a/tools/build.sh b/tools/build.sh index 0389446..0ab76d3 100755 --- a/tools/build.sh +++ b/tools/build.sh @@ -10,7 +10,7 @@ echo "disabled startup" rm -f $PHPBREW_ROOT/php/$PHPBREW_PHP/var/db/start.ini echo "go..." -phpize && ./configure && make && make install && make clean && phpize --clean +phpize && ./configure --enable-debug && make && make install && make clean && phpize --clean echo "enabled startup" phpbrew ext enable startup From 6beb5a204f62687345449039d989c3ac19b937cb Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Mon, 19 Nov 2018 22:16:43 +0800 Subject: [PATCH 019/126] =?UTF-8?q?=E5=8F=96=E5=B7=A7=EF=BC=8C=E8=B0=83?= =?UTF-8?q?=E7=94=A8=20mb=5Fstring=20=E7=9A=84=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/settings.json | 8 ++- README.MD | 1 + spec/Stringy/StringySpec.php | 14 ++-- src/ext/stringy/stringy.c | 127 ++++++++++++++++++++++++++++++++++- src/ext/stringy/stringy.h | 4 -- src/ext/test.class.c | 84 +++++++++++------------ 6 files changed, 182 insertions(+), 56 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index bc86f28..4331181 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -14,7 +14,13 @@ "php_spl.h": "c", "zend_exceptions.h": "c", "zend_interfaces.h": "c", - "php_mt_rand.h": "c" + "php_mt_rand.h": "c", + "spl_array.h": "c", + "mbstring.h": "c", + "__locale": "c", + "__string": "c", + "string": "c", + "string_view": "c" }, "files.autoSave": "onFocusChange", "editor.fontSize": 18, diff --git a/README.MD b/README.MD index 1ea77aa..63adda3 100644 --- a/README.MD +++ b/README.MD @@ -33,6 +33,7 @@ ## 说明 - 使用 `@` 抑制符不是一个好习惯,尽量不要使用。 +- 依赖 `mb_string` 扩展 ## 已知问题 diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index 145830c..9a0dd2d 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -31,7 +31,7 @@ \expect($closure)->toThrow(new \InvalidArgumentException('Passed value cannot be an array')); }); - xit("test missing __toString", function () { + it("test missing __toString", function () { $closure = function () { (string)_($this->class, [new \stdClass()]); }; @@ -70,8 +70,8 @@ \expect('FÒÔ bÀŘ')->toBe((string) $stringy->collapseWhiteSpace()->swapCase()->upperCaseFirst()); }); - xit('test count', function () { - $stringy = Stringy::create('Fòô', 'UTF-8'); + it('test count', function () { + $stringy = __('Stringy')::create('Fòô', 'UTF-8'); \expect($stringy->count())->toBe(3); \expect(count($stringy))->toBe(3); }); @@ -143,7 +143,7 @@ \expect($callable)->toThrow(new \Exception('Stringy object is immutable, cannot unset char')); }); - xit('test IndexOf', function () { + it('test IndexOf', function () { $data = [ [6, 'foo & bar', 'bar'], [6, 'foo & bar', 'bar', 0], @@ -159,12 +159,12 @@ foreach ($data as $value) { @list($expectd, $str, $subStr, $offset, $encoding) = $value; - $result = Stringy::create($str, $encoding)->indexOf($subStr, $offset); + $result = __('Stringy')::create($str, $encoding)->indexOf($subStr, $offset); \expect($result)->toBe($expectd); } }); - xit('test IndexOfLast', function () { + it('test IndexOfLast', function () { $data = [ [6, 'foo & bar', 'bar'], [6, 'foo & bar', 'bar', 0], @@ -180,7 +180,7 @@ foreach ($data as $value) { @list($expectd, $str, $subStr, $offset, $encoding) = $value; - $result = Stringy::create($str, $encoding)->indexOfLast($subStr, $offset); + $result = __('Stringy')::create($str, $encoding)->indexOfLast($subStr, $offset); \expect($result)->toBe($expectd); } }); diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index 3c3709b..1529d14 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -1,4 +1,11 @@ #include "stringy.h" +#include "php.h" +#include "../common.h" +#include "ext/standard/php_standard.h" +#include "Zend/zend_exceptions.h" +#include "ext/spl/spl_exceptions.h" +#include "ext/spl/spl_iterators.h" +#include "ext/mbstring/mbstring.h" zend_class_entry *stringy_ce; @@ -15,6 +22,7 @@ PHP_METHOD(Stringy, __construct) zval *str; char *string; size_t str_len, encoding_len; + zval func; if (EX_NUM_ARGS() == 0) { RETURN_NULL(); @@ -48,6 +56,27 @@ PHP_METHOD(Stringy, __construct) encoding = ""; } + // 这里需要加一下了逻辑, 如果这里需要判断 encoding 是否支持, 不支持话,就用默认的编码 + ZVAL_STRING(&func, "mb_list_encodings"); + call_user_function_ex(NULL, NULL, &func, return_value, 0, NULL, 0, NULL); + + zval *tmp; + size_t count = 0; + zend_string *encoding_str = zend_string_init(encoding, strlen(encoding), 0); + ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(return_value), tmp) { + if (encoding == Z_STRVAL_P(tmp)) { + count++; + break; + } + }ZEND_HASH_FOREACH_END(); + + if (count == 0) { + ZVAL_STRING(&func, "mb_internal_encoding"); + call_user_function_ex(NULL, NULL, &func, return_value, 0, NULL, 0, NULL); + + encoding = Z_STRVAL_P(return_value); + } + zend_update_property_string(stringy_ce, getThis(), "str", strlen("str"), string); zend_update_property_string(stringy_ce, getThis(), "encoding", strlen("encoding"), encoding); } @@ -87,8 +116,96 @@ PHP_METHOD(Stringy, create) RETURN_ZVAL(&instance, 0, 1); } ZEND_BEGIN_ARG_INFO_EX(arginfo_create, 0, 0, 2) - ZEND_ARG_INFO(0, str) - ZEND_ARG_INFO(0, encoding) + ZEND_ARG_INFO(0, str) + ZEND_ARG_INFO(0, encoding) +ZEND_END_ARG_INFO() + +/* {{{ int length(): int +}}} */ +PHP_METHOD(Stringy, count) +{ + zval instance = {}, func = {}, rv = {}; + + ZVAL_STRING(&func, "length"); + + call_user_function_ex(NULL, getThis(), &func, return_value, 0, NULL, 0, NULL); +} + +/* {{{ int length(): int + todo: 这里依赖 mb_string 扩展 +}}} */ +PHP_METHOD(Stringy, length) +{ + zval func = {}, args[1] = {}, rv = {}; + zval *value; + ZVAL_STRING(&func, "mb_strlen"); + + value = zend_read_property(stringy_ce, getThis(), "str", strlen("str"), 0, &rv); + + args[0] = *value; + + call_user_function_ex(NULL, NULL, &func, return_value, 1, args, 0, NULL); +} + +/*{{{ int indexOfLast($needle, $offset = 0) +}}}*/ +PHP_METHOD(Stringy, indexOfLast) +{ + zval func = {}, args[4] = {}, rv = {}; + zval *value, *encoding, *needle, *offset; + + ZEND_PARSE_PARAMETERS_START(1, 2) + Z_PARAM_ZVAL(needle) + Z_PARAM_OPTIONAL + Z_PARAM_ZVAL(offset) + ZEND_PARSE_PARAMETERS_END(); + + ZVAL_STRING(&func, "mb_strrpos"); + + value = zend_read_property(stringy_ce, getThis(), "str", strlen("str"), 0, &rv); + encoding = zend_read_property(stringy_ce, getThis(), "encoding", strlen("encoding"), 0, &rv); + + args[0] = *value; + args[1] = *needle; + args[2] = *offset; + args[3] = *encoding; + + call_user_function_ex(NULL, NULL, &func, return_value, 4, args, 0, NULL); +} +ZEND_BEGIN_ARG_INFO(args_indexOfLast, 2) + ZEND_ARG_INFO(0, needle) + ZEND_ARG_INFO(0, offset) +ZEND_END_ARG_INFO() + +/*{{{ int indexOf($needle, $offset = 0) + TODO: 这个和上个重复率太高,暂时不知道怎么优化 +}}}*/ +PHP_METHOD(Stringy, indexOf) +{ + zval func = {}, args[4] = {}, rv = {}; + zval *value, *encoding, *needle, *offset; + + ZEND_PARSE_PARAMETERS_START(1, 2) + Z_PARAM_ZVAL(needle) + Z_PARAM_OPTIONAL + Z_PARAM_ZVAL(offset) + ZEND_PARSE_PARAMETERS_END(); + + ZVAL_STRING(&func, "mb_strpos"); + + value = zend_read_property(stringy_ce, getThis(), "str", strlen("str"), 0, &rv); + encoding = zend_read_property(stringy_ce, getThis(), "encoding", strlen("encoding"), 0, &rv); + + args[0] = *value; + args[1] = *needle; + args[2] = *offset; + args[3] = *encoding; + + call_user_function_ex(NULL, NULL, &func, return_value, 4, args, 0, NULL); +} +ZEND_BEGIN_ARG_INFO(args_indexOf, 2) + ZEND_ARG_INFO(0, needle) + ZEND_ARG_INFO(0, offset) ZEND_END_ARG_INFO() static zend_function_entry methods[] = { @@ -96,6 +213,10 @@ static zend_function_entry methods[] = { PHP_ME(Stringy, __toString, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, getEncoding, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, create, arginfo_create, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) + PHP_ME(Stringy, count, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, length, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, indexOfLast, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, indexOf, NULL, ZEND_ACC_PUBLIC) PHP_FE_END }; @@ -109,4 +230,6 @@ void php_startup_register_stringy() zend_declare_property_string(stringy_ce, "str", strlen("str"), "", ZEND_ACC_PROTECTED); zend_declare_property_string(stringy_ce, "encoding", strlen("encoding"), "", ZEND_ACC_PROTECTED); + + zend_class_implements(stringy_ce, 1, spl_ce_Countable); } diff --git a/src/ext/stringy/stringy.h b/src/ext/stringy/stringy.h index fafdfa8..41d739a 100644 --- a/src/ext/stringy/stringy.h +++ b/src/ext/stringy/stringy.h @@ -2,10 +2,6 @@ #define STARTUP_STRINGY_STRINGY_H #include "php.h" -#include "../common.h" -#include "ext/standard/php_standard.h" -#include "Zend/zend_exceptions.h" -#include "ext/spl/spl_exceptions.h" #define PHP_STARTUP_STRINGY_NS(cls) PHP_STARTUP_NS_NAME "Stringy\\" #cls diff --git a/src/ext/test.class.c b/src/ext/test.class.c index fe25815..320aefb 100644 --- a/src/ext/test.class.c +++ b/src/ext/test.class.c @@ -4,92 +4,92 @@ zend_class_entry *test_ce; PHP_METHOD(Test, helloworld) { - if (zend_parse_parameters_none() == FAILURE ) { + if (zend_parse_parameters_none() == FAILURE ) { return; } - php_printf("hello world!"); - RETVAL_NULL(); + php_printf("hello world!"); + RETVAL_NULL(); } PHP_METHOD(Test, echoHelloWorld) { - if (zend_parse_parameters_none() == FAILURE ) { + if (zend_parse_parameters_none() == FAILURE ) { return; } - php_printf("hello world!!"); + php_printf("hello world!!"); - RETURN_NULL(); + RETURN_NULL(); } PHP_METHOD(Test, __call) { zval *params; char *method; - size_t method_len; - zend_string *strg; + size_t method_len; + zend_string *strg; if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz", &method, &method_len, ¶ms) == FAILURE) { return; } - zend_string *delim = zend_string_init("-", sizeof("-"), 0); + zend_string *delim = zend_string_init("-", sizeof("-"), 0); - zval *tmp; - zval result = {}; - zval delimPtr = {}; - - ZVAL_STRINGL(&delimPtr, "-", 1); - ZVAL_EMPTY_STRING(&result); + zval *tmp; + zval result = {}; + zval delimPtr = {}; + + ZVAL_STRINGL(&delimPtr, "-", 1); + ZVAL_EMPTY_STRING(&result); - // 初学者不知道这里有什么其他实现方式。这里以能用为准 + // 初学者不知道这里有什么其他实现方式。这里以能用为准 - uint32_t count = zend_array_count(params->value.arr); - uint32_t index = 0; + uint32_t count = zend_array_count(params->value.arr); + uint32_t index = 0; - if (count > 0) { - ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(params), tmp) { - concat_function(&result, &result, tmp); + if (count > 0) { + ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(params), tmp) { + concat_function(&result, &result, tmp); - if (index == count-1) { - break; - } + if (index == count-1) { + break; + } - concat_function(&result, &result, &delimPtr); - index ++; - } ZEND_HASH_FOREACH_END(); - } + concat_function(&result, &result, &delimPtr); + index ++; + } ZEND_HASH_FOREACH_END(); + } - strg = strpprintf(0, "method:%s,count:%d,args:%s", method, count, Z_STRVAL_P(&result)); + strg = strpprintf(0, "method:%s,count:%d,args:%s", method, count, Z_STRVAL_P(&result)); - RETURN_STR(strg); + RETURN_STR(strg); } ZEND_BEGIN_ARG_INFO_EX(arginfo_call, 0, 0, 2) - ZEND_ARG_INFO(0, method) - ZEND_ARG_INFO(0, params) + ZEND_ARG_INFO(0, method) + ZEND_ARG_INFO(0, params) ZEND_END_ARG_INFO() static zend_function_entry methods[] = { - PHP_ME(Test, helloworld, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) - PHP_ME(Test, echoHelloWorld, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Test, __call, arginfo_call, ZEND_ACC_PUBLIC) - PHP_FE_END + PHP_ME(Test, helloworld, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) + PHP_ME(Test, echoHelloWorld, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Test, __call, arginfo_call, ZEND_ACC_PUBLIC) + PHP_FE_END }; void php_startup_register_test() { - zend_class_entry ce; + zend_class_entry ce; - INIT_CLASS_ENTRY(ce, PHP_STARTUP_TEST_NS(Test), methods); + INIT_CLASS_ENTRY(ce, PHP_STARTUP_TEST_NS(Test), methods); - test_ce = zend_register_internal_class(&ce); + test_ce = zend_register_internal_class(&ce); - zend_declare_property_string(test_ce, "publicProperty", strlen("publicProperty"), "hello world +property", ZEND_ACC_PUBLIC); + zend_declare_property_string(test_ce, "publicProperty", strlen("publicProperty"), "hello world +property", ZEND_ACC_PUBLIC); - zend_declare_property_string(test_ce, "publicPropertyStatic", strlen("publicPropertyStatic"), "hello world +property +static", ZEND_ACC_PUBLIC | ZEND_ACC_STATIC); + zend_declare_property_string(test_ce, "publicPropertyStatic", strlen("publicPropertyStatic"), "hello world +property +static", ZEND_ACC_PUBLIC | ZEND_ACC_STATIC); - zend_declare_class_constant_string(test_ce, "PUBLIC_CONST", strlen("PUBLIC_CONST"), "hello world +const"); + zend_declare_class_constant_string(test_ce, "PUBLIC_CONST", strlen("PUBLIC_CONST"), "hello world +const"); } From 7098f989353f28341049c88ef4898e4d438f03ea Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Tue, 20 Nov 2018 00:06:27 +0800 Subject: [PATCH 020/126] =?UTF-8?q?=E4=BC=98=E6=83=A0=E5=87=BD=E6=95=B0?= =?UTF-8?q?=E8=B0=83=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ext/stringy/stringy.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index 1529d14..665689f 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -58,7 +58,7 @@ PHP_METHOD(Stringy, __construct) // 这里需要加一下了逻辑, 如果这里需要判断 encoding 是否支持, 不支持话,就用默认的编码 ZVAL_STRING(&func, "mb_list_encodings"); - call_user_function_ex(NULL, NULL, &func, return_value, 0, NULL, 0, NULL); + call_user_function(NULL, NULL, &func, return_value, 0, NULL); zval *tmp; size_t count = 0; @@ -72,7 +72,7 @@ PHP_METHOD(Stringy, __construct) if (count == 0) { ZVAL_STRING(&func, "mb_internal_encoding"); - call_user_function_ex(NULL, NULL, &func, return_value, 0, NULL, 0, NULL); + call_user_function(NULL, NULL, &func, return_value, 0, NULL); encoding = Z_STRVAL_P(return_value); } @@ -111,7 +111,7 @@ PHP_METHOD(Stringy, create) ZVAL_STRING(&func, "__construct"); - call_user_function_ex(NULL, &instance, &func, &retval, 2, args, 0, NULL); + call_user_function(NULL, &instance, &func, &retval, 2, args); RETURN_ZVAL(&instance, 0, 1); } @@ -128,7 +128,7 @@ PHP_METHOD(Stringy, count) ZVAL_STRING(&func, "length"); - call_user_function_ex(NULL, getThis(), &func, return_value, 0, NULL, 0, NULL); + call_user_function(NULL, getThis(), &func, return_value, 0, NULL); } /* {{{ int length(): int @@ -144,7 +144,7 @@ PHP_METHOD(Stringy, length) args[0] = *value; - call_user_function_ex(NULL, NULL, &func, return_value, 1, args, 0, NULL); + call_user_function(NULL, NULL, &func, return_value, 1, args); } /*{{{ int indexOfLast($needle, $offset = 0) From 07887c66cefb9257fb8a7f7abcb8b6e6cdf120bd Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Wed, 21 Nov 2018 01:16:37 +0800 Subject: [PATCH 021/126] =?UTF-8?q?=E8=BF=98=E6=9C=89=E9=97=AE=E9=A2=98?= =?UTF-8?q?=EF=BC=8C=E7=AD=89=E5=BE=85=E8=A7=A3=E5=86=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/settings.json | 4 +- .vscode/snnipt.code-snippets | 93 +++++++++++++++------ spec/Stringy/StringySpec.php | 4 +- src/ext/stringy/stringy.c | 154 +++++++++++++++++++++++++++++++++-- startup.php | 11 ++- 5 files changed, 231 insertions(+), 35 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 4331181..2da3e73 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -20,8 +20,10 @@ "__locale": "c", "__string": "c", "string": "c", - "string_view": "c" + "string_view": "c", + "spl_iterators.h": "c" }, + "editor.mouseWheelZoom": false, "files.autoSave": "onFocusChange", "editor.fontSize": 18, "editor.renderWhitespace": "boundary", diff --git a/.vscode/snnipt.code-snippets b/.vscode/snnipt.code-snippets index f394eaf..bea6080 100644 --- a/.vscode/snnipt.code-snippets +++ b/.vscode/snnipt.code-snippets @@ -1,28 +1,69 @@ { - // Place your global snippets here. Each snippet is defined under a snippet name and has a scope, prefix, body and - // description. Add comma separated ids of the languages where the snippet is applicable in the scope field. If scope - // is left empty or omitted, the snippet gets applied to all languages. The prefix is what is - // used to trigger the snippet and the body will be expanded and inserted. Possible variables are: - // $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders. - // Placeholders with the same ids are connected. - // Example: - // "Print to console": { - // "scope": "javascript,typescript", - // "prefix": "log", - // "body": [ - // "console.log('$1');", - // "$2" - // ], - // "description": "Log output to console" - // } - "itf": { - "prefix": "ift", - "scope": "php", - "body": [ - "it('test $1', function () {", - " $0", - "});" - ], - "description": "it function scope" - } + // Place your global snippets here. Each snippet is defined under a snippet name and has a scope, prefix, body and + // description. Add comma separated ids of the languages where the snippet is applicable in the scope field. If scope + // is left empty or omitted, the snippet gets applied to all languages. The prefix is what is + // used to trigger the snippet and the body will be expanded and inserted. Possible variables are: + // $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders. + // Placeholders with the same ids are connected. + // Example: + // "Print to console": { + // "scope": "javascript,typescript", + // "prefix": "log", + // "body": [ + // "console.log('$1');", + // "$2" + // ], + // "description": "Log output to console" + // } + "itf": { + "prefix": "ift", + "scope": "php", + "body": [ + "it('test $1', function () {", + " $0", + "});" + ], + "description": "it function scope" + }, + "cuf": { + "prefix": "cuf", + "scope": "c,h", + "body": [ + "zval func = {};", + "ZVAL_STRING(&func, \"$1\");", + "call_user_function(NULL, NULL, &func, ${2:return_value}, 0, NULL);" + ], + "description": "args" + }, + "cufa": { + "prefix": "cufa", + "scope": "c,h", + "body": [ + "zval func = {}, args[$0] = {};", + "ZVAL_STRING(&func, \"$1\");", + "args[0] = $3;", + "call_user_function(NULL, NULL, &func, ${2:return_value}, $0, args);" + ], + "description": "args" + }, + "argparse": { + "prefix": "argparse", + "scope": "c,h", + "body": [ + "ZEND_PARSE_PARAMETERS_START($1, $2)", + " Z_PARAM_$0", + "ZEND_PARSE_PARAMETERS_END();" + ], + "description": "args" + }, + "argdefine": { + "prefix": "argdefine", + "scope": "c,h", + "body": [ + "ZEND_BEGIN_ARG_INFO($1, $2)", + " ZEND_ARG_TYPE_$0", + "ZEND_END_ARG_INFO();" + ], + "description": "args" + } } diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index 9a0dd2d..7138a5b 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -76,8 +76,8 @@ \expect(count($stringy))->toBe(3); }); - xit('test GetIterator', function () { - $stringy = Stringy::create('Fòô Bàř', 'UTF-8'); + it('test GetIterator', function () { + $stringy = __('Stringy')::create('Fòô Bàř', 'UTF-8'); $valResult = []; foreach ($stringy as $char) { $valResult[] = $char; diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index 665689f..9b9877f 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -6,9 +6,28 @@ #include "ext/spl/spl_exceptions.h" #include "ext/spl/spl_iterators.h" #include "ext/mbstring/mbstring.h" +#include "zend_interfaces.h" +#include "ext/spl/spl_array.h" zend_class_entry *stringy_ce; +// @TODO: 这个地方似乎用法有问题,全是动态调用本类的方法,这个思路是是面向对象的用法,理论上这个地方应该把公用的地方提取成公共方法。 + +// zval* substr(zval *str, zval *start, zval *length, zval *encoding) +// { +// zval func = {}, args[4] = {}, return_value = {}; +// ZVAL_STRING(&func, "mb_substr"); +// args[0] = *str; +// args[1] = *start; +// args[2] = *length; +// args[3] = *encoding; +// call_user_function(NULL, NULL, &func, &return_value, 4, args); + +// return &return_value; +// } + +//================================================= + PHP_METHOD(Stringy, __toString) { zval rv = {}, *value; @@ -80,11 +99,10 @@ PHP_METHOD(Stringy, __construct) zend_update_property_string(stringy_ce, getThis(), "str", strlen("str"), string); zend_update_property_string(stringy_ce, getThis(), "encoding", strlen("encoding"), encoding); } - -ZEND_BEGIN_ARG_INFO_EX(arginfo_construct, 0, 0, 2) +ZEND_BEGIN_ARG_INFO_EX(arginfo___construct, 0, 0, 2) ZEND_ARG_INFO(0, str) ZEND_ARG_INFO(0, encoding) -ZEND_END_ARG_INFO() +ZEND_END_ARG_INFO(); PHP_METHOD(Stringy, getEncoding) { @@ -208,8 +226,125 @@ ZEND_BEGIN_ARG_INFO(args_indexOf, 2) ZEND_ARG_INFO(0, offset) ZEND_END_ARG_INFO() +PHP_METHOD(Stringy, getIterator) +{ + zval instance = {}; + object_init_ex(&instance, spl_ce_ArrayIterator); + + zval func = {}, ret = {}; + ZVAL_STRING(&func, "chars"); + call_user_function(NULL, getThis(), &func, &ret, 0, NULL); + php_var_dump(&ret, 1); + + zval args[1] = {}; + ZVAL_STRING(&func, "__construct"); + args[0] = ret; + call_user_function(NULL, &instance, &func, NULL, 1, args); + // php_var_dump(&instance, 1); + + RETURN_ZVAL(&instance, 0, 1); +} + +PHP_METHOD(Stringy, chars) +{ + size_t str_len; + zval func = {}; + + ZVAL_STRING(&func, "length"); + + call_user_function(NULL, getThis(), &func, return_value, 0, NULL); + // php_var_dump(return_value, 1); + + str_len = (size_t) Z_LVAL_P(return_value); + + zval chars = {}, index = {}, rv = {}, *str; + + array_init(&chars); + + for(int i = 0, l = str_len; i < l; i++) + { + ZVAL_LONG(&index, i); + + zval args[1] = {}; + + ZVAL_STRING(&func, "at"); + + args[0] = index; + + call_user_function(NULL, getThis(), &func, return_value, 1, args); + + str = zend_read_property(stringy_ce, return_value, "str", strlen("str"), 1, &rv); + + add_next_index_zval(&chars, str); + } + + RETURN_ARR(Z_ARRVAL(chars)); +} + +PHP_METHOD(Stringy, at) +{ + zval *start, length; + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ZVAL(start) + ZEND_PARSE_PARAMETERS_END(); + + ZVAL_LONG(&length, 1); + + zval func = {}, args[2] = {}; + ZVAL_STRING(&func, "substr"); + args[0] = *start; + args[1] = length; + call_user_function(NULL, getThis(), &func, return_value, 2, args); +} +ZEND_BEGIN_ARG_INFO(arginfo_at, 1) + ZEND_ARG_TYPE_INFO(0, index, IS_LONG, 0) +ZEND_END_ARG_INFO(); + +PHP_METHOD(Stringy, substr) +{ + zval *start, *length; + zval func = {}; + + ZEND_PARSE_PARAMETERS_START(1, 2) + Z_PARAM_ZVAL(start) + Z_PARAM_OPTIONAL + Z_PARAM_ZVAL(length) + ZEND_PARSE_PARAMETERS_END(); + + if (Z_TYPE_P(length) == IS_NULL) { + zval func = {}; + ZVAL_STRING(&func, "length"); + call_user_function(NULL, NULL, &func, return_value, 0, NULL); + length = return_value; + } + + zval rv = {}; + zval *string = zend_read_property(stringy_ce, getThis(), "str", strlen("str"), 1, &rv); + zval *encoding = zend_read_property(stringy_ce, getThis(), "encoding", strlen("encoding"), 1, &rv); + + zval args[4] = {}; + ZVAL_STRING(&func, "mb_substr"); + args[0] = *string; + args[1] = *start; + args[2] = *length; + args[3] = *encoding; + call_user_function(NULL, NULL, &func, return_value, 4, args); + + zval newStr = {}; + ZVAL_STRING(&newStr, Z_STRVAL_P(return_value)); + zval argsCreate[2] = {}; + ZVAL_STRING(&func, "create"); + argsCreate[0] = newStr; + argsCreate[1] = *encoding; + call_user_function(NULL, getThis(), &func, return_value, 2, argsCreate); +} +ZEND_BEGIN_ARG_INFO(arginfo_substr, 2) + ZEND_ARG_TYPE_INFO(0, index, IS_LONG, 0) + ZEND_ARG_TYPE_INFO(0, length, IS_LONG, 1) +ZEND_END_ARG_INFO(); + static zend_function_entry methods[] = { - PHP_ME(Stringy, __construct, arginfo_construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) + PHP_ME(Stringy, __construct, arginfo___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) PHP_ME(Stringy, __toString, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, getEncoding, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, create, arginfo_create, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) @@ -217,6 +352,10 @@ static zend_function_entry methods[] = { PHP_ME(Stringy, length, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, indexOfLast, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, indexOf, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, getIterator, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, chars, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, at, arginfo_at, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, substr, arginfo_substr, ZEND_ACC_PUBLIC) PHP_FE_END }; @@ -231,5 +370,10 @@ void php_startup_register_stringy() zend_declare_property_string(stringy_ce, "str", strlen("str"), "", ZEND_ACC_PROTECTED); zend_declare_property_string(stringy_ce, "encoding", strlen("encoding"), "", ZEND_ACC_PROTECTED); - zend_class_implements(stringy_ce, 1, spl_ce_Countable); + zend_class_implements( + stringy_ce, + 2, + spl_ce_Countable, + spl_ce_Aggregate + ); } diff --git a/startup.php b/startup.php index a556049..be6d384 100644 --- a/startup.php +++ b/startup.php @@ -48,7 +48,16 @@ function checkExt() function main() { _ns(NS_STRINGY); - $i = __('Stringy')::create(1, 'UTF-8'); + $stringy = __('Stringy')::create('Fòô Bàř', 'UTF-8'); + $stringy->at(1); + // $valResult = []; + // foreach ($stringy as $char) { + // $valResult[] = $char; + // } + // $keyValResult = []; + // foreach ($stringy as $pos => $char) { + // $keyValResult[$pos] = $char; + // } } From 0df95815b50fad3bbe97aac164bfaadce4173aba Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Wed, 21 Nov 2018 01:49:16 +0800 Subject: [PATCH 022/126] =?UTF-8?q?=E8=BF=AD=E4=BB=A3=E6=90=9E=E8=B5=B7?= =?UTF-8?q?=E6=9D=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ext/stringy/stringy.c | 17 ++++++++++------- startup.php | 11 ++++++----- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index 9b9877f..202b755 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -12,6 +12,7 @@ zend_class_entry *stringy_ce; // @TODO: 这个地方似乎用法有问题,全是动态调用本类的方法,这个思路是是面向对象的用法,理论上这个地方应该把公用的地方提取成公共方法。 +// @TODO: 先把这个写完,然后去学习一下其他项目,然后再来优化这个地方的代码,先跑起来 // zval* substr(zval *str, zval *start, zval *length, zval *encoding) // { @@ -234,14 +235,17 @@ PHP_METHOD(Stringy, getIterator) zval func = {}, ret = {}; ZVAL_STRING(&func, "chars"); call_user_function(NULL, getThis(), &func, &ret, 0, NULL); - php_var_dump(&ret, 1); - zval args[1] = {}; + zval x = {}, flags = {}; + ZVAL_STRING(&func, "__construct"); - args[0] = ret; - call_user_function(NULL, &instance, &func, NULL, 1, args); - // php_var_dump(&instance, 1); - + zval args[2] = {}; + ZVAL_ARR(&x, Z_ARRVAL(ret)); + ZVAL_LONG(&flags, 0); + args[0] = x; + args[1] = flags; + call_user_function(NULL, &instance, &func, return_value, 2, args); + RETURN_ZVAL(&instance, 0, 1); } @@ -253,7 +257,6 @@ PHP_METHOD(Stringy, chars) ZVAL_STRING(&func, "length"); call_user_function(NULL, getThis(), &func, return_value, 0, NULL); - // php_var_dump(return_value, 1); str_len = (size_t) Z_LVAL_P(return_value); diff --git a/startup.php b/startup.php index be6d384..7dccc39 100644 --- a/startup.php +++ b/startup.php @@ -49,11 +49,12 @@ function checkExt() function main() { _ns(NS_STRINGY); $stringy = __('Stringy')::create('Fòô Bàř', 'UTF-8'); - $stringy->at(1); - // $valResult = []; - // foreach ($stringy as $char) { - // $valResult[] = $char; - // } + // var_dump($stringy->test()); + $valResult = []; + foreach ($stringy as $char) { + $valResult[] = $char; + } + var_dump($valResult); // $keyValResult = []; // foreach ($stringy as $pos => $char) { // $keyValResult[$pos] = $char; From c7b878d144d53dc8556237a3c9e997bd4ab1bc4b Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Thu, 22 Nov 2018 00:00:39 +0800 Subject: [PATCH 023/126] ArrayAccess --- spec/Stringy/StringySpec.php | 20 ++++---- src/ext/stringy/stringy.c | 93 +++++++++++++++++++++++++++++++++++- 2 files changed, 101 insertions(+), 12 deletions(-) diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index 7138a5b..f61fdb2 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -91,7 +91,7 @@ \expect($keyValResult)->toBe(['F', 'ò', 'ô', ' ', 'B', 'à', 'ř']); }); - xit('test offsetExists', function () { + it('test offsetExists', function () { $data = [ [true, 0], [true, 2], @@ -101,7 +101,7 @@ [false, -4] ]; - $stringy = Stringy::create('fòô', 'UTF-8'); + $stringy = __('Stringy')::create('fòô', 'UTF-8'); foreach ($data as $value) { [$expected, $offset] = $value; @@ -110,8 +110,8 @@ } }); - xit('test OffsetGet', function () { - $stringy = Stringy::create('fòô', 'UTF-8'); + it('test OffsetGet', function () { + $stringy = __('Stringy')::create('fòô', 'UTF-8'); \expect($stringy->offsetGet(0))->toBe('f'); \expect($stringy->offsetGet(1))->toBe('ò'); @@ -119,24 +119,24 @@ \expect($stringy[2])->toBe('ô'); }); - xit('test OffsetGet out of bounds', function () { - $stringy = Stringy::create('fòô', 'UTF-8'); + it('test OffsetGet out of bounds', function () { + $stringy = __('Stringy')::create('fòô', 'UTF-8'); $callable = function () use ($stringy) { $test = $stringy[3]; }; \expect($callable)->toThrow(new \OutOfBoundsException('No character exists at the index')); }); - xit('test OffsetSet', function () { - $stringy = Stringy::create('fòô', 'UTF-8'); + it('test OffsetSet', function () { + $stringy = __('Stringy')::create('fòô', 'UTF-8'); $callable = function () use ($stringy) { $stringy[1] = 'invalid'; }; \expect($callable)->toThrow(new \Exception('Stringy object is immutable, cannot modify char')); }); - xit('test OffsetUnset', function () { - $stringy = Stringy::create('fòô', 'UTF-8'); + it('test OffsetUnset', function () { + $stringy = __('Stringy')::create('fòô', 'UTF-8'); $callable = function () use ($stringy) { unset($stringy[1]); }; diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index 202b755..35126d2 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -346,6 +346,90 @@ ZEND_BEGIN_ARG_INFO(arginfo_substr, 2) ZEND_ARG_TYPE_INFO(0, length, IS_LONG, 1) ZEND_END_ARG_INFO(); +PHP_METHOD(Stringy, offsetExists) +{ + zval *offset; + int offset_int = 0, length = 0; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ZVAL(offset) + ZEND_PARSE_PARAMETERS_END(); + + convert_to_long(offset); + + offset_int = Z_LVAL_P(offset); + + zval func = {}; + ZVAL_STRING(&func, "length"); + call_user_function(NULL, getThis(), &func, return_value, 0, NULL); + length = Z_LVAL_P(return_value); + + if (offset_int >= 0) { + RETURN_BOOL(length > offset_int); + } + + RETURN_BOOL(length >= abs(offset_int)); +} +ZEND_BEGIN_ARG_INFO(arginfo_offsetExists, 1) + ZEND_ARG_INFO(0, offset) +ZEND_END_ARG_INFO(); + +PHP_METHOD(Stringy, offsetGet) +{ + zval *offset; + int offset_int = 0, length = 0; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ZVAL(offset) + ZEND_PARSE_PARAMETERS_END(); + + convert_to_long(offset); + + offset_int = Z_LVAL_P(offset); + + zval func = {}; + ZVAL_STRING(&func, "length"); + call_user_function(NULL, getThis(), &func, return_value, 0, NULL); + length = Z_LVAL_P(return_value); + + if ((offset_int >= 0 && length <= offset_int) || length < abs(offset_int)) { + zend_throw_exception(spl_ce_OutOfBoundsException, "No character exists at the index", 0); + return; + } + + zval args[4] = {}, substrLen = {}, rv = {}; + ZVAL_LONG(&substrLen, 1); + ZVAL_STRING(&func, "mb_substr"); + zval *string = zend_read_property(stringy_ce, getThis(), "str", strlen("str"), 1, &rv); + zval *encoding = zend_read_property(stringy_ce, getThis(), "encoding", strlen("encoding"), 1, &rv); + args[0] = *string; + args[1] = *offset; + args[2] = substrLen; + args[3] = *encoding; + call_user_function(NULL, NULL, &func, return_value, 4 , args); +} +ZEND_BEGIN_ARG_INFO(arginfo_offsetGet, 1) + ZEND_ARG_INFO(0, offset) +ZEND_END_ARG_INFO(); + +PHP_METHOD(Stringy, offsetSet) +{ + zend_throw_exception_ex(zend_ce_exception, 0, "%s", "Stringy object is immutable, cannot modify char"); +} +ZEND_BEGIN_ARG_INFO(arginfo_offsetSet, 2) + ZEND_ARG_INFO(0, offset) + ZEND_ARG_INFO(0, value) +ZEND_END_ARG_INFO(); + +PHP_METHOD(Stringy, offsetUnset) +{ + zend_throw_exception_ex(zend_ce_exception, 0, "%s", "Stringy object is immutable, cannot unset char"); +} +ZEND_BEGIN_ARG_INFO(arginfo_offsetUnset, 1) + ZEND_ARG_INFO(0, offset) +ZEND_END_ARG_INFO(); + + static zend_function_entry methods[] = { PHP_ME(Stringy, __construct, arginfo___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) PHP_ME(Stringy, __toString, NULL, ZEND_ACC_PUBLIC) @@ -359,6 +443,10 @@ static zend_function_entry methods[] = { PHP_ME(Stringy, chars, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, at, arginfo_at, ZEND_ACC_PUBLIC) PHP_ME(Stringy, substr, arginfo_substr, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, offsetExists, arginfo_offsetExists, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, offsetGet, arginfo_offsetGet, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, offsetSet, arginfo_offsetSet, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, offsetUnset, arginfo_offsetUnset, ZEND_ACC_PUBLIC) PHP_FE_END }; @@ -375,8 +463,9 @@ void php_startup_register_stringy() zend_class_implements( stringy_ce, - 2, + 3, spl_ce_Countable, - spl_ce_Aggregate + spl_ce_Aggregate, + spl_ce_ArrayAccess ); } From dd7a100524bcc5215f9b963c14d8bcebc4b101d7 Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Fri, 23 Nov 2018 00:39:59 +0800 Subject: [PATCH 024/126] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E4=B8=80=E6=B3=A2?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=EF=BC=8C=E6=B5=8B=E8=AF=95=E6=9A=82=E6=97=B6?= =?UTF-8?q?=E8=BF=98=E8=B7=91=E4=B8=8D=E9=80=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/snnipt.code-snippets | 8 +-- spec/Stringy/StringySpec.php | 9 +-- src/ext/stringy/stringy.c | 136 +++++++++++++++++++++++++++++++++++ 3 files changed, 145 insertions(+), 8 deletions(-) diff --git a/.vscode/snnipt.code-snippets b/.vscode/snnipt.code-snippets index bea6080..8271cb1 100644 --- a/.vscode/snnipt.code-snippets +++ b/.vscode/snnipt.code-snippets @@ -39,10 +39,10 @@ "prefix": "cufa", "scope": "c,h", "body": [ - "zval func = {}, args[$0] = {};", - "ZVAL_STRING(&func, \"$1\");", - "args[0] = $3;", - "call_user_function(NULL, NULL, &func, ${2:return_value}, $0, args);" + "zval ${1:func} = {}, args[$2] = {};", + "ZVAL_STRING(&${1:func}, \"$0\");", + "args[0] = $4;", + "call_user_function(NULL, NULL, &${1:func}, ${3:return_value}, $2, args);" ], "description": "args" }, diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index f61fdb2..8be00dd 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -64,10 +64,11 @@ \expect('UTF-8')->toBe($stringy->getEncoding()); }); - xit('test chaining', function () { - $stringy = Stringy::create('Fòô Bàř', 'UTF-8'); - \expect($stringy)->toBeAnInstanceOf(Stringy::class); - \expect('FÒÔ bÀŘ')->toBe((string) $stringy->collapseWhiteSpace()->swapCase()->upperCaseFirst()); + it('test chaining', function () { + $stringy = __('Stringy')::create('x y', 'UTF-8'); + \expect($stringy)->toBeAnInstanceOf(__('Stringy')); + var_dump((string)$stringy->regexReplace('[[:space:]]+', ' '));die(); + \expect("x y")->toBe((string) $stringy->collapseWhiteSpace());//->swapCase()->upperCaseFirst()); }); it('test count', function () { diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index 35126d2..2a5d285 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -97,6 +97,7 @@ PHP_METHOD(Stringy, __construct) encoding = Z_STRVAL_P(return_value); } + // PHPWRITE(encoding, strlen(encoding)); zend_update_property_string(stringy_ce, getThis(), "str", strlen("str"), string); zend_update_property_string(stringy_ce, getThis(), "encoding", strlen("encoding"), encoding); } @@ -429,6 +430,138 @@ ZEND_BEGIN_ARG_INFO(arginfo_offsetUnset, 1) ZEND_ARG_INFO(0, offset) ZEND_END_ARG_INFO(); +PHP_METHOD(Stringy, collapseWhiteSpace) +{ + zval instance = {}, retval = {}, func = {}, args[3] = {}, args_trim[1] = {}; + zval pattern, replacement, options = {}, chars = {}; + + object_init_ex(&instance, stringy_ce); + + // call regexReplace + + ZVAL_STRING(&pattern, "[[:space:]]+"); + ZVAL_STRING(&replacement, " "); + + args[0] = pattern; + args[1] = replacement; + args[2] = options; + + ZVAL_STRING(&func, "regexReplace"); + call_user_function(NULL, getThis(), &func, &retval, 3, args); + + // call trim() + + ZVAL_STRING(&func, "trim"); + args_trim[0] = chars; + call_user_function(NULL, &retval, &func, return_value, 1, args_trim); + + RETURN_ZVAL(return_value, 0, 1); +} + +PHP_METHOD(Stringy, regexReplace) +{ + zval *pattern, *replacement, *options, rv = {}; + zval func = {}; + + ZEND_PARSE_PARAMETERS_START(2, 3) + Z_PARAM_ZVAL(pattern) + Z_PARAM_ZVAL(replacement) + Z_PARAM_OPTIONAL + Z_PARAM_ZVAL(options) + ZEND_PARSE_PARAMETERS_END(); + + zval *encoding = zend_read_property(stringy_ce, getThis(), "encoding", strlen("encoding"), 0, &rv); + zval *str = zend_read_property(stringy_ce, getThis(), "str", strlen("str"), 1, &rv); + + zval regexEncoding = {}; + ZVAL_STRING(&func, "regexEncoding"); + call_user_function(NULL, getThis(), &func, ®exEncoding, 0, NULL); + + zval args[1] = {}; + ZVAL_STRING(&func, "regexEncoding"); + args[0] = *encoding; + call_user_function(NULL, getThis(), &func, return_value, 1, args); + +//TODO: 实现 eregReplace + zval args_eregReplace[1] = {}, retStr = {}; + ZVAL_STRING(&func, "eregReplace"); + args_eregReplace[0] = *pattern; + args_eregReplace[1] = *replacement; + args_eregReplace[2] = *str; + args_eregReplace[3] = *options; + call_user_function(NULL, getThis(), &func, &retStr, 1, args); + + ZVAL_STRING(&func, "regexEncoding"); + args[0] = regexEncoding; + call_user_function(NULL, getThis(), &func, return_value, 1, args); + + zval instance = {}; + object_init_ex(&instance, stringy_ce); + + args[0] = retStr; + args[1] = *encoding; + + php_var_dump(&retStr, 1); + php_var_dump(encoding, 1); + + ZVAL_STRING(&func, "__construct"); + + call_user_function(NULL, &instance, &func, return_value, 2, args); + + RETURN_ZVAL(&instance, 0, 1); +} +ZEND_BEGIN_ARG_INFO(arginfo_regexReplace, 3) + ZEND_ARG_INFO(0, pattern) + ZEND_ARG_INFO(0, replacement) + ZEND_ARG_INFO(0, options) +ZEND_END_ARG_INFO(); + +PHP_METHOD(Stringy, trim) +{ + zval *chars; + ZEND_PARSE_PARAMETERS_START(0, 1) + Z_PARAM_ZVAL(chars) + ZEND_PARSE_PARAMETERS_END(); + + if (Z_TYPE_P(chars) != IS_NULL) { + zval func = {}, args[2] = {}, delimiter = {}; + ZVAL_STRING(&func, "preg_quote"); + args[0] = *chars; + args[1] = delimiter; + call_user_function(NULL, NULL, &func, return_value, 2, args); + } else { + ZVAL_STRING(chars, "[:space:]"); + } + + zval func_regexReplace = {}, args[3] = {}, pattern = {}, replacement = {}, options = {}; + ZVAL_STRING(&func_regexReplace, "regexReplace"); + ZVAL_STRING(&pattern, "^[$chars]+|[$chars]+$"); + ZVAL_STRING(&replacement, ""); + args[0] = pattern; + args[1] = replacement; + args[2] = options; + call_user_function(NULL, getThis(), &func_regexReplace, return_value, 3, args); +} +ZEND_BEGIN_ARG_INFO(arginfo_trim, 1) + ZEND_ARG_INFO(0, chars) +ZEND_END_ARG_INFO(); + +PHP_METHOD(Stringy, regexEncoding) +{ + zval *encoding; + ZEND_PARSE_PARAMETERS_START(0, 1) + Z_PARAM_OPTIONAL + Z_PARAM_ZVAL(encoding) + ZEND_PARSE_PARAMETERS_END(); + + zval func = {}, args[1] = {}; + ZVAL_STRING(&func, "mb_regex_encoding"); + args[0] = *encoding; + call_user_function(NULL, NULL, &func, return_value, 0, NULL); +} +ZEND_BEGIN_ARG_INFO(arginfo_regexEncoding, 1) + ZEND_ARG_INFO(0, encoding) +ZEND_END_ARG_INFO(); static zend_function_entry methods[] = { PHP_ME(Stringy, __construct, arginfo___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) @@ -447,6 +580,9 @@ static zend_function_entry methods[] = { PHP_ME(Stringy, offsetGet, arginfo_offsetGet, ZEND_ACC_PUBLIC) PHP_ME(Stringy, offsetSet, arginfo_offsetSet, ZEND_ACC_PUBLIC) PHP_ME(Stringy, offsetUnset, arginfo_offsetUnset, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, collapseWhiteSpace, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, regexReplace, arginfo_regexReplace, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, regexEncoding, arginfo_regexEncoding, ZEND_ACC_PUBLIC) PHP_FE_END }; From e45e09169aebd940488db01103ca8d66405ea531 Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Fri, 23 Nov 2018 09:16:46 +0800 Subject: [PATCH 025/126] update readme --- README.MD | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.MD b/README.MD index 63adda3..86025c9 100644 --- a/README.MD +++ b/README.MD @@ -15,8 +15,10 @@ 利用 php [自动加载](http://www.php.net/manual/zh/language.oop5.autoload.php)的逻辑。 -1. 默认禁用扩展执行一遍测试,这个时候执行的是 PHP 逻辑 -2. 启用扩展再执行一次扩展, 这个时候执行的是 EXT 逻辑 (这个地方有个问题,如果 ext 扩展不存在,那么就会降级使用 php 代码) +1. ~~默认禁用扩展执行一遍测试,这个时候执行的是 PHP 逻辑~~ +2. ~~启用扩展再执行一次扩展, 这个时候执行的是 EXT 逻辑 (这个地方有个问题,如果 ext 扩展不存在,那么就会降级使用 php 代码)~~ + +使用函数动态生成对应的带有命名空间的类名,原因是之前的思路存在漏洞,因为自动加载的存在,导致如果 ext 中不存在,就会自动降级为 php 代码。 ## 学习方式 From 2109ce049cf31723a8c592054eb8d434c7cd4d61 Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Fri, 23 Nov 2018 20:47:41 +0800 Subject: [PATCH 026/126] update --- .vscode/settings.json | 3 ++- spec/Stringy/StringySpec.php | 4 +-- src/ext/stringy/stringy.c | 52 +++++++++++++++++++++++++++--------- tools/build.sh | 4 ++- 4 files changed, 47 insertions(+), 16 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 2da3e73..6cca03c 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -21,7 +21,8 @@ "__string": "c", "string": "c", "string_view": "c", - "spl_iterators.h": "c" + "spl_iterators.h": "c", + "iosfwd": "c" }, "editor.mouseWheelZoom": false, "files.autoSave": "onFocusChange", diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index 8be00dd..03abc70 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -67,8 +67,8 @@ it('test chaining', function () { $stringy = __('Stringy')::create('x y', 'UTF-8'); \expect($stringy)->toBeAnInstanceOf(__('Stringy')); - var_dump((string)$stringy->regexReplace('[[:space:]]+', ' '));die(); - \expect("x y")->toBe((string) $stringy->collapseWhiteSpace());//->swapCase()->upperCaseFirst()); + var_dump((string) $stringy->collapseWhiteSpace()); + \expect("x y")->toBe((string) $stringy->collapseWhiteSpace());//->swapCase()->upperCaseFirst()); }); it('test count', function () { diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index 2a5d285..6c559e3 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -452,10 +452,10 @@ PHP_METHOD(Stringy, collapseWhiteSpace) // call trim() ZVAL_STRING(&func, "trim"); - args_trim[0] = chars; - call_user_function(NULL, &retval, &func, return_value, 1, args_trim); + args_trim[0] = retval; + call_user_function(NULL, getThis(), &func, return_value, 1, args_trim); - RETURN_ZVAL(return_value, 0, 1); + RETURN_ZVAL(getThis(), 0, 1); } PHP_METHOD(Stringy, regexReplace) @@ -482,14 +482,13 @@ PHP_METHOD(Stringy, regexReplace) args[0] = *encoding; call_user_function(NULL, getThis(), &func, return_value, 1, args); -//TODO: 实现 eregReplace - zval args_eregReplace[1] = {}, retStr = {}; + zval args_eregReplace[4] = {}, retStr = {}; ZVAL_STRING(&func, "eregReplace"); args_eregReplace[0] = *pattern; args_eregReplace[1] = *replacement; args_eregReplace[2] = *str; args_eregReplace[3] = *options; - call_user_function(NULL, getThis(), &func, &retStr, 1, args); + call_user_function(NULL, getThis(), &func, &retStr, 4, args_eregReplace); ZVAL_STRING(&func, "regexEncoding"); args[0] = regexEncoding; @@ -498,15 +497,13 @@ PHP_METHOD(Stringy, regexReplace) zval instance = {}; object_init_ex(&instance, stringy_ce); - args[0] = retStr; - args[1] = *encoding; - - php_var_dump(&retStr, 1); - php_var_dump(encoding, 1); + zval args_construct[2] = {}; + args_construct[0] = retStr; + args_construct[1] = *encoding; ZVAL_STRING(&func, "__construct"); - call_user_function(NULL, &instance, &func, return_value, 2, args); + call_user_function(NULL, &instance, &func, return_value, 2, args_construct); RETURN_ZVAL(&instance, 0, 1); } @@ -563,6 +560,36 @@ ZEND_BEGIN_ARG_INFO(arginfo_regexEncoding, 1) ZEND_ARG_INFO(0, encoding) ZEND_END_ARG_INFO(); +PHP_METHOD(Stringy, eregReplace) +{ + zval *pattern, *replace, *string, *option; + ZEND_PARSE_PARAMETERS_START(3, 4) + Z_PARAM_ZVAL(pattern) + Z_PARAM_ZVAL(replace) + Z_PARAM_ZVAL(string) + Z_PARAM_ZVAL(option) + ZEND_PARSE_PARAMETERS_END(); + + convert_to_string(replace); + convert_to_string(pattern); + convert_to_string(string); + convert_to_string(option); + + zval func = {}, args[4] = {}; + ZVAL_STRING(&func, "mb_ereg_replace"); + args[0] = *pattern; + args[1] = *replace; + args[2] = *string; + args[3] = *option; + call_user_function(NULL, NULL, &func, return_value, 4, args); +} +ZEND_BEGIN_ARG_INFO(arginfo_eregReplace, 4) + ZEND_ARG_INFO(0, pattern) + ZEND_ARG_INFO(0, replacement) + ZEND_ARG_INFO(0, string) + ZEND_ARG_INFO(0, option) +ZEND_END_ARG_INFO(); + static zend_function_entry methods[] = { PHP_ME(Stringy, __construct, arginfo___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) PHP_ME(Stringy, __toString, NULL, ZEND_ACC_PUBLIC) @@ -583,6 +610,7 @@ static zend_function_entry methods[] = { PHP_ME(Stringy, collapseWhiteSpace, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, regexReplace, arginfo_regexReplace, ZEND_ACC_PUBLIC) PHP_ME(Stringy, regexEncoding, arginfo_regexEncoding, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, eregReplace, arginfo_eregReplace, ZEND_ACC_PUBLIC) PHP_FE_END }; diff --git a/tools/build.sh b/tools/build.sh index 0ab76d3..27b1c6f 100755 --- a/tools/build.sh +++ b/tools/build.sh @@ -10,7 +10,9 @@ echo "disabled startup" rm -f $PHPBREW_ROOT/php/$PHPBREW_PHP/var/db/start.ini echo "go..." -phpize && ./configure --enable-debug && make && make install && make clean && phpize --clean +# phpize && ./configure --enable-debug && make && make install && make clean && phpize --clean + +make && make install echo "enabled startup" phpbrew ext enable startup From 684be9e05d728bd6f1ed514dce8fe85f10d69807 Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Sat, 24 Nov 2018 00:03:12 +0800 Subject: [PATCH 027/126] update --- spec/Stringy/StringySpec.php | 3 +-- src/ext/stringy/stringy.c | 22 ++++++++++++++++++++-- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index 03abc70..3cee58d 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -67,8 +67,7 @@ it('test chaining', function () { $stringy = __('Stringy')::create('x y', 'UTF-8'); \expect($stringy)->toBeAnInstanceOf(__('Stringy')); - var_dump((string) $stringy->collapseWhiteSpace()); - \expect("x y")->toBe((string) $stringy->collapseWhiteSpace());//->swapCase()->upperCaseFirst()); + \expect("X Y")->toBe((string) $stringy->collapseWhiteSpace()->swapCase());//->upperCaseFirst()); }); it('test count', function () { diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index 6c559e3..9370972 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -7,6 +7,7 @@ #include "ext/spl/spl_iterators.h" #include "ext/mbstring/mbstring.h" #include "zend_interfaces.h" +#include "zend_closures.h" #include "ext/spl/spl_array.h" zend_class_entry *stringy_ce; @@ -453,9 +454,9 @@ PHP_METHOD(Stringy, collapseWhiteSpace) ZVAL_STRING(&func, "trim"); args_trim[0] = retval; - call_user_function(NULL, getThis(), &func, return_value, 1, args_trim); + call_user_function(NULL, &retval, &func, return_value, 1, args_trim); - RETURN_ZVAL(getThis(), 0, 1); + RETURN_ZVAL(&retval, 0, 1); } PHP_METHOD(Stringy, regexReplace) @@ -567,6 +568,7 @@ PHP_METHOD(Stringy, eregReplace) Z_PARAM_ZVAL(pattern) Z_PARAM_ZVAL(replace) Z_PARAM_ZVAL(string) + Z_PARAM_OPTIONAL Z_PARAM_ZVAL(option) ZEND_PARSE_PARAMETERS_END(); @@ -590,6 +592,22 @@ ZEND_BEGIN_ARG_INFO(arginfo_eregReplace, 4) ZEND_ARG_INFO(0, option) ZEND_END_ARG_INFO(); +PHP_METHOD(Stringy, swapCase) +{ + zval rv = {}; + zval *encoding = zend_read_property(stringy_ce, getThis(), "encoding", strlen("encoding"), 1, &rv); + zval *string = zend_read_property(stringy_ce, getThis(), "str", strlen("str"), 1, &rv); + + zval func = {}, args[5] = {}, pattern = {}, callback = {}, subject = {}, limit = {}, count = {}; + ZVAL_STRING(&pattern, "/[\S]/u"); + + zend_create_closure(&callback, "") + + ZVAL_STRING(&func, "preg_repace_callback"); + // args[0] = ; + call_user_function(NULL, NULL, &func, return_value, 5, args); +} + static zend_function_entry methods[] = { PHP_ME(Stringy, __construct, arginfo___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) PHP_ME(Stringy, __toString, NULL, ZEND_ACC_PUBLIC) From ceb322714bace628683099bf3f01000ac972d492 Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Sat, 24 Nov 2018 18:35:35 +0800 Subject: [PATCH 028/126] update --- spec/Stringy/StringySpec.php | 2 +- src/ext/stringy/stringy.c | 357 +++++++++++++++++++++-------------- startup.php | 3 +- 3 files changed, 220 insertions(+), 142 deletions(-) diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index 3cee58d..37b72de 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -67,7 +67,7 @@ it('test chaining', function () { $stringy = __('Stringy')::create('x y', 'UTF-8'); \expect($stringy)->toBeAnInstanceOf(__('Stringy')); - \expect("X Y")->toBe((string) $stringy->collapseWhiteSpace()->swapCase());//->upperCaseFirst()); + \expect("X Y")->toBe((string) $stringy->swapCase());//->upperCaseFirst()); }); it('test count', function () { diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index 9370972..b45031f 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -14,10 +14,13 @@ zend_class_entry *stringy_ce; // @TODO: 这个地方似乎用法有问题,全是动态调用本类的方法,这个思路是是面向对象的用法,理论上这个地方应该把公用的地方提取成公共方法。 // @TODO: 先把这个写完,然后去学习一下其他项目,然后再来优化这个地方的代码,先跑起来 +///* don't forget to free the zvals */ +//zval_ptr_dtor(&retval_ptr); +//zval_dtor(&function_name); // zval* substr(zval *str, zval *start, zval *length, zval *encoding) // { -// zval func = {}, args[4] = {}, return_value = {}; +// zval func, args[4], return_value; // ZVAL_STRING(&func, "mb_substr"); // args[0] = *str; // args[1] = *start; @@ -32,7 +35,7 @@ zend_class_entry *stringy_ce; PHP_METHOD(Stringy, __toString) { - zval rv = {}, *value; + zval rv, *value; value = zend_read_property(stringy_ce, getThis(), "str", strlen("str"), 0, &rv); RETURN_STRING(Z_STRVAL_P(value)); } @@ -45,66 +48,75 @@ PHP_METHOD(Stringy, __construct) size_t str_len, encoding_len; zval func; - if (EX_NUM_ARGS() == 0) { + if (EX_NUM_ARGS() == 0) + { RETURN_NULL(); } ZEND_PARSE_PARAMETERS_START(0, 2) - Z_PARAM_OPTIONAL - Z_PARAM_ZVAL(str) - Z_PARAM_STRING(encoding, encoding_len) + Z_PARAM_OPTIONAL + Z_PARAM_ZVAL(str) + Z_PARAM_STRING(encoding, encoding_len) ZEND_PARSE_PARAMETERS_END(); - if (Z_TYPE_P(str) == IS_ARRAY) { + if (Z_TYPE_P(str) == IS_ARRAY) + { zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0, "%s", "Passed value cannot be an array"); return; } - if (Z_TYPE_P(str) == IS_OBJECT) { + if (Z_TYPE_P(str) == IS_OBJECT) + { zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0, "%s", "Passed object must have a __toString method"); return; } convert_to_string(str) - string = Z_STRVAL_P(str); + string = Z_STRVAL_P(str); - if (string == NULL) { + if (string == NULL) + { string = ""; } - if (encoding == NULL) { + if (encoding == NULL) + { encoding = ""; } // 这里需要加一下了逻辑, 如果这里需要判断 encoding 是否支持, 不支持话,就用默认的编码 - ZVAL_STRING(&func, "mb_list_encodings"); + ZVAL_STRING(&func, "mb_list_encodings"); call_user_function(NULL, NULL, &func, return_value, 0, NULL); zval *tmp; size_t count = 0; zend_string *encoding_str = zend_string_init(encoding, strlen(encoding), 0); - ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(return_value), tmp) { - if (encoding == Z_STRVAL_P(tmp)) { + ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(return_value), tmp) + { + if (encoding == Z_STRVAL_P(tmp)) + { count++; break; } - }ZEND_HASH_FOREACH_END(); + } + ZEND_HASH_FOREACH_END(); - if (count == 0) { - ZVAL_STRING(&func, "mb_internal_encoding"); + if (count == 0) + { + ZVAL_STRING(&func, "mb_internal_encoding"); call_user_function(NULL, NULL, &func, return_value, 0, NULL); encoding = Z_STRVAL_P(return_value); - } + } // PHPWRITE(encoding, strlen(encoding)); zend_update_property_string(stringy_ce, getThis(), "str", strlen("str"), string); zend_update_property_string(stringy_ce, getThis(), "encoding", strlen("encoding"), encoding); } ZEND_BEGIN_ARG_INFO_EX(arginfo___construct, 0, 0, 2) - ZEND_ARG_INFO(0, str) - ZEND_ARG_INFO(0, encoding) +ZEND_ARG_INFO(0, str) +ZEND_ARG_INFO(0, encoding) ZEND_END_ARG_INFO(); PHP_METHOD(Stringy, getEncoding) @@ -116,17 +128,17 @@ PHP_METHOD(Stringy, getEncoding) PHP_METHOD(Stringy, create) { - zval instance = {}, retval = {}, func = {}, args[2] = {}; + zval instance, retval, func, args[2]; zval *str, *encoding; ZEND_PARSE_PARAMETERS_START(0, 2) - Z_PARAM_OPTIONAL - Z_PARAM_ZVAL(str) - Z_PARAM_ZVAL(encoding) + Z_PARAM_OPTIONAL + Z_PARAM_ZVAL(str) + Z_PARAM_ZVAL(encoding) ZEND_PARSE_PARAMETERS_END(); object_init_ex(&instance, stringy_ce); - + args[0] = *str; args[1] = *encoding; @@ -137,15 +149,15 @@ PHP_METHOD(Stringy, create) RETURN_ZVAL(&instance, 0, 1); } ZEND_BEGIN_ARG_INFO_EX(arginfo_create, 0, 0, 2) - ZEND_ARG_INFO(0, str) - ZEND_ARG_INFO(0, encoding) +ZEND_ARG_INFO(0, str) +ZEND_ARG_INFO(0, encoding) ZEND_END_ARG_INFO() /* {{{ int length(): int }}} */ PHP_METHOD(Stringy, count) { - zval instance = {}, func = {}, rv = {}; + zval instance, func, rv; ZVAL_STRING(&func, "length"); @@ -157,7 +169,7 @@ PHP_METHOD(Stringy, count) }}} */ PHP_METHOD(Stringy, length) { - zval func = {}, args[1] = {}, rv = {}; + zval func, args[1], rv; zval *value; ZVAL_STRING(&func, "mb_strlen"); @@ -172,13 +184,13 @@ PHP_METHOD(Stringy, length) }}}*/ PHP_METHOD(Stringy, indexOfLast) { - zval func = {}, args[4] = {}, rv = {}; + zval func, args[4], rv; zval *value, *encoding, *needle, *offset; ZEND_PARSE_PARAMETERS_START(1, 2) - Z_PARAM_ZVAL(needle) - Z_PARAM_OPTIONAL - Z_PARAM_ZVAL(offset) + Z_PARAM_ZVAL(needle) + Z_PARAM_OPTIONAL + Z_PARAM_ZVAL(offset) ZEND_PARSE_PARAMETERS_END(); ZVAL_STRING(&func, "mb_strrpos"); @@ -194,8 +206,8 @@ PHP_METHOD(Stringy, indexOfLast) call_user_function_ex(NULL, NULL, &func, return_value, 4, args, 0, NULL); } ZEND_BEGIN_ARG_INFO(args_indexOfLast, 2) - ZEND_ARG_INFO(0, needle) - ZEND_ARG_INFO(0, offset) +ZEND_ARG_INFO(0, needle) +ZEND_ARG_INFO(0, offset) ZEND_END_ARG_INFO() /*{{{ int indexOf($needle, $offset = 0) @@ -203,13 +215,13 @@ ZEND_END_ARG_INFO() }}}*/ PHP_METHOD(Stringy, indexOf) { - zval func = {}, args[4] = {}, rv = {}; + zval func, args[4], rv; zval *value, *encoding, *needle, *offset; ZEND_PARSE_PARAMETERS_START(1, 2) - Z_PARAM_ZVAL(needle) - Z_PARAM_OPTIONAL - Z_PARAM_ZVAL(offset) + Z_PARAM_ZVAL(needle) + Z_PARAM_OPTIONAL + Z_PARAM_ZVAL(offset) ZEND_PARSE_PARAMETERS_END(); ZVAL_STRING(&func, "mb_strpos"); @@ -225,52 +237,52 @@ PHP_METHOD(Stringy, indexOf) call_user_function_ex(NULL, NULL, &func, return_value, 4, args, 0, NULL); } ZEND_BEGIN_ARG_INFO(args_indexOf, 2) - ZEND_ARG_INFO(0, needle) - ZEND_ARG_INFO(0, offset) +ZEND_ARG_INFO(0, needle) +ZEND_ARG_INFO(0, offset) ZEND_END_ARG_INFO() PHP_METHOD(Stringy, getIterator) { - zval instance = {}; + zval instance; object_init_ex(&instance, spl_ce_ArrayIterator); - zval func = {}, ret = {}; + zval func, ret; ZVAL_STRING(&func, "chars"); call_user_function(NULL, getThis(), &func, &ret, 0, NULL); - zval x = {}, flags = {}; - + zval zendFunction, flags; + ZVAL_STRING(&func, "__construct"); - zval args[2] = {}; - ZVAL_ARR(&x, Z_ARRVAL(ret)); + zval args[2]; + ZVAL_ARR(&zendFunction, Z_ARRVAL(ret)); ZVAL_LONG(&flags, 0); - args[0] = x; + args[0] = zendFunction; args[1] = flags; call_user_function(NULL, &instance, &func, return_value, 2, args); - + RETURN_ZVAL(&instance, 0, 1); } PHP_METHOD(Stringy, chars) { size_t str_len; - zval func = {}; + zval func; ZVAL_STRING(&func, "length"); call_user_function(NULL, getThis(), &func, return_value, 0, NULL); - str_len = (size_t) Z_LVAL_P(return_value); - - zval chars = {}, index = {}, rv = {}, *str; + str_len = (size_t)Z_LVAL_P(return_value); + + zval chars, index, rv, *str; array_init(&chars); - - for(int i = 0, l = str_len; i < l; i++) + + for (int i = 0, l = str_len; i < l; i++) { ZVAL_LONG(&index, i); - zval args[1] = {}; + zval args[1]; ZVAL_STRING(&func, "at"); @@ -290,44 +302,45 @@ PHP_METHOD(Stringy, at) { zval *start, length; ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_ZVAL(start) + Z_PARAM_ZVAL(start) ZEND_PARSE_PARAMETERS_END(); ZVAL_LONG(&length, 1); - zval func = {}, args[2] = {}; + zval func, args[2]; ZVAL_STRING(&func, "substr"); args[0] = *start; args[1] = length; call_user_function(NULL, getThis(), &func, return_value, 2, args); } ZEND_BEGIN_ARG_INFO(arginfo_at, 1) - ZEND_ARG_TYPE_INFO(0, index, IS_LONG, 0) +ZEND_ARG_TYPE_INFO(0, index, IS_LONG, 0) ZEND_END_ARG_INFO(); PHP_METHOD(Stringy, substr) { zval *start, *length; - zval func = {}; + zval func; ZEND_PARSE_PARAMETERS_START(1, 2) - Z_PARAM_ZVAL(start) - Z_PARAM_OPTIONAL - Z_PARAM_ZVAL(length) + Z_PARAM_ZVAL(start) + Z_PARAM_OPTIONAL + Z_PARAM_ZVAL(length) ZEND_PARSE_PARAMETERS_END(); - if (Z_TYPE_P(length) == IS_NULL) { - zval func = {}; + if (Z_TYPE_P(length) == IS_NULL) + { + zval func; ZVAL_STRING(&func, "length"); call_user_function(NULL, NULL, &func, return_value, 0, NULL); length = return_value; } - zval rv = {}; + zval rv; zval *string = zend_read_property(stringy_ce, getThis(), "str", strlen("str"), 1, &rv); zval *encoding = zend_read_property(stringy_ce, getThis(), "encoding", strlen("encoding"), 1, &rv); - zval args[4] = {}; + zval args[4]; ZVAL_STRING(&func, "mb_substr"); args[0] = *string; args[1] = *start; @@ -335,17 +348,17 @@ PHP_METHOD(Stringy, substr) args[3] = *encoding; call_user_function(NULL, NULL, &func, return_value, 4, args); - zval newStr = {}; + zval newStr; ZVAL_STRING(&newStr, Z_STRVAL_P(return_value)); - zval argsCreate[2] = {}; + zval argsCreate[2]; ZVAL_STRING(&func, "create"); argsCreate[0] = newStr; argsCreate[1] = *encoding; call_user_function(NULL, getThis(), &func, return_value, 2, argsCreate); } ZEND_BEGIN_ARG_INFO(arginfo_substr, 2) - ZEND_ARG_TYPE_INFO(0, index, IS_LONG, 0) - ZEND_ARG_TYPE_INFO(0, length, IS_LONG, 1) +ZEND_ARG_TYPE_INFO(0, index, IS_LONG, 0) +ZEND_ARG_TYPE_INFO(0, length, IS_LONG, 1) ZEND_END_ARG_INFO(); PHP_METHOD(Stringy, offsetExists) @@ -354,26 +367,27 @@ PHP_METHOD(Stringy, offsetExists) int offset_int = 0, length = 0; ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_ZVAL(offset) + Z_PARAM_ZVAL(offset) ZEND_PARSE_PARAMETERS_END(); convert_to_long(offset); offset_int = Z_LVAL_P(offset); - zval func = {}; + zval func; ZVAL_STRING(&func, "length"); call_user_function(NULL, getThis(), &func, return_value, 0, NULL); length = Z_LVAL_P(return_value); - if (offset_int >= 0) { + if (offset_int >= 0) + { RETURN_BOOL(length > offset_int); } RETURN_BOOL(length >= abs(offset_int)); } ZEND_BEGIN_ARG_INFO(arginfo_offsetExists, 1) - ZEND_ARG_INFO(0, offset) +ZEND_ARG_INFO(0, offset) ZEND_END_ARG_INFO(); PHP_METHOD(Stringy, offsetGet) @@ -382,24 +396,25 @@ PHP_METHOD(Stringy, offsetGet) int offset_int = 0, length = 0; ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_ZVAL(offset) + Z_PARAM_ZVAL(offset) ZEND_PARSE_PARAMETERS_END(); convert_to_long(offset); offset_int = Z_LVAL_P(offset); - - zval func = {}; + + zval func; ZVAL_STRING(&func, "length"); call_user_function(NULL, getThis(), &func, return_value, 0, NULL); length = Z_LVAL_P(return_value); - if ((offset_int >= 0 && length <= offset_int) || length < abs(offset_int)) { + if ((offset_int >= 0 && length <= offset_int) || length < abs(offset_int)) + { zend_throw_exception(spl_ce_OutOfBoundsException, "No character exists at the index", 0); return; } - zval args[4] = {}, substrLen = {}, rv = {}; + zval args[4], substrLen, rv; ZVAL_LONG(&substrLen, 1); ZVAL_STRING(&func, "mb_substr"); zval *string = zend_read_property(stringy_ce, getThis(), "str", strlen("str"), 1, &rv); @@ -408,10 +423,10 @@ PHP_METHOD(Stringy, offsetGet) args[1] = *offset; args[2] = substrLen; args[3] = *encoding; - call_user_function(NULL, NULL, &func, return_value, 4 , args); + call_user_function(NULL, NULL, &func, return_value, 4, args); } ZEND_BEGIN_ARG_INFO(arginfo_offsetGet, 1) - ZEND_ARG_INFO(0, offset) +ZEND_ARG_INFO(0, offset) ZEND_END_ARG_INFO(); PHP_METHOD(Stringy, offsetSet) @@ -419,25 +434,25 @@ PHP_METHOD(Stringy, offsetSet) zend_throw_exception_ex(zend_ce_exception, 0, "%s", "Stringy object is immutable, cannot modify char"); } ZEND_BEGIN_ARG_INFO(arginfo_offsetSet, 2) - ZEND_ARG_INFO(0, offset) - ZEND_ARG_INFO(0, value) +ZEND_ARG_INFO(0, offset) +ZEND_ARG_INFO(0, value) ZEND_END_ARG_INFO(); PHP_METHOD(Stringy, offsetUnset) { - zend_throw_exception_ex(zend_ce_exception, 0, "%s", "Stringy object is immutable, cannot unset char"); + zend_throw_exception_ex(zend_ce_exception, 0, "%s", "Stringy object is immutable, cannot unset char"); } ZEND_BEGIN_ARG_INFO(arginfo_offsetUnset, 1) - ZEND_ARG_INFO(0, offset) +ZEND_ARG_INFO(0, offset) ZEND_END_ARG_INFO(); PHP_METHOD(Stringy, collapseWhiteSpace) { - zval instance = {}, retval = {}, func = {}, args[3] = {}, args_trim[1] = {}; - zval pattern, replacement, options = {}, chars = {}; + zval instance, retval, func, args[3], args_trim[1]; + zval pattern, replacement, options, chars; object_init_ex(&instance, stringy_ce); - + // call regexReplace ZVAL_STRING(&pattern, "[[:space:]]+"); @@ -461,29 +476,29 @@ PHP_METHOD(Stringy, collapseWhiteSpace) PHP_METHOD(Stringy, regexReplace) { - zval *pattern, *replacement, *options, rv = {}; - zval func = {}; + zval *pattern, *replacement, *options, rv; + zval func; ZEND_PARSE_PARAMETERS_START(2, 3) - Z_PARAM_ZVAL(pattern) - Z_PARAM_ZVAL(replacement) - Z_PARAM_OPTIONAL - Z_PARAM_ZVAL(options) + Z_PARAM_ZVAL(pattern) + Z_PARAM_ZVAL(replacement) + Z_PARAM_OPTIONAL + Z_PARAM_ZVAL(options) ZEND_PARSE_PARAMETERS_END(); zval *encoding = zend_read_property(stringy_ce, getThis(), "encoding", strlen("encoding"), 0, &rv); zval *str = zend_read_property(stringy_ce, getThis(), "str", strlen("str"), 1, &rv); - zval regexEncoding = {}; + zval regexEncoding; ZVAL_STRING(&func, "regexEncoding"); call_user_function(NULL, getThis(), &func, ®exEncoding, 0, NULL); - zval args[1] = {}; + zval args[1]; ZVAL_STRING(&func, "regexEncoding"); args[0] = *encoding; call_user_function(NULL, getThis(), &func, return_value, 1, args); - zval args_eregReplace[4] = {}, retStr = {}; + zval args_eregReplace[4], retStr; ZVAL_STRING(&func, "eregReplace"); args_eregReplace[0] = *pattern; args_eregReplace[1] = *replacement; @@ -495,10 +510,10 @@ PHP_METHOD(Stringy, regexReplace) args[0] = regexEncoding; call_user_function(NULL, getThis(), &func, return_value, 1, args); - zval instance = {}; + zval instance; object_init_ex(&instance, stringy_ce); - - zval args_construct[2] = {}; + + zval args_construct[2]; args_construct[0] = retStr; args_construct[1] = *encoding; @@ -509,29 +524,32 @@ PHP_METHOD(Stringy, regexReplace) RETURN_ZVAL(&instance, 0, 1); } ZEND_BEGIN_ARG_INFO(arginfo_regexReplace, 3) - ZEND_ARG_INFO(0, pattern) - ZEND_ARG_INFO(0, replacement) - ZEND_ARG_INFO(0, options) +ZEND_ARG_INFO(0, pattern) +ZEND_ARG_INFO(0, replacement) +ZEND_ARG_INFO(0, options) ZEND_END_ARG_INFO(); PHP_METHOD(Stringy, trim) { zval *chars; ZEND_PARSE_PARAMETERS_START(0, 1) - Z_PARAM_ZVAL(chars) + Z_PARAM_ZVAL(chars) ZEND_PARSE_PARAMETERS_END(); - if (Z_TYPE_P(chars) != IS_NULL) { - zval func = {}, args[2] = {}, delimiter = {}; + if (Z_TYPE_P(chars) != IS_NULL) + { + zval func, args[2], delimiter; ZVAL_STRING(&func, "preg_quote"); args[0] = *chars; args[1] = delimiter; call_user_function(NULL, NULL, &func, return_value, 2, args); - } else { + } + else + { ZVAL_STRING(chars, "[:space:]"); } - zval func_regexReplace = {}, args[3] = {}, pattern = {}, replacement = {}, options = {}; + zval func_regexReplace, args[3], pattern, replacement, options; ZVAL_STRING(&func_regexReplace, "regexReplace"); ZVAL_STRING(&pattern, "^[$chars]+|[$chars]+$"); ZVAL_STRING(&replacement, ""); @@ -541,35 +559,35 @@ PHP_METHOD(Stringy, trim) call_user_function(NULL, getThis(), &func_regexReplace, return_value, 3, args); } ZEND_BEGIN_ARG_INFO(arginfo_trim, 1) - ZEND_ARG_INFO(0, chars) +ZEND_ARG_INFO(0, chars) ZEND_END_ARG_INFO(); PHP_METHOD(Stringy, regexEncoding) { zval *encoding; ZEND_PARSE_PARAMETERS_START(0, 1) - Z_PARAM_OPTIONAL - Z_PARAM_ZVAL(encoding) + Z_PARAM_OPTIONAL + Z_PARAM_ZVAL(encoding) ZEND_PARSE_PARAMETERS_END(); - zval func = {}, args[1] = {}; + zval func, args[1]; ZVAL_STRING(&func, "mb_regex_encoding"); args[0] = *encoding; call_user_function(NULL, NULL, &func, return_value, 0, NULL); } ZEND_BEGIN_ARG_INFO(arginfo_regexEncoding, 1) - ZEND_ARG_INFO(0, encoding) +ZEND_ARG_INFO(0, encoding) ZEND_END_ARG_INFO(); PHP_METHOD(Stringy, eregReplace) { zval *pattern, *replace, *string, *option; ZEND_PARSE_PARAMETERS_START(3, 4) - Z_PARAM_ZVAL(pattern) - Z_PARAM_ZVAL(replace) - Z_PARAM_ZVAL(string) - Z_PARAM_OPTIONAL - Z_PARAM_ZVAL(option) + Z_PARAM_ZVAL(pattern) + Z_PARAM_ZVAL(replace) + Z_PARAM_ZVAL(string) + Z_PARAM_OPTIONAL + Z_PARAM_ZVAL(option) ZEND_PARSE_PARAMETERS_END(); convert_to_string(replace); @@ -577,7 +595,7 @@ PHP_METHOD(Stringy, eregReplace) convert_to_string(string); convert_to_string(option); - zval func = {}, args[4] = {}; + zval func, args[4]; ZVAL_STRING(&func, "mb_ereg_replace"); args[0] = *pattern; args[1] = *replace; @@ -586,26 +604,85 @@ PHP_METHOD(Stringy, eregReplace) call_user_function(NULL, NULL, &func, return_value, 4, args); } ZEND_BEGIN_ARG_INFO(arginfo_eregReplace, 4) - ZEND_ARG_INFO(0, pattern) - ZEND_ARG_INFO(0, replacement) - ZEND_ARG_INFO(0, string) - ZEND_ARG_INFO(0, option) +ZEND_ARG_INFO(0, pattern) +ZEND_ARG_INFO(0, replacement) +ZEND_ARG_INFO(0, string) +ZEND_ARG_INFO(0, option) ZEND_END_ARG_INFO(); +static void once_listener_handler(INTERNAL_FUNCTION_PARAMETERS) +{ + // How to get variables from syntax `use(&$onceListener, $event, $listener)` here. + // And use these variables like `php_var_dump(zval);`. + + // HashTable *static_variables = EX(func)->internal_function.prototype->op_array.static_variables; + // zval *handler = zend_hash_str_find(static_variables, ZEND_STRL("handler")); + + // zval *request,*options; + + // if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &request, &options) == FAILURE) { + // RETURN_FALSE; + // } + + // zval arr; + + // ZEND_PARSE_PARAMETERS_START(1, 1) + // Z_PARAM_ARRAY(*arr) + // ZEND_PARSE_PARAMETERS_END(); + // if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &arr) == FAILURE) { + // RETURN_FALSE; + // } + + printf("%d-aa\n\n\n", ZEND_NUM_ARGS()); + + // php_var_dump(request, 1); + + RETURN_STRING("FUCK"); +} + PHP_METHOD(Stringy, swapCase) { - zval rv = {}; + zval rv; zval *encoding = zend_read_property(stringy_ce, getThis(), "encoding", strlen("encoding"), 1, &rv); zval *string = zend_read_property(stringy_ce, getThis(), "str", strlen("str"), 1, &rv); - zval func = {}, args[5] = {}, pattern = {}, callback = {}, subject = {}, limit = {}, count = {}; - ZVAL_STRING(&pattern, "/[\S]/u"); + zval func, args[5], pattern, callback, subject, limit, count; + ZVAL_STRING(&pattern, "/[\\S]/u"); - zend_create_closure(&callback, "") - - ZVAL_STRING(&func, "preg_repace_callback"); - // args[0] = ; - call_user_function(NULL, NULL, &func, return_value, 5, args); + subject = *zend_read_property(stringy_ce, getThis(), ZEND_STRL("str"), 0, &rv); + + //mixed preg_replace_callback ( mixed $pattern , callable $callback , mixed $subject [, int $limit = -1 [, int &$count ]] ) + zend_function zendFunction; + zendFunction.type = ZEND_INTERNAL_FUNCTION; + + zend_arg_info zai; + zai.name = zend_string_init(ZEND_STRL("matches"), 0); + zai.pass_by_reference = 0; + zai.allow_null = 0; + zai.is_variadic = 0; + zai.type_hint = IS_STRING; + + zendFunction.common.num_args = 1; + zendFunction.common.arg_info = &zai; + zendFunction.internal_function.handler = once_listener_handler; + + zend_create_closure(&callback, &zendFunction, NULL, NULL, NULL); + + call_user_function(NULL, NULL , &callback, return_value, 0, NULL); +php_var_dump(return_value, 1); + zval ret; + ZVAL_MAKE_REF(&count); + ZVAL_STRING(&func, "preg_replace_callback"); + args[0] = pattern; + args[1] = callback; + args[2] = subject; + args[3] = limit; + args[4] = count; + call_user_function(NULL, NULL, &func, &ret, 5, args); + + zend_update_property_string(stringy_ce, getThis(), ZEND_STRL("str"), Z_STRVAL_P(return_value)); +php_var_dump(&ret, 1); + RETURN_ZVAL(getThis(), 1, 0); } static zend_function_entry methods[] = { @@ -629,6 +706,7 @@ static zend_function_entry methods[] = { PHP_ME(Stringy, regexReplace, arginfo_regexReplace, ZEND_ACC_PUBLIC) PHP_ME(Stringy, regexEncoding, arginfo_regexEncoding, ZEND_ACC_PUBLIC) PHP_ME(Stringy, eregReplace, arginfo_eregReplace, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, swapCase, NULL, ZEND_ACC_PUBLIC) PHP_FE_END }; @@ -640,14 +718,13 @@ void php_startup_register_stringy() stringy_ce = zend_register_internal_class(&ce); - zend_declare_property_string(stringy_ce, "str", strlen("str"), "", ZEND_ACC_PROTECTED); - zend_declare_property_string(stringy_ce, "encoding", strlen("encoding"), "", ZEND_ACC_PROTECTED); - + zend_declare_property_string(stringy_ce, ZEND_STRL("str"), "", ZEND_ACC_PROTECTED); + zend_declare_property_string(stringy_ce, ZEND_STRL("str"), "", ZEND_ACC_PROTECTED); + zend_class_implements( - stringy_ce, - 3, - spl_ce_Countable, + stringy_ce, + 3, + spl_ce_Countable, spl_ce_Aggregate, - spl_ce_ArrayAccess - ); + spl_ce_ArrayAccess); } diff --git a/startup.php b/startup.php index 7dccc39..ea2dfe6 100644 --- a/startup.php +++ b/startup.php @@ -49,12 +49,13 @@ function checkExt() function main() { _ns(NS_STRINGY); $stringy = __('Stringy')::create('Fòô Bàř', 'UTF-8'); + $stringy = $stringy->swapCase(); // var_dump($stringy->test()); $valResult = []; foreach ($stringy as $char) { $valResult[] = $char; } - var_dump($valResult); + // var_dump($valResult, function($a){}); // $keyValResult = []; // foreach ($stringy as $pos => $char) { // $keyValResult[$pos] = $char; From 23458ea4d5ad0d9de5cbdd1855ae12535b4cad56 Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Sat, 24 Nov 2018 19:23:09 +0800 Subject: [PATCH 029/126] update lock file && typo --- composer.lock | 6 ++++-- config.m4 | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/composer.lock b/composer.lock index 0a370b5..89de072 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "b7d7f74907b4b4c4618804584733febe", + "content-hash": "dd3acc8564f4e994ab0a77217e18d4e7", "packages": [], "packages-dev": [ { @@ -73,6 +73,8 @@ "stability-flags": [], "prefer-stable": false, "prefer-lowest": false, - "platform": [], + "platform": { + "php": "^7.1" + }, "platform-dev": [] } diff --git a/config.m4 b/config.m4 index 5abc715..9a25795 100644 --- a/config.m4 +++ b/config.m4 @@ -68,7 +68,7 @@ fi if test -z "$PHP_DEBUG"; then AC_ARG_ENABLE(debug, - [--enable-debg compile with debugging system], + [--enable-debug compile with debugging system], [PHP_DEBUG=$enableval], [PHP_DEBUG=no] ) fi From 9116b61f0c5d3b44591479626dece9fb34cfb039 Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Tue, 27 Nov 2018 18:47:10 +0800 Subject: [PATCH 030/126] rename dir && fetch scripts --- {tools => scripts}/build.sh | 0 scripts/fetch.php | 36 ++++++++++++++++++++++++++++++++++++ {tools => scripts}/test.sh | 0 3 files changed, 36 insertions(+) rename {tools => scripts}/build.sh (100%) create mode 100755 scripts/fetch.php rename {tools => scripts}/test.sh (100%) diff --git a/tools/build.sh b/scripts/build.sh similarity index 100% rename from tools/build.sh rename to scripts/build.sh diff --git a/scripts/fetch.php b/scripts/fetch.php new file mode 100755 index 0000000..87e4a61 --- /dev/null +++ b/scripts/fetch.php @@ -0,0 +1,36 @@ +#!/usr/bin/env php + 'https://github.com/tpunt/pht', + 'php-ds' => 'https://github.com/php-ds/extension.git', + 'phactor' => 'https://github.com/tpunt/phactor', + 'phpredis' => 'https://github.com/phpredis/phpredis', + 'yaf' => 'https://github.com/laruence/yaf.git', + 'yar' => 'https://github.com/laruence/yar.git', + 'yac' => 'https://github.com/laruence/yac.git', + 'yaconf' => 'https://github.com/laruence/yaconf.git', + 'yaf' => 'https://github.com/laruence/yaf.git', + 'xhprof' => 'https://github.com/phacility/xhprof', + 'msgpack-php' => 'https://github.com/msgpack/msgpack-php', + 'phptrace' => 'https://github.com/Qihoo360/phptrace', + 'php-memcached' => 'https://github.com/php-memcached-dev/php-memcached', + 'swoole' => 'https://github.com/swoole/swoole-src', + 'pthreads' => 'https://github.com/krakjoe/pthreads', + 'SeasLog' => 'https://github.com/SeasX/SeasLog', + 'phpdbg' => 'https://github.com/krakjoe/phpdbg', + 'php-rdkafka' => 'https://github.com/arnaud-lb/php-rdkafka', + 'runkit' => 'https://github.com/zenovich/runkit', + 'php-git' => 'https://github.com/libgit2/php-git', + 'AOP' => 'https://github.com/AOP-PHP/AOP', +]; + +// PHPBREW_ROOT/build/php-7.1.17/ext/ + +$path = sprintf("%s/build/%s/ext", $_SERVER['PHPBREW_ROOT'], $_SERVER['PHPBREW_PHP']); + +foreach($data as $key => $value) { + echo "clone repo:[", $key, "]", PHP_EOL; + echo "path:[", $path, "]", PHP_EOL; + `cd $path && git clone $value && cd -`; +} diff --git a/tools/test.sh b/scripts/test.sh similarity index 100% rename from tools/test.sh rename to scripts/test.sh From 9097218532571d6b24cd54d6f6ac8f9a9f24644c Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Tue, 27 Nov 2018 19:01:09 +0800 Subject: [PATCH 031/126] update --- scripts/fetch.php | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/scripts/fetch.php b/scripts/fetch.php index 87e4a61..9a9d754 100755 --- a/scripts/fetch.php +++ b/scripts/fetch.php @@ -30,7 +30,11 @@ $path = sprintf("%s/build/%s/ext", $_SERVER['PHPBREW_ROOT'], $_SERVER['PHPBREW_PHP']); foreach($data as $key => $value) { - echo "clone repo:[", $key, "]", PHP_EOL; - echo "path:[", $path, "]", PHP_EOL; - `cd $path && git clone $value && cd -`; + if (file_exists("{$path}/{$key}")) { + echo "[INFO] 有了 {$path}/{$key}", PHP_EOL; + continue; + } + echo "[INFO] clone repo:[", $key, "]", PHP_EOL; + echo "[INFO] path:[", $path, "]", PHP_EOL; + `cd $path && git clone $value $key && cd -`; } From 731b87066b3a5076504f9d562a1ae666d2c1542e Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Tue, 27 Nov 2018 20:20:59 +0800 Subject: [PATCH 032/126] update scripts --- scripts/build.sh | 4 +--- scripts/clean.sh | 7 +++++++ scripts/prepare.sh | 7 +++++++ 3 files changed, 15 insertions(+), 3 deletions(-) create mode 100755 scripts/clean.sh create mode 100755 scripts/prepare.sh diff --git a/scripts/build.sh b/scripts/build.sh index 27b1c6f..f7af8b3 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -9,9 +9,7 @@ echo "disabled startup" # phpbrew ext disable startup # 如果 ext 出问题了,这个命令就无法执行了 rm -f $PHPBREW_ROOT/php/$PHPBREW_PHP/var/db/start.ini -echo "go..." -# phpize && ./configure --enable-debug && make && make install && make clean && phpize --clean - +echo "build" make && make install echo "enabled startup" diff --git a/scripts/clean.sh b/scripts/clean.sh new file mode 100755 index 0000000..f38f362 --- /dev/null +++ b/scripts/clean.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +set -e +set -x + +echo "clean..." +make clean && phpize --clean diff --git a/scripts/prepare.sh b/scripts/prepare.sh new file mode 100755 index 0000000..1b272db --- /dev/null +++ b/scripts/prepare.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +set -e +set -x + +echo "prepare..." +phpize && ./configure --enable-debug From 374ee3affe3103deadc774b7ddba5c0b1ea95e7b Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Tue, 27 Nov 2018 23:03:01 +0800 Subject: [PATCH 033/126] update --- src/ext/stringy/stringy.c | 50 ++++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index b45031f..15f3025 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -618,24 +618,24 @@ static void once_listener_handler(INTERNAL_FUNCTION_PARAMETERS) // HashTable *static_variables = EX(func)->internal_function.prototype->op_array.static_variables; // zval *handler = zend_hash_str_find(static_variables, ZEND_STRL("handler")); - // zval *request,*options; + zval *request,*options; // if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &request, &options) == FAILURE) { // RETURN_FALSE; // } - // zval arr; + zval *arr; - // ZEND_PARSE_PARAMETERS_START(1, 1) - // Z_PARAM_ARRAY(*arr) - // ZEND_PARSE_PARAMETERS_END(); + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ARRAY(arr) + ZEND_PARSE_PARAMETERS_END(); // if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &arr) == FAILURE) { // RETURN_FALSE; // } printf("%d-aa\n\n\n", ZEND_NUM_ARGS()); - // php_var_dump(request, 1); + php_var_dump(arr, 1); RETURN_STRING("FUCK"); } @@ -651,25 +651,36 @@ PHP_METHOD(Stringy, swapCase) subject = *zend_read_property(stringy_ce, getThis(), ZEND_STRL("str"), 0, &rv); - //mixed preg_replace_callback ( mixed $pattern , callable $callback , mixed $subject [, int $limit = -1 [, int &$count ]] ) zend_function zendFunction; - zendFunction.type = ZEND_INTERNAL_FUNCTION; - zend_arg_info zai; - zai.name = zend_string_init(ZEND_STRL("matches"), 0); - zai.pass_by_reference = 0; - zai.allow_null = 0; - zai.is_variadic = 0; - zai.type_hint = IS_STRING; + zend_arg_info zai[1]; + zai[0].name = zend_string_init(ZEND_STRL("matches"), 0); + zai[0].pass_by_reference = 0; + zai[0].allow_null = 0; + zai[0].is_variadic = 0; + zai[0].type_hint = IS_STRING; + zendFunction.type = ZEND_INTERNAL_FUNCTION; zendFunction.common.num_args = 1; - zendFunction.common.arg_info = &zai; + zendFunction.common.required_num_args = 1; + zendFunction.common.arg_info = zai; + zendFunction.common.prototype = NULL; + zendFunction.common.scope = NULL; zendFunction.internal_function.handler = once_listener_handler; zend_create_closure(&callback, &zendFunction, NULL, NULL, NULL); - call_user_function(NULL, NULL , &callback, return_value, 0, NULL); -php_var_dump(return_value, 1); + zval x[1] = {}; + zval y; + ZVAL_STRING(&y, "abab"); + x[0] = y; + +zval yyy; +zval *yyy_func = zend_string_init(ZEND_STRL("abab"), 0); + zend_closure_bind_var(&callback, yyy_func, &yyy); + + call_user_function(NULL, NULL, &yyy_func, return_value, 0, NULL); + zval ret; ZVAL_MAKE_REF(&count); ZVAL_STRING(&func, "preg_replace_callback"); @@ -680,8 +691,9 @@ php_var_dump(return_value, 1); args[4] = count; call_user_function(NULL, NULL, &func, &ret, 5, args); - zend_update_property_string(stringy_ce, getThis(), ZEND_STRL("str"), Z_STRVAL_P(return_value)); -php_var_dump(&ret, 1); + convert_to_string(&ret); + zend_update_property_string(stringy_ce, getThis(), ZEND_STRL("str"), Z_STRVAL(ret)); + RETURN_ZVAL(getThis(), 1, 0); } From d4da95678d5a83ef1f2c87f6547133cbfcc71382 Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Wed, 28 Nov 2018 00:44:26 +0800 Subject: [PATCH 034/126] test swapCase --- .gitignore | 2 +- src/ext/stringy/stringy.c | 28 +++---- startup.c | 152 ++++++++++++++++++++++++++------------ startup.php | 37 ++++++---- 4 files changed, 134 insertions(+), 85 deletions(-) diff --git a/.gitignore b/.gitignore index e422bd6..99f4afd 100644 --- a/.gitignore +++ b/.gitignore @@ -43,4 +43,4 @@ GPATH /vendor/ *.loT -/nbproject/private/ +core diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index 15f3025..0a1c1de 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -128,7 +128,7 @@ PHP_METHOD(Stringy, getEncoding) PHP_METHOD(Stringy, create) { - zval instance, retval, func, args[2]; + zval instance; zval *str, *encoding; ZEND_PARSE_PARAMETERS_START(0, 2) @@ -139,12 +139,7 @@ PHP_METHOD(Stringy, create) object_init_ex(&instance, stringy_ce); - args[0] = *str; - args[1] = *encoding; - - ZVAL_STRING(&func, "__construct"); - - call_user_function(NULL, &instance, &func, &retval, 2, args); + zend_call_method(&instance, stringy_ce, NULL, ZEND_STRL("__construct"), return_value, 2, str, encoding); RETURN_ZVAL(&instance, 0, 1); } @@ -643,10 +638,10 @@ static void once_listener_handler(INTERNAL_FUNCTION_PARAMETERS) PHP_METHOD(Stringy, swapCase) { zval rv; - zval *encoding = zend_read_property(stringy_ce, getThis(), "encoding", strlen("encoding"), 1, &rv); - zval *string = zend_read_property(stringy_ce, getThis(), "str", strlen("str"), 1, &rv); + // zval *encoding = zend_read_property(stringy_ce, getThis(), "encoding", strlen("encoding"), 1, &rv); + // zval *string = zend_read_property(stringy_ce, getThis(), "str", strlen("str"), 1, &rv); - zval func, args[5], pattern, callback, subject, limit, count; + zval func, args[5], pattern, subject, limit, count; ZVAL_STRING(&pattern, "/[\\S]/u"); subject = *zend_read_property(stringy_ce, getThis(), ZEND_STRL("str"), 0, &rv); @@ -668,18 +663,13 @@ PHP_METHOD(Stringy, swapCase) zendFunction.common.scope = NULL; zendFunction.internal_function.handler = once_listener_handler; + zval callback; zend_create_closure(&callback, &zendFunction, NULL, NULL, NULL); - zval x[1] = {}; - zval y; - ZVAL_STRING(&y, "abab"); - x[0] = y; - -zval yyy; -zval *yyy_func = zend_string_init(ZEND_STRL("abab"), 0); - zend_closure_bind_var(&callback, yyy_func, &yyy); + zval arr; + array_init(&arr); - call_user_function(NULL, NULL, &yyy_func, return_value, 0, NULL); + call_user_function(NULL, NULL, &callback, return_value, 1, &arr); zval ret; ZVAL_MAKE_REF(&count); diff --git a/startup.c b/startup.c index 555c8ea..7fc81d0 100644 --- a/startup.c +++ b/startup.c @@ -29,6 +29,7 @@ #include "php_startup.h" #include "src/ext/test.class.h" #include "src/ext/stringy/stringy.h" +#include "zend_closures.h" /* If you declare any globals in php_startup.h uncomment this: ZEND_DECLARE_MODULE_GLOBALS(startup) @@ -59,17 +60,17 @@ PHP_INI_END() Return a string to confirm that the module is compiled in */ PHP_FUNCTION(confirm_startup_compiled) { - char *arg = NULL; - size_t arg_len, len; - zend_string *strg; + char *arg = NULL; + size_t arg_len, len; + zend_string *strg; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &arg, &arg_len) == FAILURE) { - return; - } + if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &arg, &arg_len) == FAILURE) { + return; + } - strg = strpprintf(0, "Congratulations! You have successfully modified ext/%.78s/config.m4. Module %.78s is now compiled into PHP.", "startup", arg); + strg = strpprintf(0, "Congratulations! You have successfully modified ext/%.78s/config.m4. Module %.78s is now compiled into PHP.", "startup", arg); - RETURN_STR(strg); + RETURN_STR(strg); } /* }}} */ /* The previous line is meant for vim and emacs, so it can correctly fold and @@ -83,21 +84,74 @@ PHP_FUNCTION(confirm_startup_compiled) /* Uncomment this function if you have INI entries static void php_startup_init_globals(zend_startup_globals *startup_globals) { - startup_globals->global_value = 0; - startup_globals->global_string = NULL; + startup_globals->global_value = 0; + startup_globals->global_string = NULL; } */ /* }}} */ +static void once_listener_handler(INTERNAL_FUNCTION_PARAMETERS) +{ + // How to get variables from syntax `use(&$onceListener, $event, $listener)` here. + // And use these variables like `php_var_dump(zval);`. + + // HashTable *static_variables = EX(func)->internal_function.prototype->op_array.static_variables; + // zval *handler = zend_hash_str_find(static_variables, ZEND_STRL("handler")); + + zval *request,*options; + + // if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &request, &options) == FAILURE) { + // RETURN_FALSE; + // } + + zval *arr; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ARRAY(arr) + ZEND_PARSE_PARAMETERS_END(); + // if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &arr) == FAILURE) { + // RETURN_FALSE; + // } + + printf("%d-aa\n\n\n", ZEND_NUM_ARGS()); + + php_var_dump(arr, 1); + + RETURN_STRING("FUCK"); +} PHP_METHOD(myclass, abab) { - php_printf("我是public\n"); + zend_function zendFunction; + + zend_arg_info zai[1]; + zai[0].name = zend_string_init(ZEND_STRL("matches"), 0); + zai[0].pass_by_reference = 0; + zai[0].allow_null = 0; + zai[0].is_variadic = 0; + zai[0].type_hint = IS_STRING; + + zendFunction.type = ZEND_INTERNAL_FUNCTION; + zendFunction.common.num_args = 1; + zendFunction.common.required_num_args = 1; + zendFunction.common.arg_info = zai; + zendFunction.common.prototype = NULL; + zendFunction.common.scope = NULL; + zendFunction.internal_function.handler = once_listener_handler; + + zval callback; + + zend_create_closure(&callback, &zendFunction, NULL, NULL, NULL); + + zval arr; + array_init(&arr); + + call_user_function(NULL, NULL, &callback, return_value, 1, &arr); } static zend_function_entry myclass_method[] = { - PHP_ME(myclass, abab, NULL, ZEND_ACC_PUBLIC) - {NULL, NULL, NULL} + PHP_ME(myclass, abab, NULL, ZEND_ACC_PUBLIC) + {NULL, NULL, NULL} }; @@ -105,21 +159,21 @@ static zend_function_entry myclass_method[] = { */ PHP_MINIT_FUNCTION(startup) { - /* If you have INI entries, uncomment these lines - REGISTER_INI_ENTRIES(); - */ + /* If you have INI entries, uncomment these lines + REGISTER_INI_ENTRIES(); + */ - zend_class_entry ce; + zend_class_entry ce; - INIT_CLASS_ENTRY(ce, "myclass", myclass_method); - myclass_ce = zend_register_internal_class(&ce TSRMLS_CC); + INIT_CLASS_ENTRY(ce, "myclass", myclass_method); + myclass_ce = zend_register_internal_class(&ce TSRMLS_CC); - zend_declare_property_null(myclass_ce, "pub_var", strlen("pub_var"), ZEND_ACC_PUBLIC TSRMLS_CC); + zend_declare_property_null(myclass_ce, "pub_var", strlen("pub_var"), ZEND_ACC_PUBLIC TSRMLS_CC); - php_startup_register_test(); + php_startup_register_test(); php_startup_register_stringy(); - return SUCCESS; + return SUCCESS; } /* }}} */ @@ -127,10 +181,10 @@ PHP_MINIT_FUNCTION(startup) */ PHP_MSHUTDOWN_FUNCTION(startup) { - /* uncomment this line if you have INI entries - UNREGISTER_INI_ENTRIES(); - */ - return SUCCESS; + /* uncomment this line if you have INI entries + UNREGISTER_INI_ENTRIES(); + */ + return SUCCESS; } /* }}} */ @@ -140,9 +194,9 @@ PHP_MSHUTDOWN_FUNCTION(startup) PHP_RINIT_FUNCTION(startup) { #if defined(COMPILE_DL_STARTUP) && defined(ZTS) - ZEND_TSRMLS_CACHE_UPDATE(); + ZEND_TSRMLS_CACHE_UPDATE(); #endif - return SUCCESS; + return SUCCESS; } /* }}} */ @@ -151,7 +205,7 @@ PHP_RINIT_FUNCTION(startup) */ PHP_RSHUTDOWN_FUNCTION(startup) { - return SUCCESS; + return SUCCESS; } /* }}} */ @@ -159,14 +213,14 @@ PHP_RSHUTDOWN_FUNCTION(startup) */ PHP_MINFO_FUNCTION(startup) { - php_info_print_table_start(); - php_info_print_table_header(2, "startup support", "enabled"); - php_info_print_table_row(2, "version", PHP_STARTUP_VERSION); - php_info_print_table_end(); - - /* Remove comments if you have entries in php.ini - DISPLAY_INI_ENTRIES(); - */ + php_info_print_table_start(); + php_info_print_table_header(2, "startup support", "enabled"); + php_info_print_table_row(2, "version", PHP_STARTUP_VERSION); + php_info_print_table_end(); + + /* Remove comments if you have entries in php.ini + DISPLAY_INI_ENTRIES(); + */ } /* }}} */ @@ -175,24 +229,24 @@ PHP_MINFO_FUNCTION(startup) * Every user visible function must have an entry in startup_functions[]. */ const zend_function_entry startup_functions[] = { - PHP_FE(confirm_startup_compiled, NULL) /* For testing, remove later. */ - PHP_FE_END /* Must be the last line in startup_functions[] */ + PHP_FE(confirm_startup_compiled, NULL) /* For testing, remove later. */ + PHP_FE_END /* Must be the last line in startup_functions[] */ }; /* }}} */ /* {{{ startup_module_entry */ zend_module_entry startup_module_entry = { - STANDARD_MODULE_HEADER, - "startup", - startup_functions, - PHP_MINIT(startup), - PHP_MSHUTDOWN(startup), - PHP_RINIT(startup), /* Replace with NULL if there's nothing to do at request start */ - PHP_RSHUTDOWN(startup), /* Replace with NULL if there's nothing to do at request end */ - PHP_MINFO(startup), - PHP_STARTUP_VERSION, - STANDARD_MODULE_PROPERTIES + STANDARD_MODULE_HEADER, + "startup", + startup_functions, + PHP_MINIT(startup), + PHP_MSHUTDOWN(startup), + PHP_RINIT(startup), /* Replace with NULL if there's nothing to do at request start */ + PHP_RSHUTDOWN(startup), /* Replace with NULL if there's nothing to do at request end */ + PHP_MINFO(startup), + PHP_STARTUP_VERSION, + STANDARD_MODULE_PROPERTIES }; /* }}} */ diff --git a/startup.php b/startup.php index ea2dfe6..568fb57 100644 --- a/startup.php +++ b/startup.php @@ -46,21 +46,26 @@ function checkExt() include __DIR__ . "/spec/const.php"; include __DIR__ . "/spec/functions.php"; -function main() { - _ns(NS_STRINGY); - $stringy = __('Stringy')::create('Fòô Bàř', 'UTF-8'); - $stringy = $stringy->swapCase(); - // var_dump($stringy->test()); - $valResult = []; - foreach ($stringy as $char) { - $valResult[] = $char; - } - // var_dump($valResult, function($a){}); - // $keyValResult = []; - // foreach ($stringy as $pos => $char) { - // $keyValResult[$pos] = $char; - // } -} +// function main() { +// _ns(NS_STRINGY); +// $stringy = __('Stringy')::create('Fòô Bàř', 'UTF-8'); +// $stringy = $stringy->swapCase(); +// // var_dump($stringy->test()); +// $valResult = []; +// foreach ($stringy as $char) { +// $valResult[] = $char; +// } +// // var_dump($valResult, function($a){}); +// // $keyValResult = []; +// // foreach ($stringy as $pos => $char) { +// // $keyValResult[$pos] = $char; +// // } +// } + + +// main(); -main(); +_ns(NS_STRINGY); +_('Stringy', ['Fòô Bàř', 'UTF-8'])->swapCase(); +echo (string)__('Stringy')::create('Fòô Bàř', 'UTF-8'); From b504e8bf14e3eb0e1e527aaac78566387a52c819 Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Fri, 30 Nov 2018 17:32:07 +0800 Subject: [PATCH 035/126] tab to space --- src/ext/functions.c | 6 ++++++ src/ext/functions.h | 9 +++++++++ src/ext/stringy/stringy.c | 14 +++++++------- 3 files changed, 22 insertions(+), 7 deletions(-) create mode 100644 src/ext/functions.c create mode 100644 src/ext/functions.h diff --git a/src/ext/functions.c b/src/ext/functions.c new file mode 100644 index 0000000..5c25496 --- /dev/null +++ b/src/ext/functions.c @@ -0,0 +1,6 @@ +#include "functions.h" + +void php_startup_register_functions() +{ + +} diff --git a/src/ext/functions.h b/src/ext/functions.h new file mode 100644 index 0000000..a84536a --- /dev/null +++ b/src/ext/functions.h @@ -0,0 +1,9 @@ +#ifndef STARTUP_TEST_H +#define STARTUP_TEST_H + +#include "php.h" +#include "common.h" +#include "ext/standard/php_standard.h" + +void php_startup_register_test(); +#endif diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index 0a1c1de..45ca0cd 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -637,11 +637,8 @@ static void once_listener_handler(INTERNAL_FUNCTION_PARAMETERS) PHP_METHOD(Stringy, swapCase) { - zval rv; - // zval *encoding = zend_read_property(stringy_ce, getThis(), "encoding", strlen("encoding"), 1, &rv); - // zval *string = zend_read_property(stringy_ce, getThis(), "str", strlen("str"), 1, &rv); - - zval func, args[5], pattern, subject, limit, count; + zval rv, func, args[5], pattern, subject, limit, count, ret; + ZVAL_STRING(&pattern, "/[\\S]/u"); subject = *zend_read_property(stringy_ce, getThis(), ZEND_STRL("str"), 0, &rv); @@ -669,11 +666,14 @@ PHP_METHOD(Stringy, swapCase) zval arr; array_init(&arr); - call_user_function(NULL, NULL, &callback, return_value, 1, &arr); + call_user_function(NULL, NULL, &callback, return_value, 0, NULL); - zval ret; ZVAL_MAKE_REF(&count); ZVAL_STRING(&func, "preg_replace_callback"); + + // ZVAL_LONG(&limit, 1); + + args[0] = pattern; args[1] = callback; args[2] = subject; From 728866aa1595875171ab98a93d8183475a0e4520 Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Fri, 30 Nov 2018 22:40:17 +0800 Subject: [PATCH 036/126] update --- .vscode/settings.json | 3 +- src/ext/functions.c | 7 +-- src/ext/functions.h | 6 +-- src/ext/stringy/stringy.c | 20 +++++---- startup.c | 93 +++++++-------------------------------- startup.php | 2 +- 6 files changed, 38 insertions(+), 93 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 6cca03c..a546227 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -22,7 +22,8 @@ "string": "c", "string_view": "c", "spl_iterators.h": "c", - "iosfwd": "c" + "iosfwd": "c", + "functions.h": "c" }, "editor.mouseWheelZoom": false, "files.autoSave": "onFocusChange", diff --git a/src/ext/functions.c b/src/ext/functions.c index 5c25496..d6f83a1 100644 --- a/src/ext/functions.c +++ b/src/ext/functions.c @@ -1,6 +1,7 @@ #include "functions.h" -void php_startup_register_functions() -{ +#define XXX(zend_function_entry, len) {len = sizeof(zend_function_entry) / sizeof(zend_function_entry[0]);} -} +// void php_startup_register_functions(zend_function_entry *entry) +// { +// } diff --git a/src/ext/functions.h b/src/ext/functions.h index a84536a..c134d61 100644 --- a/src/ext/functions.h +++ b/src/ext/functions.h @@ -1,9 +1,9 @@ -#ifndef STARTUP_TEST_H -#define STARTUP_TEST_H +#ifndef STARTUP_FUNCTIONS_H +#define STARTUP_FUNCTIONS_H #include "php.h" #include "common.h" #include "ext/standard/php_standard.h" -void php_startup_register_test(); +// void php_startup_register_functions(zend_function_entry *zend_function_entry); #endif diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index 45ca0cd..c72cd4f 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -637,7 +637,7 @@ static void once_listener_handler(INTERNAL_FUNCTION_PARAMETERS) PHP_METHOD(Stringy, swapCase) { - zval rv, func, args[5], pattern, subject, limit, count, ret; + zval rv, func, pattern, subject, limit, count, ret; ZVAL_STRING(&pattern, "/[\\S]/u"); @@ -663,6 +663,10 @@ PHP_METHOD(Stringy, swapCase) zval callback; zend_create_closure(&callback, &zendFunction, NULL, NULL, NULL); +#if ZEND_DEBUG + ZEND_ASSERT(false); +#endif + zval arr; array_init(&arr); @@ -671,14 +675,14 @@ PHP_METHOD(Stringy, swapCase) ZVAL_MAKE_REF(&count); ZVAL_STRING(&func, "preg_replace_callback"); - // ZVAL_LONG(&limit, 1); + zval args[] ={ + pattern, + callback, + subject, + limit, + count, + }; - - args[0] = pattern; - args[1] = callback; - args[2] = subject; - args[3] = limit; - args[4] = count; call_user_function(NULL, NULL, &func, &ret, 5, args); convert_to_string(&ret); diff --git a/startup.c b/startup.c index 7fc81d0..574025e 100644 --- a/startup.c +++ b/startup.c @@ -29,15 +29,13 @@ #include "php_startup.h" #include "src/ext/test.class.h" #include "src/ext/stringy/stringy.h" +#include "src/ext/functions.h" #include "zend_closures.h" /* If you declare any globals in php_startup.h uncomment this: ZEND_DECLARE_MODULE_GLOBALS(startup) */ -zend_class_entry *myclass_ce; - - /* True global resources - no need for thread safety here */ static int le_startup; @@ -90,71 +88,6 @@ static void php_startup_init_globals(zend_startup_globals *startup_globals) */ /* }}} */ - -static void once_listener_handler(INTERNAL_FUNCTION_PARAMETERS) -{ - // How to get variables from syntax `use(&$onceListener, $event, $listener)` here. - // And use these variables like `php_var_dump(zval);`. - - // HashTable *static_variables = EX(func)->internal_function.prototype->op_array.static_variables; - // zval *handler = zend_hash_str_find(static_variables, ZEND_STRL("handler")); - - zval *request,*options; - - // if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &request, &options) == FAILURE) { - // RETURN_FALSE; - // } - - zval *arr; - - ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_ARRAY(arr) - ZEND_PARSE_PARAMETERS_END(); - // if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &arr) == FAILURE) { - // RETURN_FALSE; - // } - - printf("%d-aa\n\n\n", ZEND_NUM_ARGS()); - - php_var_dump(arr, 1); - - RETURN_STRING("FUCK"); -} -PHP_METHOD(myclass, abab) -{ - zend_function zendFunction; - - zend_arg_info zai[1]; - zai[0].name = zend_string_init(ZEND_STRL("matches"), 0); - zai[0].pass_by_reference = 0; - zai[0].allow_null = 0; - zai[0].is_variadic = 0; - zai[0].type_hint = IS_STRING; - - zendFunction.type = ZEND_INTERNAL_FUNCTION; - zendFunction.common.num_args = 1; - zendFunction.common.required_num_args = 1; - zendFunction.common.arg_info = zai; - zendFunction.common.prototype = NULL; - zendFunction.common.scope = NULL; - zendFunction.internal_function.handler = once_listener_handler; - - zval callback; - - zend_create_closure(&callback, &zendFunction, NULL, NULL, NULL); - - zval arr; - array_init(&arr); - - call_user_function(NULL, NULL, &callback, return_value, 1, &arr); -} - -static zend_function_entry myclass_method[] = { - PHP_ME(myclass, abab, NULL, ZEND_ACC_PUBLIC) - {NULL, NULL, NULL} -}; - - /* {{{ PHP_MINIT_FUNCTION */ PHP_MINIT_FUNCTION(startup) @@ -162,14 +95,6 @@ PHP_MINIT_FUNCTION(startup) /* If you have INI entries, uncomment these lines REGISTER_INI_ENTRIES(); */ - - zend_class_entry ce; - - INIT_CLASS_ENTRY(ce, "myclass", myclass_method); - myclass_ce = zend_register_internal_class(&ce TSRMLS_CC); - - zend_declare_property_null(myclass_ce, "pub_var", strlen("pub_var"), ZEND_ACC_PUBLIC TSRMLS_CC); - php_startup_register_test(); php_startup_register_stringy(); @@ -224,11 +149,25 @@ PHP_MINFO_FUNCTION(startup) } /* }}} */ +PHP_FUNCTION(tttt_test) +{ + zval *arr; + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ARRAY(arr) + ZEND_PARSE_PARAMETERS_END(); + + RETURN_ZVAL(arr, 1, 1); +} +ZEND_BEGIN_ARG_INFO(arginfo_tttt_test, 1) + ZEND_ARG_INFO(0, matches) +ZEND_END_ARG_INFO(); + /* {{{ startup_functions[] * * Every user visible function must have an entry in startup_functions[]. */ -const zend_function_entry startup_functions[] = { +zend_function_entry startup_functions[] = { + PHP_FE(tttt_test, arginfo_tttt_test) PHP_FE(confirm_startup_compiled, NULL) /* For testing, remove later. */ PHP_FE_END /* Must be the last line in startup_functions[] */ }; diff --git a/startup.php b/startup.php index 568fb57..b909c3e 100644 --- a/startup.php +++ b/startup.php @@ -68,4 +68,4 @@ function checkExt() _ns(NS_STRINGY); _('Stringy', ['Fòô Bàř', 'UTF-8'])->swapCase(); -echo (string)__('Stringy')::create('Fòô Bàř', 'UTF-8'); +// var_dump(tttt_test($_SERVER)); From fa684ececb14985eaec02e135a647e9c042d477d Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Sat, 1 Dec 2018 14:21:19 +0800 Subject: [PATCH 037/126] =?UTF-8?q?=E5=93=8E=E5=91=80=EF=BC=8C=E8=BF=99?= =?UTF-8?q?=E4=B8=AA=E7=BB=88=E4=BA=8E=E5=8F=AF=E4=BB=A5=E4=BA=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/tasks.json | 4 +-- spec/Stringy/StringySpec.php | 2 +- src/ext/stringy/stringy.c | 61 +++++++++++++++++++++--------------- startup.php | 2 +- 4 files changed, 39 insertions(+), 30 deletions(-) diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 7388e21..b8541c1 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -6,7 +6,7 @@ { "label": "run build", "type": "shell", - "command": "./tools/build.sh", + "command": "./scripts/build.sh", "group": { "kind": "build", "isDefault": true @@ -26,7 +26,7 @@ { "label": "run test", "type": "shell", - "command": "./tools/test.sh", + "command": "./scripts/test.sh", "group": { "kind": "test", "isDefault": true diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index 37b72de..dcf8baf 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -67,7 +67,7 @@ it('test chaining', function () { $stringy = __('Stringy')::create('x y', 'UTF-8'); \expect($stringy)->toBeAnInstanceOf(__('Stringy')); - \expect("X Y")->toBe((string) $stringy->swapCase());//->upperCaseFirst()); + \expect("X Y")->toBe((string) $stringy->swapCase());//->upperCaseFirst()); }); it('test count', function () { diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index c72cd4f..43d3aad 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -607,37 +607,35 @@ ZEND_END_ARG_INFO(); static void once_listener_handler(INTERNAL_FUNCTION_PARAMETERS) { - // How to get variables from syntax `use(&$onceListener, $event, $listener)` here. - // And use these variables like `php_var_dump(zval);`. - - // HashTable *static_variables = EX(func)->internal_function.prototype->op_array.static_variables; - // zval *handler = zend_hash_str_find(static_variables, ZEND_STRL("handler")); - - zval *request,*options; - - // if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &request, &options) == FAILURE) { - // RETURN_FALSE; - // } - zval *arr; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ARRAY(arr) ZEND_PARSE_PARAMETERS_END(); - // if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &arr) == FAILURE) { - // RETURN_FALSE; - // } - printf("%d-aa\n\n\n", ZEND_NUM_ARGS()); + zval *ret = zend_hash_index_find(Z_ARRVAL_P(arr), 0); - php_var_dump(arr, 1); + zval func = {}; + ZVAL_STRING(&func, "mb_strtoupper"); + zval args[] = { + *ret, + }; + call_user_function(NULL, NULL, &func, return_value, 1, args); - RETURN_STRING("FUCK"); + if (zend_string_equals(Z_STR_P(return_value), Z_STR_P(ret)) == 1) { + ZVAL_STRING(&func, "mb_strtolower"); + zval args[] = { + *ret, + }; + call_user_function(NULL, NULL, &func, return_value, 1, args); + } + + RETURN_ZVAL(return_value, 0, 1); } PHP_METHOD(Stringy, swapCase) { - zval rv, func, pattern, subject, limit, count, ret; + zval rv, func, pattern, subject, limit, count, ret, encoding; ZVAL_STRING(&pattern, "/[\\S]/u"); @@ -664,16 +662,12 @@ PHP_METHOD(Stringy, swapCase) zend_create_closure(&callback, &zendFunction, NULL, NULL, NULL); #if ZEND_DEBUG - ZEND_ASSERT(false); + ZEND_ASSERT(1); #endif - zval arr; - array_init(&arr); - - call_user_function(NULL, NULL, &callback, return_value, 0, NULL); - ZVAL_MAKE_REF(&count); ZVAL_STRING(&func, "preg_replace_callback"); + ZVAL_LONG(&limit, -1); zval args[] ={ pattern, @@ -688,7 +682,22 @@ PHP_METHOD(Stringy, swapCase) convert_to_string(&ret); zend_update_property_string(stringy_ce, getThis(), ZEND_STRL("str"), Z_STRVAL(ret)); - RETURN_ZVAL(getThis(), 1, 0); + zval instance; + object_init_ex(&instance, stringy_ce); + + encoding = *zend_read_property(stringy_ce, getThis(), ZEND_STRL("encoding"), 0, &rv); + + zval args_construct[] = { + ret, + encoding, + }; + + ZVAL_STRING(&func, "__construct"); + + call_user_function(NULL, &instance, &func, return_value, 2, args_construct); + + RETURN_ZVAL(&instance, 0, 1); + } static zend_function_entry methods[] = { diff --git a/startup.php b/startup.php index b909c3e..7797316 100644 --- a/startup.php +++ b/startup.php @@ -67,5 +67,5 @@ function checkExt() _ns(NS_STRINGY); -_('Stringy', ['Fòô Bàř', 'UTF-8'])->swapCase(); +// var_dump((string)_('Stringy', ['Fòô Bàř', 'UTF-8'])->swapCase()); // var_dump(tttt_test($_SERVER)); From 3cb759274b45234e9b08f09268755002f199e92d Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Sat, 1 Dec 2018 17:39:54 +0800 Subject: [PATCH 038/126] =?UTF-8?q?=E6=9C=89=E9=97=AE=E9=A2=98=EF=BC=8C?= =?UTF-8?q?=E6=9A=82=E6=97=B6=E8=A7=A3=E5=86=B3=E4=BA=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/snnipt.code-snippets | 5 ++- scripts/gdb.sh | 19 +++++++++ spec/Stringy/StringySpec.php | 2 +- src/ext/stringy/stringy.c | 78 +++++++++++++++++++++++++++--------- startup.c | 26 ++++++------ startup.php | 4 +- 6 files changed, 96 insertions(+), 38 deletions(-) create mode 100755 scripts/gdb.sh diff --git a/.vscode/snnipt.code-snippets b/.vscode/snnipt.code-snippets index 8271cb1..bae6f21 100644 --- a/.vscode/snnipt.code-snippets +++ b/.vscode/snnipt.code-snippets @@ -39,9 +39,10 @@ "prefix": "cufa", "scope": "c,h", "body": [ - "zval ${1:func} = {}, args[$2] = {};", + "zval ${1:func}, args[] = {", + " $4", + "};", "ZVAL_STRING(&${1:func}, \"$0\");", - "args[0] = $4;", "call_user_function(NULL, NULL, &${1:func}, ${3:return_value}, $2, args);" ], "description": "args" diff --git a/scripts/gdb.sh b/scripts/gdb.sh new file mode 100755 index 0000000..28facae --- /dev/null +++ b/scripts/gdb.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash + +set -e +set -x + +# source your_php_src_path/.gdbinit +# gdb php -f startup.php + +[[ ! -e ~/.gdbinit ]]&& cp ~/.gdbinit ~/.gdbinit.bak + +ln -sf $PHPBREW_HOME/build/$PHPBREW_PHP/.gdbinit ~/.gdbinit + +ulimit -c unlimited + +MINBABY_TEST_EXT=1 php -f startup.php + +ulimit -c 0 + +gdb -c core php diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index dcf8baf..12ab223 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -67,7 +67,7 @@ it('test chaining', function () { $stringy = __('Stringy')::create('x y', 'UTF-8'); \expect($stringy)->toBeAnInstanceOf(__('Stringy')); - \expect("X Y")->toBe((string) $stringy->swapCase());//->upperCaseFirst()); + \expect("X Y")->toBe((string) $stringy->swapCase()); }); it('test count', function () { diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index 43d3aad..107b353 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -73,7 +73,7 @@ PHP_METHOD(Stringy, __construct) convert_to_string(str) - string = Z_STRVAL_P(str); + string = Z_STRVAL_P(str); if (string == NULL) { @@ -128,8 +128,7 @@ PHP_METHOD(Stringy, getEncoding) PHP_METHOD(Stringy, create) { - zval instance; - zval *str, *encoding; + zval instance, *str, *encoding; ZEND_PARSE_PARAMETERS_START(0, 2) Z_PARAM_OPTIONAL @@ -505,18 +504,20 @@ PHP_METHOD(Stringy, regexReplace) args[0] = regexEncoding; call_user_function(NULL, getThis(), &func, return_value, 1, args); - zval instance; - object_init_ex(&instance, stringy_ce); + // zval instance; + // object_init_ex(&instance, stringy_ce); - zval args_construct[2]; - args_construct[0] = retStr; - args_construct[1] = *encoding; + // zval args_construct[2]; + // args_construct[0] = retStr; + // args_construct[1] = *encoding; - ZVAL_STRING(&func, "__construct"); + // ZVAL_STRING(&func, "__construct"); - call_user_function(NULL, &instance, &func, return_value, 2, args_construct); + // call_user_function(NULL, &instance, &func, return_value, 2, args_construct); - RETURN_ZVAL(&instance, 0, 1); + // RETURN_ZVAL(&instance, 0, 1); + + RETURN_ZVAL(getThis(), 1, 0); } ZEND_BEGIN_ARG_INFO(arginfo_regexReplace, 3) ZEND_ARG_INFO(0, pattern) @@ -635,7 +636,9 @@ static void once_listener_handler(INTERNAL_FUNCTION_PARAMETERS) PHP_METHOD(Stringy, swapCase) { - zval rv, func, pattern, subject, limit, count, ret, encoding; + zval rv, func, pattern={}, subject, limit, count, ret, encoding; + + php_var_dump(&pattern, 1); ZVAL_STRING(&pattern, "/[\\S]/u"); @@ -657,7 +660,7 @@ PHP_METHOD(Stringy, swapCase) zendFunction.common.prototype = NULL; zendFunction.common.scope = NULL; zendFunction.internal_function.handler = once_listener_handler; - + zval callback; zend_create_closure(&callback, &zendFunction, NULL, NULL, NULL); @@ -682,22 +685,56 @@ PHP_METHOD(Stringy, swapCase) convert_to_string(&ret); zend_update_property_string(stringy_ce, getThis(), ZEND_STRL("str"), Z_STRVAL(ret)); - zval instance; - object_init_ex(&instance, stringy_ce); + RETURN_ZVAL(getThis(), 1, 0); +} + +PHP_METHOD(Stringy, upperCaseFirst) +{ + zval instance, encoding, str, func, ret, start, len, first, rest, rv; + ZVAL_STRING(&func, "length"); + call_user_function(NULL, getThis(), &func, return_value, 0, NULL); + size_t length = Z_LVAL_P(return_value); + + str = *zend_read_property(stringy_ce, getThis(), ZEND_STRL("str"), 0, &rv); encoding = *zend_read_property(stringy_ce, getThis(), ZEND_STRL("encoding"), 0, &rv); - zval args_construct[] = { - ret, + ZVAL_LONG(&start, 0); + ZVAL_LONG(&len, 1); + zval args[] = { + str, + start, + len, + encoding, + }; + ZVAL_STRING(&func, "mb_substr"); + call_user_function(NULL, NULL, &func, &first, 4, args); + + ZVAL_LONG(&start, 1); + ZVAL_LONG(&len, length-1); + zval args_rest[] = { + str, + start, + len, encoding, }; + ZVAL_STRING(&func, "mb_substr"); + call_user_function(NULL, NULL, &func, &rest, 4, args_rest); - ZVAL_STRING(&func, "__construct"); + zval args_upper[] = { + first, + encoding, + }; + ZVAL_STRING(&func, "mb_strtoupper"); + call_user_function(NULL, NULL, &func, &first, 2, args_upper); - call_user_function(NULL, &instance, &func, return_value, 2, args_construct); + concat_function(&ret, &first, &rest); - RETURN_ZVAL(&instance, 0, 1); + php_var_dump(&first, 1); + php_var_dump(&rest, 1); + php_var_dump(&ret, 1); + RETURN_ZVAL(getThis(), 1, 0); } static zend_function_entry methods[] = { @@ -722,6 +759,7 @@ static zend_function_entry methods[] = { PHP_ME(Stringy, regexEncoding, arginfo_regexEncoding, ZEND_ACC_PUBLIC) PHP_ME(Stringy, eregReplace, arginfo_eregReplace, ZEND_ACC_PUBLIC) PHP_ME(Stringy, swapCase, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, upperCaseFirst, NULL, ZEND_ACC_PUBLIC) PHP_FE_END }; diff --git a/startup.c b/startup.c index 574025e..f67ed38 100644 --- a/startup.c +++ b/startup.c @@ -149,25 +149,25 @@ PHP_MINFO_FUNCTION(startup) } /* }}} */ -PHP_FUNCTION(tttt_test) -{ - zval *arr; - ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_ARRAY(arr) - ZEND_PARSE_PARAMETERS_END(); - - RETURN_ZVAL(arr, 1, 1); -} -ZEND_BEGIN_ARG_INFO(arginfo_tttt_test, 1) - ZEND_ARG_INFO(0, matches) -ZEND_END_ARG_INFO(); +// zval* check_ext_load(char* name) +// { +// zval return_value, z_name; +// ZVAL_STRING(&z_name, name); +// zval func, args[] = { +// z_name, +// }; +// ZVAL_STRING(&func, "extension_loaded"); +// call_user_function(NULL, NULL, &func, &return_value, 1, args); +// // convert_to_boolean(&return_value); +// // return zval_is_true(&return_value); +// return &return_value; +// } /* {{{ startup_functions[] * * Every user visible function must have an entry in startup_functions[]. */ zend_function_entry startup_functions[] = { - PHP_FE(tttt_test, arginfo_tttt_test) PHP_FE(confirm_startup_compiled, NULL) /* For testing, remove later. */ PHP_FE_END /* Must be the last line in startup_functions[] */ }; diff --git a/startup.php b/startup.php index 7797316..6ae61fe 100644 --- a/startup.php +++ b/startup.php @@ -67,5 +67,5 @@ function checkExt() _ns(NS_STRINGY); -// var_dump((string)_('Stringy', ['Fòô Bàř', 'UTF-8'])->swapCase()); -// var_dump(tttt_test($_SERVER)); +// $x = _('Stringy', ['test test2 test3', 'UTF-8']); +$x = __('Stringy')::create('test test2 test3', 'UTF-8')->swapCase(); From 97026e38605a6d14c4589640905d5d759a14b4d9 Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Sun, 2 Dec 2018 13:34:41 +0800 Subject: [PATCH 039/126] =?UTF-8?q?=E6=9D=A1=E4=BB=B6=E5=88=86=E6=94=AF?= =?UTF-8?q?=E6=B2=A1=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 ++ .vscode/settings.json | 2 +- scripts/gdb.sh | 21 ++++++++++++--------- src/ext/stringy/stringy.c | 37 +++++++++++++++++++++++++++---------- 4 files changed, 42 insertions(+), 20 deletions(-) diff --git a/.gitignore b/.gitignore index 99f4afd..1572d00 100644 --- a/.gitignore +++ b/.gitignore @@ -44,3 +44,5 @@ GPATH /vendor/ *.loT core +.gdb_history +peda-session-php.txt diff --git a/.vscode/settings.json b/.vscode/settings.json index a546227..9a2197a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -27,7 +27,7 @@ }, "editor.mouseWheelZoom": false, "files.autoSave": "onFocusChange", - "editor.fontSize": 18, + "editor.fontSize": 16, "editor.renderWhitespace": "boundary", "editor.cursorStyle": "line-thin", "files.exclude": { diff --git a/scripts/gdb.sh b/scripts/gdb.sh index 28facae..c070b96 100755 --- a/scripts/gdb.sh +++ b/scripts/gdb.sh @@ -1,19 +1,22 @@ -#!/usr/bin/env bash +# #!/usr/bin/env bash -set -e -set -x +# set -e +# set -x # source your_php_src_path/.gdbinit # gdb php -f startup.php -[[ ! -e ~/.gdbinit ]]&& cp ~/.gdbinit ~/.gdbinit.bak +# [[ ! -e ~/.gdbinit ]]&& cp ~/.gdbinit ~/.gdbinit.bak -ln -sf $PHPBREW_HOME/build/$PHPBREW_PHP/.gdbinit ~/.gdbinit +# ln -sf $PHPBREW_HOME/build/$PHPBREW_PHP/.gdbinit ~/.gdbinit -ulimit -c unlimited +# ulimit -c unlimited -MINBABY_TEST_EXT=1 php -f startup.php +# MINBABY_TEST_EXT=1 php -f startup.php -ulimit -c 0 +# ulimit -c 0 -gdb -c core php +# gdb -c core php + +b src/ext/stringy.c:665 +b /home/minbaby/.phpbrew/build/php-7.1.23/Zend/zend_execute_API.c:782 diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index 107b353..6cfd218 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -616,6 +616,11 @@ static void once_listener_handler(INTERNAL_FUNCTION_PARAMETERS) zval *ret = zend_hash_index_find(Z_ARRVAL_P(arr), 0); + zval *ret = zend_hash_index_find(ht, 0); + if (ret == NULL) { + RETURN_EMPTY_STRING(); + } + zval func = {}; ZVAL_STRING(&func, "mb_strtoupper"); zval args[] = { @@ -646,12 +651,11 @@ PHP_METHOD(Stringy, swapCase) zend_function zendFunction; - zend_arg_info zai[1]; - zai[0].name = zend_string_init(ZEND_STRL("matches"), 0); - zai[0].pass_by_reference = 0; - zai[0].allow_null = 0; - zai[0].is_variadic = 0; - zai[0].type_hint = IS_STRING; + zend_internal_arg_info zai[] = { + ZEND_ARG_ARRAY_INFO(0, "matches", 0) + }; + + zend_string *f = zend_string_init(ZEND_STRL("callback"), 0); zendFunction.type = ZEND_INTERNAL_FUNCTION; zendFunction.common.num_args = 1; @@ -659,11 +663,28 @@ PHP_METHOD(Stringy, swapCase) zendFunction.common.arg_info = zai; zendFunction.common.prototype = NULL; zendFunction.common.scope = NULL; + zendFunction.common.fn_flags = ZEND_ACC_CLOSURE; + zendFunction.common.function_name = f; zendFunction.internal_function.handler = once_listener_handler; + zendFunction.internal_function.type = ZEND_INTERNAL_FUNCTION; + zendFunction.internal_function.fn_flags = ZEND_ACC_CLOSURE; + zendFunction.internal_function.arg_info = zai; + zendFunction.internal_function.required_num_args =1; + zendFunction.internal_function.num_args = 1; zval callback; zend_create_closure(&callback, &zendFunction, NULL, NULL, NULL); + zval arr; + array_init(&arr); + add_assoc_string(&arr, "1", "b"); + zval args1[] = { + arr + }; + + call_user_function(NULL, NULL, &callback, return_value, 1, args1); + + #if ZEND_DEBUG ZEND_ASSERT(1); #endif @@ -730,10 +751,6 @@ PHP_METHOD(Stringy, upperCaseFirst) concat_function(&ret, &first, &rest); - php_var_dump(&first, 1); - php_var_dump(&rest, 1); - php_var_dump(&ret, 1); - RETURN_ZVAL(getThis(), 1, 0); } From 9290c7e4949133288a1036baef9345006548b358 Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Sun, 2 Dec 2018 13:38:54 +0800 Subject: [PATCH 040/126] fix redefine --- src/ext/stringy/stringy.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index 6cfd218..20e11f5 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -616,7 +616,6 @@ static void once_listener_handler(INTERNAL_FUNCTION_PARAMETERS) zval *ret = zend_hash_index_find(Z_ARRVAL_P(arr), 0); - zval *ret = zend_hash_index_find(ht, 0); if (ret == NULL) { RETURN_EMPTY_STRING(); } From 8d099cd893322b9d237ad3590a1ef8f15cf683e1 Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Sun, 2 Dec 2018 15:11:17 +0800 Subject: [PATCH 041/126] append test+php+ext --- spec/Stringy/StringySpec.php | 13 +++++++++++++ src/Minbaby/Php/Stringy/Stringy.php | 5 +++++ src/ext/stringy/stringy.c | 22 ++++++++++++++++++++++ 3 files changed, 40 insertions(+) diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index 12ab223..fcf96ca 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -184,4 +184,17 @@ \expect($result)->toBe($expectd); } }); + + it('test append', function () { + $data = [ + ['foobar', 'foo', 'bar'], + ['fòôbàř', 'fòô', 'bàř', 'UTF-8'] + ]; + foreach($data as $value) { + @list($expect, $str, $string, $encoding) = $value; + $result = __('Stringy')::create($str, $encoding)->append($string); + \expect($result)->toBeAnInstanceOf(__('Stringy')); + \expect((string)$result)->toBe($expect); + } + }); }); diff --git a/src/Minbaby/Php/Stringy/Stringy.php b/src/Minbaby/Php/Stringy/Stringy.php index c4530de..e60b567 100644 --- a/src/Minbaby/Php/Stringy/Stringy.php +++ b/src/Minbaby/Php/Stringy/Stringy.php @@ -206,4 +206,9 @@ public function indexOfLast($needle, $offset = 0) $this->encoding ); } + + public function append($string) + { + return static::create($this->str . $string, $this->encoding); + } } diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index 20e11f5..a365e65 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -753,6 +753,27 @@ PHP_METHOD(Stringy, upperCaseFirst) RETURN_ZVAL(getThis(), 1, 0); } +PHP_METHOD(Stringy, append) +{ + zval *str_param; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ZVAL(str_param) + ZEND_PARSE_PARAMETERS_END(); + + zval rv; + zval *str = zend_read_property(stringy_ce, getThis(), ZEND_STRL("str"), 1, &rv); + + concat_function(return_value, str, str_param); + + zend_update_property_string(stringy_ce, getThis(), ZEND_STRL("str"), Zzzz_STRVAL_P(return_value)); + + RETURN_ZVAL(getThis(), 1, 0); +} +ZEND_BEGIN_ARG_INFO(arginfo_append, 1) + ZEND_ARG_TYPE_INFO(0, str, IS_STRING, 0) +ZEND_END_ARG_INFO(); + static zend_function_entry methods[] = { PHP_ME(Stringy, __construct, arginfo___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) PHP_ME(Stringy, __toString, NULL, ZEND_ACC_PUBLIC) @@ -776,6 +797,7 @@ static zend_function_entry methods[] = { PHP_ME(Stringy, eregReplace, arginfo_eregReplace, ZEND_ACC_PUBLIC) PHP_ME(Stringy, swapCase, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, upperCaseFirst, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, append, NULL, ZEND_ACC_PUBLIC) PHP_FE_END }; From 1ce577e651e20178b7f7d28f0bbdde833df3a203 Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Sun, 2 Dec 2018 15:24:35 +0800 Subject: [PATCH 042/126] fix typo --- src/ext/stringy/stringy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index a365e65..f144874 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -766,7 +766,7 @@ PHP_METHOD(Stringy, append) concat_function(return_value, str, str_param); - zend_update_property_string(stringy_ce, getThis(), ZEND_STRL("str"), Zzzz_STRVAL_P(return_value)); + zend_update_property_string(stringy_ce, getThis(), ZEND_STRL("str"), Z_STRVAL_P(return_value)); RETURN_ZVAL(getThis(), 1, 0); } From 7667b50a925cff4a9a2cb3e6babed2ebb179e157 Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Sun, 2 Dec 2018 15:30:59 +0800 Subject: [PATCH 043/126] prepend test+php+ext --- spec/Stringy/StringySpec.php | 13 +++++++++++++ src/Minbaby/Php/Stringy/Stringy.php | 5 +++++ src/ext/stringy/stringy.c | 24 ++++++++++++++++++++++-- 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index fcf96ca..069219a 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -197,4 +197,17 @@ \expect((string)$result)->toBe($expect); } }); + + it('test prepend', function () { + $data = [ + ['foobar', 'bar', 'foo'], + ['fòôbàř', 'bàř', 'fòô', 'UTF-8'] + ]; + foreach($data as $value) { + @list($expect, $str, $string, $encoding) = $value; + $result = __('Stringy')::create($str, $encoding)->prepend($string); + \expect($result)->toBeAnInstanceOf(__('Stringy')); + \expect((string)$result)->toBe($expect); + } + }); }); diff --git a/src/Minbaby/Php/Stringy/Stringy.php b/src/Minbaby/Php/Stringy/Stringy.php index e60b567..bb1b10a 100644 --- a/src/Minbaby/Php/Stringy/Stringy.php +++ b/src/Minbaby/Php/Stringy/Stringy.php @@ -211,4 +211,9 @@ public function append($string) { return static::create($this->str . $string, $this->encoding); } + + public function prepend($string) + { + return static::create($string . $this->str, $this->encoding); + } } diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index f144874..f06e16e 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -642,8 +642,6 @@ PHP_METHOD(Stringy, swapCase) { zval rv, func, pattern={}, subject, limit, count, ret, encoding; - php_var_dump(&pattern, 1); - ZVAL_STRING(&pattern, "/[\\S]/u"); subject = *zend_read_property(stringy_ce, getThis(), ZEND_STRL("str"), 0, &rv); @@ -774,6 +772,27 @@ ZEND_BEGIN_ARG_INFO(arginfo_append, 1) ZEND_ARG_TYPE_INFO(0, str, IS_STRING, 0) ZEND_END_ARG_INFO(); +PHP_METHOD(Stringy, prepend) +{ + zval *str_param; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ZVAL(str_param) + ZEND_PARSE_PARAMETERS_END(); + + zval rv; + zval *str = zend_read_property(stringy_ce, getThis(), ZEND_STRL("str"), 1, &rv); + + concat_function(return_value, str_param, str); + + zend_update_property_string(stringy_ce, getThis(), ZEND_STRL("str"), Z_STRVAL_P(return_value)); + + RETURN_ZVAL(getThis(), 1, 0); +} +ZEND_BEGIN_ARG_INFO(arginfo_prepend, 1) + ZEND_ARG_TYPE_INFO(0, str, IS_STRING, 0) +ZEND_END_ARG_INFO(); + static zend_function_entry methods[] = { PHP_ME(Stringy, __construct, arginfo___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) PHP_ME(Stringy, __toString, NULL, ZEND_ACC_PUBLIC) @@ -798,6 +817,7 @@ static zend_function_entry methods[] = { PHP_ME(Stringy, swapCase, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, upperCaseFirst, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, append, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, prepend, NULL, ZEND_ACC_PUBLIC) PHP_FE_END }; From 34ef96129e534ff429f6210a46272aa2b1badb97 Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Sun, 2 Dec 2018 15:47:45 +0800 Subject: [PATCH 044/126] =?UTF-8?q?=E5=AE=8C=E6=88=90=E3=80=80chars=20?= =?UTF-8?q?=E6=96=B9=E6=B3=95=E6=B5=8B=E8=AF=95=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- spec/Stringy/StringySpec.php | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index 069219a..414d941 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -210,4 +210,25 @@ \expect((string)$result)->toBe($expect); } }); + + it('test chars', function () { + $data = [ + [[], ''], + [['T', 'e', 's', 't'], 'Test'], + [['F', 'ò', 'ô', ' ', 'B', 'à', 'ř'], 'Fòô Bàř', 'UTF-8'] + ]; + + foreach($data as $value) { + @list($expect, $str, $encoding) = $value; + + $result = __('Stringy')::create($str, $encoding)->chars(); + \expect($result)->toBeA('array'); + + foreach ($result as $char) { + \expect($char)->toBeA('string'); + } + + \expect($result)->toBe($expect); + } + }); }); From 4deb831bea3272242a95621cc44dc7f4a3dbf272 Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Sun, 2 Dec 2018 18:32:39 +0800 Subject: [PATCH 045/126] update --- scripts/init-development.sh | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100755 scripts/init-development.sh diff --git a/scripts/init-development.sh b/scripts/init-development.sh new file mode 100755 index 0000000..0f14cd4 --- /dev/null +++ b/scripts/init-development.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash + +set -e -x + +export PATH=/usr/bin:$PATH + +export PHP_VERSION=php-7.1.23 + +export SYSTEM_NAME=`uname` + +[ "$SYSTEM_NAME" == "Darwin" ] && LIB_BZ2='+bz2=/usr/local/opt/bzip2/' +[ "$SYSTEM_NAME" == "Darwin" ] && LIB_ZIP='+zlib=/usr/local/opt/zlib' + +phpbrew --debug install --mirror=http://cn2.php.net -j 4 $PHP_VERSION +default $LIB_BZ2 $LIB_ZIP +mb +openssl=/usr/local/opt/openssl/ + +echo $PHP_VERSION + +phpbrew switch $PHP_VERSION From f03ca11ed987497f65fa3038bec0fd852b3dbcf1 Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Sun, 2 Dec 2018 23:45:39 +0800 Subject: [PATCH 046/126] =?UTF-8?q?c=20=E6=89=A9=E5=B1=95=E6=B2=A1?= =?UTF-8?q?=E6=9C=89=E8=B0=83=E9=80=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- spec/Stringy/StringySpec.php | 55 ++++++++++--- src/Minbaby/Php/Stringy/Stringy.php | 43 ++++++++++ src/ext/stringy/stringy.c | 119 +++++++++++++++++++++++----- startup.php | 4 +- 4 files changed, 189 insertions(+), 32 deletions(-) diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index 414d941..6e18fb3 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -158,9 +158,9 @@ ]; foreach ($data as $value) { - @list($expectd, $str, $subStr, $offset, $encoding) = $value; + @list($expectedd, $str, $subStr, $offset, $encoding) = $value; $result = __('Stringy')::create($str, $encoding)->indexOf($subStr, $offset); - \expect($result)->toBe($expectd); + \expect($result)->toBe($expectedd); } }); @@ -179,9 +179,9 @@ ]; foreach ($data as $value) { - @list($expectd, $str, $subStr, $offset, $encoding) = $value; + @list($expectedd, $str, $subStr, $offset, $encoding) = $value; $result = __('Stringy')::create($str, $encoding)->indexOfLast($subStr, $offset); - \expect($result)->toBe($expectd); + \expect($result)->toBe($expectedd); } }); @@ -191,10 +191,10 @@ ['fòôbàř', 'fòô', 'bàř', 'UTF-8'] ]; foreach($data as $value) { - @list($expect, $str, $string, $encoding) = $value; + @list($expected, $str, $string, $encoding) = $value; $result = __('Stringy')::create($str, $encoding)->append($string); \expect($result)->toBeAnInstanceOf(__('Stringy')); - \expect((string)$result)->toBe($expect); + \expect((string)$result)->toBe($expected); } }); @@ -204,10 +204,10 @@ ['fòôbàř', 'bàř', 'fòô', 'UTF-8'] ]; foreach($data as $value) { - @list($expect, $str, $string, $encoding) = $value; + @list($expected, $str, $string, $encoding) = $value; $result = __('Stringy')::create($str, $encoding)->prepend($string); \expect($result)->toBeAnInstanceOf(__('Stringy')); - \expect((string)$result)->toBe($expect); + \expect((string)$result)->toBe($expected); } }); @@ -219,7 +219,7 @@ ]; foreach($data as $value) { - @list($expect, $str, $encoding) = $value; + @list($expected, $str, $encoding) = $value; $result = __('Stringy')::create($str, $encoding)->chars(); \expect($result)->toBeA('array'); @@ -228,7 +228,42 @@ \expect($char)->toBeA('string'); } - \expect($result)->toBe($expect); + \expect($result)->toBe($expected); + } + }); + + it('test lines', function () { + $data = [ + [[], ""], + [[''], "\r\n"], + [['foo', 'bar'], "foo\nbar"], + [['foo', 'bar'], "foo\rbar"], + [['foo', 'bar'], "foo\r\nbar"], + [['foo', '', 'bar'], "foo\r\n\r\nbar"], + [['foo', 'bar', ''], "foo\r\nbar\r\n"], + [['', 'foo', 'bar'], "\r\nfoo\r\nbar"], + [['fòô', 'bàř'], "fòô\nbàř", 'UTF-8'], + [['fòô', 'bàř'], "fòô\rbàř", 'UTF-8'], + [['fòô', 'bàř'], "fòô\n\rbàř", 'UTF-8'], + [['fòô', 'bàř'], "fòô\r\nbàř", 'UTF-8'], + [['fòô', '', 'bàř'], "fòô\r\n\r\nbàř", 'UTF-8'], + [['fòô', 'bàř', ''], "fòô\r\nbàř\r\n", 'UTF-8'], + [['', 'fòô', 'bàř'], "\r\nfòô\r\nbàř", 'UTF-8'], + ]; + + foreach($data as $value) { + @list($expected, $str, $encoding) = $value; + + $result = __('Stringy')::create($str, $encoding)->lines(); + \expect($result)->toBeA('array'); + + foreach ($result as $char) { + \expect($char)->toBeAnInstanceOf(__('Stringy')); + } + + for ($i = 0; $i < count($expected); $i++) { + \expect((string)$result[$i])->toBe($expected[$i]); + } } }); }); diff --git a/src/Minbaby/Php/Stringy/Stringy.php b/src/Minbaby/Php/Stringy/Stringy.php index bb1b10a..c01def7 100644 --- a/src/Minbaby/Php/Stringy/Stringy.php +++ b/src/Minbaby/Php/Stringy/Stringy.php @@ -215,5 +215,48 @@ public function append($string) public function prepend($string) { return static::create($string . $this->str, $this->encoding); +} + + public function lines() + { + $array = $this->split('[\r\n]{1,2}', $this->str); + for ($i = 0; $i < count($array); $i++) { + $array[$i] = static::create($array[$i], $this->encoding); + } + return $array; + } + + public function split($pattern, $limit = null) + { + if ($limit === 0) { + return []; + } + // mb_split errors when supplied an empty pattern in < PHP 5.4.13 + // and HHVM < 3.8 + if ($pattern === '') { + return [static::create($this->str, $this->encoding)]; + } + $regexEncoding = $this->regexEncoding(); + $this->regexEncoding($this->encoding); + // mb_split returns the remaining unsplit string in the last index when + // supplying a limit + $limit = ($limit > 0) ? $limit += 1 : -1; + static $functionExists; + if ($functionExists === null) { + $functionExists = function_exists('\mb_split'); + } + if ($functionExists) { + $array = \mb_split($pattern, $this->str, $limit); + } else if ($this->supportsEncoding()) { + $array = \preg_split("/$pattern/", $this->str, $limit); + } + $this->regexEncoding($regexEncoding); + if ($limit > 0 && count($array) === $limit) { + array_pop($array); + } + for ($i = 0; $i < count($array); $i++) { + $array[$i] = static::create($array[$i], $this->encoding); + } + return $array; } } diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index f06e16e..9ac1e9d 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -442,13 +442,9 @@ ZEND_END_ARG_INFO(); PHP_METHOD(Stringy, collapseWhiteSpace) { - zval instance, retval, func, args[3], args_trim[1]; + zval retval, func, args[3], args_trim[1]; zval pattern, replacement, options, chars; - object_init_ex(&instance, stringy_ce); - - // call regexReplace - ZVAL_STRING(&pattern, "[[:space:]]+"); ZVAL_STRING(&replacement, " "); @@ -504,19 +500,6 @@ PHP_METHOD(Stringy, regexReplace) args[0] = regexEncoding; call_user_function(NULL, getThis(), &func, return_value, 1, args); - // zval instance; - // object_init_ex(&instance, stringy_ce); - - // zval args_construct[2]; - // args_construct[0] = retStr; - // args_construct[1] = *encoding; - - // ZVAL_STRING(&func, "__construct"); - - // call_user_function(NULL, &instance, &func, return_value, 2, args_construct); - - // RETURN_ZVAL(&instance, 0, 1); - RETURN_ZVAL(getThis(), 1, 0); } ZEND_BEGIN_ARG_INFO(arginfo_regexReplace, 3) @@ -640,7 +623,7 @@ static void once_listener_handler(INTERNAL_FUNCTION_PARAMETERS) PHP_METHOD(Stringy, swapCase) { - zval rv, func, pattern={}, subject, limit, count, ret, encoding; + zval rv, func, pattern={}, subject, limit_str, count, ret, encoding; ZVAL_STRING(&pattern, "/[\\S]/u"); @@ -688,13 +671,13 @@ PHP_METHOD(Stringy, swapCase) ZVAL_MAKE_REF(&count); ZVAL_STRING(&func, "preg_replace_callback"); - ZVAL_LONG(&limit, -1); + ZVAL_LONG(&limit_str, -1); zval args[] ={ pattern, callback, subject, - limit, + limit_str, count, }; @@ -793,6 +776,98 @@ ZEND_BEGIN_ARG_INFO(arginfo_prepend, 1) ZEND_ARG_TYPE_INFO(0, str, IS_STRING, 0) ZEND_END_ARG_INFO(); +PHP_METHOD(Stringy, lines) +{ + zval array, pattern, *str, rv; + + ZVAL_STRING(&pattern, "[\r\n]{1,2}"); + str =zend_read_property(stringy_ce, getThis(), ZEND_STRL("str"), 1, &rv); + + array_init(&array); + + zval func, args[] = { + pattern, + *str, + }; + ZVAL_STRING(&func, "split"); + call_user_function(NULL, getThis(), &func, &array, 2, args); + + RETURN_ZVAL(&array, 0, 1); +} + +PHP_METHOD(Stringy, split) +{ + zend_string *empty = zend_string_init(ZEND_STRL(""), 0); + zend_string *pattern; + zval *limit_zval; + + ZEND_PARSE_PARAMETERS_START(1, 2) + Z_PARAM_STR(pattern) + Z_PARAM_OPTIONAL + Z_PARAM_ZVAL(limit_zval) + ZEND_PARSE_PARAMETERS_END(); + + zval arr; + array_init(&arr); + + if (Z_TYPE_P(limit_zval) == IS_LONG && Z_LVAL_P(limit_zval) == 0) { + RETURN_ZVAL(&arr, 1, 0); + } + if (zend_string_equals(pattern, empty)) { + zval *this; + ZVAL_COPY(this, getThis()); + add_index_zval(&arr, 0, this); + RETURN_ZVAL(&arr, 1, 0); + } + + convert_to_long(limit_zval); + zend_long limit_long = Z_LVAL_P(limit_zval); + + zend_long limit = (limit_long > 0) ? limit_long += 1 : -1; + + zval pattern_zval, str_zval, rv; + + str_zval = *zend_read_property(stringy_ce, getThis(), ZEND_STRL("str"), 0, &rv); + ZVAL_STR(&pattern_zval, pattern); + + zval func, args[] = { + pattern_zval, + str_zval, + *limit_zval, + }; + ZVAL_STRING(&func, "mb_split"); + call_user_function(NULL, NULL, &func, &arr, 3, args); + + zend_long array_len = zend_array_count(Z_ARRVAL(arr)); + + zval *encoding = zend_read_property(stringy_ce, getThis(), ZEND_STRL("encoding"), 0, &rv); + + zval instance; + object_init_ex(&instance, stringy_ce); + + zval *tmp; + zend_long index; + ZEND_HASH_FOREACH_NUM_KEY_VAL(Z_ARRVAL(arr), index, tmp){ + zval args_construct[] = { + *tmp, + *encoding, + }; + + ZVAL_STRING(&func, "__construct"); + + call_user_function(NULL, &instance, &func, return_value, 2, args_construct); + + add_next_index_zval(&arr, &instance); + }ZEND_HASH_FOREACH_END(); + + + RETURN_ZVAL(&arr, 0, 1); +} +ZEND_BEGIN_ARG_INFO(arginfo_split, 2) + ZEND_ARG_TYPE_INFO(0, pattern, IS_STRING, 0) + ZEND_ARG_INFO(0, limit_str) +ZEND_END_ARG_INFO(); + static zend_function_entry methods[] = { PHP_ME(Stringy, __construct, arginfo___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) PHP_ME(Stringy, __toString, NULL, ZEND_ACC_PUBLIC) @@ -818,6 +893,8 @@ static zend_function_entry methods[] = { PHP_ME(Stringy, upperCaseFirst, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, append, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, prepend, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, lines, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, split, arginfo_split, ZEND_ACC_PUBLIC) PHP_FE_END }; diff --git a/startup.php b/startup.php index 6ae61fe..d100a95 100644 --- a/startup.php +++ b/startup.php @@ -68,4 +68,6 @@ function checkExt() _ns(NS_STRINGY); // $x = _('Stringy', ['test test2 test3', 'UTF-8']); -$x = __('Stringy')::create('test test2 test3', 'UTF-8')->swapCase(); +$x = __('Stringy')::create('foo\r\nbar', 'UTF-8')->lines(); + +var_dump($x); From 680de73e0cbd2d4a1221a62e62280aaf825c84a9 Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Mon, 3 Dec 2018 22:55:01 +0800 Subject: [PATCH 047/126] =?UTF-8?q?=E6=B5=8B=E8=AF=95=E9=80=9A=E8=BF=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- composer.json | 3 ++- src/ext/stringy/stringy.c | 47 ++++++++++++++++++++++----------------- startup.php | 7 +++--- 3 files changed, 33 insertions(+), 24 deletions(-) diff --git a/composer.json b/composer.json index 345a57c..6827e0d 100644 --- a/composer.json +++ b/composer.json @@ -10,7 +10,8 @@ } ], "require": { - "php": "^7.1" + "php": "^7.1", + "ext-json": "*" }, "autoload": { "psr-4": { diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index 9ac1e9d..1a6fde1 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -92,15 +92,13 @@ PHP_METHOD(Stringy, __construct) zval *tmp; size_t count = 0; zend_string *encoding_str = zend_string_init(encoding, strlen(encoding), 0); - ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(return_value), tmp) - { + ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(return_value), tmp) { if (encoding == Z_STRVAL_P(tmp)) { count++; break; } - } - ZEND_HASH_FOREACH_END(); + } ZEND_HASH_FOREACH_END(); if (count == 0) { @@ -792,7 +790,21 @@ PHP_METHOD(Stringy, lines) ZVAL_STRING(&func, "split"); call_user_function(NULL, getThis(), &func, &array, 2, args); - RETURN_ZVAL(&array, 0, 1); + zval ret_arr; + array_init(&ret_arr); + + zval *encoding = zend_read_property(stringy_ce, getThis(), ZEND_STRL("encoding"), 0, &rv); + zval *tmp; + + ZEND_HASH_FOREACH_VAL(Z_ARRVAL(array), tmp){ + zval instance; + object_init_ex(&instance, stringy_ce); + convert_to_string(tmp); + zend_call_method(&instance, stringy_ce, NULL, ZEND_STRL("__construct"), return_value, 2, tmp, encoding); + add_next_index_zval(&ret_arr, &instance); + }ZEND_HASH_FOREACH_END(); + + RETURN_ZVAL(&ret_arr, 0, 1); } PHP_METHOD(Stringy, split) @@ -813,6 +825,7 @@ PHP_METHOD(Stringy, split) if (Z_TYPE_P(limit_zval) == IS_LONG && Z_LVAL_P(limit_zval) == 0) { RETURN_ZVAL(&arr, 1, 0); } + if (zend_string_equals(pattern, empty)) { zval *this; ZVAL_COPY(this, getThis()); @@ -830,6 +843,7 @@ PHP_METHOD(Stringy, split) str_zval = *zend_read_property(stringy_ce, getThis(), ZEND_STRL("str"), 0, &rv); ZVAL_STR(&pattern_zval, pattern); + ZVAL_LONG(limit_zval, limit); zval func, args[] = { pattern_zval, str_zval, @@ -842,26 +856,19 @@ PHP_METHOD(Stringy, split) zval *encoding = zend_read_property(stringy_ce, getThis(), ZEND_STRL("encoding"), 0, &rv); - zval instance; - object_init_ex(&instance, stringy_ce); - zval *tmp; zend_long index; - ZEND_HASH_FOREACH_NUM_KEY_VAL(Z_ARRVAL(arr), index, tmp){ - zval args_construct[] = { - *tmp, - *encoding, - }; - - ZVAL_STRING(&func, "__construct"); - - call_user_function(NULL, &instance, &func, return_value, 2, args_construct); - - add_next_index_zval(&arr, &instance); + zval ret_arr; + array_init(&ret_arr); + ZEND_HASH_FOREACH_VAL(Z_ARRVAL(arr), tmp){ + zval instance; + object_init_ex(&instance, stringy_ce); + zend_call_method(&instance, stringy_ce, NULL, ZEND_STRL("__construct"), return_value, 2, tmp, encoding); + add_next_index_zval(&ret_arr, &instance); }ZEND_HASH_FOREACH_END(); - RETURN_ZVAL(&arr, 0, 1); + RETURN_ZVAL(&ret_arr, 0, 1); } ZEND_BEGIN_ARG_INFO(arginfo_split, 2) ZEND_ARG_TYPE_INFO(0, pattern, IS_STRING, 0) diff --git a/startup.php b/startup.php index d100a95..64c8ac1 100644 --- a/startup.php +++ b/startup.php @@ -43,8 +43,9 @@ function checkExt() echo "$br\n"; } -include __DIR__ . "/spec/const.php"; -include __DIR__ . "/spec/functions.php"; +include __DIR__ . '/vendor/autoload.php'; +// include __DIR__ . "/spec/const.php"; +// include __DIR__ . "/spec/functions.php"; // function main() { // _ns(NS_STRINGY); @@ -68,6 +69,6 @@ function checkExt() _ns(NS_STRINGY); // $x = _('Stringy', ['test test2 test3', 'UTF-8']); -$x = __('Stringy')::create('foo\r\nbar', 'UTF-8')->lines(); +$x = __('Stringy')::create("foo\nbar", 'UTF-8')->lines(); var_dump($x); From c74f87a2e76dbd53ae0b33b80e79664790f4e2b3 Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Tue, 4 Dec 2018 16:00:03 +0800 Subject: [PATCH 048/126] update circleci yml --- .circleci/config.yml | 75 +++++++++++++++++++++++--------------------- 1 file changed, 39 insertions(+), 36 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 19cba95..0b564e2 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -4,43 +4,46 @@ # version: 2 jobs: - build: - branches: - # only: - # - master # list of branches to build - # - develop - ignore: - - feature/* + build-php-common: &common-build docker: - # specify the version you desire here - image: circleci/php:7.1-browsers - - # Specify service dependencies here if necessary - # CircleCI maintains a library of pre-built images - # documented at https://circleci.com/docs/2.0/circleci-images/ - # - image: circleci/mysql:9.4 - working_directory: ~/repo - steps: - - checkout - - - run: - name: composer install - command: composer install - - - run: - name: run test - command: ./vendor/bin/kahlan - - - run: - name: startup install - command: phpize && ./configure && make && sudo make install - - - run: - name: enable startup - command: sudo cp .circleci/docker-php-ext-startup.ini /usr/local/etc/php/conf.d/ - - - run: - name: run test - command: ./vendor/bin/kahlan + - run: + name: php version + command: php -v + - checkout + - run: + name: composer install + command: composer install + - run: + name: run test + command: ./vendor/bin/kahlan + - run: + name: startup install + command: phpize && ./configure && make && sudo make install + - run: + name: enable startup + command: sudo cp .circleci/docker-php-ext-startup.ini /usr/local/etc/php/conf.d/ + - run: + name: run test + command: ./vendor/bin/kahlan + build-php71: + <<: *common-build + docker: + - image: circleci/php:7.1-browsers + build-php72: + <<: *common-build + docker: + - image: circleci/php:7.2-browsers + build-php70: + <<: *common-build + docker: + - image: circleci/php:7.0-browsers +workflows: + version: 2 + build: + jobs: + - build-php71 + - build-php72 + - build-php73 From 07e9501f9a7c1f17b8c256b9e2feb9796425ffa7 Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Tue, 4 Dec 2018 16:05:47 +0800 Subject: [PATCH 049/126] rename && fix typo --- .circleci/config.yml | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 0b564e2..8ee1452 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -4,7 +4,7 @@ # version: 2 jobs: - build-php-common: &common-build + test-php-common: &common-test docker: - image: circleci/php:7.1-browsers working_directory: ~/repo @@ -28,22 +28,23 @@ jobs: - run: name: run test command: ./vendor/bin/kahlan - build-php71: - <<: *common-build + test-php71: + <<: *common-test docker: - image: circleci/php:7.1-browsers - build-php72: - <<: *common-build + test-php72: + <<: *common-test docker: - image: circleci/php:7.2-browsers - build-php70: - <<: *common-build + test-php70: + <<: *common-test docker: - image: circleci/php:7.0-browsers workflows: version: 2 build: jobs: - - build-php71 - - build-php72 - - build-php73 + - test-php70 + - test-php71 + - test-php72 + From 118e0898ea8d2f179c3a23815feed00547a40da4 Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Tue, 4 Dec 2018 16:12:59 +0800 Subject: [PATCH 050/126] =?UTF-8?q?=E6=94=AF=E6=8C=81php7.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- composer.json | 2 +- composer.lock | 17 +++++++++-------- spec/Stringy/StringySpec.php | 4 ++-- src/Minbaby/Php/Test.php | 2 +- 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/composer.json b/composer.json index 6827e0d..66fe082 100644 --- a/composer.json +++ b/composer.json @@ -10,7 +10,7 @@ } ], "require": { - "php": "^7.1", + "php": "^7.0", "ext-json": "*" }, "autoload": { diff --git a/composer.lock b/composer.lock index 89de072..e77ea92 100644 --- a/composer.lock +++ b/composer.lock @@ -4,21 +4,21 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "dd3acc8564f4e994ab0a77217e18d4e7", + "content-hash": "e9af6fb6f2ce506d427232984d336f64", "packages": [], "packages-dev": [ { "name": "kahlan/kahlan", - "version": "4.3.1", + "version": "4.4.0", "source": { "type": "git", "url": "https://github.com/kahlan/kahlan.git", - "reference": "92dbe4691f2f3049523cc525365a1a0be0c86db9" + "reference": "6a2f0d1dd1a45b518010bf8d2a3a9bae9e1bd7a9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/kahlan/kahlan/zipball/92dbe4691f2f3049523cc525365a1a0be0c86db9", - "reference": "92dbe4691f2f3049523cc525365a1a0be0c86db9", + "url": "https://api.github.com/repos/kahlan/kahlan/zipball/6a2f0d1dd1a45b518010bf8d2a3a9bae9e1bd7a9", + "reference": "6a2f0d1dd1a45b518010bf8d2a3a9bae9e1bd7a9", "shasum": "", "mirrors": [ { @@ -31,7 +31,7 @@ "php": ">=5.5" }, "require-dev": { - "squizlabs/php_codesniffer": "^2.7" + "squizlabs/php_codesniffer": "^3.3" }, "bin": [ "bin/kahlan" @@ -65,7 +65,7 @@ "testing", "unit test" ], - "time": "2018-09-28T15:39:00+00:00" + "time": "2018-12-01T00:19:49+00:00" } ], "aliases": [], @@ -74,7 +74,8 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": "^7.1" + "php": "^7.0", + "ext-json": "*" }, "platform-dev": [] } diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index 6e18fb3..ae5457a 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -51,7 +51,7 @@ ]; foreach($data as $v) { - [$key, $value] = $v; + list($key, $value) = $v; \expect($key)->toBe((string) _($this->class, [$value])); } }); @@ -104,7 +104,7 @@ $stringy = __('Stringy')::create('fòô', 'UTF-8'); foreach ($data as $value) { - [$expected, $offset] = $value; + list($expected, $offset) = $value; \expect($stringy->offsetExists($offset))->toBe($expected); \expect(isset($stringy[$offset]))->toBe($expected); } diff --git a/src/Minbaby/Php/Test.php b/src/Minbaby/Php/Test.php index bd1b442..2fe6db8 100644 --- a/src/Minbaby/Php/Test.php +++ b/src/Minbaby/Php/Test.php @@ -7,7 +7,7 @@ class Test public static $publicPropertyStatic = 'hello world +property +static'; - public const PUBLIC_CONST = 'hello world +const'; + const PUBLIC_CONST = 'hello world +const'; public static function helloWorld() { From 04b3fedd60ecf7a99cebecfbaaaec4c84587340c Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Wed, 5 Dec 2018 01:04:55 +0800 Subject: [PATCH 051/126] upperCaseFirst spec & fix func --- spec/Stringy/StringySpec.php | 16 ++++++++++++++++ src/ext/stringy/stringy.c | 3 +++ 2 files changed, 19 insertions(+) diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index ae5457a..c17c669 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -266,4 +266,20 @@ } } }); + + it('test upperCaseFirst', function () { + $data = [ + ['Test', 'Test'], + ['Test', 'test'], + ['1a', '1a'], + ['Σ test', 'σ test', 'UTF-8'], + [' σ test', ' σ test', 'UTF-8'] + ]; + foreach($data as $value) { + @list($expected, $str, $encoding) = $value; + $result = __('Stringy')::create($str, $encoding)->upperCaseFirst(); + \expect($result)->toBeAnInstanceOf(__('Stringy')); + \expect((string)$result)->toBe($expected); + } + }); }); diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index 1a6fde1..a02312c 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -729,6 +729,9 @@ PHP_METHOD(Stringy, upperCaseFirst) concat_function(&ret, &first, &rest); + zend_string *str_string = Z_STR(ret); + zend_update_property_str(stringy_ce, getThis(), ZEND_STRL("str"), str_string); + RETURN_ZVAL(getThis(), 1, 0); } From 99a08fcf8c42b222aa2985619c99940d50793854 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Wed, 5 Dec 2018 02:31:10 +0800 Subject: [PATCH 052/126] method lowerCaseFirst (#11) 1. lowerCaseFirst test+php+ext 2. update readme 3. update fetch.php --- README.MD | 2 +- scripts/fetch.php | 1 + spec/Stringy/StringySpec.php | 21 ++++++++++++ src/Minbaby/Php/Stringy/Stringy.php | 9 ++++++ src/ext/stringy/stringy.c | 50 +++++++++++++++++++++++++++++ 5 files changed, 82 insertions(+), 1 deletion(-) diff --git a/README.MD b/README.MD index 86025c9..69afc01 100644 --- a/README.MD +++ b/README.MD @@ -39,7 +39,7 @@ ## 已知问题 -- 和 xdebug 不兼容,开启 xdebug 会出现崩溃现象,原因未知(能力有限 😅) +- 0.0 ### skip ci diff --git a/scripts/fetch.php b/scripts/fetch.php index 9a9d754..12d8f2c 100755 --- a/scripts/fetch.php +++ b/scripts/fetch.php @@ -23,6 +23,7 @@ 'runkit' => 'https://github.com/zenovich/runkit', 'php-git' => 'https://github.com/libgit2/php-git', 'AOP' => 'https://github.com/AOP-PHP/AOP', + 'xdeubg' => 'https://github.com/xdebug/xdebug.git' ]; // PHPBREW_ROOT/build/php-7.1.17/ext/ diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index c17c669..07b3710 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -282,4 +282,25 @@ \expect((string)$result)->toBe($expected); } }); + + it('test lowerCaseFirst', function () { + $data = [ + ['test', 'Test'], + ['test', 'test'], + ['1a', '1a'], + ['σ test', 'Σ test', 'UTF-8'], + [' Σ test', ' Σ test', 'UTF-8'] + ]; + + foreach($data as $value) { + @list($expected, $str, $encoding) = $value; + $stringy = __('Stringy')::create($str, $encoding); + \expect((string)$stringy)->toBe($str); + $result = $stringy->lowerCaseFirst(); + \expect($result)->toBeAnInstanceOf(__('Stringy')); + \expect((string)$stringy)->toBe($str); + \expect((string)$result)->toBe($expected); + } + + }); }); diff --git a/src/Minbaby/Php/Stringy/Stringy.php b/src/Minbaby/Php/Stringy/Stringy.php index c01def7..49a952e 100644 --- a/src/Minbaby/Php/Stringy/Stringy.php +++ b/src/Minbaby/Php/Stringy/Stringy.php @@ -259,4 +259,13 @@ public function split($pattern, $limit = null) } return $array; } + + public function lowerCaseFirst() + { + $first = \mb_substr($this->str, 0, 1, $this->encoding); + $rest = \mb_substr($this->str, 1, $this->length() - 1, + $this->encoding); + $str = \mb_strtolower($first, $this->encoding) . $rest; + return static::create($str, $this->encoding); + } } diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index a02312c..ce0626f 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -735,6 +735,55 @@ PHP_METHOD(Stringy, upperCaseFirst) RETURN_ZVAL(getThis(), 1, 0); } +PHP_METHOD(Stringy, lowerCaseFirst) +{ + zval instance, encoding, str, func, ret, start, len, first, rest, rv; + + ZVAL_STRING(&func, "length"); + call_user_function(NULL, getThis(), &func, return_value, 0, NULL); + size_t length = Z_LVAL_P(return_value); + + str = *zend_read_property(stringy_ce, getThis(), ZEND_STRL("str"), 0, &rv); + encoding = *zend_read_property(stringy_ce, getThis(), ZEND_STRL("encoding"), 0, &rv); + + ZVAL_LONG(&start, 0); + ZVAL_LONG(&len, 1); + zval args[] = { + str, + start, + len, + encoding, + }; + ZVAL_STRING(&func, "mb_substr"); + call_user_function(NULL, NULL, &func, &first, 4, args); + + ZVAL_LONG(&start, 1); + ZVAL_LONG(&len, length-1); + zval args_rest[] = { + str, + start, + len, + encoding, + }; + ZVAL_STRING(&func, "mb_substr"); + call_user_function(NULL, NULL, &func, &rest, 4, args_rest); + + zval args_upper[] = { + first, + encoding, + }; + ZVAL_STRING(&func, "mb_strtolower"); + call_user_function(NULL, NULL, &func, &first, 2, args_upper); + + concat_function(&ret, &first, &rest); + + zval this; + object_init_ex(&this, stringy_ce); + zend_call_method(&this, stringy_ce, NULL, ZEND_STRL("__construct"), return_value, 2, &ret, &encoding); + + RETURN_ZVAL(&this, 0, 1); +} + PHP_METHOD(Stringy, append) { zval *str_param; @@ -901,6 +950,7 @@ static zend_function_entry methods[] = { PHP_ME(Stringy, eregReplace, arginfo_eregReplace, ZEND_ACC_PUBLIC) PHP_ME(Stringy, swapCase, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, upperCaseFirst, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, lowerCaseFirst, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, append, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, prepend, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, lines, NULL, ZEND_ACC_PUBLIC) From ce805203ac444de5b865159d218781a3ac8e73fb Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Thu, 6 Dec 2018 01:15:05 +0800 Subject: [PATCH 053/126] regexReplace test + php + TODO:ext --- spec/Stringy/StringySpec.php | 24 ++++++++++++++++++++++++ src/ext/stringy/stringy.c | 14 ++++++++++++-- startup.php | 2 +- 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index 07b3710..49a504e 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -303,4 +303,28 @@ } }); + + it('test regexReplce', function () { + + $data = [ + ['', '', '', ''], + ['bar', 'foo', 'f[o]+', 'bar'], + ['o bar', 'foo bar', 'f(o)o', '\1'], + ['bar', 'foo bar', 'f[O]+\s', '', 'i'], + ['foo', 'bar', '[[:alpha:]]{3}', 'foo'], + ['', '', '', '', 'msr', 'UTF-8'], + ['bàř', 'fòô ', 'f[òô]+\s', 'bàř', 'msr', 'UTF-8'], + ['fòô', 'fò', '(ò)', '\\1ô', 'msr', 'UTF-8'], + ['fòô', 'bàř', '[[:alpha:]]{3}', 'fòô', 'msr', 'UTF-8'] + ]; + + foreach($data as $value) { + @list($expected, $str, $pattern, $replacement, $options, $encoding) = $value; + $stringy = __('Stringy')::create($str, $encoding); + $result = $stringy->regexReplace($pattern, $replacement, $options); + \expect($result)->toBeAnInstanceOf(__('Stringy')); + \expect((string)$stringy)->toBe($str); + \expect((string)$result)->toBe($expected); + } + }); }); diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index ce0626f..5dfdaa3 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -464,7 +464,7 @@ PHP_METHOD(Stringy, collapseWhiteSpace) PHP_METHOD(Stringy, regexReplace) { - zval *pattern, *replacement, *options, rv; + zval *pattern, *replacement, *options = NULL, rv; zval func; ZEND_PARSE_PARAMETERS_START(2, 3) @@ -474,6 +474,11 @@ PHP_METHOD(Stringy, regexReplace) Z_PARAM_ZVAL(options) ZEND_PARSE_PARAMETERS_END(); + if (options == NULL) { + options = malloc(sizeof(zval)); + ZVAL_STRING(options, "msr"); + } + zval *encoding = zend_read_property(stringy_ce, getThis(), "encoding", strlen("encoding"), 0, &rv); zval *str = zend_read_property(stringy_ce, getThis(), "str", strlen("str"), 1, &rv); @@ -498,7 +503,12 @@ PHP_METHOD(Stringy, regexReplace) args[0] = regexEncoding; call_user_function(NULL, getThis(), &func, return_value, 1, args); - RETURN_ZVAL(getThis(), 1, 0); + zend_update_property(stringy_ce, getThis(), ZEND_STRL("str"), &retStr); + zval this; + object_init_ex(&this, stringy_ce); + zend_call_method(&this, stringy_ce, NULL, ZEND_STRL("__construct"), return_value, 2, &retStr, encoding); + + RETURN_ZVAL(&this, 0, 1); } ZEND_BEGIN_ARG_INFO(arginfo_regexReplace, 3) ZEND_ARG_INFO(0, pattern) diff --git a/startup.php b/startup.php index 64c8ac1..3d208e9 100644 --- a/startup.php +++ b/startup.php @@ -69,6 +69,6 @@ function checkExt() _ns(NS_STRINGY); // $x = _('Stringy', ['test test2 test3', 'UTF-8']); -$x = __('Stringy')::create("foo\nbar", 'UTF-8')->lines(); +$x = __('Stringy')::create("bàř", 'UTF-8')->regexReplce('[[:alpha:]]{3}', 'fòô', 'msr'); var_dump($x); From 73c1ed3bd15f122c9dc057f96ce17da19728105a Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Thu, 6 Dec 2018 23:14:10 +0800 Subject: [PATCH 054/126] fix regexreplace --- src/ext/stringy/stringy.c | 1 - startup.php | 19 +++++++++++++++++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index 5dfdaa3..330a953 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -503,7 +503,6 @@ PHP_METHOD(Stringy, regexReplace) args[0] = regexEncoding; call_user_function(NULL, getThis(), &func, return_value, 1, args); - zend_update_property(stringy_ce, getThis(), ZEND_STRL("str"), &retStr); zval this; object_init_ex(&this, stringy_ce); zend_call_method(&this, stringy_ce, NULL, ZEND_STRL("__construct"), return_value, 2, &retStr, encoding); diff --git a/startup.php b/startup.php index 3d208e9..68a6ed3 100644 --- a/startup.php +++ b/startup.php @@ -69,6 +69,21 @@ function checkExt() _ns(NS_STRINGY); // $x = _('Stringy', ['test test2 test3', 'UTF-8']); -$x = __('Stringy')::create("bàř", 'UTF-8')->regexReplce('[[:alpha:]]{3}', 'fòô', 'msr'); -var_dump($x); +$data = [ + ['', '', '', ''], + ['bar', 'foo', 'f[o]+', 'bar'], + ['o bar', 'foo bar', 'f(o)o', '\1'], + ['bar', 'foo bar', 'f[O]+\s', '', 'i'], + ['foo', 'bar', '[[:alpha:]]{3}', 'foo'], + ['', '', '', '', 'msr', 'UTF-8'], + ['bàř', 'fòô ', 'f[òô]+\s', 'bàř', 'msr', 'UTF-8'], + ['fòô', 'fò', '(ò)', '\\1ô', 'msr', 'UTF-8'], + ['fòô', 'bàř', '[[:alpha:]]{3}', 'fòô', 'msr', 'UTF-8'] +]; + +foreach($data as $value) { + @list($expected, $str, $pattern, $replacement, $options, $encoding) = $value; + $x = __('Stringy')::create($str, 'UTF-8')->regexReplace($pattern, $replacement, $options); + var_dump((string)$x == $expected); +} From bf79d617797334b66928bd5d03bad5e55bb8c0b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Sat, 8 Dec 2018 15:24:21 +0800 Subject: [PATCH 055/126] trim test+php+ext (#15) --- .vscode/settings.json | 14 ++++- scripts/config/dev.yml | 26 +++++++++ scripts/gdb.sh | 3 +- spec/Stringy/StringySpec.php | 29 +++++++++- src/ext/stringy/stringy.c | 101 +++++++++++++++++------------------ startup.php | 28 +++++----- 6 files changed, 129 insertions(+), 72 deletions(-) create mode 100644 scripts/config/dev.yml diff --git a/.vscode/settings.json b/.vscode/settings.json index 9a2197a..666d134 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -23,7 +23,19 @@ "string_view": "c", "spl_iterators.h": "c", "iosfwd": "c", - "functions.h": "c" + "functions.h": "c", + "__bit_reference": "c", + "hash_map": "c", + "unordered_map": "c", + "memory": "c", + "utility": "c", + "__functional_base": "c", + "atomic": "c", + "functional": "c", + "iterator": "c", + "limits": "c", + "tuple": "c", + "vector": "c" }, "editor.mouseWheelZoom": false, "files.autoSave": "onFocusChange", diff --git a/scripts/config/dev.yml b/scripts/config/dev.yml new file mode 100644 index 0000000..1f9610a --- /dev/null +++ b/scripts/config/dev.yml @@ -0,0 +1,26 @@ +variants: + php-startup: + bcmath: + bz2: + calendar: + cli: + ctype: + dom: + fileinfo: + filter: + ipc: + json: + mbregex: + mbstring: + mhash: + mcrypt: + gd: + - --with-libdir=lib/x86_64-linux-gnu + - --with-gd=shared + - --enable-gd-natf + - --with-jpeg-dir=/usr + - --with-png-dir=/usr +extensions: + php-startup: + xhprof: latest + xdebug: stable diff --git a/scripts/gdb.sh b/scripts/gdb.sh index c070b96..e81bf5a 100755 --- a/scripts/gdb.sh +++ b/scripts/gdb.sh @@ -18,5 +18,4 @@ # gdb -c core php -b src/ext/stringy.c:665 -b /home/minbaby/.phpbrew/build/php-7.1.23/Zend/zend_execute_API.c:782 +# git clone https://github.com/snare/voltron diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index 49a504e..d12acae 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -67,7 +67,7 @@ it('test chaining', function () { $stringy = __('Stringy')::create('x y', 'UTF-8'); \expect($stringy)->toBeAnInstanceOf(__('Stringy')); - \expect("X Y")->toBe((string) $stringy->swapCase()); + \expect((string) $stringy->swapCase())->toBe("X Y"); }); it('test count', function () { @@ -327,4 +327,31 @@ \expect((string)$result)->toBe($expected); } }); + + it('test trim', function () { + $data = [ + ['foo bar', ' foo bar '], + ['foo bar', ' foo bar'], + ['foo bar', 'foo bar '], + ['foo bar', "\n\t foo bar \n\t"], + ['fòô bàř', ' fòô bàř '], + ['fòô bàř', ' fòô bàř'], + ['fòô bàř', 'fòô bàř '], + [' foo bar ', "\n\t foo bar \n\t", "\n\t"], + ['fòô bàř', "\n\t fòô bàř \n\t", null, 'UTF-8'], + ['fòô', ' fòô ', null, 'UTF-8'], // narrow no-break space (U+202F) + ['fòô', '  fòô  ', null, 'UTF-8'], // medium mathematical space (U+205F) + ['fòô', '           fòô', null, 'UTF-8'] // spaces U+2000 to U+200A + ]; + + foreach($data as $value) { + @list($expected, $str, $chars, $encoding) = $value; + $stringy = __('Stringy')::create($str, $encoding); + $result = $stringy->trim($chars); + + \expect($result)->toBeAnInstanceOf(__('Stringy')); + \expect((string)$stringy)->toBe($str); + \expect((string)$result)->toBe($expected); + } + }); }); diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index 330a953..5353ea2 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -35,14 +35,14 @@ zend_class_entry *stringy_ce; PHP_METHOD(Stringy, __toString) { - zval rv, *value; - value = zend_read_property(stringy_ce, getThis(), "str", strlen("str"), 0, &rv); - RETURN_STRING(Z_STRVAL_P(value)); + zval rv; + zval *value = zend_read_property(stringy_ce, getThis(), ZEND_STRL("str"), 0, &rv); + RETURN_ZVAL(value, 1, 0); } PHP_METHOD(Stringy, __construct) { - char *encoding; + char *encoding = NULL; zval *str; char *string; size_t str_len, encoding_len; @@ -138,7 +138,7 @@ PHP_METHOD(Stringy, create) zend_call_method(&instance, stringy_ce, NULL, ZEND_STRL("__construct"), return_value, 2, str, encoding); - RETURN_ZVAL(&instance, 0, 1); + RETURN_ZVAL(&instance, 1, 0); } ZEND_BEGIN_ARG_INFO_EX(arginfo_create, 0, 0, 2) ZEND_ARG_INFO(0, str) @@ -252,7 +252,7 @@ PHP_METHOD(Stringy, getIterator) args[1] = flags; call_user_function(NULL, &instance, &func, return_value, 2, args); - RETURN_ZVAL(&instance, 0, 1); + RETURN_ZVAL(&instance, 1, 0); } PHP_METHOD(Stringy, chars) @@ -517,32 +517,45 @@ ZEND_END_ARG_INFO(); PHP_METHOD(Stringy, trim) { - zval *chars; + zval *chars = NULL; ZEND_PARSE_PARAMETERS_START(0, 1) - Z_PARAM_ZVAL(chars) + Z_PARAM_OPTIONAL + Z_PARAM_ZVAL(chars) ZEND_PARSE_PARAMETERS_END(); - if (Z_TYPE_P(chars) != IS_NULL) + if (chars != NULL && Z_TYPE_P(chars) != IS_NULL) { - zval func, args[2], delimiter; - ZVAL_STRING(&func, "preg_quote"); - args[0] = *chars; - args[1] = delimiter; - call_user_function(NULL, NULL, &func, return_value, 2, args); + convert_to_string(chars); + if (Z_STRLEN_P(chars) == 0) { + chars = malloc(sizeof(zval)); + ZVAL_STRING(chars, "[:space:]"); + } else { + zval func, delimiter; + ZVAL_STRING(&func, "preg_quote"); + zval args[] = { + *chars, + }; + call_user_function(NULL, NULL, &func, return_value, 1, args); + ZVAL_STRING(chars, Z_STRVAL_P(return_value)); + } } else { + chars = malloc(sizeof(zval)); ZVAL_STRING(chars, "[:space:]"); + } - zval func_regexReplace, args[3], pattern, replacement, options; + zval func_regexReplace, pattern, replacement, options; ZVAL_STRING(&func_regexReplace, "regexReplace"); - ZVAL_STRING(&pattern, "^[$chars]+|[$chars]+$"); + zend_string *p = strpprintf(0, "^[%s]+|[%s]+$", Z_STRVAL_P(chars), Z_STRVAL_P(chars)); + ZVAL_STR(&pattern, p); ZVAL_STRING(&replacement, ""); - args[0] = pattern; - args[1] = replacement; - args[2] = options; - call_user_function(NULL, getThis(), &func_regexReplace, return_value, 3, args); + zval args[] = { + pattern, + replacement, + }; + call_user_function(NULL, getThis(), &func_regexReplace, return_value, 2, args); } ZEND_BEGIN_ARG_INFO(arginfo_trim, 1) ZEND_ARG_INFO(0, chars) @@ -596,7 +609,7 @@ ZEND_ARG_INFO(0, string) ZEND_ARG_INFO(0, option) ZEND_END_ARG_INFO(); -static void once_listener_handler(INTERNAL_FUNCTION_PARAMETERS) +static void swap_case_handler(INTERNAL_FUNCTION_PARAMETERS) { zval *arr; @@ -604,33 +617,34 @@ static void once_listener_handler(INTERNAL_FUNCTION_PARAMETERS) Z_PARAM_ARRAY(arr) ZEND_PARSE_PARAMETERS_END(); - zval *ret = zend_hash_index_find(Z_ARRVAL_P(arr), 0); + zval *first = zend_hash_index_find(Z_ARRVAL_P(arr), 0); - if (ret == NULL) { + if (first == NULL) { RETURN_EMPTY_STRING(); } - zval func = {}; + zval func, ret; ZVAL_STRING(&func, "mb_strtoupper"); zval args[] = { - *ret, + *first, }; - call_user_function(NULL, NULL, &func, return_value, 1, args); + call_user_function(NULL, NULL, &func, &ret, 1, args); - if (zend_string_equals(Z_STR_P(return_value), Z_STR_P(ret)) == 1) { + if (zend_string_equals(Z_STR_P(&ret), Z_STR_P(first)) == 1) { + php_var_dump(&ret, 1); ZVAL_STRING(&func, "mb_strtolower"); zval args[] = { - *ret, + *first, }; - call_user_function(NULL, NULL, &func, return_value, 1, args); + call_user_function(NULL, NULL, &func, &ret, 1, args); } - RETURN_ZVAL(return_value, 0, 1); + RETURN_ZVAL(&ret, 0, 1); } PHP_METHOD(Stringy, swapCase) { - zval rv, func, pattern={}, subject, limit_str, count, ret, encoding; + zval rv, func, pattern={}, subject, limit_str, count, ret; ZVAL_STRING(&pattern, "/[\\S]/u"); @@ -652,7 +666,7 @@ PHP_METHOD(Stringy, swapCase) zendFunction.common.scope = NULL; zendFunction.common.fn_flags = ZEND_ACC_CLOSURE; zendFunction.common.function_name = f; - zendFunction.internal_function.handler = once_listener_handler; + zendFunction.internal_function.handler = swap_case_handler; zendFunction.internal_function.type = ZEND_INTERNAL_FUNCTION; zendFunction.internal_function.fn_flags = ZEND_ACC_CLOSURE; zendFunction.internal_function.arg_info = zai; @@ -662,33 +676,13 @@ PHP_METHOD(Stringy, swapCase) zval callback; zend_create_closure(&callback, &zendFunction, NULL, NULL, NULL); - zval arr; - array_init(&arr); - add_assoc_string(&arr, "1", "b"); - zval args1[] = { - arr - }; - - call_user_function(NULL, NULL, &callback, return_value, 1, args1); - - -#if ZEND_DEBUG - ZEND_ASSERT(1); -#endif - - ZVAL_MAKE_REF(&count); ZVAL_STRING(&func, "preg_replace_callback"); - ZVAL_LONG(&limit_str, -1); - zval args[] ={ pattern, callback, subject, - limit_str, - count, }; - - call_user_function(NULL, NULL, &func, &ret, 5, args); + call_user_function(NULL, NULL, &func, &ret, 3, args); convert_to_string(&ret); zend_update_property_string(stringy_ce, getThis(), ZEND_STRL("str"), Z_STRVAL(ret)); @@ -964,6 +958,7 @@ static zend_function_entry methods[] = { PHP_ME(Stringy, prepend, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, lines, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, split, arginfo_split, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, trim, arginfo_trim, ZEND_ACC_PUBLIC) PHP_FE_END }; diff --git a/startup.php b/startup.php index 68a6ed3..79496b0 100644 --- a/startup.php +++ b/startup.php @@ -1,4 +1,6 @@ "; $module = 'startup'; @@ -68,22 +70,18 @@ function checkExt() _ns(NS_STRINGY); -// $x = _('Stringy', ['test test2 test3', 'UTF-8']); - $data = [ - ['', '', '', ''], - ['bar', 'foo', 'f[o]+', 'bar'], - ['o bar', 'foo bar', 'f(o)o', '\1'], - ['bar', 'foo bar', 'f[O]+\s', '', 'i'], - ['foo', 'bar', '[[:alpha:]]{3}', 'foo'], - ['', '', '', '', 'msr', 'UTF-8'], - ['bàř', 'fòô ', 'f[òô]+\s', 'bàř', 'msr', 'UTF-8'], - ['fòô', 'fò', '(ò)', '\\1ô', 'msr', 'UTF-8'], - ['fòô', 'bàř', '[[:alpha:]]{3}', 'fòô', 'msr', 'UTF-8'] + ['', null], + ['', false], + ['1', true], + ['-9', -9], + ['1.18', 1.18], + [' string ', ' string '], + ['❤', '❤'], ]; -foreach($data as $value) { - @list($expected, $str, $pattern, $replacement, $options, $encoding) = $value; - $x = __('Stringy')::create($str, 'UTF-8')->regexReplace($pattern, $replacement, $options); - var_dump((string)$x == $expected); +foreach($data as $v) { + list($key, $value) = $v; + var_dump(new Stringy($value)); + // var_dump((string) _($this->class, [$value])) } From ece320a226ea70ae3a03fdb23b43c834b3dde94f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Sat, 8 Dec 2018 18:12:46 +0800 Subject: [PATCH 056/126] Feature/stringy camelize (#16) --- .vscode/settings.json | 39 +------ spec/Stringy/StringySpec.php | 32 ++++++ src/Minbaby/Php/Stringy/Stringy.php | 28 ++++- src/ext/stringy/stringy.c | 170 ++++++++++++++++++++++++++-- startup.php | 112 +++++------------- 5 files changed, 248 insertions(+), 133 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 666d134..273ca05 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,45 +1,10 @@ { "files.associations": { - "php.h": "c", - "php_ini.h": "c", - "zend.h": "c", - "type_traits": "c", - "typeinfo": "cpp", - "stdarg.h": "c", - "common.h": "c", - "config.h": "c", - "stringy.h": "c", - "php_standard.h": "c", - "spl_exceptions.h": "c", - "php_spl.h": "c", - "zend_exceptions.h": "c", - "zend_interfaces.h": "c", - "php_mt_rand.h": "c", - "spl_array.h": "c", - "mbstring.h": "c", - "__locale": "c", - "__string": "c", - "string": "c", - "string_view": "c", - "spl_iterators.h": "c", - "iosfwd": "c", - "functions.h": "c", - "__bit_reference": "c", - "hash_map": "c", - "unordered_map": "c", - "memory": "c", - "utility": "c", - "__functional_base": "c", - "atomic": "c", - "functional": "c", - "iterator": "c", - "limits": "c", - "tuple": "c", - "vector": "c" + "*.h": "c" }, "editor.mouseWheelZoom": false, "files.autoSave": "onFocusChange", - "editor.fontSize": 16, + "editor.fontSize": 14, "editor.renderWhitespace": "boundary", "editor.cursorStyle": "line-thin", "files.exclude": { diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index d12acae..71c2692 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -304,6 +304,38 @@ }); + it('test testCamelize', function () { + $data = [ + ['camelCase', 'CamelCase'], + ['camelCase', 'Camel-Case'], + ['camelCase', 'camel case'], + ['camelCase', 'camel -case'], + ['camelCase', 'camel - case'], + ['camelCase', 'camel_case'], + ['camelCTest', 'camel c test'], + ['stringWith1Number', 'string_with1number'], + ['stringWith22Numbers', 'string-with-2-2 numbers'], + ['dataRate', 'data_rate'], + ['backgroundColor', 'background-color'], + ['yesWeCan', 'yes_we_can'], + ['mozSomething', '-moz-something'], + ['carSpeed', '_car_speed_'], + ['serveHTTP', 'ServeHTTP'], + ['1Camel2Case', '1camel2case'], + ['camelΣase', 'camel σase', 'UTF-8'], + ['στανιλCase', 'Στανιλ case', 'UTF-8'], + ['σamelCase', 'σamel Case', 'UTF-8'] + ]; + foreach($data as $value) { + @list($expected, $str, $encoding) = $value; + $stringy = __('Stringy')::create($str, $encoding); + $result = $stringy->camelize(); + \expect($result)->toBeAnInstanceOf(__('Stringy')); + \expect((string)$stringy)->toBe($str); + \expect((string)$result)->toBe($expected); + } + }); + it('test regexReplce', function () { $data = [ diff --git a/src/Minbaby/Php/Stringy/Stringy.php b/src/Minbaby/Php/Stringy/Stringy.php index 49a952e..9b7abaa 100644 --- a/src/Minbaby/Php/Stringy/Stringy.php +++ b/src/Minbaby/Php/Stringy/Stringy.php @@ -263,9 +263,33 @@ public function split($pattern, $limit = null) public function lowerCaseFirst() { $first = \mb_substr($this->str, 0, 1, $this->encoding); - $rest = \mb_substr($this->str, 1, $this->length() - 1, - $this->encoding); + $rest = \mb_substr($this->str, 1, $this->length() - 1, $this->encoding); $str = \mb_strtolower($first, $this->encoding) . $rest; return static::create($str, $this->encoding); } + + public function camelize() + { + $encoding = $this->encoding; + $stringy = $this->trim()->lowerCaseFirst(); + $stringy->str = preg_replace('/^[-_]+/', '', $stringy->str); + $stringy->str = preg_replace_callback( + '/[-_\s]+(.)?/u', + function ($match) use ($encoding) { + if (isset($match[1])) { + return \mb_strtoupper($match[1], $encoding); + } + return ''; + }, + $stringy->str + ); + $stringy->str = preg_replace_callback( + '/[\d]+(.)?/u', + function ($match) use ($encoding) { + return \mb_strtoupper($match[0], $encoding); + }, + $stringy->str + ); + return $stringy; + } } diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index 5353ea2..deb33c0 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -491,12 +491,15 @@ PHP_METHOD(Stringy, regexReplace) args[0] = *encoding; call_user_function(NULL, getThis(), &func, return_value, 1, args); - zval args_eregReplace[4], retStr; + zval retStr; ZVAL_STRING(&func, "eregReplace"); - args_eregReplace[0] = *pattern; - args_eregReplace[1] = *replacement; - args_eregReplace[2] = *str; - args_eregReplace[3] = *options; + + zval args_eregReplace[] = { + *pattern, + *replacement, + *str, + *options, + }; call_user_function(NULL, getThis(), &func, &retStr, 4, args_eregReplace); ZVAL_STRING(&func, "regexEncoding"); @@ -580,7 +583,7 @@ ZEND_END_ARG_INFO(); PHP_METHOD(Stringy, eregReplace) { - zval *pattern, *replace, *string, *option; + zval *pattern, *replace, *string, *option = NULL; ZEND_PARSE_PARAMETERS_START(3, 4) Z_PARAM_ZVAL(pattern) Z_PARAM_ZVAL(replace) @@ -594,12 +597,15 @@ PHP_METHOD(Stringy, eregReplace) convert_to_string(string); convert_to_string(option); - zval func, args[4]; + zval func; ZVAL_STRING(&func, "mb_ereg_replace"); - args[0] = *pattern; - args[1] = *replace; - args[2] = *string; - args[3] = *option; + + zval args[] = { + *pattern, + *replace, + *string, + *option, + }; call_user_function(NULL, NULL, &func, return_value, 4, args); } ZEND_BEGIN_ARG_INFO(arginfo_eregReplace, 4) @@ -784,7 +790,7 @@ PHP_METHOD(Stringy, lowerCaseFirst) object_init_ex(&this, stringy_ce); zend_call_method(&this, stringy_ce, NULL, ZEND_STRL("__construct"), return_value, 2, &ret, &encoding); - RETURN_ZVAL(&this, 0, 1); + RETURN_ZVAL(&this, 1, 0); } PHP_METHOD(Stringy, append) @@ -930,6 +936,145 @@ ZEND_BEGIN_ARG_INFO(arginfo_split, 2) ZEND_ARG_INFO(0, limit_str) ZEND_END_ARG_INFO(); +static void preg_replace_callback_handler(INTERNAL_FUNCTION_PARAMETERS) +{ + zval *arr = NULL; + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ARRAY(arr) + ZEND_PARSE_PARAMETERS_END(); + + if (arr == NULL || zend_array_count(Z_ARRVAL_P(arr)) <= 1) { + RETURN_EMPTY_STRING(); + } + + zval *first = zend_hash_index_find(Z_ARRVAL_P(arr), 1); + // php_var_dump(arr, 1); + // php_var_dump(first, 1); + //TODO: 不知道这里如何模拟 php 里边的use, 这里先写死了 + zval encoding; + ZVAL_STRING(&encoding, "UTF-8"); + zval func, args[] = { + *first, + encoding, + }; + ZVAL_STRING(&func, "mb_strtoupper"); + call_user_function(NULL, NULL, &func, return_value, 2, args); +} + + +static void preg_replace_callback_2_handler(INTERNAL_FUNCTION_PARAMETERS) +{ + zval *arr = NULL; + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ARRAY(arr) + ZEND_PARSE_PARAMETERS_END(); + + if (arr == NULL || zend_array_count(Z_ARRVAL_P(arr)) < 1) { + RETURN_EMPTY_STRING(); + } + + zval *first = zend_hash_index_find(Z_ARRVAL_P(arr), 0); + + //TODO: 不知道这里如何模拟 php 里边的use, 这里先写死了 + zval encoding; + ZVAL_STRING(&encoding, "UTF-8"); + zval func, args[] = { + *first, + encoding, + }; + ZVAL_STRING(&func, "mb_strtoupper"); + call_user_function(NULL, NULL, &func, return_value, 2, args); +} + +PHP_METHOD(Stringy, camelize) +{ + zval rv, func; + zval *encoding = zend_read_property(stringy_ce, getThis(), ZEND_STRL("encoding"), 1, &rv); + + zval instance; + + ZVAL_STRING(&func, "trim"); + call_user_function(NULL, getThis(), &func, return_value, 0, NULL); + + ZVAL_STRING(&func, "lowerCaseFirst"); + call_user_function(NULL, return_value, &func, &instance, 0, NULL); + + zval *str_zval = zend_read_property(stringy_ce, &instance, ZEND_STRL("str"), 1, &rv); + + zval pattern, replacement; + ZVAL_STRING(&pattern, "/^[-_]+/"); + ZVAL_EMPTY_STRING(&replacement); + zval args[] = { + pattern, + replacement, + *str_zval, + }; + ZVAL_STRING(&func, "preg_replace"); + call_user_function(NULL, NULL, &func, return_value, 3, args); + zend_update_property(stringy_ce, &instance, ZEND_STRL("str"), return_value); + + zend_function zendFunction; + + zend_internal_arg_info zai[] = { + ZEND_ARG_ARRAY_INFO(0, "matches", 0) + }; +#pragma region first + zend_string *f = zend_string_init(ZEND_STRL("callback"), 0); + + zendFunction.type = ZEND_INTERNAL_FUNCTION; + zendFunction.common.num_args = 1; + zendFunction.common.required_num_args = 1; + zendFunction.common.arg_info = zai; + zendFunction.common.prototype = NULL; + zendFunction.common.scope = NULL; + zendFunction.common.fn_flags = ZEND_ACC_CLOSURE; + zendFunction.common.function_name = f; + zendFunction.internal_function.handler = preg_replace_callback_handler; + zendFunction.internal_function.type = ZEND_INTERNAL_FUNCTION; + zendFunction.internal_function.fn_flags = ZEND_ACC_CLOSURE; + zendFunction.internal_function.arg_info = zai; + zendFunction.internal_function.required_num_args =1; + zendFunction.internal_function.num_args = 1; + + zval callback; + zend_create_closure(&callback, &zendFunction, NULL, NULL, NULL); + + str_zval = zend_read_property(stringy_ce, &instance, ZEND_STRL("str"), 1, &rv); + ZVAL_STRING(&pattern, "/[-_\\s]+(.)?/u"); + ZVAL_EMPTY_STRING(&replacement); + zval args_callback[] = { + pattern, + callback, + *str_zval, + }; + ZVAL_STRING(&func, "preg_replace_callback"); + call_user_function(NULL, NULL, &func, return_value, 3, args_callback); +#pragma endregion + + zend_update_property(stringy_ce, &instance, ZEND_STRL("str"), return_value); + +#pragma region second + + zendFunction.internal_function.handler = preg_replace_callback_2_handler; + + zend_create_closure(&callback, &zendFunction, NULL, NULL, NULL); + + str_zval = zend_read_property(stringy_ce, &instance, ZEND_STRL("str"), 1, &rv); + ZVAL_STRING(&pattern, "/[\\d]+(.)?/u"); + ZVAL_EMPTY_STRING(&replacement); + args_callback[0] = pattern; + args_callback[1] = callback; + args_callback[2] = *str_zval; + + ZVAL_STRING(&func, "preg_replace_callback"); + call_user_function(NULL, NULL, &func, return_value, 3, args_callback); +#pragma endregion + + zend_update_property(stringy_ce, &instance, ZEND_STRL("str"), return_value); + + RETURN_ZVAL(&instance, 1, 0); +} + static zend_function_entry methods[] = { PHP_ME(Stringy, __construct, arginfo___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) PHP_ME(Stringy, __toString, NULL, ZEND_ACC_PUBLIC) @@ -958,6 +1103,7 @@ static zend_function_entry methods[] = { PHP_ME(Stringy, prepend, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, lines, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, split, arginfo_split, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, camelize, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, trim, arginfo_trim, ZEND_ACC_PUBLIC) PHP_FE_END }; diff --git a/startup.php b/startup.php index 79496b0..68a43a8 100644 --- a/startup.php +++ b/startup.php @@ -1,87 +1,35 @@ "; -$module = 'startup'; - -function handleFunc() -{ - global $br, $module; - - $function = 'confirm_' . $module . '_compiled'; - if (extension_loaded($module)) { - $str = $function($module); - } else { - $str = "Module $module is not compiled into PHP"; - } - echo "$str\n"; -} - -function handleClass() -{ - if (class_exists('myclass')) { - echo 'myclass exists'; - } else { - echo 'myclass exists'; - } - - $class = new myclass(); - var_dump($class); - $class->abab(); -} - -function checkExt() -{ - global $br, $module; - if (!extension_loaded('startup')) { - dl('startup.' . PHP_SHLIB_SUFFIX); - } - $module = 'startup'; - $functions = get_extension_funcs($module); - echo "Functions available in the test extension:$br\n"; - foreach ($functions as $func) { - echo $func . "$br\n"; - } - echo "$br\n"; -} - include __DIR__ . '/vendor/autoload.php'; -// include __DIR__ . "/spec/const.php"; -// include __DIR__ . "/spec/functions.php"; - -// function main() { -// _ns(NS_STRINGY); -// $stringy = __('Stringy')::create('Fòô Bàř', 'UTF-8'); -// $stringy = $stringy->swapCase(); -// // var_dump($stringy->test()); -// $valResult = []; -// foreach ($stringy as $char) { -// $valResult[] = $char; -// } -// // var_dump($valResult, function($a){}); -// // $keyValResult = []; -// // foreach ($stringy as $pos => $char) { -// // $keyValResult[$pos] = $char; -// // } -// } - - -// main(); - _ns(NS_STRINGY); -$data = [ - ['', null], - ['', false], - ['1', true], - ['-9', -9], - ['1.18', 1.18], - [' string ', ' string '], - ['❤', '❤'], -]; -foreach($data as $v) { - list($key, $value) = $v; - var_dump(new Stringy($value)); - // var_dump((string) _($this->class, [$value])) -} +// $data = [ +// ['camelCase', 'CamelCase'], +// ['camelCase', 'Camel-Case'], +// ['camelCase', 'camel case'], +// ['camelCase', 'camel -case'], +// ['camelCase', 'camel - case'], +// ['camelCase', 'camel_case'], +// ['camelCTest', 'camel c test'], +// ['stringWith1Number', 'string_with1number'], +// ['stringWith22Numbers', 'string-with-2-2 numbers'], +// ['dataRate', 'data_rate'], +// ['backgroundColor', 'background-color'], +// ['yesWeCan', 'yes_we_can'], +// ['mozSomething', '-moz-something'], +// ['carSpeed', '_car_speed_'], +// ['serveHTTP', 'ServeHTTP'], +// ['1Camel2Case', '1camel2case'], +// ['camelΣase', 'camel σase', 'UTF-8'], +// ['στανιλCase', 'Στανιλ case', 'UTF-8'], +// ['σamelCase', 'σamel Case', 'UTF-8'] +// ]; + +// foreach($data as $value) { +// @list($expected, $str, $encoding) = $value; +// $x = __('Stringy')::create($str, $encoding)->lowerCaseFirstY(); +// var_dump($x); +// } + +$x = __('Stringy')::create("")->camelize(); +var_dump(get_class_methods($x)); From 86c1ca869280c2b33835b5a4f95719c2386244d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Sat, 8 Dec 2018 21:57:11 +0800 Subject: [PATCH 057/126] Feature/stringy trim left (#17) * trimLeft test+php+ext --- spec/Stringy/StringySpec.php | 28 +++++++++++++++++ src/Minbaby/Php/Stringy/Stringy.php | 6 ++++ src/ext/stringy/stringy.c | 48 +++++++++++++++++++++++++++- startup.php | 49 +++++++++++++---------------- 4 files changed, 102 insertions(+), 29 deletions(-) diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index 71c2692..809339a 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -386,4 +386,32 @@ \expect((string)$result)->toBe($expected); } }); + + it('test trimLeft', function () { + $data = [ + ['foo bar ', ' foo bar '], + ['foo bar', ' foo bar'], + ['foo bar ', 'foo bar '], + ["foo bar \n\t", "\n\t foo bar \n\t"], + ['fòô bàř ', ' fòô bàř '], + ['fòô bàř', ' fòô bàř'], + ['fòô bàř ', 'fòô bàř '], + ['foo bar', '--foo bar', '-'], + ['fòô bàř', 'òòfòô bàř', 'ò', 'UTF-8'], + ["fòô bàř \n\t", "\n\t fòô bàř \n\t", null, 'UTF-8'], + ['fòô ', ' fòô ', null, 'UTF-8'], // narrow no-break space (U+202F) + ['fòô  ', '  fòô  ', null, 'UTF-8'], // medium mathematical space (U+205F) + ['fòô', '           fòô', null, 'UTF-8'] // spaces U+2000 to U+200A + ]; + + foreach($data as $value) { + @list($expected, $str, $chars, $encoding) = $value; + $stringy = __('Stringy')::create($str, $encoding); + $result = $stringy->trimLeft($chars); + + \expect($result)->toBeAnInstanceOf(__('Stringy')); + \expect((string)$stringy)->toBe($str); + \expect((string)$result)->toBe($expected); + } + }); }); diff --git a/src/Minbaby/Php/Stringy/Stringy.php b/src/Minbaby/Php/Stringy/Stringy.php index 9b7abaa..6cacfe9 100644 --- a/src/Minbaby/Php/Stringy/Stringy.php +++ b/src/Minbaby/Php/Stringy/Stringy.php @@ -292,4 +292,10 @@ function ($match) use ($encoding) { ); return $stringy; } + + public function trimLeft($chars = null) + { + $chars = ($chars) ? preg_quote($chars) : '[:space:]'; + return $this->regexReplace("^[$chars]+", ''); + } } diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index deb33c0..5bc1560 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -637,7 +637,6 @@ static void swap_case_handler(INTERNAL_FUNCTION_PARAMETERS) call_user_function(NULL, NULL, &func, &ret, 1, args); if (zend_string_equals(Z_STR_P(&ret), Z_STR_P(first)) == 1) { - php_var_dump(&ret, 1); ZVAL_STRING(&func, "mb_strtolower"); zval args[] = { *first, @@ -1075,6 +1074,52 @@ PHP_METHOD(Stringy, camelize) RETURN_ZVAL(&instance, 1, 0); } +PHP_METHOD(Stringy, trimLeft) +{ + zval *chars = NULL; + ZEND_PARSE_PARAMETERS_START(0, 1) + Z_PARAM_OPTIONAL + Z_PARAM_ZVAL(chars) + ZEND_PARSE_PARAMETERS_END(); + + if (chars != NULL && Z_TYPE_P(chars) != IS_NULL) + { + convert_to_string(chars); + if (Z_STRLEN_P(chars) == 0) { + chars = malloc(sizeof(zval)); + ZVAL_STRING(chars, "[:space:]"); + } else { + zval func, delimiter; + ZVAL_STRING(&func, "preg_quote"); + zval args[] = { + *chars, + }; + call_user_function(NULL, NULL, &func, return_value, 1, args); + ZVAL_STRING(chars, Z_STRVAL_P(return_value)); + } + } + else + { + chars = malloc(sizeof(zval)); + ZVAL_STRING(chars, "[:space:]"); + + } + + zval func_regexReplace, pattern, replacement, options; + ZVAL_STRING(&func_regexReplace, "regexReplace"); + zend_string *p = strpprintf(0, "^[%s]+", Z_STRVAL_P(chars)); + ZVAL_STR(&pattern, p); + ZVAL_STRING(&replacement, ""); + zval args[] = { + pattern, + replacement, + }; + call_user_function(NULL, getThis(), &func_regexReplace, return_value, 2, args); +} +ZEND_BEGIN_ARG_INFO(arginfo_trimLeft, 1) +ZEND_ARG_INFO(0, chars) +ZEND_END_ARG_INFO(); + static zend_function_entry methods[] = { PHP_ME(Stringy, __construct, arginfo___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) PHP_ME(Stringy, __toString, NULL, ZEND_ACC_PUBLIC) @@ -1105,6 +1150,7 @@ static zend_function_entry methods[] = { PHP_ME(Stringy, split, arginfo_split, ZEND_ACC_PUBLIC) PHP_ME(Stringy, camelize, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, trim, arginfo_trim, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, trimLeft, arginfo_trimLeft, ZEND_ACC_PUBLIC) PHP_FE_END }; diff --git a/startup.php b/startup.php index 68a43a8..0f887dd 100644 --- a/startup.php +++ b/startup.php @@ -3,33 +3,26 @@ _ns(NS_STRINGY); -// $data = [ -// ['camelCase', 'CamelCase'], -// ['camelCase', 'Camel-Case'], -// ['camelCase', 'camel case'], -// ['camelCase', 'camel -case'], -// ['camelCase', 'camel - case'], -// ['camelCase', 'camel_case'], -// ['camelCTest', 'camel c test'], -// ['stringWith1Number', 'string_with1number'], -// ['stringWith22Numbers', 'string-with-2-2 numbers'], -// ['dataRate', 'data_rate'], -// ['backgroundColor', 'background-color'], -// ['yesWeCan', 'yes_we_can'], -// ['mozSomething', '-moz-something'], -// ['carSpeed', '_car_speed_'], -// ['serveHTTP', 'ServeHTTP'], -// ['1Camel2Case', '1camel2case'], -// ['camelΣase', 'camel σase', 'UTF-8'], -// ['στανιλCase', 'Στανιλ case', 'UTF-8'], -// ['σamelCase', 'σamel Case', 'UTF-8'] -// ]; +$data = [ + ['foo bar ', ' foo bar '], + ['foo bar', ' foo bar'], + ['foo bar ', 'foo bar '], + ["foo bar \n\t", "\n\t foo bar \n\t"], + ['fòô bàř ', ' fòô bàř '], + ['fòô bàř', ' fòô bàř'], + ['fòô bàř ', 'fòô bàř '], + ['foo bar', '--foo bar', '-'], + ['fòô bàř', 'òòfòô bàř', 'ò', 'UTF-8'], + ["fòô bàř \n\t", "\n\t fòô bàř \n\t", null, 'UTF-8'], + ['fòô ', ' fòô ', null, 'UTF-8'], // narrow no-break space (U+202F) + ['fòô  ', '  fòô  ', null, 'UTF-8'], // medium mathematical space (U+205F) + ['fòô', '           fòô', null, 'UTF-8'] // spaces U+2000 to U+200A +]; -// foreach($data as $value) { -// @list($expected, $str, $encoding) = $value; -// $x = __('Stringy')::create($str, $encoding)->lowerCaseFirstY(); -// var_dump($x); -// } +foreach($data as $value) { + @list($expected, $str, $chars, $encoding) = $value; + $stringy = __('Stringy')::create($str, $encoding); + $result = $stringy->trimLeft($chars); -$x = __('Stringy')::create("")->camelize(); -var_dump(get_class_methods($x)); + // var_dump((string)$result); +} From 0f6c9d24fecc045552a0334755a3072ddbb0b27b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Sun, 9 Dec 2018 00:05:40 +0800 Subject: [PATCH 058/126] stringy trimRight test+php+ext (#18) --- spec/Stringy/StringySpec.php | 28 +++++++++++++++++ src/Minbaby/Php/Stringy/Stringy.php | 6 ++++ src/ext/stringy/stringy.c | 47 +++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+) diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index 809339a..0c9e19d 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -414,4 +414,32 @@ \expect((string)$result)->toBe($expected); } }); + + it('test trimRight', function () { + $data = [ + [' foo bar', ' foo bar '], + ['foo bar', 'foo bar '], + [' foo bar', ' foo bar'], + ["\n\t foo bar", "\n\t foo bar \n\t"], + [' fòô bàř', ' fòô bàř '], + ['fòô bàř', 'fòô bàř '], + [' fòô bàř', ' fòô bàř'], + ['foo bar', 'foo bar--', '-'], + ['fòô bàř', 'fòô bàřòò', 'ò', 'UTF-8'], + ["\n\t fòô bàř", "\n\t fòô bàř \n\t", null, 'UTF-8'], + [' fòô', ' fòô ', null, 'UTF-8'], // narrow no-break space (U+202F) + ['  fòô', '  fòô  ', null, 'UTF-8'], // medium mathematical space (U+205F) + ['fòô', 'fòô           ', null, 'UTF-8'] // spaces U+2000 to U+200A + ]; + + foreach($data as $value) { + @list($expected, $str, $chars, $encoding) = $value; + $stringy = __('Stringy')::create($str, $encoding); + $result = $stringy->trimRight($chars); + + \expect($result)->toBeAnInstanceOf(__('Stringy')); + \expect((string)$stringy)->toBe($str); + \expect((string)$result)->toBe($expected); + } + }); }); diff --git a/src/Minbaby/Php/Stringy/Stringy.php b/src/Minbaby/Php/Stringy/Stringy.php index 6cacfe9..7fd50e6 100644 --- a/src/Minbaby/Php/Stringy/Stringy.php +++ b/src/Minbaby/Php/Stringy/Stringy.php @@ -298,4 +298,10 @@ public function trimLeft($chars = null) $chars = ($chars) ? preg_quote($chars) : '[:space:]'; return $this->regexReplace("^[$chars]+", ''); } + + public function trimRight($chars = null) + { + $chars = ($chars) ? preg_quote($chars) : '[:space:]'; + return $this->regexReplace("[$chars]+\$", ''); + } } diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index 5bc1560..d7147ca 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -1120,6 +1120,52 @@ ZEND_BEGIN_ARG_INFO(arginfo_trimLeft, 1) ZEND_ARG_INFO(0, chars) ZEND_END_ARG_INFO(); +PHP_METHOD(Stringy, trimRight) +{ + zval *chars = NULL; + ZEND_PARSE_PARAMETERS_START(0, 1) + Z_PARAM_OPTIONAL + Z_PARAM_ZVAL(chars) + ZEND_PARSE_PARAMETERS_END(); + + if (chars != NULL && Z_TYPE_P(chars) != IS_NULL) + { + convert_to_string(chars); + if (Z_STRLEN_P(chars) == 0) { + chars = malloc(sizeof(zval)); + ZVAL_STRING(chars, "[:space:]"); + } else { + zval func, delimiter; + ZVAL_STRING(&func, "preg_quote"); + zval args[] = { + *chars, + }; + call_user_function(NULL, NULL, &func, return_value, 1, args); + ZVAL_STRING(chars, Z_STRVAL_P(return_value)); + } + } + else + { + chars = malloc(sizeof(zval)); + ZVAL_STRING(chars, "[:space:]"); + + } + + zval func_regexReplace, pattern, replacement, options; + ZVAL_STRING(&func_regexReplace, "regexReplace"); + zend_string *p = strpprintf(0, "[%s]+$", Z_STRVAL_P(chars)); + ZVAL_STR(&pattern, p); + ZVAL_STRING(&replacement, ""); + zval args[] = { + pattern, + replacement, + }; + call_user_function(NULL, getThis(), &func_regexReplace, return_value, 2, args); +} +ZEND_BEGIN_ARG_INFO(arginfo_trimRight, 1) +ZEND_ARG_INFO(0, chars) +ZEND_END_ARG_INFO(); + static zend_function_entry methods[] = { PHP_ME(Stringy, __construct, arginfo___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) PHP_ME(Stringy, __toString, NULL, ZEND_ACC_PUBLIC) @@ -1151,6 +1197,7 @@ static zend_function_entry methods[] = { PHP_ME(Stringy, camelize, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, trim, arginfo_trim, ZEND_ACC_PUBLIC) PHP_ME(Stringy, trimLeft, arginfo_trimLeft, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, trimRight, arginfo_trimRight, ZEND_ACC_PUBLIC) PHP_FE_END }; From 7dbc1e0c1071ff716af64c4b020326a5c29408c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Sun, 9 Dec 2018 13:43:20 +0800 Subject: [PATCH 059/126] =?UTF-8?q?stringy-at=20=E8=A1=A5=E5=85=85test=20(?= =?UTF-8?q?#20)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- spec/Stringy/StringySpec.php | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index 0c9e19d..9762d91 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -442,4 +442,27 @@ \expect((string)$result)->toBe($expected); } }); + + it('test at', function () { + + $data = [ + ['f', 'foo bar', 0], + ['o', 'foo bar', 1], + ['r', 'foo bar', 6], + ['', 'foo bar', 7], + ['f', 'fòô bàř', 0, 'UTF-8'], + ['ò', 'fòô bàř', 1, 'UTF-8'], + ['ř', 'fòô bàř', 6, 'UTF-8'], + ['', 'fòô bàř', 7, 'UTF-8'], + ]; + + foreach($data as $value) { + @list($expected, $str, $index, $encoding) = $value; + $stringy = __('Stringy')::create($str, $encoding); + $result = $stringy->at($index); + \expect($result)->toBeAnInstanceOf(__('Stringy')); + \expect((string)$stringy)->toBe($str); + \expect((string)$result)->toBe($expected); + } + }); }); From 9a87476fdcb69868ed6a9be248eb5cc33dba6fc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Sun, 9 Dec 2018 18:15:53 +0800 Subject: [PATCH 060/126] stringy-between, test+php+ext (#21) --- .vscode/snnipt.code-snippets | 2 +- README.MD | 4 +- spec/Stringy/StringySpec.php | 30 ++++++++++++ src/Minbaby/Php/Stringy/Stringy.php | 14 ++++++ src/ext/stringy/stringy.c | 73 +++++++++++++++++++++++++++++ 5 files changed, 120 insertions(+), 3 deletions(-) diff --git a/.vscode/snnipt.code-snippets b/.vscode/snnipt.code-snippets index bae6f21..96b984a 100644 --- a/.vscode/snnipt.code-snippets +++ b/.vscode/snnipt.code-snippets @@ -62,7 +62,7 @@ "scope": "c,h", "body": [ "ZEND_BEGIN_ARG_INFO($1, $2)", - " ZEND_ARG_TYPE_$0", + " ZEND_ARG_INFO(0, $0)", "ZEND_END_ARG_INFO();" ], "description": "args" diff --git a/README.MD b/README.MD index 69afc01..68ec58f 100644 --- a/README.MD +++ b/README.MD @@ -1,8 +1,8 @@ # 学习 php 扩展 -[TOC] - [![CircleCI](https://circleci.com/gh/minbaby/php-ext-startup/tree/master.svg?style=svg)](https://circleci.com/gh/minbaby/php-ext-startup/tree/master) +[![xcxc](https://img.shields.io/github/license/minbaby/php-ext-startup.svg)](https://github.com/minbaby/php-ext-startup/blob/master/README.MD) + ## 基本思路 diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index 9762d91..4fc73fc 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -465,4 +465,34 @@ \expect((string)$result)->toBe($expected); } }); + + it('test between', function () { + $data = [ + ['', 'foo', '{', '}'], + ['', '{foo', '{', '}'], + ['foo', '{foo}', '{', '}'], + ['{foo', '{{foo}', '{', '}'], + ['', '{}foo}', '{', '}'], + ['foo', '}{foo}', '{', '}'], + ['foo', 'A description of {foo} goes here', '{', '}'], + ['bar', '{foo} and {bar}', '{', '}', 1], + ['', 'fòô', '{', '}', 0, 'UTF-8'], + ['', '{fòô', '{', '}', 0, 'UTF-8'], + ['fòô', '{fòô}', '{', '}', 0, 'UTF-8'], + ['{fòô', '{{fòô}', '{', '}', 0, 'UTF-8'], + ['', '{}fòô}', '{', '}', 0, 'UTF-8'], + ['fòô', '}{fòô}', '{', '}', 0, 'UTF-8'], + ['fòô', 'A description of {fòô} goes here', '{', '}', 0, 'UTF-8'], + ['bàř', '{fòô} and {bàř}', '{', '}', 1, 'UTF-8'] + ]; + foreach($data as $value) { + @list($expected, $str, $start, $end, $offset, $encoding) = $value; + $stringy = __('Stringy')::create($str, $encoding); + $result = $stringy->between($start, $end, $offset); + \expect($result)->toBeAnInstanceOf(__('Stringy')); + \expect((string)$stringy)->toBe($str); + \expect((string)$result)->toBe($expected); + } + + }); }); diff --git a/src/Minbaby/Php/Stringy/Stringy.php b/src/Minbaby/Php/Stringy/Stringy.php index 7fd50e6..5fa332a 100644 --- a/src/Minbaby/Php/Stringy/Stringy.php +++ b/src/Minbaby/Php/Stringy/Stringy.php @@ -304,4 +304,18 @@ public function trimRight($chars = null) $chars = ($chars) ? preg_quote($chars) : '[:space:]'; return $this->regexReplace("[$chars]+\$", ''); } + + public function between($start, $end, $offset = 0) + { + $startIndex = $this->indexOf($start, $offset); + if ($startIndex === false) { + return static::create('', $this->encoding); + } + $substrIndex = $startIndex + \mb_strlen($start, $this->encoding); + $endIndex = $this->indexOf($end, $substrIndex); + if ($endIndex === false) { + return static::create('', $this->encoding); + } + return $this->substr($substrIndex, $endIndex - $substrIndex); + } } diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index d7147ca..19d52fc 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -1166,6 +1166,78 @@ ZEND_BEGIN_ARG_INFO(arginfo_trimRight, 1) ZEND_ARG_INFO(0, chars) ZEND_END_ARG_INFO(); +PHP_METHOD(Stringy, between) +{ + zval *start_zval, *end_zval, *offset_zval = NULL; + ZEND_PARSE_PARAMETERS_START(2, 3) + Z_PARAM_ZVAL(start_zval) + Z_PARAM_ZVAL(end_zval) + Z_PARAM_OPTIONAL + Z_PARAM_ZVAL(offset_zval) + ZEND_PARSE_PARAMETERS_END(); + + convert_to_string(start_zval); + convert_to_string(start_zval); + convert_to_long(offset_zval); + + zval rv; + zval *encoding = zend_read_property(stringy_ce, getThis(), ZEND_STRL("encoding"), 0, &rv); + + zval empty; + ZVAL_EMPTY_STRING(&empty); + + zval instance; + object_init_ex(&instance, stringy_ce); + zend_call_method(&instance, stringy_ce, NULL, ZEND_STRL("__construct"), return_value, 2, &empty, encoding); + + zval func, args[] = { + *start_zval, + *offset_zval, + }; + ZVAL_STRING(&func, "indexOf"); + call_user_function(NULL, getThis(), &func, return_value, 2, args); + if (Z_TYPE_P(return_value) == IS_FALSE) { + RETURN_ZVAL(&instance, 0, 1); + } + size_t start_index_l = Z_LVAL_P(return_value); + + zval args_strlen[] = { + *start_zval, + *encoding, + }; + ZVAL_STRING(&func, "mb_strlen"); + call_user_function(NULL, NULL, &func, return_value, 2, args_strlen); + + size_t substrIndex = start_index_l + Z_LVAL_P(return_value); + zval substrIndex_zval; + ZVAL_LONG(&substrIndex_zval, substrIndex); + + zval args_indexOf[] = { + *end_zval, + substrIndex_zval, + }; + ZVAL_STRING(&func, "indexOf"); + call_user_function(NULL, getThis(), &func, return_value, 2, args_indexOf); + if (Z_TYPE_P(return_value) == IS_FALSE) { + RETURN_ZVAL(&instance, 0, 1); + } + size_t x_l = Z_LVAL_P(return_value) - substrIndex; + zval x_zval; + ZVAL_LONG(&x_zval, x_l); + + zval args_substr[] = { + substrIndex_zval, + x_zval, + }; + ZVAL_STRING(&func, "substr"); + call_user_function(NULL, getThis(), &func, return_value, 2, args_substr); +} +ZEND_BEGIN_ARG_INFO(arginfo_between, 3) + ZEND_ARG_INFO(0, start) + ZEND_ARG_INFO(0, end) + ZEND_ARG_INFO(0, offset) +ZEND_END_ARG_INFO(); + static zend_function_entry methods[] = { PHP_ME(Stringy, __construct, arginfo___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) PHP_ME(Stringy, __toString, NULL, ZEND_ACC_PUBLIC) @@ -1198,6 +1270,7 @@ static zend_function_entry methods[] = { PHP_ME(Stringy, trim, arginfo_trim, ZEND_ACC_PUBLIC) PHP_ME(Stringy, trimLeft, arginfo_trimLeft, ZEND_ACC_PUBLIC) PHP_ME(Stringy, trimRight, arginfo_trimRight, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, between, arginfo_between, ZEND_ACC_PUBLIC) PHP_FE_END }; From aa851a04813b6f2a22aeed252a15e084d6b1a540 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Sun, 9 Dec 2018 23:43:33 +0800 Subject: [PATCH 061/126] stringy::contains test+php+ext (#22) --- .vscode/settings.json | 3 +- spec/Stringy/StringySpec.php | 33 ++++++++++++++++++++ src/Minbaby/Php/Stringy/Stringy.php | 9 ++++++ src/ext/stringy/stringy.c | 47 +++++++++++++++++++++++++++++ startup.php | 2 ++ 5 files changed, 93 insertions(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 273ca05..f2f49eb 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -13,5 +13,6 @@ "**/.hg": true, "**/CVS": true, "**/.DS_Store": true - } + }, + "editor.minimap.enabled": false } diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index 4fc73fc..b00e739 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -493,6 +493,39 @@ \expect((string)$stringy)->toBe($str); \expect((string)$result)->toBe($expected); } + }); + it('test contains', function () { + $data = [ + [true, 'Str contains foo bar', 'foo bar'], + [true, '12398!@(*%!@# @!%#*&^%', ' @!%#*&^%'], + [true, 'Ο συγγραφέας είπε', 'συγγραφέας', 'UTF-8'], + [true, 'å´¥©¨ˆßå˚ ∆∂˙©å∑¥øœ¬', 'å´¥©', true, 'UTF-8'], + [true, 'å´¥©¨ˆßå˚ ∆∂˙©å∑¥øœ¬', 'å˚ ∆', true, 'UTF-8'], + [true, 'å´¥©¨ˆßå˚ ∆∂˙©å∑¥øœ¬', 'øœ¬', true, 'UTF-8'], + [false, 'Str contains foo bar', 'Foo bar'], + [false, 'Str contains foo bar', 'foobar'], + [false, 'Str contains foo bar', 'foo bar '], + [false, 'Ο συγγραφέας είπε', ' συγγραφέας ', true, 'UTF-8'], + [false, 'å´¥©¨ˆßå˚ ∆∂˙©å∑¥øœ¬', ' ßå˚', true, 'UTF-8'], + [true, 'Str contains foo bar', 'Foo bar', false], + [true, '12398!@(*%!@# @!%#*&^%', ' @!%#*&^%', false], + [true, 'Ο συγγραφέας είπε', 'ΣΥΓΓΡΑΦΈΑΣ', false, 'UTF-8'], + [true, 'å´¥©¨ˆßå˚ ∆∂˙©å∑¥øœ¬', 'Å´¥©', false, 'UTF-8'], + [true, 'å´¥©¨ˆßå˚ ∆∂˙©å∑¥øœ¬', 'Å˚ ∆', false, 'UTF-8'], + [true, 'å´¥©¨ˆßå˚ ∆∂˙©å∑¥øœ¬', 'ØŒ¬', false, 'UTF-8'], + [false, 'Str contains foo bar', 'foobar', false], + [false, 'Str contains foo bar', 'foo bar ', false], + [false, 'Ο συγγραφέας είπε', ' συγγραφέας ', false, 'UTF-8'], + [false, 'å´¥©¨ˆßå˚ ∆∂˙©å∑¥øœ¬', ' ßÅ˚', false, 'UTF-8'] + ]; + foreach($data as $value) { + @list($expected, $haystack, $needle, $caseSensitive, $encoding) = $value; + $stringy = __('Stringy')::create($haystack, $encoding); + $result = $stringy->contains($needle, $caseSensitive === true || $caseSensitive === NULL); // 默认值是 NULl, 这里需要特殊处理 + \expect($result)->toBeA('bool'); + \expect((string)$stringy)->toBe($haystack); + \expect((bool)$result)->toBe($expected); + } }); }); diff --git a/src/Minbaby/Php/Stringy/Stringy.php b/src/Minbaby/Php/Stringy/Stringy.php index 5fa332a..6c07886 100644 --- a/src/Minbaby/Php/Stringy/Stringy.php +++ b/src/Minbaby/Php/Stringy/Stringy.php @@ -318,4 +318,13 @@ public function between($start, $end, $offset = 0) } return $this->substr($substrIndex, $endIndex - $substrIndex); } + + public function contains($needle, $caseSensitive = true) + { + $encoding = $this->encoding; + if ($caseSensitive) { + return (\mb_strpos($this->str, $needle, 0, $encoding) !== false); + } + return (\mb_stripos($this->str, $needle, 0, $encoding) !== false); + } } diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index 19d52fc..a404dc5 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -1238,6 +1238,52 @@ ZEND_BEGIN_ARG_INFO(arginfo_between, 3) ZEND_ARG_INFO(0, offset) ZEND_END_ARG_INFO(); +PHP_METHOD(Stringy, contains) +{ + zval *needle, *caseSensitive = NULL; + ZEND_PARSE_PARAMETERS_START(1, 2) + Z_PARAM_ZVAL(needle) + Z_PARAM_OPTIONAL + Z_PARAM_ZVAL(caseSensitive) + ZEND_PARSE_PARAMETERS_END(); + + convert_to_boolean(caseSensitive); + + zval rv; + zval *encoding = zend_read_property(stringy_ce, getThis(), ZEND_STRL("encoding"), 0, &rv); + zval *str = zend_read_property(stringy_ce, getThis(), ZEND_STRL("str"), 0, &rv); + + zval z, func; + ZVAL_LONG(&z, 0); + + if (Z_TYPE_P(caseSensitive) == IS_TRUE) { + zval args[] = { + *str, + *needle, + z, + *encoding, + }; + ZVAL_STRING(&func, "mb_strpos"); + call_user_function(NULL, NULL, &func, return_value, 4, args); + ZVAL_BOOL(return_value, Z_TYPE_P(return_value) != IS_FALSE); + return; + } + + zval args_i[] = { + *str, + *needle, + z, + *encoding, + }; + ZVAL_STRING(&func, "mb_stripos"); + call_user_function(NULL, NULL, &func, return_value, 4, args_i); + ZVAL_BOOL(return_value, Z_TYPE_P(return_value) != IS_FALSE); +} +ZEND_BEGIN_ARG_INFO(arginfo_contains, 3) + ZEND_ARG_INFO(0, needle) + ZEND_ARG_INFO(0, caseSensitive) +ZEND_END_ARG_INFO(); + static zend_function_entry methods[] = { PHP_ME(Stringy, __construct, arginfo___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) PHP_ME(Stringy, __toString, NULL, ZEND_ACC_PUBLIC) @@ -1271,6 +1317,7 @@ static zend_function_entry methods[] = { PHP_ME(Stringy, trimLeft, arginfo_trimLeft, ZEND_ACC_PUBLIC) PHP_ME(Stringy, trimRight, arginfo_trimRight, ZEND_ACC_PUBLIC) PHP_ME(Stringy, between, arginfo_between, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, contains, arginfo_contains, ZEND_ACC_PUBLIC) PHP_FE_END }; diff --git a/startup.php b/startup.php index 0f887dd..1ccacb7 100644 --- a/startup.php +++ b/startup.php @@ -26,3 +26,5 @@ // var_dump((string)$result); } + +var_dump(mb_strpos('Str contains foo bar', 'Foo bar', 0, "UTF-8")); From 1269693d2ce1aa9ba63b94f5990145b2c8a8f630 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Tue, 11 Dec 2018 23:41:04 +0800 Subject: [PATCH 062/126] stringy-containsAll test+php+ext (#23) --- spec/Stringy/StringySpec.php | 66 +++++++++++++++++++++++++---- src/Minbaby/Php/Stringy/Stringy.php | 13 ++++++ src/ext/stringy/stringy.c | 40 +++++++++++++++++ 3 files changed, 110 insertions(+), 9 deletions(-) diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index b00e739..7e9b504 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -495,7 +495,7 @@ } }); - it('test contains', function () { + \context('', function(){ $data = [ [true, 'Str contains foo bar', 'foo bar'], [true, '12398!@(*%!@# @!%#*&^%', ' @!%#*&^%'], @@ -519,13 +519,61 @@ [false, 'Ο συγγραφέας είπε', ' συγγραφέας ', false, 'UTF-8'], [false, 'å´¥©¨ˆßå˚ ∆∂˙©å∑¥øœ¬', ' ßÅ˚', false, 'UTF-8'] ]; - foreach($data as $value) { - @list($expected, $haystack, $needle, $caseSensitive, $encoding) = $value; - $stringy = __('Stringy')::create($haystack, $encoding); - $result = $stringy->contains($needle, $caseSensitive === true || $caseSensitive === NULL); // 默认值是 NULl, 这里需要特殊处理 - \expect($result)->toBeA('bool'); - \expect((string)$stringy)->toBe($haystack); - \expect((bool)$result)->toBe($expected); - } + + $dataContainsAll = array_merge( + array_map(function ($array) { + $array[2] = [$array[2]]; + return $array; + }, $data), + [ + // One needle + [false, 'Str contains foo bar', []], + // Multiple needles + [true, 'Str contains foo bar', ['foo', 'bar']], + [true, '12398!@(*%!@# @!%#*&^%', [' @!%#*', '&^%']], + [true, 'Ο συγγραφέας είπε', ['συγγρ', 'αφέας'], 'UTF-8'], + [true, 'å´¥©¨ˆßå˚ ∆∂˙©å∑¥øœ¬', ['å´¥', '©'], true, 'UTF-8'], + [true, 'å´¥©¨ˆßå˚ ∆∂˙©å∑¥øœ¬', ['å˚ ', '∆'], true, 'UTF-8'], + [true, 'å´¥©¨ˆßå˚ ∆∂˙©å∑¥øœ¬', ['øœ', '¬'], true, 'UTF-8'], + [false, 'Str contains foo bar', ['Foo', 'bar']], + [false, 'Str contains foo bar', ['foobar', 'bar']], + [false, 'Str contains foo bar', ['foo bar ', 'bar']], + [false, 'Ο συγγραφέας είπε', [' συγγραφέας ', ' συγγραφ '], true, 'UTF-8'], + [false, 'å´¥©¨ˆßå˚ ∆∂˙©å∑¥øœ¬', [' ßå˚', ' ß '], true, 'UTF-8'], + [true, 'Str contains foo bar', ['Foo bar', 'bar'], false], + [true, '12398!@(*%!@# @!%#*&^%', [' @!%#*&^%', '*&^%'], false], + [true, 'Ο συγγραφέας είπε', ['ΣΥΓΓΡΑΦΈΑΣ', 'ΑΦΈΑ'], false, 'UTF-8'], + [true, 'å´¥©¨ˆßå˚ ∆∂˙©å∑¥øœ¬', ['Å´¥©', '¥©'], false, 'UTF-8'], + [true, 'å´¥©¨ˆßå˚ ∆∂˙©å∑¥øœ¬', ['Å˚ ∆', ' ∆'], false, 'UTF-8'], + [true, 'å´¥©¨ˆßå˚ ∆∂˙©å∑¥øœ¬', ['ØŒ¬', 'Œ'], false, 'UTF-8'], + [false, 'Str contains foo bar', ['foobar', 'none'], false], + [false, 'Str contains foo bar', ['foo bar ', ' ba'], false], + [false, 'Ο συγγραφέας είπε', [' συγγραφέας ', ' ραφέ '], false, 'UTF-8'], + [false, 'å´¥©¨ˆßå˚ ∆∂˙©å∑¥øœ¬', [' ßÅ˚', ' Å˚ '], false, 'UTF-8'], + ]); + + it('test contains', function () use ($data) { + + foreach($data as $value) { + @list($expected, $haystack, $needle, $caseSensitive, $encoding) = $value; + $stringy = __('Stringy')::create($haystack, $encoding); + $result = $stringy->contains($needle, $caseSensitive === true || $caseSensitive === NULL); // 默认值是 NULl, 这里需要特殊处理 + \expect($result)->toBeA('bool'); + \expect((string)$stringy)->toBe($haystack); + \expect((bool)$result)->toBe($expected); + } + }); + + it('test containsAll', function () use ($dataContainsAll) { + foreach($dataContainsAll as $value) { + @list($expected, $haystack, $needle, $caseSensitive, $encoding) = $value; + + $stringy = __('Stringy')::create($haystack, $encoding); + $result = $stringy->containsAll($needle, $caseSensitive === true || $caseSensitive === NULL); // 默认值是 NULl, 这里需要特殊处理 + \expect($result)->toBeA('bool'); + \expect((string)$stringy)->toBe($haystack); + \expect((bool)$result)->toBe($expected); + } + }); }); }); diff --git a/src/Minbaby/Php/Stringy/Stringy.php b/src/Minbaby/Php/Stringy/Stringy.php index 6c07886..c041b32 100644 --- a/src/Minbaby/Php/Stringy/Stringy.php +++ b/src/Minbaby/Php/Stringy/Stringy.php @@ -327,4 +327,17 @@ public function contains($needle, $caseSensitive = true) } return (\mb_stripos($this->str, $needle, 0, $encoding) !== false); } + + public function containsAll($needles, $caseSensitive = true) + { + if (empty($needles)) { + return false; + } + foreach ($needles as $needle) { + if (!$this->contains($needle, $caseSensitive)) { + return false; + } + } + return true; + } } diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index a404dc5..6a79f30 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -1284,6 +1284,45 @@ ZEND_BEGIN_ARG_INFO(arginfo_contains, 3) ZEND_ARG_INFO(0, caseSensitive) ZEND_END_ARG_INFO(); +PHP_METHOD(Stringy, containsAll) +{ + zval *needles = NULL, *caseSensitive = NULL; + ZEND_PARSE_PARAMETERS_START(1, 2) + Z_PARAM_ZVAL(needles) + Z_PARAM_OPTIONAL + Z_PARAM_ZVAL(caseSensitive) + ZEND_PARSE_PARAMETERS_END(); + + zval rv; + zval *encoding = zend_read_property(stringy_ce, getThis(), ZEND_STRL("encoding"), 0, &rv); + zval *str = zend_read_property(stringy_ce, getThis(), ZEND_STRL("str"), 0, &rv); + + convert_to_array(needles); + + if (zend_array_count(Z_ARRVAL_P(needles)) == 0) { + RETURN_BOOL(0); + } + + zval *needle; + ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(needles), needle){ + zval func, args[] = { + *needle, + *caseSensitive + }; + ZVAL_STRING(&func, "contains"); + call_user_function(NULL, getThis(), &func, return_value, 2, args); + if (Z_TYPE_P(return_value) == IS_FALSE) { + RETURN_BOOL(0); + } + }ZEND_HASH_FOREACH_END(); + + RETURN_BOOL(1); +} +ZEND_BEGIN_ARG_INFO(arginfo_containsAll, 3) + ZEND_ARG_INFO(0, needle) + ZEND_ARG_INFO(0, caseSensitive) +ZEND_END_ARG_INFO(); + static zend_function_entry methods[] = { PHP_ME(Stringy, __construct, arginfo___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) PHP_ME(Stringy, __toString, NULL, ZEND_ACC_PUBLIC) @@ -1318,6 +1357,7 @@ static zend_function_entry methods[] = { PHP_ME(Stringy, trimRight, arginfo_trimRight, ZEND_ACC_PUBLIC) PHP_ME(Stringy, between, arginfo_between, ZEND_ACC_PUBLIC) PHP_ME(Stringy, contains, arginfo_contains, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, containsAll, arginfo_containsAll, ZEND_ACC_PUBLIC) PHP_FE_END }; From 3cc01bdb441ace50277faad9416bbc9655b98bb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Thu, 13 Dec 2018 00:07:36 +0800 Subject: [PATCH 063/126] do code coverage something (#24) --- .circleci/config.yml | 2 +- .gitignore | 5 +- README.MD | 2 +- kahlan-config.php | 2 +- scripts/codecov.sh | 1550 ++++++++++++++++++++++++++++++++++++++++++ scripts/fetch.php | 2 +- scripts/test.sh | 3 +- 7 files changed, 1558 insertions(+), 8 deletions(-) create mode 100755 scripts/codecov.sh diff --git a/.circleci/config.yml b/.circleci/config.yml index 8ee1452..131b9ff 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -15,7 +15,7 @@ jobs: - checkout - run: name: composer install - command: composer install + command: composer install --no-interaction --prefer-source - run: name: run test command: ./vendor/bin/kahlan diff --git a/.gitignore b/.gitignore index 1572d00..2917c43 100644 --- a/.gitignore +++ b/.gitignore @@ -43,6 +43,7 @@ GPATH /vendor/ *.loT -core -.gdb_history +/core +/.gdb_history peda-session-php.txt +/coverage.xml diff --git a/README.MD b/README.MD index 68ec58f..ddf7c0f 100644 --- a/README.MD +++ b/README.MD @@ -2,7 +2,7 @@ [![CircleCI](https://circleci.com/gh/minbaby/php-ext-startup/tree/master.svg?style=svg)](https://circleci.com/gh/minbaby/php-ext-startup/tree/master) [![xcxc](https://img.shields.io/github/license/minbaby/php-ext-startup.svg)](https://github.com/minbaby/php-ext-startup/blob/master/README.MD) - +[![codecov](https://codecov.io/gh/minbaby/php-ext-startup/branch/master/graph/badge.svg)](https://codecov.io/gh/minbaby/php-ext-startup) ## 基本思路 diff --git a/kahlan-config.php b/kahlan-config.php index 1d57af1..73e0b0b 100644 --- a/kahlan-config.php +++ b/kahlan-config.php @@ -3,5 +3,5 @@ /**@var \Kahlan\Cli\CommandLine $commandLine */ $commandLine = $this->commandLine(); -$commandLine->option('reporter', 'default', 'verbose'); +// $commandLine->option('reporter', 'default', 'verbose'); $commandLine->option('ff', 'default', 1); diff --git a/scripts/codecov.sh b/scripts/codecov.sh new file mode 100755 index 0000000..1ef332b --- /dev/null +++ b/scripts/codecov.sh @@ -0,0 +1,1550 @@ +#!/usr/bin/env bash + +# Apache License Version 2.0, January 2004 +# https://github.com/codecov/codecov-bash/blob/master/LICENSE + + +set -e +o pipefail + +VERSION="0b37652" + +url="https://codecov.io" +env="$CODECOV_ENV" +service="" +token="" +search_in="" +flags="" +exit_with=0 +curlargs="" +curlawsargs="" +dump="0" +clean="0" +curl_s="-s" +name="$CODECOV_NAME" +include_cov="" +exclude_cov="" +ddp="$(echo ~)/Library/Developer/Xcode/DerivedData" +xp="" +files="" +cacert="$CODECOV_CA_BUNDLE" +gcov_ignore="-not -path './bower_components/**' -not -path './node_modules/**' -not -path './vendor/**'" +gcov_include="" + +ft_gcov="1" +ft_coveragepy="1" +ft_fix="1" +ft_search="1" +ft_s3="1" +ft_network="1" +ft_xcodellvm="1" +ft_xcodeplist="0" + +_git_root=$(git rev-parse --show-toplevel 2>/dev/null || hg root 2>/dev/null || echo $PWD) +git_root="$_git_root" +codecov_yml="" +remote_addr="" +if [ "$git_root" = "$PWD" ]; +then + git_root="." +fi + +url_o="" +pr_o="" +build_o="" +commit_o="" +search_in_o="" +tag_o="" +branch_o="" +slug_o="" +prefix_o="" + +commit="$VCS_COMMIT_ID" +branch="$VCS_BRANCH_NAME" +pr="$VCS_PULL_REQUEST" +slug="$VCS_SLUG" +tag="$VCS_TAG" +build_url="$CI_BUILD_URL" +build="$CI_BUILD_ID" +job="$CI_JOB_ID" + +beta_xcode_partials="" + +proj_root="$git_root" +gcov_exe="gcov" +gcov_arg="" + +b="\033[0;36m" +g="\033[0;32m" +r="\033[0;31m" +e="\033[0;90m" +x="\033[0m" + +show_help() { +cat << EOF + + Codecov Bash $VERSION + + Global report uploading tool for Codecov + Documentation at https://docs.codecov.io/docs + Contribute at https://github.com/codecov/codecov-bash + + + -h Display this help and exit + -f FILE Target file(s) to upload + + -f "path/to/file" only upload this file + skips searching unless provided patterns below + + -f '!*.bar' ignore all files at pattern *.bar + -f '*.foo' include all files at pattern *.foo + Must use single quotes. + This is non-exclusive, use -s "*.foo" to match specific paths. + + -s DIR Directory to search for coverage reports. + Already searches project root and artifact folders. + -t TOKEN Set the private repository token + (option) set environment variable CODECOV_TOKEN=:uuid + + -t @/path/to/token_file + -t uuid + + -n NAME Custom defined name of the upload. Visible in Codecov UI + + -e ENV Specify environment variables to be included with this build + Also accepting environment variables: CODECOV_ENV=VAR,VAR2 + + -e VAR,VAR2 + + -X feature Toggle functionalities + + -X gcov Disable gcov + -X coveragepy Disable python coverage + -X fix Disable report fixing + -X search Disable searching for reports + -X xcode Disable xcode processing + -X network Disable uploading the file network + + -R root dir Used when not in git/hg project to identify project root directory + -y conf file Used to specify the location of the .codecov.yml config file + -F flag Flag the upload to group coverage metrics + + -F unittests This upload is only unittests + -F integration This upload is only integration tests + -F ui,chrome This upload is Chrome - UI tests + + -c Move discovered coverage reports to the trash + -Z Exit with 1 if not successful. Default will Exit with 0 + + -- xcode -- + -D Custom Derived Data Path for Coverage.profdata and gcov processing + Default '~/Library/Developer/Xcode/DerivedData' + -J Specify packages to build coverage. + This can significantly reduces time to build coverage reports. + + -J 'MyAppName' Will match "MyAppName" and "MyAppNameTests" + -J '^ExampleApp$' Will match only "ExampleApp" not "ExampleAppTests" + + -- gcov -- + -g GLOB Paths to ignore during gcov gathering + -G GLOB Paths to include during gcov gathering + -p dir Project root directory + Also used when preparing gcov + -k prefix Prefix filepaths to help resolve path fixing: https://github.com/codecov/support/issues/472 + -x gcovexe gcov executable to run. Defaults to 'gcov' + -a gcovargs extra arguments to pass to gcov + + -- Override CI Environment Variables -- + These variables are automatically detected by popular CI providers + + -B branch Specify the branch name + -C sha Specify the commit sha + -P pr Specify the pull request number + -b build Specify the build number + -T tag Specify the git tag + + -- Enterprise -- + -u URL Set the target url for Enterprise customers + Not required when retrieving the bash uploader from your CCE + (option) Set environment variable CODECOV_URL=https://my-hosted-codecov.com + -r SLUG owner/repo slug used instead of the private repo token in Enterprise + (option) set environment variable CODECOV_SLUG=:owner/:repo + (option) set in your codecov.yml "codecov.slug" + -S PATH File path to your cacert.pem file used to verify ssl with Codecov Enterprise (optional) + (option) Set environment variable: CODECOV_CA_BUNDLE="/path/to/ca.pem" + -U curlargs Extra curl arguments to communicate with Codecov. e.g., -U "--proxy http://http-proxy" + -A curlargs Extra curl arguments to communicate with AWS. + + -- Debugging -- + -d Don't upload, but dump upload file to stdout + -K Remove color from the output + -v Verbose mode + +EOF +} + + +say() { + echo -e "$1" +} + + +urlencode() { + echo "$1" | curl -Gso /dev/null -w %{url_effective} --data-urlencode @- "" | cut -c 3- | sed -e 's/%0A//' +} + + +swiftcov() { + _dir=$(dirname "$1" | sed 's/\(Build\).*/\1/g') + for _type in app framework xctest + do + find "$_dir" -name "*.$_type" | while read f + do + _proj=${f##*/} + _proj=${_proj%."$_type"} + if [ "$2" = "" ] || [ "$(echo "$_proj" | grep -i "$2")" != "" ]; + then + say " $g+$x Building reports for $_proj $_type" + dest=$([ -f "$f/$_proj" ] && echo "$f/$_proj" || echo "$f/Contents/MacOS/$_proj") + _proj_name=$(echo "$_proj" | sed -e 's/[[:space:]]//g') + xcrun llvm-cov show $beta_xcode_partials -instr-profile "$1" "$dest" > "$_proj_name.$_type.coverage.txt" \ + || say " ${r}x>${x} llvm-cov failed to produce results for $dest" + fi + done + done +} + + +# Credits to: https://gist.github.com/pkuczynski/8665367 +parse_yaml() { + local prefix=$2 + local s='[[:space:]]*' w='[a-zA-Z0-9_]*' fs=$(echo @|tr @ '\034') + sed -ne "s|^\($s\)\($w\)$s:$s\"\(.*\)\"$s\$|\1$fs\2$fs\3|p" \ + -e "s|^\($s\)\($w\)$s:$s\(.*\)$s\$|\1$fs\2$fs\3|p" $1 | + awk -F$fs '{ + indent = length($1)/2; + vname[indent] = $2; + for (i in vname) {if (i > indent) {delete vname[i]}} + if (length($3) > 0) { + vn=""; if (indent > 0) {vn=(vn)(vname[0])("_")} + printf("%s%s%s=\"%s\"\n", "'$prefix'",vn, $2, $3); + } + }' +} + + +if [ $# != 0 ]; +then + while getopts "a:A:b:B:cC:dD:e:f:F:g:G:hJ:k:Kn:p:P:r:R:y:s:S:t:T:u:U:vx:X:Z" o + do + case "$o" in + "a") + gcov_arg=$OPTARG + ;; + "A") + curlawsargs="$OPTARG" + ;; + "b") + build_o="$OPTARG" + ;; + "B") + branch_o="$OPTARG" + ;; + "c") + clean="1" + ;; + "C") + commit_o="$OPTARG" + ;; + "d") + dump="1" + ;; + "D") + ddp="$OPTARG" + ;; + "e") + env="$env,$OPTARG" + ;; + "f") + if [ "${OPTARG::1}" = "!" ]; + then + exclude_cov="$exclude_cov -not -path '${OPTARG:1}'" + + elif [[ "$OPTARG" = *"*"* ]]; + then + include_cov="$include_cov -or -name '$OPTARG'" + + else + ft_search=0 + if [ "$files" = "" ]; + then + files="$OPTARG" + else + files="$files +$OPTARG" + fi + fi + ;; + "F") + if [ "$flags" = "" ]; + then + flags="$OPTARG" + else + flags="$flags,$OPTARG" + fi + ;; + "g") + gcov_ignore="$gcov_ignore -not -path '$OPTARG'" + ;; + "G") + gcov_include="$gcov_include -path '$OPTARG'" + ;; + "h") + show_help + exit 0; + ;; + "J") + ft_xcodellvm="1" + ft_xcodeplist="0" + if [ "$xp" = "" ]; + then + xp="$OPTARG" + else + xp="$xp\|$OPTARG" + fi + ;; + "k") + prefix_o=$(echo "$OPTARG" | sed -e 's:^/*::' -e 's:/*$::') + ;; + "K") + b="" + g="" + r="" + e="" + x="" + ;; + "n") + name="$OPTARG" + ;; + "p") + proj_root="$OPTARG" + ;; + "P") + pr_o="$OPTARG" + ;; + "r") + slug_o="$OPTARG" + ;; + "R") + git_root="$OPTARG" + ;; + "s") + if [ "$search_in_o" = "" ]; + then + search_in_o="$OPTARG" + else + search_in_o="$search_in_o $OPTARG" + fi + ;; + "S") + cacert="--cacert \"$OPTARG\"" + ;; + "t") + if [ "${OPTARG::1}" = "@" ]; + then + token=$(cat "${OPTARG:1}" | tr -d ' \n') + else + token="$OPTARG" + fi + ;; + "T") + tag_o="$OPTARG" + ;; + "u") + url_o=$(echo "$OPTARG" | sed -e 's/\/$//') + ;; + "U") + curlargs="$OPTARG" + ;; + "v") + set -x + curl_s="" + ;; + "x") + gcov_exe=$OPTARG + ;; + "X") + if [ "$OPTARG" = "gcov" ]; + then + ft_gcov="0" + elif [ "$OPTARG" = "coveragepy" ] || [ "$OPTARG" = "py" ]; + then + ft_coveragepy="0" + elif [ "$OPTARG" = "xcodellvm" ]; + then + ft_xcodellvm="1" + ft_xcodeplist="0" + elif [ "$OPTARG" = "fix" ] || [ "$OPTARG" = "fixes" ]; + then + ft_fix="0" + elif [ "$OPTARG" = "xcode" ]; + then + ft_xcodellvm="0" + ft_xcodeplist="0" + elif [ "$OPTARG" = "search" ]; + then + ft_search="0" + elif [ "$OPTARG" = "xcodepartials" ]; + then + beta_xcode_partials="-use-color" + elif [ "$OPTARG" = "network" ]; + then + ft_network="0" + elif [ "$OPTARG" = "s3" ]; + then + ft_s3="0" + fi + ;; + "y") + codecov_yml="$OPTARG" + ;; + "Z") + exit_with=1 + ;; + esac + done +fi + +say " + _____ _ + / ____| | | +| | ___ __| | ___ ___ _____ __ +| | / _ \\ / _\` |/ _ \\/ __/ _ \\ \\ / / +| |___| (_) | (_| | __/ (_| (_) \\ V / + \\_____\\___/ \\__,_|\\___|\\___\\___/ \\_/ + Bash-$VERSION + +" + +search_in="$proj_root" + +if [ "$JENKINS_URL" != "" ]; +then + say "$e==>$x Jenkins CI detected." + # https://wiki.jenkins-ci.org/display/JENKINS/Building+a+software+project + # https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin#GitHubpullrequestbuilderplugin-EnvironmentVariables + service="jenkins" + + if [ "$ghprbSourceBranch" != "" ]; + then + branch="$ghprbSourceBranch" + elif [ "$GIT_BRANCH" != "" ]; + then + branch="$GIT_BRANCH" + elif [ "$BRANCH_NAME" != "" ]; + then + branch="$BRANCH_NAME" + fi + + if [ "$ghprbActualCommit" != "" ]; + then + commit="$ghprbActualCommit" + elif [ "$GIT_COMMIT" != "" ]; + then + commit="$GIT_COMMIT" + fi + + if [ "$ghprbPullId" != "" ]; + then + pr="$ghprbPullId" + elif [ "$CHANGE_ID" != "" ]; + then + pr="$CHANGE_ID" + fi + + build="$BUILD_NUMBER" + build_url=$(urlencode "$BUILD_URL") + +elif [ "$CI" = "true" ] && [ "$TRAVIS" = "true" ] && [ "$SHIPPABLE" != "true" ]; +then + say "$e==>$x Travis CI detected." + # https://docs.travis-ci.com/user/environment-variables/ + service="travis" + commit="${TRAVIS_PULL_REQUEST_SHA:-$TRAVIS_COMMIT}" + build="$TRAVIS_JOB_NUMBER" + pr="$TRAVIS_PULL_REQUEST" + job="$TRAVIS_JOB_ID" + slug="$TRAVIS_REPO_SLUG" + env="$env,TRAVIS_OS_NAME" + tag="$TRAVIS_TAG" + if [ "$TRAVIS_BRANCH" != "$TRAVIS_TAG" ]; + then + branch="$TRAVIS_BRANCH" + fi + + language=$(printenv | grep "TRAVIS_.*_VERSION" | head -1) + if [ "$language" != "" ]; + then + env="$env,${language%=*}" + fi + +elif [ "$DOCKER_REPO" != "" ]; +then + say "$e==>$x Docker detected." + # https://docs.docker.com/docker-cloud/builds/advanced/ + service="docker" + branch="$SOURCE_BRANCH" + commit="$SOURCE_COMMIT" + slug="$DOCKER_REPO" + tag="$CACHE_TAG" + env="$env,IMAGE_NAME" + +elif [ "$CI" = "true" ] && [ "$CI_NAME" = "codeship" ]; +then + say "$e==>$x Codeship CI detected." + # https://www.codeship.io/documentation/continuous-integration/set-environment-variables/ + service="codeship" + branch="$CI_BRANCH" + build="$CI_BUILD_NUMBER" + build_url=$(urlencode "$CI_BUILD_URL") + commit="$CI_COMMIT_ID" + +elif [ ! -z "$CF_BUILD_URL" ] && [ ! -z "$CF_BUILD_ID" ]; +then + say "$e==>$x Codefresh CI detected." + # https://docs.codefresh.io/v1.0/docs/variables + service="codefresh" + branch="$CF_BRANCH" + build="$CF_BUILD_ID" + build_url=$(urlencode "$CF_BUILD_URL") + commit="$CF_REVISION" + +elif [ "$TEAMCITY_VERSION" != "" ]; +then + say "$e==>$x TeamCity CI detected." + # https://confluence.jetbrains.com/display/TCD8/Predefined+Build+Parameters + # https://confluence.jetbrains.com/plugins/servlet/mobile#content/view/74847298 + if [ "$TEAMCITY_BUILD_BRANCH" = '' ]; + then + echo " Teamcity does not automatically make build parameters available as environment variables." + echo " Add the following environment parameters to the build configuration" + echo " env.TEAMCITY_BUILD_BRANCH = %teamcity.build.branch%" + echo " env.TEAMCITY_BUILD_ID = %teamcity.build.id%" + echo " env.TEAMCITY_BUILD_URL = %teamcity.serverUrl%/viewLog.html?buildId=%teamcity.build.id%" + echo " env.TEAMCITY_BUILD_COMMIT = %system.build.vcs.number%" + echo " env.TEAMCITY_BUILD_REPOSITORY = %vcsroot..url%" + fi + service="teamcity" + branch="$TEAMCITY_BUILD_BRANCH" + build="$TEAMCITY_BUILD_ID" + build_url=$(urlencode "$TEAMCITY_BUILD_URL") + if [ "$TEAMCITY_BUILD_COMMIT" != "" ]; + then + commit="$TEAMCITY_BUILD_COMMIT" + else + commit="$BUILD_VCS_NUMBER" + fi + remote_addr="$TEAMCITY_BUILD_REPOSITORY" + +elif [ "$CI" = "true" ] && [ "$CIRCLECI" = "true" ]; +then + say "$e==>$x Circle CI detected." + # https://circleci.com/docs/environment-variables + service="circleci" + branch="$CIRCLE_BRANCH" + build="$CIRCLE_BUILD_NUM" + job="$CIRCLE_NODE_INDEX" + if [ "$CIRCLE_PROJECT_REPONAME" != "" ]; + then + slug="$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME" + else + # git@github.com:owner/repo.git + slug="${CIRCLE_REPOSITORY_URL##*:}" + # owner/repo.git + slug="${slug%%.git}" + fi + pr="$CIRCLE_PR_NUMBER" + commit="$CIRCLE_SHA1" + search_in="$search_in $CIRCLE_ARTIFACTS $CIRCLE_TEST_REPORTS" + +elif [ "$BUDDYBUILD_BRANCH" != "" ]; +then + say "$e==>$x buddybuild detected" + # http://docs.buddybuild.com/v6/docs/custom-prebuild-and-postbuild-steps + service="buddybuild" + branch="$BUDDYBUILD_BRANCH" + build="$BUDDYBUILD_BUILD_NUMBER" + build_url="https://dashboard.buddybuild.com/public/apps/$BUDDYBUILD_APP_ID/build/$BUDDYBUILD_BUILD_ID" + # BUDDYBUILD_TRIGGERED_BY + if [ "$ddp" = "$(echo ~)/Library/Developer/Xcode/DerivedData" ]; + then + ddp="/private/tmp/sandbox/${BUDDYBUILD_APP_ID}/bbtest" + fi + +elif [ "${bamboo_planRepository_revision}" != "" ]; +then + say "$e==>$x Bamboo detected" + # https://confluence.atlassian.com/bamboo/bamboo-variables-289277087.html#Bamboovariables-Build-specificvariables + service="bamboo" + commit="${bamboo_planRepository_revision}" + branch="${bamboo_planRepository_branch}" + build="${bamboo_buildNumber}" + build_url="${bamboo_buildResultsUrl}" + remote_addr="${bamboo_planRepository_repositoryUrl}" + +elif [ "$CI" = "true" ] && [ "$BITRISE_IO" = "true" ]; +then + # http://devcenter.bitrise.io/faq/available-environment-variables/ + say "$e==>$x Bitrise CI detected." + service="bitrise" + branch="$BITRISE_GIT_BRANCH" + build="$BITRISE_BUILD_NUMBER" + build_url=$(urlencode "$BITRISE_BUILD_URL") + pr="$BITRISE_PULL_REQUEST" + if [ "$GIT_CLONE_COMMIT_HASH" != "" ]; + then + commit="$GIT_CLONE_COMMIT_HASH" + fi + +elif [ "$CI" = "true" ] && [ "$SEMAPHORE" = "true" ]; +then + say "$e==>$x Semaphore CI detected." + # https://semaphoreapp.com/docs/available-environment-variables.html + service="semaphore" + branch="$BRANCH_NAME" + build="$SEMAPHORE_BUILD_NUMBER" + job="$SEMAPHORE_CURRENT_THREAD" + pr="$PULL_REQUEST_NUMBER" + slug="$SEMAPHORE_REPO_SLUG" + commit="$REVISION" + env="$env,SEMAPHORE_TRIGGER_SOURCE" + +elif [ "$CI" = "true" ] && [ "$BUILDKITE" = "true" ]; +then + say "$e==>$x Buildkite CI detected." + # https://buildkite.com/docs/guides/environment-variables + service="buildkite" + branch="$BUILDKITE_BRANCH" + build="$BUILDKITE_BUILD_NUMBER" + job="$BUILDKITE_JOB_ID" + build_url=$(urlencode "$BUILDKITE_BUILD_URL") + slug="$BUILDKITE_PROJECT_SLUG" + commit="$BUILDKITE_COMMIT" + if [[ "$BUILDKITE_PULL_REQUEST" != "false" ]]; then + pr="$BUILDKITE_PULL_REQUEST" + fi + tag="$BUILDKITE_TAG" + +elif [ "$CI" = "drone" ] || [ "$DRONE" = "true" ]; +then + say "$e==>$x Drone CI detected." + # http://docs.drone.io/env.html + # drone commits are not full shas + service="drone.io" + branch="$DRONE_BRANCH" + build="$DRONE_BUILD_NUMBER" + build_url=$(urlencode "${DRONE_BUILD_LINK}") + pr="$DRONE_PULL_REQUEST" + job="$DRONE_JOB_NUMBER" + tag="$DRONE_TAG" + +elif [ "$HEROKU_TEST_RUN_BRANCH" != "" ]; +then + say "$e==>$x Heroku CI detected." + # https://devcenter.heroku.com/articles/heroku-ci#environment-variables + service="heroku" + branch="$HEROKU_TEST_RUN_BRANCH" + build="$HEROKU_TEST_RUN_ID" + +elif [ "$CI" = "True" ] && [ "$APPVEYOR" = "True" ]; +then + say "$e==>$x Appveyor CI detected." + # http://www.appveyor.com/docs/environment-variables + service="appveyor" + branch="$APPVEYOR_REPO_BRANCH" + build=$(urlencode "$APPVEYOR_JOB_ID") + pr="$APPVEYOR_PULL_REQUEST_NUMBER" + job="$APPVEYOR_ACCOUNT_NAME%2F$APPVEYOR_PROJECT_SLUG%2F$APPVEYOR_BUILD_VERSION" + slug="$APPVEYOR_REPO_NAME" + commit="$APPVEYOR_REPO_COMMIT" + +elif [ "$CI" = "true" ] && [ "$WERCKER_GIT_BRANCH" != "" ]; +then + say "$e==>$x Wercker CI detected." + # http://devcenter.wercker.com/articles/steps/variables.html + service="wercker" + branch="$WERCKER_GIT_BRANCH" + build="$WERCKER_MAIN_PIPELINE_STARTED" + slug="$WERCKER_GIT_OWNER/$WERCKER_GIT_REPOSITORY" + commit="$WERCKER_GIT_COMMIT" + +elif [ "$CI" = "true" ] && [ "$MAGNUM" = "true" ]; +then + say "$e==>$x Magnum CI detected." + # https://magnum-ci.com/docs/environment + service="magnum" + branch="$CI_BRANCH" + build="$CI_BUILD_NUMBER" + commit="$CI_COMMIT" + +elif [ "$SHIPPABLE" = "true" ]; +then + say "$e==>$x Shippable CI detected." + # http://docs.shippable.com/ci_configure/ + service="shippable" + branch=$([ "$HEAD_BRANCH" != "" ] && echo "$HEAD_BRANCH" || echo "$BRANCH") + build="$BUILD_NUMBER" + build_url=$(urlencode "$BUILD_URL") + pr="$PULL_REQUEST" + slug="$REPO_FULL_NAME" + commit="$COMMIT" + +elif [ "$TDDIUM" = "true" ]; +then + say "Solano CI detected." + # http://docs.solanolabs.com/Setup/tddium-set-environment-variables/ + service="solano" + commit="$TDDIUM_CURRENT_COMMIT" + branch="$TDDIUM_CURRENT_BRANCH" + build="$TDDIUM_TID" + pr="$TDDIUM_PR_ID" + +elif [ "$GREENHOUSE" = "true" ]; +then + say "$e==>$x Greenhouse CI detected." + # http://docs.greenhouseci.com/docs/environment-variables-files + service="greenhouse" + branch="$GREENHOUSE_BRANCH" + build="$GREENHOUSE_BUILD_NUMBER" + build_url=$(urlencode "$GREENHOUSE_BUILD_URL") + pr="$GREENHOUSE_PULL_REQUEST" + commit="$GREENHOUSE_COMMIT" + search_in="$search_in $GREENHOUSE_EXPORT_DIR" + +elif [ "$GITLAB_CI" != "" ]; +then + say "$e==>$x GitLab CI detected." + # http://doc.gitlab.com/ce/ci/variables/README.html + service="gitlab" + branch="${CI_BUILD_REF_NAME:-$CI_COMMIT_REF_NAME}" + build="${CI_BUILD_ID:-$CI_JOB_ID}" + remote_addr="${CI_BUILD_REPO:-$CI_REPOSITORY_URL}" + commit="${CI_BUILD_REF:-$CI_COMMIT_SHA}" + +else + say "${r}x>${x} No CI provider detected." + say " Testing inside Docker? ${b}http://docs.codecov.io/docs/testing-with-docker${x}" + say " Testing with Tox? ${b}https://docs.codecov.io/docs/python#section-testing-with-tox${x}" + +fi + +say " ${e}project root:${x} $git_root" + +# find branch, commit, repo from git command +if [ "$GIT_BRANCH" != "" ]; +then + branch="$GIT_BRANCH" + +elif [ "$branch" = "" ]; +then + branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || hg branch 2>/dev/null || echo "") + if [ "$branch" = "HEAD" ]; + then + branch="" + fi +fi + +if [ "$commit_o" = "" ]; +then + # merge commit -> actual commit + mc= + if [ -n "$pr" ] && [ "$pr" != false ]; + then + mc=$(git show --no-patch --format="%P" 2>/dev/null || echo "") + fi + if [[ "$mc" =~ ^[a-z0-9]{40}[[:space:]][a-z0-9]{40}$ ]]; + then + say " Fixing merge commit SHA" + commit=$(echo "$mc" | cut -d' ' -f2) + elif [ "$GIT_COMMIT" != "" ]; + then + commit="$GIT_COMMIT" + elif [ "$commit" = "" ]; + then + commit=$(git log -1 --format="%H" 2>/dev/null || hg id -i --debug 2>/dev/null | tr -d '+' || echo "") + fi +else + commit="$commit_o" +fi + +if [ "$CODECOV_TOKEN" != "" ] && [ "$token" = "" ]; +then + say "${e}-->${x} token set from env" + token="$CODECOV_TOKEN" +fi + +if [ "$CODECOV_URL" != "" ] && [ "$url_o" = "" ]; +then + say "${e}-->${x} url set from env" + url_o=$(echo "$CODECOV_URL" | sed -e 's/\/$//') +fi + +if [ "$CODECOV_SLUG" != "" ]; +then + say "${e}-->${x} slug set from env" + slug_o="$CODECOV_SLUG" + +elif [ "$slug" = "" ]; +then + if [ "$remote_addr" = "" ]; + then + remote_addr=$(git config --get remote.origin.url || hg paths default || echo '') + fi + if [ "$remote_addr" != "" ]; + then + if echo "$remote_addr" | grep -q "//"; then + # https + slug=$(echo "$remote_addr" | cut -d / -f 4,5 | sed -e 's/\.git$//') + else + # ssh + slug=$(echo "$remote_addr" | cut -d : -f 2 | sed -e 's/\.git$//') + fi + fi + if [ "$slug" = "/" ]; + then + slug="" + fi +fi + +yaml=$(test -n "$codecov_yml" && echo "$codecov_yml" \ + || cd "$git_root" && \ + git ls-files "*codecov.yml" "*codecov.yaml" 2>/dev/null \ + || hg locate "*codecov.yml" "*codecov.yaml" 2>/dev/null \ + || cd $proj_root && find . -type f -name '*codecov.y*ml' -depth 1 2>/dev/null \ + || echo '') +yaml=$(echo "$yaml" | head -1) + +if [ "$yaml" != "" ]; +then + say " ${e}Yaml found at:${x} $yaml" + config=$(parse_yaml "$git_root/$yaml" || echo '') + + # TODO validate the yaml here + + if [ "$(echo "$config" | grep 'codecov_token="')" != "" ] && [ "$token" = "" ]; + then + say "${e}-->${x} token set from yaml" + token="$(echo "$config" | grep 'codecov_token="' | sed -e 's/codecov_token="//' | sed -e 's/"\.*//')" + fi + + if [ "$(echo "$config" | grep 'codecov_url="')" != "" ] && [ "$url_o" = "" ]; + then + say "${e}-->${x} url set from yaml" + url_o="$(echo "$config" | grep 'codecov_url="' | sed -e 's/codecov_url="//' | sed -e 's/"\.*//')" + fi + + if [ "$(echo "$config" | grep 'codecov_slug="')" != "" ] && [ "$slug_o" = "" ]; + then + say "${e}-->${x} slug set from yaml" + slug_o="$(echo "$config" | grep 'codecov_slug="' | sed -e 's/codecov_slug="//' | sed -e 's/"\.*//')" + fi +else + say " ${g}Yaml not found, that's ok! Learn more at${x} ${b}http://docs.codecov.io/docs/codecov-yaml${x}" + +fi + +if [ "$branch_o" != "" ]; +then + branch=$(urlencode "$branch_o") +else + branch=$(urlencode "$branch") +fi + +query="branch=$branch\ + &commit=$commit\ + &build=$([ "$build_o" = "" ] && echo "$build" || echo "$build_o")\ + &build_url=$build_url\ + &name=$(urlencode "$name")\ + &tag=$([ "$tag_o" = "" ] && echo "$tag" || echo "$tag_o")\ + &slug=$([ "$slug_o" = "" ] && urlencode "$slug" || urlencode "$slug_o")\ + &service=$service\ + &flags=$flags\ + &pr=$([ "$pr_o" = "" ] && echo "${pr##\#}" || echo "${pr_o##\#}")\ + &job=$job" + +if [ "$ft_search" = "1" ]; +then + # detect bower comoponents location + bower_components="bower_components" + bower_rc=$(cd "$git_root" && cat .bowerrc 2>/dev/null || echo "") + if [ "$bower_rc" != "" ]; + then + bower_components=$(echo "$bower_rc" | tr -d '\n' | grep '"directory"' | cut -d'"' -f4 | sed -e 's/\/$//') + if [ "$bower_components" = "" ]; + then + bower_components="bower_components" + fi + fi + + # Swift Coverage + if [ "$ft_xcodellvm" = "1" ] && [ -d "$ddp" ]; + then + say "${e}==>${x} Processing Xcode reports via llvm-cov" + say " DerivedData folder: $ddp" + profdata_files=$(find "$ddp" -name '*.profdata' 2>/dev/null || echo '') + if [ "$profdata_files" != "" ]; + then + # xcode via profdata + if [ "$xp" = "" ]; + then + # xp=$(xcodebuild -showBuildSettings 2>/dev/null | grep -i "^\s*PRODUCT_NAME" | sed -e 's/.*= \(.*\)/\1/') + # say " ${e}->${x} Speed up Xcode processing by adding ${e}-J '$xp'${x}" + say " ${g}hint${x} Speed up Swift processing by using use ${g}-J 'AppName'${x} (regexp accepted)" + say " ${g}hint${x} This will remove Pods/ from your report. Also ${b}https://docs.codecov.io/docs/ignoring-paths${x}" + fi + while read -r profdata; + do + if [ "$profdata" != "" ]; + then + swiftcov "$profdata" "$xp" + fi + done <<< "$profdata_files" + else + say " ${e}->${x} No Swift coverage found" + fi + + # Obj-C Gcov Coverage + if [ "$ft_gcov" = "1" ]; + then + say " ${e}->${x} Running $gcov_exe for Obj-C" + bash -c "find $ddp -type f -name '*.gcda' $gcov_include $gcov_ignore -exec $gcov_exe -p $gcov_arg {} +" || true + fi + fi + + if [ "$ft_xcodeplist" = "1" ] && [ -d "$ddp" ]; + then + say "${e}==>${x} Processing Xcode plists" + plists_files=$(find "$ddp" -name '*.xccoverage' 2>/dev/null || echo '') + if [ "$plists_files" != "" ]; + then + while read -r plist; + do + if [ "$plist" != "" ]; + then + say " ${g}Found${x} plist file at $plist" + plutil -convert xml1 -o "$(basename "$plist").plist" -- $plist + fi + done <<< "$plists_files" + fi + fi + + # Gcov Coverage + if [ "$ft_gcov" = "1" ]; + then + say "${e}==>${x} Running gcov in $proj_root ${e}(disable via -X gcov)${x}" + bash -c "find $proj_root -type f -name '*.gcno' $gcov_include $gcov_ignore -exec $gcov_exe -pb $gcov_arg {} +" || true + else + say "${e}==>${x} gcov disabled" + fi + + # Python Coverage + if [ "$ft_coveragepy" = "1" ]; + then + if [ ! -f coverage.xml ]; + then + if which coverage >/dev/null 2>&1; + then + say "${e}==>${x} Python coveragepy exists ${e}disable via -X coveragepy${x}" + + dotcoverage=$(find "$git_root" -name '.coverage' -or -name '.coverage.*' | head -1 || echo '') + if [ "$dotcoverage" != "" ]; + then + cd "$(dirname "$dotcoverage")" + if [ ! -f .coverage ]; + then + say " ${e}->${x} Running coverage combine" + coverage combine -a + fi + say " ${e}->${x} Running coverage xml" + if [ "$(coverage xml -i)" != "No data to report." ]; + then + files="$files +$PWD/coverage.xml" + else + say " ${r}No data to report.${x}" + fi + cd "$proj_root" + else + say " ${r}No .coverage file found.${x}" + fi + else + say "${e}==>${x} Python coveragepy not found" + fi + fi + else + say "${e}==>${x} Python coveragepy disabled" + fi + + if [ "$search_in_o" != "" ]; + then + # location override + search_in="$search_in_o" + fi + + say "$e==>$x Searching for coverage reports in:" + for _path in $search_in + do + say " ${g}+${x} $_path" + done + + patterns="find $search_in \( \ + -name vendor \ + -or -name htmlcov \ + -or -name virtualenv \ + -or -name js/generated/coverage \ + -or -name .virtualenv \ + -or -name virtualenvs \ + -or -name .virtualenvs \ + -or -name .env \ + -or -name .envs \ + -or -name env \ + -or -name .yarn-cache \ + -or -name envs \ + -or -name .venv \ + -or -name .venvs \ + -or -name venv \ + -or -name venvs \ + -or -name .git \ + -or -name .hg \ + -or -name .tox \ + -or -name __pycache__ \ + -or -name '.egg-info*' \ + -or -name '$bower_components' \ + -or -name node_modules \ + -or -name 'conftest_*.c.gcov' \ + \) -prune -or \ + -type f \( -name '*coverage*.*' \ + -or -name 'nosetests.xml' \ + -or -name 'jacoco*.xml' \ + -or -name 'clover.xml' \ + -or -name 'report.xml' \ + -or -name '*.codecov.*' \ + -or -name 'codecov.*' \ + -or -name 'cobertura.xml' \ + -or -name 'excoveralls.json' \ + -or -name 'luacov.report.out' \ + -or -name 'coverage-final.json' \ + -or -name 'naxsi.info' \ + -or -name 'lcov.info' \ + -or -name 'lcov.dat' \ + -or -name '*.lcov' \ + -or -name '*.clover' \ + -or -name 'cover.out' \ + -or -name 'gcov.info' \ + -or -name '*.gcov' \ + -or -name '*.lst' \ + $include_cov \) \ + $exclude_cov \ + -not -name '*.profdata' \ + -not -name 'coverage-summary.json' \ + -not -name 'phpunit-code-coverage.xml' \ + -not -name '*/classycle/report.xml' \ + -not -name 'remapInstanbul.coverage*.json' \ + -not -name 'phpunit-coverage.xml' \ + -not -name '*codecov.yml' \ + -not -name '*.serialized' \ + -not -name '.coverage*' \ + -not -name '.*coveragerc' \ + -not -name '*.sh' \ + -not -name '*.bat' \ + -not -name '*.ps1' \ + -not -name '*.env' \ + -not -name '*.cmake' \ + -not -name '*.dox' \ + -not -name '*.ec' \ + -not -name '*.rst' \ + -not -name '*.h' \ + -not -name '*.scss' \ + -not -name '*.o' \ + -not -name '*.proto' \ + -not -name '*.sbt' \ + -not -name '*.xcoverage.*' \ + -not -name '*.gz' \ + -not -name '*.conf' \ + -not -name '*.p12' \ + -not -name '*.csv' \ + -not -name '*.rsp' \ + -not -name '*.m4' \ + -not -name '*.pem' \ + -not -name '*~' \ + -not -name '*.exe' \ + -not -name '*.am' \ + -not -name '*.template' \ + -not -name '*.cp' \ + -not -name '*.bw' \ + -not -name '*.crt' \ + -not -name '*.log' \ + -not -name '*.cmake' \ + -not -name '*.pth' \ + -not -name '*.in' \ + -not -name '*.jar*' \ + -not -name '*.pom*' \ + -not -name '*.png' \ + -not -name '*.jpg' \ + -not -name '*.sql' \ + -not -name '*.jpeg' \ + -not -name '*.svg' \ + -not -name '*.gif' \ + -not -name '*.csv' \ + -not -name '*.snapshot' \ + -not -name '*.mak*' \ + -not -name '*.bash' \ + -not -name '*.data' \ + -not -name '*.py' \ + -not -name '*.class' \ + -not -name '*.xcconfig' \ + -not -name '*.ec' \ + -not -name '*.coverage' \ + -not -name '*.pyc' \ + -not -name '*.cfg' \ + -not -name '*.egg' \ + -not -name '*.ru' \ + -not -name '*.css' \ + -not -name '*.less' \ + -not -name '*.pyo' \ + -not -name '*.whl' \ + -not -name '*.html' \ + -not -name '*.ftl' \ + -not -name '*.erb' \ + -not -name '*.rb' \ + -not -name '*.js' \ + -not -name '*.jade' \ + -not -name '*.db' \ + -not -name '*.md' \ + -not -name '*.cpp' \ + -not -name '*.gradle' \ + -not -name '*.tar.tz' \ + -not -name '*.scss' \ + -not -name 'include.lst' \ + -not -name 'fullLocaleNames.lst' \ + -not -name 'inputFiles.lst' \ + -not -name 'createdFiles.lst' \ + -not -name 'scoverage.measurements.*' \ + -not -name 'test_*_coverage.txt' \ + -not -name 'testrunner-coverage*' \ + -print 2>/dev/null" + files=$(eval "$patterns" || echo '') + +elif [ "$include_cov" != "" ]; +then + files=$(eval "find $search_in -type f \( ${include_cov:5} \)$exclude_cov 2>/dev/null" || echo '') +fi + +num_of_files=$(echo "$files" | wc -l | tr -d ' ') +if [ "$num_of_files" != '' ] && [ "$files" != '' ]; +then + say " ${e}->${x} Found $num_of_files reports" +fi + +# no files found +if [ "$files" = "" ]; +then + say "${r}-->${x} No coverage report found." + say " Please visit ${b}http://docs.codecov.io/docs/supported-languages${x}" + exit ${exit_with}; +fi + +if [ "$ft_network" == "1" ]; +then + say "${e}==>${x} Detecting git/mercurial file structure" + network=$(cd "$git_root" && git ls-files 2>/dev/null || hg locate 2>/dev/null || echo "") + if [ "$network" = "" ]; + then + network=$(find "$git_root" \( \ + -name virtualenv \ + -name .virtualenv \ + -name virtualenvs \ + -name .virtualenvs \ + -name '*.png' \ + -name '*.gif' \ + -name '*.jpg' \ + -name '*.jpeg' \ + -name '*.md' \ + -name .env \ + -name .envs \ + -name env \ + -name envs \ + -name .venv \ + -name .venvs \ + -name venv \ + -name venvs \ + -name .git \ + -name .egg-info \ + -name shunit2-2.1.6 \ + -name vendor \ + -name __pycache__ \ + -name node_modules \ + -path '*/$bower_components/*' \ + -path '*/target/delombok/*' \ + -path '*/build/lib/*' \ + -path '*/js/generated/coverage/*' \ + \) -prune -or \ + -type f -print 2>/dev/null || echo '') + fi + + if [ "$prefix_o" != "" ]; + then + network=$(echo "$network" | awk "{print \"$prefix_o/\"\$0}") + fi +fi + +upload_file=`mktemp /tmp/codecov.XXXXXX` +adjustments_file=`mktemp /tmp/codecov.adjustments.XXXXXX` + +cleanup() { + rm -f $upload_file $adjustments_file $upload_file.gz +} + +trap cleanup INT ABRT TERM + +if [ "$env" != "" ]; +then + inc_env="" + say "${e}==>${x} Appending build variables" + for varname in $(echo "$env" | tr ',' ' ') + do + if [ "$varname" != "" ]; + then + say " ${g}+${x} $varname" + inc_env="${inc_env}${varname}=$(eval echo "\$${varname}") +" + fi + done + +echo "$inc_env<<<<<< ENV" >> $upload_file +fi + +# Append git file list +# write discovered yaml location +echo "$yaml" >> $upload_file +if [ "$ft_network" == "1" ]; +then + i="woff|eot|otf" # fonts + i="$i|gif|png|jpg|jpeg|psd" # images + i="$i|ptt|pptx|numbers|pages|md|txt|xlsx|docx|doc|pdf|html|csv" # docs + i="$i|yml|yaml|.gitignore" # supporting docs + echo "$network" | grep -vwE "($i)$" >> $upload_file +fi +echo "<<<<<< network" >> $upload_file + +fr=0 +say "${e}==>${x} Reading reports" +while IFS='' read -r file; +do + # read the coverage file + if [ "$(echo "$file" | tr -d ' ')" != '' ]; + then + if [ -f "$file" ]; + then + report_len=$(wc -c < "$file") + if [ "$report_len" -ne 0 ]; + then + say " ${g}+${x} $file ${e}bytes=$(echo "$report_len" | tr -d ' ')${x}" + # append to to upload + _filename=$(basename "$file") + if [ "${_filename##*.}" = 'gcov' ]; + then + echo "# path=$(echo "$file.reduced" | sed "s|^$git_root/||")" >> $upload_file + # get file name + head -1 $file >> $upload_file + # 1. remove source code + # 2. remove ending bracket lines + # 3. remove whitespace + # 4. remove contextual lines + # 5. remove function names + awk -F': *' '{print $1":"$2":"}' $file \ + | sed '\/: *} *$/d' \ + | sed 's/^ *//' \ + | sed '/^-/d' \ + | sed 's/^function.*/func/' >> $upload_file + else + echo "# path=$(echo "$file" | sed "s|^$git_root/||")" >> $upload_file + cat "$file" >> $upload_file + fi + echo "<<<<<< EOF" >> $upload_file + fr=1 + if [ "$clean" = "1" ]; + then + rm "$file" + fi + else + say " ${r}-${x} Skipping empty file $file" + fi + else + say " ${r}-${x} file not found at $file" + fi + fi +done <<< "$(echo -e "$files")" + +if [ "$fr" = "0" ]; +then + say "${r}-->${x} No coverage data found." + say " Please visit ${b}http://docs.codecov.io/docs/supported-languages${x}" + say " search for your projects language to learn how to collect reports." + exit ${exit_with}; +fi + +if [ "$ft_fix" = "1" ]; +then + say "${e}==>${x} Appending adjustments" + say " ${b}http://docs.codecov.io/docs/fixing-reports${x}" + + empty_line='^[[:space:]]*$' + # // + syntax_comment='^[[:space:]]*//.*' + # /* or */ + syntax_comment_block='^[[:space:]]*(\/\*|\*\/)[[:space:]]*$' + # { or } + syntax_bracket='^[[:space:]]*[\{\}][[:space:]]*(//.*)?$' + # [ or ] + syntax_list='^[[:space:]]*[][][[:space:]]*(//.*)?$' + + skip_dirs="-not -path '*/$bower_components/*' \ + -not -path '*/node_modules/*'" + + cut_and_join() { + awk 'BEGIN { FS=":" } + $3 ~ /\/\*/ || $3 ~ /\*\// { print $0 ; next } + $1!=key { if (key!="") print out ; key=$1 ; out=$1":"$2 ; next } + { out=out","$2 } + END { print out }' 2>/dev/null + } + + if echo "$network" | grep -m1 '.kt$' 1>/dev/null; + then + # skip brackets and comments + find "$git_root" -type f \ + -name '*.kt' \ + -exec \ + grep -nIHE -e $syntax_bracket \ + -e $syntax_comment_block {} \; \ + | cut_and_join \ + >> $adjustments_file \ + || echo '' + + # last line in file + find "$git_root" -type f \ + -name '*.kt' -exec \ + wc -l {} \; \ + | while read l; do echo "EOF: $l"; done \ + 2>/dev/null \ + >> $adjustments_file \ + || echo '' + + fi + + if echo "$network" | grep -m1 '.go$' 1>/dev/null; + then + # skip empty lines, comments, and brackets + find "$git_root" -not -path '*/vendor/*' \ + -type f \ + -name '*.go' \ + -exec \ + grep -nIHE \ + -e $empty_line \ + -e $syntax_comment \ + -e $syntax_comment_block \ + -e $syntax_bracket \ + {} \; \ + | cut_and_join \ + >> $adjustments_file \ + || echo '' + fi + + if echo "$network" | grep -m1 '.dart$' 1>/dev/null; + then + # skip brackets + find "$git_root" -type f \ + -name '*.dart' \ + -exec \ + grep -nIHE \ + -e $syntax_bracket \ + {} \; \ + | cut_and_join \ + >> $adjustments_file \ + || echo '' + fi + + if echo "$network" | grep -m1 '.php$' 1>/dev/null; + then + # skip empty lines, comments, and brackets + find "$git_root" -not -path "*/vendor/*" \ + -type f \ + -name '*.php' \ + -exec \ + grep -nIHE \ + -e $syntax_list \ + -e $syntax_bracket \ + -e '^[[:space:]]*\);[[:space:]]*(//.*)?$' \ + {} \; \ + | cut_and_join \ + >> $adjustments_file \ + || echo '' + fi + + if echo "$network" | grep -m1 '\(.cpp\|.h\|.cxx\|.c\|.hpp\|.m\)$' 1>/dev/null; + then + # skip brackets + find "$git_root" -type f \ + $skip_dirs \ + \( \ + -name '*.h' \ + -or -name '*.cpp' \ + -or -name '*.cxx' \ + -or -name '*.m' \ + -or -name '*.c' \ + -or -name '*.hpp' \ + \) -exec \ + grep -nIHE \ + -e $empty_line \ + -e $syntax_bracket \ + -e '// LCOV_EXCL' \ + {} \; \ + | cut_and_join \ + >> $adjustments_file \ + || echo '' + + # skip brackets + find "$git_root" -type f \ + $skip_dirs \ + \( \ + -name '*.h' \ + -or -name '*.cpp' \ + -or -name '*.cxx' \ + -or -name '*.m' \ + -or -name '*.c' \ + -or -name '*.hpp' \ + \) -exec \ + grep -nIH '// LCOV_EXCL' \ + {} \; \ + >> $adjustments_file \ + || echo '' + + fi + + found=$(cat $adjustments_file | tr -d ' ') + + if [ "$found" != "" ]; + then + say " ${g}+${x} Found adjustments" + echo "# path=fixes" >> $upload_file + cat $adjustments_file >> $upload_file + echo "<<<<<< EOF" >> $upload_file + rm -rf $adjustments_file + else + say " ${e}->${x} No adjustments found" + fi +fi + +if [ "$url_o" != "" ]; +then + url="$url_o" +fi + +if [ "$dump" != "0" ]; +then + # trim whitespace from query + say " ${e}->${x} Dumping upload file (no upload)" + echo "$url/upload/v4?$(echo "package=bash-$VERSION&token=$token&$query" | tr -d ' ')" + cat $upload_file +else + + say "${e}==>${x} Gzipping contents" + gzip -nf9 $upload_file + + query=$(echo "${query}" | tr -d ' ') + say "${e}==>${x} Uploading reports" + say " ${e}url:${x} $url" + say " ${e}query:${x} $query" + + # now add token to query + query=$(echo "package=bash-$VERSION&token=$token&$query" | tr -d ' ') + + if [ "$ft_s3" = "1" ]; + then + i="0" + while [ $i -lt 4 ] + do + i=$[$i+1] + say " ${e}->${x} Pinging Codecov" + res=$(curl $curl_s -X POST $curlargs $cacert \ + -H 'X-Reduced-Redundancy: false' \ + -H 'X-Content-Type: application/x-gzip' \ + "$url/upload/v4?$query" || true) + # a good replay is "https://codecov.io" + "\n" + "https://codecov.s3.amazonaws.com/..." + status=$(echo "$res" | head -1 | grep 'HTTP ' | cut -d' ' -f2) + if [ "$status" = "" ]; + then + s3target=$(echo "$res" | sed -n 2p) + say " ${e}->${x} Uploading" + s3=$(curl $curl_s -fiX PUT $curlawsargs \ + --data-binary @$upload_file.gz \ + -H 'Content-Type: application/x-gzip' \ + -H 'Content-Encoding: gzip' \ + -H 'x-amz-acl: public-read' \ + "$s3target" || true) + if [ "$s3" != "" ]; + then + say " ${g}->${x} View reports at ${b}$(echo "$res" | sed -n 1p)${x}" + exit 0 + else + say " ${r}X>${x} Failed to upload" + fi + elif [ "$status" = "400" ]; + then + # 400 Error + say "${g}${res}${x}" + exit ${exit_with} + fi + say " ${e}->${x} Sleeping for 30s and trying again..." + sleep 30 + done + fi + + say " ${e}->${x} Uploading to Codecov" + i="0" + while [ $i -lt 4 ] + do + i=$[$i+1] + + res=$(curl $curl_s -X POST $curlargs $cacert \ + --data-binary @$upload_file.gz \ + -H 'Content-Type: text/plain' \ + -H 'Content-Encoding: gzip' \ + -H 'X-Content-Encoding: gzip' \ + -H 'Accept: text/plain' \ + "$url/upload/v2?$query" || echo 'HTTP 500') + # HTTP 200 + # http://.... + status=$(echo "$res" | head -1 | cut -d' ' -f2) + if [ "$status" = "" ]; + then + say " View reports at ${b}$(echo "$res" | head -2 | tail -1)${x}" + exit 0 + + elif [ "${status:0:1}" = "5" ]; + then + say " ${e}->${x} Sleeping for 30s and trying again..." + sleep 30 + + else + say " ${g}${res}${x}" + exit 0 + exit ${exit_with} + fi + + done + + say " ${r}X> Failed to upload coverage reports${x}" +fi + +exit ${exit_with} diff --git a/scripts/fetch.php b/scripts/fetch.php index 12d8f2c..b5654fb 100755 --- a/scripts/fetch.php +++ b/scripts/fetch.php @@ -23,7 +23,7 @@ 'runkit' => 'https://github.com/zenovich/runkit', 'php-git' => 'https://github.com/libgit2/php-git', 'AOP' => 'https://github.com/AOP-PHP/AOP', - 'xdeubg' => 'https://github.com/xdebug/xdebug.git' + 'xdeubg' => 'https://github.com/xdebug/xdebug.git', ]; // PHPBREW_ROOT/build/php-7.1.17/ext/ diff --git a/scripts/test.sh b/scripts/test.sh index c6b5130..4685d7f 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -9,10 +9,9 @@ pwd phpbrew ext disable startup export MINBABY_TEST_EXT=0 ./vendor/bin/kahlan +./vendor/bin/kahlan --coverage=0 --clover=coverage.xml # echo "enable ext start.so" phpbrew ext enable startup export MINBABY_TEST_EXT=1 ./vendor/bin/kahlan - - From ae6b22f57a25f9bc4dbd9572b9a175618622445e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Thu, 13 Dec 2018 00:36:39 +0800 Subject: [PATCH 064/126] stringy-split test (#25) * stringy-split test * coverage --- .circleci/config.yml | 3 +++ spec/Stringy/StringySpec.php | 39 ++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 131b9ff..eb1b284 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -19,6 +19,9 @@ jobs: - run: name: run test command: ./vendor/bin/kahlan + - run: + name: upload coverage + command: bash <(curl -s https://codecov.io/bash) - run: name: startup install command: phpize && ./configure && make && sudo make install diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index 7e9b504..afbbe6a 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -576,4 +576,43 @@ } }); }); + + it('test split', function () { + + $data = [ + [['foo,bar,baz'], 'foo,bar,baz', ''], + [['foo,bar,baz'], 'foo,bar,baz', '-'], + [['foo', 'bar', 'baz'], 'foo,bar,baz', ','], + [['foo', 'bar', 'baz'], 'foo,bar,baz', ',', null], + [['foo', 'bar', 'baz'], 'foo,bar,baz', ',', -1], + [[], 'foo,bar,baz', ',', 0], + [['foo'], 'foo,bar,baz', ',', 1], + [['foo', 'bar'], 'foo,bar,baz', ',', 2], + [['foo', 'bar', 'baz'], 'foo,bar,baz', ',', 3], + [['foo', 'bar', 'baz'], 'foo,bar,baz', ',', 10], + [['fòô,bàř,baz'], 'fòô,bàř,baz', '-', null, 'UTF-8'], + [['fòô', 'bàř', 'baz'], 'fòô,bàř,baz', ',', null, 'UTF-8'], + [['fòô', 'bàř', 'baz'], 'fòô,bàř,baz', ',', null, 'UTF-8'], + [['fòô', 'bàř', 'baz'], 'fòô,bàř,baz', ',', -1, 'UTF-8'], + [[], 'fòô,bàř,baz', ',', 0, 'UTF-8'], + [['fòô'], 'fòô,bàř,baz', ',', 1, 'UTF-8'], + [['fòô', 'bàř'], 'fòô,bàř,baz', ',', 2, 'UTF-8'], + [['fòô', 'bàř', 'baz'], 'fòô,bàř,baz', ',', 3, 'UTF-8'], + [['fòô', 'bàř', 'baz'], 'fòô,bàř,baz', ',', 10, 'UTF-8'] + ]; + + foreach($data as $value) { + @list($expected, $str, $pattern, $limit, $encoding) = $value; + $stringy = __('Stringy')::create($str, $encoding); + $result = $stringy->split($pattern, $limit); + \expect($result)->toBeA('array'); + foreach ($result as $string) { + \expect($string)->toBeAnInstanceOf(__('Stringy')); + } + for ($i = 0; $i < count($expected); $i++) { + \expect((string)$result[$i])->toBe($expected[$i]); + } + } + + }); }); From c5d7c129f5b896fd529260b93543ea372b83689a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Thu, 13 Dec 2018 00:42:11 +0800 Subject: [PATCH 065/126] Stringy split (#26) * stringy-split test * coverage * do --- kahlan-config.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kahlan-config.php b/kahlan-config.php index 73e0b0b..24a7b1b 100644 --- a/kahlan-config.php +++ b/kahlan-config.php @@ -5,3 +5,5 @@ $commandLine = $this->commandLine(); // $commandLine->option('reporter', 'default', 'verbose'); $commandLine->option('ff', 'default', 1); +$commandLine->option('clover', 'default', 'coverage.xml'); +$commandLine->option('coverage', 'default', '4'); From c50ee0ec123d62c72a1c3189b4ad4dda624d2732 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Thu, 13 Dec 2018 22:54:50 +0800 Subject: [PATCH 066/126] stringy-collapseWhiteSpace test+php+ext (#27) --- kahlan-config.php | 1 - scripts/test.sh | 5 ++--- spec/Stringy/StringySpec.php | 29 ++++++++++++++++++++++++++++- src/ext/stringy/stringy.c | 30 +++++++++++++++--------------- 4 files changed, 45 insertions(+), 20 deletions(-) diff --git a/kahlan-config.php b/kahlan-config.php index 24a7b1b..da4686c 100644 --- a/kahlan-config.php +++ b/kahlan-config.php @@ -6,4 +6,3 @@ // $commandLine->option('reporter', 'default', 'verbose'); $commandLine->option('ff', 'default', 1); $commandLine->option('clover', 'default', 'coverage.xml'); -$commandLine->option('coverage', 'default', '4'); diff --git a/scripts/test.sh b/scripts/test.sh index 4685d7f..616683f 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -8,10 +8,9 @@ pwd # echo "disable ext startup.so" phpbrew ext disable startup export MINBABY_TEST_EXT=0 -./vendor/bin/kahlan -./vendor/bin/kahlan --coverage=0 --clover=coverage.xml +./vendor/bin/kahlan --coverage=1 --clover=coverage.xml # echo "enable ext start.so" phpbrew ext enable startup export MINBABY_TEST_EXT=1 -./vendor/bin/kahlan +./vendor/bin/kahlan --coverage=1 --clover=coverage.xml diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index afbbe6a..4c8ec8e 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -578,7 +578,6 @@ }); it('test split', function () { - $data = [ [['foo,bar,baz'], 'foo,bar,baz', ''], [['foo,bar,baz'], 'foo,bar,baz', '-'], @@ -615,4 +614,32 @@ } }); + + it('test CollapseWhitespace', function () { + $data = [ + ['foo bar', ' foo bar '], + ['test string', 'test string'], + ['Ο συγγραφέας', ' Ο συγγραφέας '], + ['123', ' 123 '], + ['', ' ', 'UTF-8'], // no-break space (U+00A0) + ['', '           ', 'UTF-8'], // spaces U+2000 to U+200A + ['', ' ', 'UTF-8'], // narrow no-break space (U+202F) + ['', ' ', 'UTF-8'], // medium mathematical space (U+205F) + ['', ' ', 'UTF-8'], // ideographic space (U+3000) + ['1 2 3', ' 1  2  3  ', 'UTF-8'], + ['', ' '], + ['', ''], + ]; + + foreach($data as $value) { + @list($expected, $str, $encoding) = $value; + { + $stringy = __('Stringy')::create($str, $encoding); + $result = $stringy->collapseWhitespace(); + \expect($result)->toBeAnInstanceOf(__('Stringy')); + \expect((string)$stringy)->toBe($str); + \expect((string)$result)->toBe($expected); + } + } + }); }); diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index 6a79f30..d23a3dc 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -453,13 +453,8 @@ PHP_METHOD(Stringy, collapseWhiteSpace) ZVAL_STRING(&func, "regexReplace"); call_user_function(NULL, getThis(), &func, &retval, 3, args); - // call trim() - ZVAL_STRING(&func, "trim"); - args_trim[0] = retval; - call_user_function(NULL, &retval, &func, return_value, 1, args_trim); - - RETURN_ZVAL(&retval, 0, 1); + call_user_function(NULL, &retval, &func, return_value, 0, NULL); } PHP_METHOD(Stringy, regexReplace) @@ -879,17 +874,27 @@ PHP_METHOD(Stringy, split) Z_PARAM_ZVAL(limit_zval) ZEND_PARSE_PARAMETERS_END(); + zval pattern_zval, str_zval, rv; + + zval *encoding = zend_read_property(stringy_ce, getThis(), ZEND_STRL("encoding"), 0, &rv); + str_zval = *zend_read_property(stringy_ce, getThis(), ZEND_STRL("str"), 0, &rv); + zval arr; array_init(&arr); if (Z_TYPE_P(limit_zval) == IS_LONG && Z_LVAL_P(limit_zval) == 0) { - RETURN_ZVAL(&arr, 1, 0); + RETURN_ZVAL(&arr, 0, 1); } if (zend_string_equals(pattern, empty)) { - zval *this; - ZVAL_COPY(this, getThis()); - add_index_zval(&arr, 0, this); + zval instance; + zval tmp; + ZVAL_EMPTY_STRING(&tmp); + + object_init_ex(&instance, stringy_ce); + zend_call_method(&instance, stringy_ce, NULL, ZEND_STRL("__construct"), return_value, 2, &str_zval, encoding); + + add_index_zval(&arr, 0, &instance); RETURN_ZVAL(&arr, 1, 0); } @@ -898,9 +903,6 @@ PHP_METHOD(Stringy, split) zend_long limit = (limit_long > 0) ? limit_long += 1 : -1; - zval pattern_zval, str_zval, rv; - - str_zval = *zend_read_property(stringy_ce, getThis(), ZEND_STRL("str"), 0, &rv); ZVAL_STR(&pattern_zval, pattern); ZVAL_LONG(limit_zval, limit); @@ -914,8 +916,6 @@ PHP_METHOD(Stringy, split) zend_long array_len = zend_array_count(Z_ARRVAL(arr)); - zval *encoding = zend_read_property(stringy_ce, getThis(), ZEND_STRL("encoding"), 0, &rv); - zval *tmp; zend_long index; zval ret_arr; From 2b4f4120189270abb45165dbf00adee46e75c290 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Fri, 14 Dec 2018 14:50:26 +0800 Subject: [PATCH 067/126] stringy-indexOf test (#28) --- spec/Stringy/StringySpec.php | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index 4c8ec8e..a7032ea 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -642,4 +642,25 @@ } } }); + + it('test indexOf', function () { + $data = [ + [6, 'foo & bar', 'bar'], + [6, 'foo & bar', 'bar', 0], + [false, 'foo & bar', 'baz'], + [false, 'foo & bar', 'baz', 0], + [0, 'foo & bar & foo', 'foo', 0], + [12, 'foo & bar & foo', 'foo', 5], + [6, 'fòô & bàř', 'bàř', 0, 'UTF-8'], + [false, 'fòô & bàř', 'baz', 0, 'UTF-8'], + [0, 'fòô & bàř & fòô', 'fòô', 0, 'UTF-8'], + [12, 'fòô & bàř & fòô', 'fòô', 5, 'UTF-8'], + ]; + + foreach($data as $value) { + @list($expected, $str, $subStr, $offset, $encoding) = $value; + $result = __('Stringy')::create($str, $encoding)->indexOf($subStr, $offset); + \expect($result)->toBe($expected); + } + }); }); From 0978ee4773cc06459e5cadc01cc4b964a7f00916 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Fri, 14 Dec 2018 16:42:54 +0800 Subject: [PATCH 068/126] stringy-containsAny test+php+ext (#29) --- spec/Stringy/StringySpec.php | 78 +++++++++++++++++++++++------ src/Minbaby/Php/Stringy/Stringy.php | 13 +++++ src/ext/stringy/stringy.c | 45 ++++++++++++++++- 3 files changed, 118 insertions(+), 18 deletions(-) diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index a7032ea..a00d2b6 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -2,6 +2,9 @@ namespace Minbaby\Startup\Spec\Stringy; +use function Kahlan\context; + + \describe("Stringy Test", function () { \beforeAll(function () { _ns(NS_STRINGY); @@ -495,7 +498,7 @@ } }); - \context('', function(){ + \context('contains', function(){ $data = [ [true, 'Str contains foo bar', 'foo bar'], [true, '12398!@(*%!@# @!%#*&^%', ' @!%#*&^%'], @@ -552,8 +555,39 @@ [false, 'å´¥©¨ˆßå˚ ∆∂˙©å∑¥øœ¬', [' ßÅ˚', ' Å˚ '], false, 'UTF-8'], ]); - it('test contains', function () use ($data) { + $dataContainsAny = array_merge( + array_map(function ($array) { + $array[2] = [$array[2]]; + return $array; + }, $data), + [ + // No needles + [false, 'Str contains foo bar', []], + // Multiple needles + [true, 'Str contains foo bar', ['foo', 'bar']], + [true, '12398!@(*%!@# @!%#*&^%', [' @!%#*', '&^%']], + [true, 'Ο συγγραφέας είπε', ['συγγρ', 'αφέας'], 'UTF-8'], + [true, 'å´¥©¨ˆßå˚ ∆∂˙©å∑¥øœ¬', ['å´¥', '©'], true, 'UTF-8'], + [true, 'å´¥©¨ˆßå˚ ∆∂˙©å∑¥øœ¬', ['å˚ ', '∆'], true, 'UTF-8'], + [true, 'å´¥©¨ˆßå˚ ∆∂˙©å∑¥øœ¬', ['øœ', '¬'], true, 'UTF-8'], + [false, 'Str contains foo bar', ['Foo', 'Bar']], + [false, 'Str contains foo bar', ['foobar', 'bar ']], + [false, 'Str contains foo bar', ['foo bar ', ' foo']], + [false, 'Ο συγγραφέας είπε', [' συγγραφέας ', ' συγγραφ '], true, 'UTF-8'], + [false, 'å´¥©¨ˆßå˚ ∆∂˙©å∑¥øœ¬', [' ßå˚', ' ß '], true, 'UTF-8'], + [true, 'Str contains foo bar', ['Foo bar', 'bar'], false], + [true, '12398!@(*%!@# @!%#*&^%', [' @!%#*&^%', '*&^%'], false], + [true, 'Ο συγγραφέας είπε', ['ΣΥΓΓΡΑΦΈΑΣ', 'ΑΦΈΑ'], false, 'UTF-8'], + [true, 'å´¥©¨ˆßå˚ ∆∂˙©å∑¥øœ¬', ['Å´¥©', '¥©'], false, 'UTF-8'], + [true, 'å´¥©¨ˆßå˚ ∆∂˙©å∑¥øœ¬', ['Å˚ ∆', ' ∆'], false, 'UTF-8'], + [true, 'å´¥©¨ˆßå˚ ∆∂˙©å∑¥øœ¬', ['ØŒ¬', 'Œ'], false, 'UTF-8'], + [false, 'Str contains foo bar', ['foobar', 'none'], false], + [false, 'Str contains foo bar', ['foo bar ', ' ba '], false], + [false, 'Ο συγγραφέας είπε', [' συγγραφέας ', ' ραφέ '], false, 'UTF-8'], + [false, 'å´¥©¨ˆßå˚ ∆∂˙©å∑¥øœ¬', [' ßÅ˚', ' Å˚ '], false, 'UTF-8'], + ]); + it('test contains', function () use ($data) { foreach($data as $value) { @list($expected, $haystack, $needle, $caseSensitive, $encoding) = $value; $stringy = __('Stringy')::create($haystack, $encoding); @@ -575,6 +609,18 @@ \expect((bool)$result)->toBe($expected); } }); + + it('test containsAny', function () use ($dataContainsAny) { + foreach($dataContainsAny as $value) { + @list($expected, $haystack, $needles, $caseSensitive, $encoding) = $value; + $stringy = __('Stringy')::create($haystack, $encoding); + + $result = $stringy->containsAny($needles, $caseSensitive === true || $caseSensitive === NULL); + \expect($result)->toBeA('bool'); + \expect((string)$stringy)->toBe($haystack); + \expect((bool)$result)->toBe($expected); + } + }); }); it('test split', function () { @@ -643,20 +689,20 @@ } }); - it('test indexOf', function () { - $data = [ - [6, 'foo & bar', 'bar'], - [6, 'foo & bar', 'bar', 0], - [false, 'foo & bar', 'baz'], - [false, 'foo & bar', 'baz', 0], - [0, 'foo & bar & foo', 'foo', 0], - [12, 'foo & bar & foo', 'foo', 5], - [6, 'fòô & bàř', 'bàř', 0, 'UTF-8'], - [false, 'fòô & bàř', 'baz', 0, 'UTF-8'], - [0, 'fòô & bàř & fòô', 'fòô', 0, 'UTF-8'], - [12, 'fòô & bàř & fòô', 'fòô', 5, 'UTF-8'], - ]; - + $data = [ + [6, 'foo & bar', 'bar'], + [6, 'foo & bar', 'bar', 0], + [false, 'foo & bar', 'baz'], + [false, 'foo & bar', 'baz', 0], + [0, 'foo & bar & foo', 'foo', 0], + [12, 'foo & bar & foo', 'foo', 5], + [6, 'fòô & bàř', 'bàř', 0, 'UTF-8'], + [false, 'fòô & bàř', 'baz', 0, 'UTF-8'], + [0, 'fòô & bàř & fòô', 'fòô', 0, 'UTF-8'], + [12, 'fòô & bàř & fòô', 'fòô', 5, 'UTF-8'], + ]; + + it('test indexOf', function () use ($data) { foreach($data as $value) { @list($expected, $str, $subStr, $offset, $encoding) = $value; $result = __('Stringy')::create($str, $encoding)->indexOf($subStr, $offset); diff --git a/src/Minbaby/Php/Stringy/Stringy.php b/src/Minbaby/Php/Stringy/Stringy.php index c041b32..f0b6a43 100644 --- a/src/Minbaby/Php/Stringy/Stringy.php +++ b/src/Minbaby/Php/Stringy/Stringy.php @@ -340,4 +340,17 @@ public function containsAll($needles, $caseSensitive = true) } return true; } + + public function containsAny($needles, $caseSensitive = true) + { + if (empty($needles)) { + return false; + } + foreach ($needles as $needle) { + if ($this->contains($needle, $caseSensitive)) { + return true; + } + } + return false; + } } diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index d23a3dc..8f8d0de 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -1279,7 +1279,7 @@ PHP_METHOD(Stringy, contains) call_user_function(NULL, NULL, &func, return_value, 4, args_i); ZVAL_BOOL(return_value, Z_TYPE_P(return_value) != IS_FALSE); } -ZEND_BEGIN_ARG_INFO(arginfo_contains, 3) +ZEND_BEGIN_ARG_INFO(arginfo_contains, 2) ZEND_ARG_INFO(0, needle) ZEND_ARG_INFO(0, caseSensitive) ZEND_END_ARG_INFO(); @@ -1318,7 +1318,47 @@ PHP_METHOD(Stringy, containsAll) RETURN_BOOL(1); } -ZEND_BEGIN_ARG_INFO(arginfo_containsAll, 3) +ZEND_BEGIN_ARG_INFO(arginfo_containsAll, 2) + ZEND_ARG_INFO(0, needle) + ZEND_ARG_INFO(0, caseSensitive) +ZEND_END_ARG_INFO(); + + +PHP_METHOD(Stringy, containsAny) +{ + zval *needles = NULL, *caseSensitive = NULL; + ZEND_PARSE_PARAMETERS_START(1, 2) + Z_PARAM_ZVAL(needles) + Z_PARAM_OPTIONAL + Z_PARAM_ZVAL(caseSensitive) + ZEND_PARSE_PARAMETERS_END(); + + zval rv; + zval *encoding = zend_read_property(stringy_ce, getThis(), ZEND_STRL("encoding"), 0, &rv); + zval *str = zend_read_property(stringy_ce, getThis(), ZEND_STRL("str"), 0, &rv); + + convert_to_array(needles); + + if (zend_array_count(Z_ARRVAL_P(needles)) == 0) { + RETURN_BOOL(0); + } + + zval *needle; + ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(needles), needle){ + zval func, args[] = { + *needle, + *caseSensitive + }; + ZVAL_STRING(&func, "contains"); + call_user_function(NULL, getThis(), &func, return_value, 2, args); + if (Z_TYPE_P(return_value) == IS_TRUE) { + RETURN_BOOL(1); + } + }ZEND_HASH_FOREACH_END(); + + RETURN_BOOL(0); +} +ZEND_BEGIN_ARG_INFO(arginfo_containsAny, 2) ZEND_ARG_INFO(0, needle) ZEND_ARG_INFO(0, caseSensitive) ZEND_END_ARG_INFO(); @@ -1358,6 +1398,7 @@ static zend_function_entry methods[] = { PHP_ME(Stringy, between, arginfo_between, ZEND_ACC_PUBLIC) PHP_ME(Stringy, contains, arginfo_contains, ZEND_ACC_PUBLIC) PHP_ME(Stringy, containsAll, arginfo_containsAll, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, containsAny, arginfo_containsAny, ZEND_ACC_PUBLIC) PHP_FE_END }; From e42774a9f98f27f294838f9a370259b268eb9976 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Sat, 15 Dec 2018 10:57:04 +0800 Subject: [PATCH 069/126] Feature/stringy count substr (#30) * remove unsed $data * stringy-countSubStr test+php+ext --- spec/Stringy/StringySpec.php | 30 ++++++++++++++++ src/Minbaby/Php/Stringy/Stringy.php | 10 ++++++ src/ext/stringy/stringy.c | 53 +++++++++++++++++++++++++++++ 3 files changed, 93 insertions(+) diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index a00d2b6..9c00f10 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -709,4 +709,34 @@ \expect($result)->toBe($expected); } }); + + it('test countSubStr', function () { + $data = [ + [0, '', 'foo'], + [0, 'foo', 'bar'], + [1, 'foo bar', 'foo'], + [2, 'foo bar', 'o'], + [0, '', 'fòô', true, 'UTF-8'], + [0, 'fòô', 'bàř', true, 'UTF-8'], + [1, 'fòô bàř', 'fòô', true, 'UTF-8'], + [2, 'fôòô bàř', 'ô', true, 'UTF-8'], + [0, 'fÔÒÔ bàř', 'ô', true, 'UTF-8'], + [0, 'foo', 'BAR', false], + [1, 'foo bar', 'FOo', false], + [2, 'foo bar', 'O', false], + [1, 'fòô bàř', 'fÒÔ', false, 'UTF-8'], + [2, 'fôòô bàř', 'Ô', false, 'UTF-8'], + [2, 'συγγραφέας', 'Σ', false, 'UTF-8'] + ]; + + foreach($data as $value) + { + @list($expected, $str, $substring, $caseSensitive, $encoding) = $value; + $stringy = __('Stringy')::create($str, $encoding); + $result = $stringy->countSubstr($substring, $caseSensitive === true || $caseSensitive === NULL); + \expect($result)->toBeA('int'); + \expect($result)->toBe($expected); + \expect((string)$stringy)->toBe($str); + } + }); }); diff --git a/src/Minbaby/Php/Stringy/Stringy.php b/src/Minbaby/Php/Stringy/Stringy.php index f0b6a43..228438d 100644 --- a/src/Minbaby/Php/Stringy/Stringy.php +++ b/src/Minbaby/Php/Stringy/Stringy.php @@ -353,4 +353,14 @@ public function containsAny($needles, $caseSensitive = true) } return false; } + + public function countSubstr($substring, $caseSensitive = true) + { + if ($caseSensitive) { + return \mb_substr_count($this->str, $substring, $this->encoding); + } + $str = \mb_strtoupper($this->str, $this->encoding); + $substring = \mb_strtoupper($substring, $this->encoding); + return \mb_substr_count($str, $substring, $this->encoding); + } } diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index 8f8d0de..3e24e35 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -1363,6 +1363,58 @@ ZEND_BEGIN_ARG_INFO(arginfo_containsAny, 2) ZEND_ARG_INFO(0, caseSensitive) ZEND_END_ARG_INFO(); +PHP_METHOD(Stringy, countSubstr) +{ + zval *substring = NULL, *caseSensitive = NULL; + ZEND_PARSE_PARAMETERS_START(1, 2) + Z_PARAM_ZVAL(substring) + Z_PARAM_OPTIONAL + Z_PARAM_ZVAL(caseSensitive) + ZEND_PARSE_PARAMETERS_END(); + + zval rv; + zval *encoding = zend_read_property(stringy_ce, getThis(), ZEND_STRL("encoding"), 0, &rv); + zval *str = zend_read_property(stringy_ce, getThis(), ZEND_STRL("str"), 0, &rv); + + if (Z_TYPE_P(caseSensitive) == IS_TRUE) { + zval func, args[] = { + *str, + *substring, + *encoding, + }; + ZVAL_STRING(&func, "mb_substr_count"); + call_user_function(NULL, NULL, &func, return_value, 3, args); + return; + } + + zval str_zval, substring_zval; + zval func, args[] = { + *str, + *encoding, + }; + ZVAL_STRING(&func, "mb_strtoupper"); + call_user_function(NULL, NULL, &func, &str_zval, 2, args); + + zval args_substring[] = { + *substring, + *encoding, + }; + ZVAL_STRING(&func, "mb_strtoupper"); + call_user_function(NULL, NULL, &func, &substring_zval, 2, args_substring); + + zval args_count[] = { + str_zval, + substring_zval, + *encoding, + }; + ZVAL_STRING(&func, "mb_substr_count"); + call_user_function(NULL, NULL, &func, return_value, 3, args_count); +} +ZEND_BEGIN_ARG_INFO(arginfo_countSubstr, 2) + ZEND_ARG_INFO(0, substring) + ZEND_ARG_INFO(0, caseSensitive) +ZEND_END_ARG_INFO(); + static zend_function_entry methods[] = { PHP_ME(Stringy, __construct, arginfo___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) PHP_ME(Stringy, __toString, NULL, ZEND_ACC_PUBLIC) @@ -1399,6 +1451,7 @@ static zend_function_entry methods[] = { PHP_ME(Stringy, contains, arginfo_contains, ZEND_ACC_PUBLIC) PHP_ME(Stringy, containsAll, arginfo_containsAll, ZEND_ACC_PUBLIC) PHP_ME(Stringy, containsAny, arginfo_containsAny, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, countSubstr, arginfo_countSubstr, ZEND_ACC_PUBLIC) PHP_FE_END }; From c392f76c6da761ab06ae6706d149a0b34311e4fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Sat, 15 Dec 2018 14:11:26 +0800 Subject: [PATCH 070/126] stringy-delimit test+php+ext (#31) --- spec/Stringy/StringySpec.php | 29 ++++++++++++++ src/Minbaby/Php/Stringy/Stringy.php | 11 +++++ src/ext/stringy/stringy.c | 62 +++++++++++++++++++++++++++-- 3 files changed, 99 insertions(+), 3 deletions(-) diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index 9c00f10..eb3cc76 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -739,4 +739,33 @@ \expect((string)$stringy)->toBe($str); } }); + + it('test delimit', function () { + $data = [ + ['test*case', 'testCase', '*'], + ['test&case', 'Test-Case', '&'], + ['test#case', 'test case', '#'], + ['test**case', 'test -case', '**'], + ['~!~test~!~case', '-test - case', '~!~'], + ['test*case', 'test_case', '*'], + ['test%c%test', ' test c test', '%'], + ['test+u+case', 'TestUCase', '+'], + ['test=c=c=test', 'TestCCTest', '='], + ['string#>with1number', 'string_with1number', '#>'], + ['1test2case', '1test2case', '*'], + ['test ύα σase', 'test Σase', ' ύα ', 'UTF-8',], + ['στανιλαcase', 'Στανιλ case', 'α', 'UTF-8',], + ['σashΘcase', 'Σash Case', 'Θ', 'UTF-8'] + ]; + + foreach($data as $value) { + @list($expected, $str, $delimiter, $encoding) = $value; + $stringy = __('Stringy')::create($str, $encoding); + $result = $stringy->delimit($delimiter); + + \expect($result)->toBeAnInstanceOf(__('Stringy')); + \expect((string)$stringy)->toBe($str); + \expect((string)$result)->toBe($expected); + } + }); }); diff --git a/src/Minbaby/Php/Stringy/Stringy.php b/src/Minbaby/Php/Stringy/Stringy.php index 228438d..c58f0dc 100644 --- a/src/Minbaby/Php/Stringy/Stringy.php +++ b/src/Minbaby/Php/Stringy/Stringy.php @@ -363,4 +363,15 @@ public function countSubstr($substring, $caseSensitive = true) $substring = \mb_strtoupper($substring, $this->encoding); return \mb_substr_count($str, $substring, $this->encoding); } + + public function delimit($delimiter) + { + $regexEncoding = $this->regexEncoding(); + $this->regexEncoding($this->encoding); + $str = $this->eregReplace('\B([A-Z])', '-\1', $this->trim()); + $str = \mb_strtolower($str, $this->encoding); + $str = $this->eregReplace('[-_\s]+', $delimiter, $str); + $this->regexEncoding($regexEncoding); + return static::create($str, $this->encoding); + } } diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index 3e24e35..36cbcdb 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -587,14 +587,19 @@ PHP_METHOD(Stringy, eregReplace) Z_PARAM_ZVAL(option) ZEND_PARSE_PARAMETERS_END(); + zval func; + ZVAL_STRING(&func, "mb_ereg_replace"); + + if (option == NULL) { + option = malloc(sizeof(zval)); + ZVAL_EMPTY_STRING(option); + } + convert_to_string(replace); convert_to_string(pattern); convert_to_string(string); convert_to_string(option); - zval func; - ZVAL_STRING(&func, "mb_ereg_replace"); - zval args[] = { *pattern, *replace, @@ -1415,6 +1420,56 @@ ZEND_BEGIN_ARG_INFO(arginfo_countSubstr, 2) ZEND_ARG_INFO(0, caseSensitive) ZEND_END_ARG_INFO(); +PHP_METHOD(Stringy, delimit) +{ + zval *delimiter = NULL; + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ZVAL(delimiter) + ZEND_PARSE_PARAMETERS_END(); + + zval rv, ret; + zval *encoding = zend_read_property(stringy_ce, getThis(), ZEND_STRL("encoding"), 0, &rv); + + zval func; + ZVAL_STRING(&func, "trim"); + call_user_function(NULL, getThis(), &func, return_value, 0, NULL); + + zval pattern, replacement; + ZVAL_STRING(&pattern, "\\B([A-Z])"); + ZVAL_STRING(&replacement, "-\\1"); + zval args[] = { + pattern, + replacement, + *return_value + }; + ZVAL_STRING(&func, "eregReplace"); + call_user_function(NULL, getThis(), &func, &ret, 3, args); + + zval args_strtolower[] = { + ret, + *encoding, + }; + ZVAL_STRING(&func, "mb_strtolower"); + call_user_function(NULL, NULL, &func, return_value, 2, args_strtolower); + + ZVAL_STRING(&pattern, "[-_\\s]+"); + zval args_eregReplace[] = { + pattern, + *delimiter, + *return_value + }; + ZVAL_STRING(&func, "eregReplace"); + call_user_function(NULL, getThis(), &func, &ret, 3, args_eregReplace); + + zval instance; + object_init_ex(&instance, stringy_ce); + zend_call_method(&instance, stringy_ce, NULL, ZEND_STRL("__construct"), return_value, 2, &ret, encoding); + RETURN_ZVAL(&instance, 0, 1); +} +ZEND_BEGIN_ARG_INFO(arginfo_delimit, 0) + ZEND_ARG_INFO(0, delimiter) +ZEND_END_ARG_INFO(); + static zend_function_entry methods[] = { PHP_ME(Stringy, __construct, arginfo___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) PHP_ME(Stringy, __toString, NULL, ZEND_ACC_PUBLIC) @@ -1452,6 +1507,7 @@ static zend_function_entry methods[] = { PHP_ME(Stringy, containsAll, arginfo_containsAll, ZEND_ACC_PUBLIC) PHP_ME(Stringy, containsAny, arginfo_containsAny, ZEND_ACC_PUBLIC) PHP_ME(Stringy, countSubstr, arginfo_countSubstr, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, delimit, arginfo_delimit, ZEND_ACC_PUBLIC) PHP_FE_END }; From 273bace408ba0716e41968f3a16bedf2ef36798e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Sat, 22 Dec 2018 13:32:31 +0800 Subject: [PATCH 071/126] stringy test+php+ext (#32) --- spec/Stringy/StringySpec.php | 34 +++++++++++++++++++++++++++++ src/Minbaby/Php/Stringy/Stringy.php | 5 +++++ src/ext/stringy/stringy.c | 12 ++++++++++ 3 files changed, 51 insertions(+) diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index eb3cc76..6bd2f2c 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -768,4 +768,38 @@ \expect((string)$result)->toBe($expected); } }); + + it('test dasherize', function () { + $data = [ + ['test-case', 'testCase'], + ['test-case', 'Test-Case'], + ['test-case', 'test case'], + ['-test-case', '-test -case'], + ['test-case', 'test - case'], + ['test-case', 'test_case'], + ['test-c-test', 'test c test'], + ['test-d-case', 'TestDCase'], + ['test-c-c-test', 'TestCCTest'], + ['string-with1number', 'string_with1number'], + ['string-with-2-2-numbers', 'String-with_2_2 numbers'], + ['1test2case', '1test2case'], + ['data-rate', 'dataRate'], + ['car-speed', 'CarSpeed'], + ['yes-we-can', 'yesWeCan'], + ['background-color', 'backgroundColor'], + ['dash-σase', 'dash Σase', 'UTF-8'], + ['στανιλ-case', 'Στανιλ case', 'UTF-8'], + ['σash-case', 'Σash Case', 'UTF-8'] + ]; + + foreach($data as $value) + { + @list($expected, $str, $encoding) = $value; + $stringy = __('Stringy')::create($str, $encoding); + $result = $stringy->dasherize(); + \expect($result)->toBeAnInstanceOf(__('Stringy')); + \expect((string)$stringy)->toBe($str); + \expect((string)$result)->toBe($expected); + } + }); }); diff --git a/src/Minbaby/Php/Stringy/Stringy.php b/src/Minbaby/Php/Stringy/Stringy.php index c58f0dc..371b1cf 100644 --- a/src/Minbaby/Php/Stringy/Stringy.php +++ b/src/Minbaby/Php/Stringy/Stringy.php @@ -374,4 +374,9 @@ public function delimit($delimiter) $this->regexEncoding($regexEncoding); return static::create($str, $this->encoding); } + + public function dasherize() + { + return $this->delimit('-'); + } } diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index 36cbcdb..9f5d2b2 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -1470,6 +1470,17 @@ ZEND_BEGIN_ARG_INFO(arginfo_delimit, 0) ZEND_ARG_INFO(0, delimiter) ZEND_END_ARG_INFO(); +PHP_METHOD(Stringy, dasherize) +{ + zval delimit; + ZVAL_STRING(&delimit, "-"); + zval func, args[] = { + delimit, + }; + ZVAL_STRING(&func, "delimit"); + call_user_function(NULL, getThis(), &func, return_value, 1, args); +} + static zend_function_entry methods[] = { PHP_ME(Stringy, __construct, arginfo___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) PHP_ME(Stringy, __toString, NULL, ZEND_ACC_PUBLIC) @@ -1508,6 +1519,7 @@ static zend_function_entry methods[] = { PHP_ME(Stringy, containsAny, arginfo_containsAny, ZEND_ACC_PUBLIC) PHP_ME(Stringy, countSubstr, arginfo_countSubstr, ZEND_ACC_PUBLIC) PHP_ME(Stringy, delimit, arginfo_delimit, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, dasherize, NULL, ZEND_ACC_PUBLIC) PHP_FE_END }; From d35f5dc07d9a8896a6c256d06fe98390dbdcb8f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Sat, 22 Dec 2018 16:49:58 +0800 Subject: [PATCH 072/126] stringy test+php+ext (#33) * stringy test+php+ext * remove --- spec/Stringy/StringySpec.php | 25 ++++++++++ src/Minbaby/Php/Stringy/Stringy.php | 24 ++++++++++ src/ext/stringy/stringy.c | 73 +++++++++++++++++++++++++++++ 3 files changed, 122 insertions(+) diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index 6bd2f2c..1345592 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -802,4 +802,29 @@ \expect((string)$result)->toBe($expected); } }); + + it('test endsWith', function () { + $data = [ + [true, 'foo bars', 'o bars'], + [true, 'FOO bars', 'o bars', false], + [true, 'FOO bars', 'o BARs', false], + [true, 'FÒÔ bàřs', 'ô bàřs', false, 'UTF-8'], + [true, 'fòô bàřs', 'ô BÀŘs', false, 'UTF-8'], + [false, 'foo bar', 'foo'], + [false, 'foo bar', 'foo bars'], + [false, 'FOO bar', 'foo bars'], + [false, 'FOO bars', 'foo BARS'], + [false, 'FÒÔ bàřs', 'fòô bàřs', true, 'UTF-8'], + [false, 'fòô bàřs', 'fòô BÀŘS', true, 'UTF-8'], + ]; + foreach($data as $value) { + @list($expected, $str, $substring, $caseSensitive, $encoding) = $value; + $stringy = __('Stringy')::create($str, $encoding); + $result = $stringy->endsWith($substring, $caseSensitive === true || $caseSensitive === NULL); + + \expect($result)->toBeA('boolean'); + \expect((string) $stringy)->toBe($str); + \expect($result)->toBe($expected); + } + }); }); diff --git a/src/Minbaby/Php/Stringy/Stringy.php b/src/Minbaby/Php/Stringy/Stringy.php index 371b1cf..00155eb 100644 --- a/src/Minbaby/Php/Stringy/Stringy.php +++ b/src/Minbaby/Php/Stringy/Stringy.php @@ -379,4 +379,28 @@ public function dasherize() { return $this->delimit('-'); } + + // protected function supportsEncoding() + // { + // $supported = ['UTF-8' => true, 'ASCII' => true]; + // if (isset($supported[$this->encoding])) { + // return true; + // } else { + // throw new \RuntimeException('Stringy method requires the ' . + // 'mbstring module for encodings other than ASCII and UTF-8. ' . + // 'Encoding used: ' . $this->encoding); + // } + // } + + public function endsWith($substring, $caseSensitive = true) + { + $substringLength = \mb_strlen($substring, $this->encoding); + $strLength = $this->length(); + $endOfStr = \mb_substr($this->str, $strLength - $substringLength, $substringLength, $this->encoding); + if (!$caseSensitive) { + $substring = \mb_strtolower($substring, $this->encoding); + $endOfStr = \mb_strtolower($endOfStr, $this->encoding); + } + return (string) $substring === $endOfStr; + } } diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index 9f5d2b2..013d5e6 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -1480,6 +1480,78 @@ PHP_METHOD(Stringy, dasherize) ZVAL_STRING(&func, "delimit"); call_user_function(NULL, getThis(), &func, return_value, 1, args); } + +PHP_METHOD(Stringy, endsWith) +{ + zval *substring, *caseSensitive = NULL; + ZEND_PARSE_PARAMETERS_START(1, 2) + Z_PARAM_ZVAL(substring) + Z_PARAM_OPTIONAL + Z_PARAM_ZVAL(caseSensitive) + ZEND_PARSE_PARAMETERS_END(); + + if (caseSensitive == NULL) { + caseSensitive = malloc(sizeof(zval)); + ZVAL_BOOL(caseSensitive, IS_TRUE); + } + + zval rv; + zval *str = zend_read_property(stringy_ce, getThis(), ZEND_STRL("str"), 0, &rv); + zval *encoding = zend_read_property(stringy_ce, getThis(), ZEND_STRL("encoding"), 0, &rv); + + zval substring_len; + zval func, args[] = { + *substring, + *encoding, + }; + ZVAL_STRING(&func, "mb_strlen"); + call_user_function(NULL, NULL, &func, &substring_len, 2, args); + + zval str_len; + ZVAL_STRING(&func, "length"); + call_user_function(NULL, getThis(), &func, &str_len, 0, NULL); + + zval start; + size_t str_length = Z_LVAL(str_len); + size_t substring_length = Z_LVAL(substring_len); + ZVAL_LONG(&start, str_length - substring_length); + zval endOfStr; + //\mb_substr($this->str, $strLength - $substringLength, $substringLength, $this->encoding); + zval args_substr[] = { + *str, + start, + substring_len, + *encoding, + }; + ZVAL_STRING(&func, "mb_substr"); + call_user_function(NULL, NULL, &func, &endOfStr, 4, args_substr); + + if (Z_TYPE_P(caseSensitive) == IS_FALSE) { + zval args_tolower_substring[] = { + *substring, + *encoding, + }; + ZVAL_STRING(&func, "mb_strtolower"); + call_user_function(NULL, NULL, &func, substring, 2, args_tolower_substring); + + zval args_tolower_endOfStr[] = { + endOfStr, + *encoding, + }; + ZVAL_STRING(&func, "mb_strtolower"); + call_user_function(NULL, NULL, &func, &endOfStr, 2, args_tolower_endOfStr); + } + + if (zend_string_equals(Z_STR_P(substring), Z_STR(endOfStr))) { + RETURN_BOOL(1); + } + + RETURN_BOOL(0); +} +ZEND_BEGIN_ARG_INFO(arginfo_endsWith, 0) + ZEND_ARG_INFO(0, substring) + ZEND_ARG_INFO(0, caseSensitive) +ZEND_END_ARG_INFO(); static zend_function_entry methods[] = { PHP_ME(Stringy, __construct, arginfo___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) @@ -1520,6 +1592,7 @@ static zend_function_entry methods[] = { PHP_ME(Stringy, countSubstr, arginfo_countSubstr, ZEND_ACC_PUBLIC) PHP_ME(Stringy, delimit, arginfo_delimit, ZEND_ACC_PUBLIC) PHP_ME(Stringy, dasherize, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, endsWith, arginfo_endsWith, ZEND_ACC_PUBLIC) PHP_FE_END }; From 8aab183ef1b939fd023791d3c42734f1e04b9323 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Sun, 23 Dec 2018 01:15:52 +0800 Subject: [PATCH 073/126] Stringy-endsWithAny test+php+ext (#34) --- spec/Stringy/StringySpec.php | 27 +++++++++++++++++++++ src/Minbaby/Php/Stringy/Stringy.php | 13 ++++++++++ src/ext/stringy/stringy.c | 37 +++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+) diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index 1345592..148f99f 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -827,4 +827,31 @@ \expect($result)->toBe($expected); } }); + + it('test endWithAny', function () { + $data = [ + [true, 'foo bars', ['foo', 'o bars']], + [true, 'FOO bars', ['foo', 'o bars'], false], + [true, 'FOO bars', ['foo', 'o BARs'], false], + [true, 'FÒÔ bàřs', ['foo', 'ô bàřs'], false, 'UTF-8'], + [true, 'fòô bàřs', ['foo', 'ô BÀŘs'], false, 'UTF-8'], + [false, 'foo bar', ['foo']], + [false, 'foo bar', ['foo', 'foo bars']], + [false, 'FOO bar', ['foo', 'foo bars']], + [false, 'FOO bars', ['foo', 'foo BARS']], + [false, 'FÒÔ bàřs', ['fòô', 'fòô bàřs'], true, 'UTF-8'], + [false, 'fòô bàřs', ['fòô', 'fòô BÀŘS'], true, 'UTF-8'], + ]; + + foreach($data as $value) { + @list($expected, $str, $substrings, $caseSensitive, $encoding) = $value; + $stringy = __('Stringy')::create($str, $encoding); + $result = $stringy->endsWithAny($substrings, $caseSensitive === true || $caseSensitive === NULL); + + \expect($result)->toBeA('boolean'); + \expect((string) $stringy)->toBe($str); + \expect($result)->toBe($expected); + } + + }); }); diff --git a/src/Minbaby/Php/Stringy/Stringy.php b/src/Minbaby/Php/Stringy/Stringy.php index 00155eb..3d0bb92 100644 --- a/src/Minbaby/Php/Stringy/Stringy.php +++ b/src/Minbaby/Php/Stringy/Stringy.php @@ -403,4 +403,17 @@ public function endsWith($substring, $caseSensitive = true) } return (string) $substring === $endOfStr; } + + public function endsWithAny($substrings, $caseSensitive = true) + { + if (empty($substrings)) { + return false; + } + foreach ($substrings as $substring) { + if ($this->endsWith($substring, $caseSensitive)) { + return true; + } + } + return false; + } } diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index 013d5e6..42f8795 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -1553,6 +1553,42 @@ ZEND_BEGIN_ARG_INFO(arginfo_endsWith, 0) ZEND_ARG_INFO(0, caseSensitive) ZEND_END_ARG_INFO(); +PHP_METHOD(Stringy, endsWithAny) +{ + zval *substring, *caseSensitive = NULL; + ZEND_PARSE_PARAMETERS_START(1, 2) + Z_PARAM_ZVAL(substring) + Z_PARAM_OPTIONAL + Z_PARAM_ZVAL(caseSensitive) + ZEND_PARSE_PARAMETERS_END(); + + if (caseSensitive == NULL) { + caseSensitive = malloc(sizeof(zval)); + ZVAL_BOOL(caseSensitive, IS_TRUE); + } + + convert_to_array(substring); + + zval *val; + ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(substring), val) { + zval func, args[] = { + *val, + *caseSensitive, + }; + ZVAL_STRING(&func, "endsWith"); + call_user_function(NULL, getThis(), &func, return_value, 2, args); + if (Z_TYPE_P(return_value) == IS_TRUE) { + RETURN_BOOL(1); + } + } ZEND_HASH_FOREACH_END(); + + RETURN_BOOL(0); +} +ZEND_BEGIN_ARG_INFO(arginfo_endsWithAny, 0) + ZEND_ARG_INFO(0, substring) + ZEND_ARG_INFO(0, caseSensitive) +ZEND_END_ARG_INFO(); + static zend_function_entry methods[] = { PHP_ME(Stringy, __construct, arginfo___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) PHP_ME(Stringy, __toString, NULL, ZEND_ACC_PUBLIC) @@ -1593,6 +1629,7 @@ static zend_function_entry methods[] = { PHP_ME(Stringy, delimit, arginfo_delimit, ZEND_ACC_PUBLIC) PHP_ME(Stringy, dasherize, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, endsWith, arginfo_endsWith, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, endsWithAny, arginfo_endsWithAny, ZEND_ACC_PUBLIC) PHP_FE_END }; From 117e439813ba4cc01d08a20af24d040571ffc547 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Sun, 23 Dec 2018 01:20:14 +0800 Subject: [PATCH 074/126] update test for coverage (#35) * Stringy-endsWithAny test+php+ext * update test for coverage --- spec/Stringy/StringySpec.php | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index 148f99f..b23e433 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -841,6 +841,7 @@ [false, 'FOO bars', ['foo', 'foo BARS']], [false, 'FÒÔ bàřs', ['fòô', 'fòô bàřs'], true, 'UTF-8'], [false, 'fòô bàřs', ['fòô', 'fòô BÀŘS'], true, 'UTF-8'], + [false, 'fòô bàřs', [], true, 'UTF-8'], ]; foreach($data as $value) { From 5624d7d4d7cf2503169473fca27e5fc647e46067 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Tue, 1 Jan 2019 23:43:26 +0800 Subject: [PATCH 075/126] stringy startsWith test+ext+php (#36) --- spec/Stringy/StringySpec.php | 26 ++++++++++ src/Minbaby/Php/Stringy/Stringy.php | 11 ++++ src/ext/stringy/stringy.c | 78 ++++++++++++++++++++++++++--- 3 files changed, 109 insertions(+), 6 deletions(-) diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index b23e433..f28fba1 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -855,4 +855,30 @@ } }); + + it('test startWith', function () { + $data = [ + [true, 'foo bars', 'foo bar'], + [true, 'FOO bars', 'foo bar', false], + [true, 'FOO bars', 'foo BAR', false], + [true, 'FÒÔ bàřs', 'fòô bàř', false, 'UTF-8'], + [true, 'fòô bàřs', 'fòô BÀŘ', false, 'UTF-8'], + [false, 'foo bar', 'bar'], + [false, 'foo bar', 'foo bars'], + [false, 'FOO bar', 'foo bars'], + [false, 'FOO bars', 'foo BAR'], + [false, 'FÒÔ bàřs', 'fòô bàř', true, 'UTF-8'], + [false, 'fòô bàřs', 'fòô BÀŘ', true, 'UTF-8'], + ]; + foreach($data as $value){ + @list($expected, $str, $substring, $caseSensitive, $encoding) = $value; + $stringy = _('Stringy')::create($str, $encoding); + $result = $stringy->startsWith($substring, $caseSensitive === true || $caseSensitive === NULL); + + \expect($result)->toBeA('boolean'); + \expect((string) $stringy)->toBe($str); + \expect($result)->toBe($expected); + } + + }); }); diff --git a/src/Minbaby/Php/Stringy/Stringy.php b/src/Minbaby/Php/Stringy/Stringy.php index 3d0bb92..bfc7ec1 100644 --- a/src/Minbaby/Php/Stringy/Stringy.php +++ b/src/Minbaby/Php/Stringy/Stringy.php @@ -416,4 +416,15 @@ public function endsWithAny($substrings, $caseSensitive = true) } return false; } + + public function startsWith($substring, $caseSensitive = true) + { + $substringLength = \mb_strlen($substring, $this->encoding); + $startOfStr = \mb_substr($this->str, 0, $substringLength, $this->encoding); + if (!$caseSensitive) { + $substring = \mb_strtolower($substring, $this->encoding); + $startOfStr = \mb_strtolower($startOfStr, $this->encoding); + } + return (string) $substring === $startOfStr; + } } diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index 42f8795..fbf76ba 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -1515,7 +1515,7 @@ PHP_METHOD(Stringy, endsWith) size_t str_length = Z_LVAL(str_len); size_t substring_length = Z_LVAL(substring_len); ZVAL_LONG(&start, str_length - substring_length); - zval endOfStr; + zval startOfStr; //\mb_substr($this->str, $strLength - $substringLength, $substringLength, $this->encoding); zval args_substr[] = { *str, @@ -1524,7 +1524,7 @@ PHP_METHOD(Stringy, endsWith) *encoding, }; ZVAL_STRING(&func, "mb_substr"); - call_user_function(NULL, NULL, &func, &endOfStr, 4, args_substr); + call_user_function(NULL, NULL, &func, &startOfStr, 4, args_substr); if (Z_TYPE_P(caseSensitive) == IS_FALSE) { zval args_tolower_substring[] = { @@ -1534,15 +1534,15 @@ PHP_METHOD(Stringy, endsWith) ZVAL_STRING(&func, "mb_strtolower"); call_user_function(NULL, NULL, &func, substring, 2, args_tolower_substring); - zval args_tolower_endOfStr[] = { - endOfStr, + zval args_tolower_startOfStr[] = { + startOfStr, *encoding, }; ZVAL_STRING(&func, "mb_strtolower"); - call_user_function(NULL, NULL, &func, &endOfStr, 2, args_tolower_endOfStr); + call_user_function(NULL, NULL, &func, &startOfStr, 2, args_tolower_startOfStr); } - if (zend_string_equals(Z_STR_P(substring), Z_STR(endOfStr))) { + if (zend_string_equals(Z_STR_P(substring), Z_STR(startOfStr))) { RETURN_BOOL(1); } @@ -1589,6 +1589,71 @@ ZEND_BEGIN_ARG_INFO(arginfo_endsWithAny, 0) ZEND_ARG_INFO(0, caseSensitive) ZEND_END_ARG_INFO(); +PHP_METHOD(Stringy, startsWith) +{ + zval *substring, *caseSensitive = NULL; + ZEND_PARSE_PARAMETERS_START(1, 2) + Z_PARAM_ZVAL(substring) + Z_PARAM_OPTIONAL + Z_PARAM_ZVAL(caseSensitive) + ZEND_PARSE_PARAMETERS_END(); + + if (caseSensitive == NULL) { + caseSensitive = malloc(sizeof(zval)); + ZVAL_BOOL(caseSensitive, IS_TRUE); + } + + zval rv; + zval *str = zend_read_property(stringy_ce, getThis(), ZEND_STRL("str"), 0, &rv); + zval *encoding = zend_read_property(stringy_ce, getThis(), ZEND_STRL("encoding"), 0, &rv); + + zval substring_len; + zval func, args[] = { + *substring, + *encoding, + }; + ZVAL_STRING(&func, "mb_strlen"); + call_user_function(NULL, NULL, &func, &substring_len, 2, args); + + zval start; + ZVAL_LONG(&start, 0); + zval startOfStr; + zval args_substr[] = { + *str, + start, + substring_len, + *encoding, + }; + ZVAL_STRING(&func, "mb_substr"); + call_user_function(NULL, NULL, &func, &startOfStr, 4, args_substr); + + if (Z_TYPE_P(caseSensitive) == IS_FALSE) { + zval args_tolower_substring[] = { + *substring, + *encoding, + }; + ZVAL_STRING(&func, "mb_strtolower"); + call_user_function(NULL, NULL, &func, substring, 2, args_tolower_substring); + + zval args_tolower_startOfStr[] = { + startOfStr, + *encoding, + }; + ZVAL_STRING(&func, "mb_strtolower"); + call_user_function(NULL, NULL, &func, &startOfStr, 2, args_tolower_startOfStr); + } + + if (zend_string_equals(Z_STR_P(substring), Z_STR(startOfStr))) { + RETURN_BOOL(1); + } + + RETURN_BOOL(0); +} +ZEND_BEGIN_ARG_INFO(arginfo_startsWith, 0) + ZEND_ARG_INFO(0, substring) + ZEND_ARG_INFO(0, caseSensitive) +ZEND_END_ARG_INFO(); + static zend_function_entry methods[] = { PHP_ME(Stringy, __construct, arginfo___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) PHP_ME(Stringy, __toString, NULL, ZEND_ACC_PUBLIC) @@ -1629,6 +1694,7 @@ static zend_function_entry methods[] = { PHP_ME(Stringy, delimit, arginfo_delimit, ZEND_ACC_PUBLIC) PHP_ME(Stringy, dasherize, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, endsWith, arginfo_endsWith, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, startsWith, arginfo_startsWith, ZEND_ACC_PUBLIC) PHP_ME(Stringy, endsWithAny, arginfo_endsWithAny, ZEND_ACC_PUBLIC) PHP_FE_END }; From b74b466ee4f21ab97ff30e26a9c4b02a7fb4420e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Wed, 2 Jan 2019 00:08:34 +0800 Subject: [PATCH 076/126] update (#37) --- spec/Stringy/StringySpec.php | 25 ++++++++++++++++ src/Minbaby/Php/Stringy/Stringy.php | 9 ++++++ src/ext/stringy/stringy.c | 44 ++++++++++++++++++++++++++++- 3 files changed, 77 insertions(+), 1 deletion(-) diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index f28fba1..056c309 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -856,6 +856,31 @@ }); + it('test ensureLeft', function () { + $data = [ + ['foobar', 'foobar', 'f'], + ['foobar', 'foobar', 'foo'], + ['foo/foobar', 'foobar', 'foo/'], + ['http://foobar', 'foobar', 'http://'], + ['http://foobar', 'http://foobar', 'http://'], + ['fòôbàř', 'fòôbàř', 'f', 'UTF-8'], + ['fòôbàř', 'fòôbàř', 'fòô', 'UTF-8'], + ['fòô/fòôbàř', 'fòôbàř', 'fòô/', 'UTF-8'], + ['http://fòôbàř', 'fòôbàř', 'http://', 'UTF-8'], + ['http://fòôbàř', 'http://fòôbàř', 'http://', 'UTF-8'], + ]; + + foreach($data as $value){ + @list($expected, $str, $substring, $encoding) = $value; + $stringy = __('Stringy')::create($str, $encoding); + $result = $stringy->ensureLeft($substring); + + \expect($stringy)->toBeAnInstanceOf(__('Stringy')); + \expect((string) $stringy)->toBe($str); + \expect((string) $result)->toBe($expected); + } + }); + it('test startWith', function () { $data = [ [true, 'foo bars', 'foo bar'], diff --git a/src/Minbaby/Php/Stringy/Stringy.php b/src/Minbaby/Php/Stringy/Stringy.php index bfc7ec1..73ee24b 100644 --- a/src/Minbaby/Php/Stringy/Stringy.php +++ b/src/Minbaby/Php/Stringy/Stringy.php @@ -417,6 +417,15 @@ public function endsWithAny($substrings, $caseSensitive = true) return false; } + public function ensureLeft($substring) + { + $stringy = static::create($this->str, $this->encoding); + if (!$stringy->startsWith($substring)) { + $stringy->str = $substring . $stringy->str; + } + return $stringy; + } + public function startsWith($substring, $caseSensitive = true) { $substringLength = \mb_strlen($substring, $this->encoding); diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index fbf76ba..131ac76 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -1654,6 +1654,46 @@ ZEND_BEGIN_ARG_INFO(arginfo_startsWith, 0) ZEND_ARG_INFO(0, caseSensitive) ZEND_END_ARG_INFO(); + + +PHP_METHOD(Stringy, ensureLeft) +{ + zval *substring = NULL; + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ZVAL(substring) + ZEND_PARSE_PARAMETERS_END(); + + zval rv; + zval *str = zend_read_property(stringy_ce, getThis(), ZEND_STRL("str"), 0, &rv); + zval *encoding = zend_read_property(stringy_ce, getThis(), ZEND_STRL("encoding"), 0, &rv); + + zval instance; + object_init_ex(&instance, stringy_ce); + zval func, args[] = { + *str, + *encoding, + }; + ZVAL_STRING(&func, "__construct"); + call_user_function(NULL, &instance, &func, return_value, 2, args); + + zval args_startWith[] = { + *substring + }; + ZVAL_STRING(&func, "startsWith"); + call_user_function(NULL, &instance, &func, return_value, 1, args_startWith); + + if (Z_TYPE_P(return_value) == IS_FALSE) { + zval tmp; + concat_function(&tmp, substring, str); + zend_update_property(stringy_ce, &instance, ZEND_STRL("str"), &tmp); + } + + RETURN_ZVAL(&instance, 0, 1); +} +ZEND_BEGIN_ARG_INFO(arginfo_ensureLeft, 0) + ZEND_ARG_INFO(0, substring) +ZEND_END_ARG_INFO(); + static zend_function_entry methods[] = { PHP_ME(Stringy, __construct, arginfo___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) PHP_ME(Stringy, __toString, NULL, ZEND_ACC_PUBLIC) @@ -1696,6 +1736,7 @@ static zend_function_entry methods[] = { PHP_ME(Stringy, endsWith, arginfo_endsWith, ZEND_ACC_PUBLIC) PHP_ME(Stringy, startsWith, arginfo_startsWith, ZEND_ACC_PUBLIC) PHP_ME(Stringy, endsWithAny, arginfo_endsWithAny, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, ensureLeft, arginfo_ensureLeft, ZEND_ACC_PUBLIC) PHP_FE_END }; @@ -1715,5 +1756,6 @@ void php_startup_register_stringy() 3, spl_ce_Countable, spl_ce_Aggregate, - spl_ce_ArrayAccess); + spl_ce_ArrayAccess + ); } From 8415cc4aae965ddfefab5801a1a377761789f859 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Thu, 3 Jan 2019 23:53:03 +0800 Subject: [PATCH 077/126] stringy/ensureRight test+ext+php (#38) --- spec/Stringy/StringySpec.php | 24 ++++++++++++++++++ spec/functions.php | 8 ++++++ src/Minbaby/Php/Stringy/Stringy.php | 9 +++++++ src/ext/stringy/stringy.c | 39 +++++++++++++++++++++++++++++ 4 files changed, 80 insertions(+) diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index 056c309..5cf04cc 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -904,6 +904,30 @@ \expect((string) $stringy)->toBe($str); \expect($result)->toBe($expected); } + }); + + it('test ensureRight', function () { + $data = [ + ['foobar', 'foobar', 'r'], + ['foobar', 'foobar', 'bar'], + ['foobar/bar', 'foobar', '/bar'], + ['foobar.com/', 'foobar', '.com/'], + ['foobar.com/', 'foobar.com/', '.com/'], + ['fòôbàř', 'fòôbàř', 'ř', 'UTF-8'], + ['fòôbàř', 'fòôbàř', 'bàř', 'UTF-8'], + ['fòôbàř/bàř', 'fòôbàř', '/bàř', 'UTF-8'], + ['fòôbàř.com/', 'fòôbàř', '.com/', 'UTF-8'], + ['fòôbàř.com/', 'fòôbàř.com/', '.com/', 'UTF-8'], + ]; + + foreach($data as $value) { + @list($expected, $str, $substring, $encoding) = $value; + $stringy = __('Stringy')::create($str, $encoding); + $result = $stringy->ensureRight($substring); + \expect($stringy)->toBeAnInstanceOf(__('Stringy')); + \expect((string) $stringy)->toBe($str); + \expect((string) $result)->toBe($expected); + } }); }); diff --git a/spec/functions.php b/spec/functions.php index 406eb45..c3d24ea 100644 --- a/spec/functions.php +++ b/spec/functions.php @@ -13,12 +13,20 @@ function _ns(string $ns = '\\') $________['ns'] = $ns; } +/** + * @var string $str 类名 + * @return object 类的实例化对象 + */ function _(string $str, array $args = []) { $class = __($str); return new $class(...$args); } +/** + * @var string $str 类名 + * @return string 带命名空间的完整类名 + */ function __(string $str): string { global $________; diff --git a/src/Minbaby/Php/Stringy/Stringy.php b/src/Minbaby/Php/Stringy/Stringy.php index 73ee24b..f388d47 100644 --- a/src/Minbaby/Php/Stringy/Stringy.php +++ b/src/Minbaby/Php/Stringy/Stringy.php @@ -436,4 +436,13 @@ public function startsWith($substring, $caseSensitive = true) } return (string) $substring === $startOfStr; } + + public function ensureRight($substring) + { + $stringy = static::create($this->str, $this->encoding); + if (!$stringy->endsWith($substring)) { + $stringy->str .= $substring; + } + return $stringy; + } } diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index 131ac76..4e48f05 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -1694,6 +1694,44 @@ ZEND_BEGIN_ARG_INFO(arginfo_ensureLeft, 0) ZEND_ARG_INFO(0, substring) ZEND_END_ARG_INFO(); +PHP_METHOD(Stringy, ensureRight) +{ + zval *substring = NULL; + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ZVAL(substring) + ZEND_PARSE_PARAMETERS_END(); + + zval rv; + zval *str = zend_read_property(stringy_ce, getThis(), ZEND_STRL("str"), 0, &rv); + zval *encoding = zend_read_property(stringy_ce, getThis(), ZEND_STRL("encoding"), 0, &rv); + + zval instance; + object_init_ex(&instance, stringy_ce); + zval func, args[] = { + *str, + *encoding, + }; + ZVAL_STRING(&func, "__construct"); + call_user_function(NULL, &instance, &func, return_value, 2, args); + + zval args_startWith[] = { + *substring + }; + ZVAL_STRING(&func, "endsWith"); + call_user_function(NULL, &instance, &func, return_value, 1, args_startWith); + + if (Z_TYPE_P(return_value) == IS_FALSE) { + zval tmp; + concat_function(&tmp, str, substring); + zend_update_property(stringy_ce, &instance, ZEND_STRL("str"), &tmp); + } + + RETURN_ZVAL(&instance, 0, 1); +} +ZEND_BEGIN_ARG_INFO(arginfo_ensureRight, 0) + ZEND_ARG_INFO(0, substring) +ZEND_END_ARG_INFO(); + static zend_function_entry methods[] = { PHP_ME(Stringy, __construct, arginfo___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) PHP_ME(Stringy, __toString, NULL, ZEND_ACC_PUBLIC) @@ -1737,6 +1775,7 @@ static zend_function_entry methods[] = { PHP_ME(Stringy, startsWith, arginfo_startsWith, ZEND_ACC_PUBLIC) PHP_ME(Stringy, endsWithAny, arginfo_endsWithAny, ZEND_ACC_PUBLIC) PHP_ME(Stringy, ensureLeft, arginfo_ensureLeft, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, ensureRight, arginfo_ensureRight, ZEND_ACC_PUBLIC) PHP_FE_END }; From ba349009ad7e954091fd241d065d737035b9cb82 Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Fri, 4 Jan 2019 00:21:57 +0800 Subject: [PATCH 078/126] stringy/first test+ext+php --- spec/Stringy/StringySpec.php | 27 +++++++++++++++++ src/Minbaby/Php/Stringy/Stringy.php | 10 +++++++ src/ext/stringy/stringy.c | 45 +++++++++++++++++++++++++++++ 3 files changed, 82 insertions(+) diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index 5cf04cc..9704667 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -930,4 +930,31 @@ \expect((string) $result)->toBe($expected); } }); + + it('test first', function () { + $data = [ + ['', 'foo bar', -5], + ['', 'foo bar', 0], + ['f', 'foo bar', 1], + ['foo', 'foo bar', 3], + ['foo bar', 'foo bar', 7], + ['foo bar', 'foo bar', 8], + ['', 'fòô bàř', -5, 'UTF-8'], + ['', 'fòô bàř', 0, 'UTF-8'], + ['f', 'fòô bàř', 1, 'UTF-8'], + ['fòô', 'fòô bàř', 3, 'UTF-8'], + ['fòô bàř', 'fòô bàř', 7, 'UTF-8'], + ['fòô bàř', 'fòô bàř', 8, 'UTF-8'], + ]; + + foreach($data as $value) { + @list($expected, $str, $n, $encoding) = $value; + $stringy = __('Stringy')::create($str, $encoding); + $result = $stringy->first($n); + + \expect($stringy)->toBeAnInstanceOf(__('Stringy')); + \expect((string) $stringy)->toBe($str); + \expect((string) $result)->toBe($expected); + } + }); }); diff --git a/src/Minbaby/Php/Stringy/Stringy.php b/src/Minbaby/Php/Stringy/Stringy.php index f388d47..80e3797 100644 --- a/src/Minbaby/Php/Stringy/Stringy.php +++ b/src/Minbaby/Php/Stringy/Stringy.php @@ -445,4 +445,14 @@ public function ensureRight($substring) } return $stringy; } + + public function first($n) + { + $stringy = static::create($this->str, $this->encoding); + if ($n < 0) { + $stringy->str = ''; + return $stringy; + } + return $stringy->substr(0, $n); + } } diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index 4e48f05..918e790 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -1732,6 +1732,50 @@ ZEND_BEGIN_ARG_INFO(arginfo_ensureRight, 0) ZEND_ARG_INFO(0, substring) ZEND_END_ARG_INFO(); +PHP_METHOD(Stringy, first) +{ + zval *n = NULL; + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ZVAL(n) + ZEND_PARSE_PARAMETERS_END(); + + if (n == NULL) { + ZVAL_LONG(n, 0); + } + + zval rv; + zval *str = zend_read_property(stringy_ce, getThis(), ZEND_STRL("str"), 0, &rv); + zval *encoding = zend_read_property(stringy_ce, getThis(), ZEND_STRL("encoding"), 0, &rv); + + zval instance; + object_init_ex(&instance, stringy_ce); + zval func, args[] = { + *str, + *encoding, + }; + ZVAL_STRING(&func, "__construct"); + call_user_function(NULL, &instance, &func, return_value, 2, args); + + zend_long len = Z_LVAL_P(n); + if (len < 0) { + zend_update_property_string(stringy_ce, &instance, ZEND_STRL("str"), ""); + RETURN_ZVAL(&instance, 0, 1); + } + + zval start; + ZVAL_LONG(&start, 0); + + zval args_substr[] = { + start, + *n, + }; + ZVAL_STRING(&func, "substr"); + call_user_function(NULL, &instance, &func, return_value, 2, args_substr); +} +ZEND_BEGIN_ARG_INFO(arginfo_first, 0) + ZEND_ARG_INFO(0, substring) +ZEND_END_ARG_INFO(); + static zend_function_entry methods[] = { PHP_ME(Stringy, __construct, arginfo___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) PHP_ME(Stringy, __toString, NULL, ZEND_ACC_PUBLIC) @@ -1776,6 +1820,7 @@ static zend_function_entry methods[] = { PHP_ME(Stringy, endsWithAny, arginfo_endsWithAny, ZEND_ACC_PUBLIC) PHP_ME(Stringy, ensureLeft, arginfo_ensureLeft, ZEND_ACC_PUBLIC) PHP_ME(Stringy, ensureRight, arginfo_ensureRight, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, first, arginfo_first, ZEND_ACC_PUBLIC) PHP_FE_END }; From 4ed5366d6b2d421dedd1273ffe11371036d9d75f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Mon, 7 Jan 2019 11:56:55 +0800 Subject: [PATCH 079/126] Apply fixes from StyleCI (#39) --- kahlan-config.php | 4 +- scripts/fetch.php | 8 +- spec/Stringy/StringySpec.php | 244 ++++++++++++++-------------- spec/TestSpec.php | 15 +- spec/const.php | 2 +- spec/functions.php | 13 +- src/Minbaby/Php/Stringy/Stringy.php | 68 +++++--- src/Minbaby/Php/Test.php | 3 +- startup.php | 9 +- 9 files changed, 195 insertions(+), 171 deletions(-) diff --git a/kahlan-config.php b/kahlan-config.php index da4686c..a6b0d51 100644 --- a/kahlan-config.php +++ b/kahlan-config.php @@ -1,7 +1,7 @@ commandLine(); // $commandLine->option('reporter', 'default', 'verbose'); $commandLine->option('ff', 'default', 1); diff --git a/scripts/fetch.php b/scripts/fetch.php index b5654fb..dc98a3c 100755 --- a/scripts/fetch.php +++ b/scripts/fetch.php @@ -28,14 +28,14 @@ // PHPBREW_ROOT/build/php-7.1.17/ext/ -$path = sprintf("%s/build/%s/ext", $_SERVER['PHPBREW_ROOT'], $_SERVER['PHPBREW_PHP']); +$path = sprintf('%s/build/%s/ext', $_SERVER['PHPBREW_ROOT'], $_SERVER['PHPBREW_PHP']); -foreach($data as $key => $value) { +foreach ($data as $key => $value) { if (file_exists("{$path}/{$key}")) { echo "[INFO] 有了 {$path}/{$key}", PHP_EOL; continue; } - echo "[INFO] clone repo:[", $key, "]", PHP_EOL; - echo "[INFO] path:[", $path, "]", PHP_EOL; + echo '[INFO] clone repo:[', $key, ']', PHP_EOL; + echo '[INFO] path:[', $path, ']', PHP_EOL; `cd $path && git clone $value $key && cd -`; } diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index 9704667..2664764 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -2,17 +2,14 @@ namespace Minbaby\Startup\Spec\Stringy; -use function Kahlan\context; - - -\describe("Stringy Test", function () { +\describe('Stringy Test', function () { \beforeAll(function () { _ns(NS_STRINGY); $this->class = 'Stringy'; $this->className = __($this->class); }); - it("test construct", function () { + it('test construct', function () { $stringy = _('Stringy', ['test test2 test3', 'UTF-8']); \expect($stringy)->toBeAnInstanceOf(__('Stringy')); @@ -20,29 +17,29 @@ \expect($stringy->getEncoding())->toBe('UTF-8'); }); - it("test empty construct", function () { + it('test empty construct', function () { $stringy = _('Stringy'); \expect($stringy instanceof $this->className)->toBe(true); \expect((string) $stringy)->toBe(''); }); - it("test construct with array", function () { + it('test construct with array', function () { $closure = function () { - (string)_($this->class, [[]]); + (string) _($this->class, [[]]); }; \expect($closure)->toThrow(new \InvalidArgumentException('Passed value cannot be an array')); }); - it("test missing __toString", function () { + it('test missing __toString', function () { $closure = function () { - (string)_($this->class, [new \stdClass()]); + (string) _($this->class, [new \stdClass()]); }; \expect($closure)->toThrow(new \InvalidArgumentException('Passed object must have a __toString method')); }); - it("test __toString", function () { + it('test __toString', function () { $data = [ ['', null], ['', false], @@ -53,13 +50,13 @@ ['❤', '❤'], ]; - foreach($data as $v) { + foreach ($data as $v) { list($key, $value) = $v; \expect($key)->toBe((string) _($this->class, [$value])); } }); - it("test create", function () { + it('test create', function () { $stringy = __('Stringy')::create('foo bar', 'UTF-8'); \expect($stringy)->toBeAnInstanceOf(__('Stringy')); @@ -70,7 +67,7 @@ it('test chaining', function () { $stringy = __('Stringy')::create('x y', 'UTF-8'); \expect($stringy)->toBeAnInstanceOf(__('Stringy')); - \expect((string) $stringy->swapCase())->toBe("X Y"); + \expect((string) $stringy->swapCase())->toBe('X Y'); }); it('test count', function () { @@ -101,7 +98,7 @@ [false, 3], [true, -1], [true, -3], - [false, -4] + [false, -4], ]; $stringy = __('Stringy')::create('fòô', 'UTF-8'); @@ -157,7 +154,7 @@ [6, 'fòô & bàř', 'bàř', 0, 'UTF-8'], [false, 'fòô & bàř', 'baz', 0, 'UTF-8'], [0, 'fòô & bàř & fòô', 'fòô', 0, 'UTF-8'], - [12, 'fòô & bàř & fòô', 'fòô', 5, 'UTF-8'] + [12, 'fòô & bàř & fòô', 'fòô', 5, 'UTF-8'], ]; foreach ($data as $value) { @@ -178,7 +175,7 @@ [6, 'fòô & bàř', 'bàř', 0, 'UTF-8'], [false, 'fòô & bàř', 'baz', 0, 'UTF-8'], [12, 'fòô & bàř & fòô', 'fòô', 0, 'UTF-8'], - [0, 'fòô & bàř & fòô', 'fòô', -5, 'UTF-8'] + [0, 'fòô & bàř & fòô', 'fòô', -5, 'UTF-8'], ]; foreach ($data as $value) { @@ -191,26 +188,26 @@ it('test append', function () { $data = [ ['foobar', 'foo', 'bar'], - ['fòôbàř', 'fòô', 'bàř', 'UTF-8'] + ['fòôbàř', 'fòô', 'bàř', 'UTF-8'], ]; - foreach($data as $value) { + foreach ($data as $value) { @list($expected, $str, $string, $encoding) = $value; $result = __('Stringy')::create($str, $encoding)->append($string); \expect($result)->toBeAnInstanceOf(__('Stringy')); - \expect((string)$result)->toBe($expected); + \expect((string) $result)->toBe($expected); } }); it('test prepend', function () { $data = [ ['foobar', 'bar', 'foo'], - ['fòôbàř', 'bàř', 'fòô', 'UTF-8'] + ['fòôbàř', 'bàř', 'fòô', 'UTF-8'], ]; - foreach($data as $value) { + foreach ($data as $value) { @list($expected, $str, $string, $encoding) = $value; $result = __('Stringy')::create($str, $encoding)->prepend($string); \expect($result)->toBeAnInstanceOf(__('Stringy')); - \expect((string)$result)->toBe($expected); + \expect((string) $result)->toBe($expected); } }); @@ -218,26 +215,26 @@ $data = [ [[], ''], [['T', 'e', 's', 't'], 'Test'], - [['F', 'ò', 'ô', ' ', 'B', 'à', 'ř'], 'Fòô Bàř', 'UTF-8'] + [['F', 'ò', 'ô', ' ', 'B', 'à', 'ř'], 'Fòô Bàř', 'UTF-8'], ]; - foreach($data as $value) { + foreach ($data as $value) { @list($expected, $str, $encoding) = $value; $result = __('Stringy')::create($str, $encoding)->chars(); \expect($result)->toBeA('array'); - + foreach ($result as $char) { \expect($char)->toBeA('string'); } - + \expect($result)->toBe($expected); } }); it('test lines', function () { $data = [ - [[], ""], + [[], ''], [[''], "\r\n"], [['foo', 'bar'], "foo\nbar"], [['foo', 'bar'], "foo\rbar"], @@ -254,18 +251,18 @@ [['', 'fòô', 'bàř'], "\r\nfòô\r\nbàř", 'UTF-8'], ]; - foreach($data as $value) { + foreach ($data as $value) { @list($expected, $str, $encoding) = $value; $result = __('Stringy')::create($str, $encoding)->lines(); \expect($result)->toBeA('array'); - + foreach ($result as $char) { \expect($char)->toBeAnInstanceOf(__('Stringy')); } - + for ($i = 0; $i < count($expected); $i++) { - \expect((string)$result[$i])->toBe($expected[$i]); + \expect((string) $result[$i])->toBe($expected[$i]); } } }); @@ -276,13 +273,13 @@ ['Test', 'test'], ['1a', '1a'], ['Σ test', 'σ test', 'UTF-8'], - [' σ test', ' σ test', 'UTF-8'] + [' σ test', ' σ test', 'UTF-8'], ]; - foreach($data as $value) { + foreach ($data as $value) { @list($expected, $str, $encoding) = $value; $result = __('Stringy')::create($str, $encoding)->upperCaseFirst(); \expect($result)->toBeAnInstanceOf(__('Stringy')); - \expect((string)$result)->toBe($expected); + \expect((string) $result)->toBe($expected); } }); @@ -292,19 +289,18 @@ ['test', 'test'], ['1a', '1a'], ['σ test', 'Σ test', 'UTF-8'], - [' Σ test', ' Σ test', 'UTF-8'] + [' Σ test', ' Σ test', 'UTF-8'], ]; - foreach($data as $value) { + foreach ($data as $value) { @list($expected, $str, $encoding) = $value; $stringy = __('Stringy')::create($str, $encoding); - \expect((string)$stringy)->toBe($str); + \expect((string) $stringy)->toBe($str); $result = $stringy->lowerCaseFirst(); \expect($result)->toBeAnInstanceOf(__('Stringy')); - \expect((string)$stringy)->toBe($str); - \expect((string)$result)->toBe($expected); + \expect((string) $stringy)->toBe($str); + \expect((string) $result)->toBe($expected); } - }); it('test testCamelize', function () { @@ -327,20 +323,19 @@ ['1Camel2Case', '1camel2case'], ['camelΣase', 'camel σase', 'UTF-8'], ['στανιλCase', 'Στανιλ case', 'UTF-8'], - ['σamelCase', 'σamel Case', 'UTF-8'] + ['σamelCase', 'σamel Case', 'UTF-8'], ]; - foreach($data as $value) { + foreach ($data as $value) { @list($expected, $str, $encoding) = $value; $stringy = __('Stringy')::create($str, $encoding); $result = $stringy->camelize(); \expect($result)->toBeAnInstanceOf(__('Stringy')); - \expect((string)$stringy)->toBe($str); - \expect((string)$result)->toBe($expected); + \expect((string) $stringy)->toBe($str); + \expect((string) $result)->toBe($expected); } }); it('test regexReplce', function () { - $data = [ ['', '', '', ''], ['bar', 'foo', 'f[o]+', 'bar'], @@ -350,16 +345,16 @@ ['', '', '', '', 'msr', 'UTF-8'], ['bàř', 'fòô ', 'f[òô]+\s', 'bàř', 'msr', 'UTF-8'], ['fòô', 'fò', '(ò)', '\\1ô', 'msr', 'UTF-8'], - ['fòô', 'bàř', '[[:alpha:]]{3}', 'fòô', 'msr', 'UTF-8'] + ['fòô', 'bàř', '[[:alpha:]]{3}', 'fòô', 'msr', 'UTF-8'], ]; - foreach($data as $value) { + foreach ($data as $value) { @list($expected, $str, $pattern, $replacement, $options, $encoding) = $value; $stringy = __('Stringy')::create($str, $encoding); $result = $stringy->regexReplace($pattern, $replacement, $options); \expect($result)->toBeAnInstanceOf(__('Stringy')); - \expect((string)$stringy)->toBe($str); - \expect((string)$result)->toBe($expected); + \expect((string) $stringy)->toBe($str); + \expect((string) $result)->toBe($expected); } }); @@ -376,17 +371,17 @@ ['fòô bàř', "\n\t fòô bàř \n\t", null, 'UTF-8'], ['fòô', ' fòô ', null, 'UTF-8'], // narrow no-break space (U+202F) ['fòô', '  fòô  ', null, 'UTF-8'], // medium mathematical space (U+205F) - ['fòô', '           fòô', null, 'UTF-8'] // spaces U+2000 to U+200A + ['fòô', '           fòô', null, 'UTF-8'], // spaces U+2000 to U+200A ]; - foreach($data as $value) { + foreach ($data as $value) { @list($expected, $str, $chars, $encoding) = $value; $stringy = __('Stringy')::create($str, $encoding); $result = $stringy->trim($chars); \expect($result)->toBeAnInstanceOf(__('Stringy')); - \expect((string)$stringy)->toBe($str); - \expect((string)$result)->toBe($expected); + \expect((string) $stringy)->toBe($str); + \expect((string) $result)->toBe($expected); } }); @@ -404,17 +399,17 @@ ["fòô bàř \n\t", "\n\t fòô bàř \n\t", null, 'UTF-8'], ['fòô ', ' fòô ', null, 'UTF-8'], // narrow no-break space (U+202F) ['fòô  ', '  fòô  ', null, 'UTF-8'], // medium mathematical space (U+205F) - ['fòô', '           fòô', null, 'UTF-8'] // spaces U+2000 to U+200A + ['fòô', '           fòô', null, 'UTF-8'], // spaces U+2000 to U+200A ]; - foreach($data as $value) { + foreach ($data as $value) { @list($expected, $str, $chars, $encoding) = $value; $stringy = __('Stringy')::create($str, $encoding); $result = $stringy->trimLeft($chars); \expect($result)->toBeAnInstanceOf(__('Stringy')); - \expect((string)$stringy)->toBe($str); - \expect((string)$result)->toBe($expected); + \expect((string) $stringy)->toBe($str); + \expect((string) $result)->toBe($expected); } }); @@ -432,22 +427,21 @@ ["\n\t fòô bàř", "\n\t fòô bàř \n\t", null, 'UTF-8'], [' fòô', ' fòô ', null, 'UTF-8'], // narrow no-break space (U+202F) ['  fòô', '  fòô  ', null, 'UTF-8'], // medium mathematical space (U+205F) - ['fòô', 'fòô           ', null, 'UTF-8'] // spaces U+2000 to U+200A + ['fòô', 'fòô           ', null, 'UTF-8'], // spaces U+2000 to U+200A ]; - foreach($data as $value) { + foreach ($data as $value) { @list($expected, $str, $chars, $encoding) = $value; $stringy = __('Stringy')::create($str, $encoding); $result = $stringy->trimRight($chars); \expect($result)->toBeAnInstanceOf(__('Stringy')); - \expect((string)$stringy)->toBe($str); - \expect((string)$result)->toBe($expected); + \expect((string) $stringy)->toBe($str); + \expect((string) $result)->toBe($expected); } }); it('test at', function () { - $data = [ ['f', 'foo bar', 0], ['o', 'foo bar', 1], @@ -459,13 +453,13 @@ ['', 'fòô bàř', 7, 'UTF-8'], ]; - foreach($data as $value) { + foreach ($data as $value) { @list($expected, $str, $index, $encoding) = $value; $stringy = __('Stringy')::create($str, $encoding); $result = $stringy->at($index); \expect($result)->toBeAnInstanceOf(__('Stringy')); - \expect((string)$stringy)->toBe($str); - \expect((string)$result)->toBe($expected); + \expect((string) $stringy)->toBe($str); + \expect((string) $result)->toBe($expected); } }); @@ -486,19 +480,19 @@ ['', '{}fòô}', '{', '}', 0, 'UTF-8'], ['fòô', '}{fòô}', '{', '}', 0, 'UTF-8'], ['fòô', 'A description of {fòô} goes here', '{', '}', 0, 'UTF-8'], - ['bàř', '{fòô} and {bàř}', '{', '}', 1, 'UTF-8'] + ['bàř', '{fòô} and {bàř}', '{', '}', 1, 'UTF-8'], ]; - foreach($data as $value) { + foreach ($data as $value) { @list($expected, $str, $start, $end, $offset, $encoding) = $value; $stringy = __('Stringy')::create($str, $encoding); $result = $stringy->between($start, $end, $offset); \expect($result)->toBeAnInstanceOf(__('Stringy')); - \expect((string)$stringy)->toBe($str); - \expect((string)$result)->toBe($expected); + \expect((string) $stringy)->toBe($str); + \expect((string) $result)->toBe($expected); } }); - \context('contains', function(){ + \context('contains', function () { $data = [ [true, 'Str contains foo bar', 'foo bar'], [true, '12398!@(*%!@# @!%#*&^%', ' @!%#*&^%'], @@ -520,14 +514,15 @@ [false, 'Str contains foo bar', 'foobar', false], [false, 'Str contains foo bar', 'foo bar ', false], [false, 'Ο συγγραφέας είπε', ' συγγραφέας ', false, 'UTF-8'], - [false, 'å´¥©¨ˆßå˚ ∆∂˙©å∑¥øœ¬', ' ßÅ˚', false, 'UTF-8'] + [false, 'å´¥©¨ˆßå˚ ∆∂˙©å∑¥øœ¬', ' ßÅ˚', false, 'UTF-8'], ]; $dataContainsAll = array_merge( array_map(function ($array) { $array[2] = [$array[2]]; + return $array; - }, $data), + }, $data), [ // One needle [false, 'Str contains foo bar', []], @@ -558,6 +553,7 @@ $dataContainsAny = array_merge( array_map(function ($array) { $array[2] = [$array[2]]; + return $array; }, $data), [ @@ -588,39 +584,39 @@ ]); it('test contains', function () use ($data) { - foreach($data as $value) { + foreach ($data as $value) { @list($expected, $haystack, $needle, $caseSensitive, $encoding) = $value; $stringy = __('Stringy')::create($haystack, $encoding); - $result = $stringy->contains($needle, $caseSensitive === true || $caseSensitive === NULL); // 默认值是 NULl, 这里需要特殊处理 + $result = $stringy->contains($needle, $caseSensitive === true || $caseSensitive === null); // 默认值是 NULl, 这里需要特殊处理 \expect($result)->toBeA('bool'); - \expect((string)$stringy)->toBe($haystack); - \expect((bool)$result)->toBe($expected); + \expect((string) $stringy)->toBe($haystack); + \expect((bool) $result)->toBe($expected); } }); it('test containsAll', function () use ($dataContainsAll) { - foreach($dataContainsAll as $value) { + foreach ($dataContainsAll as $value) { @list($expected, $haystack, $needle, $caseSensitive, $encoding) = $value; - + $stringy = __('Stringy')::create($haystack, $encoding); - $result = $stringy->containsAll($needle, $caseSensitive === true || $caseSensitive === NULL); // 默认值是 NULl, 这里需要特殊处理 + $result = $stringy->containsAll($needle, $caseSensitive === true || $caseSensitive === null); // 默认值是 NULl, 这里需要特殊处理 \expect($result)->toBeA('bool'); - \expect((string)$stringy)->toBe($haystack); - \expect((bool)$result)->toBe($expected); + \expect((string) $stringy)->toBe($haystack); + \expect((bool) $result)->toBe($expected); } }); it('test containsAny', function () use ($dataContainsAny) { - foreach($dataContainsAny as $value) { + foreach ($dataContainsAny as $value) { @list($expected, $haystack, $needles, $caseSensitive, $encoding) = $value; $stringy = __('Stringy')::create($haystack, $encoding); - - $result = $stringy->containsAny($needles, $caseSensitive === true || $caseSensitive === NULL); + + $result = $stringy->containsAny($needles, $caseSensitive === true || $caseSensitive === null); \expect($result)->toBeA('bool'); - \expect((string)$stringy)->toBe($haystack); - \expect((bool)$result)->toBe($expected); + \expect((string) $stringy)->toBe($haystack); + \expect((bool) $result)->toBe($expected); } - }); + }); }); it('test split', function () { @@ -643,10 +639,10 @@ [['fòô'], 'fòô,bàř,baz', ',', 1, 'UTF-8'], [['fòô', 'bàř'], 'fòô,bàř,baz', ',', 2, 'UTF-8'], [['fòô', 'bàř', 'baz'], 'fòô,bàř,baz', ',', 3, 'UTF-8'], - [['fòô', 'bàř', 'baz'], 'fòô,bàř,baz', ',', 10, 'UTF-8'] + [['fòô', 'bàř', 'baz'], 'fòô,bàř,baz', ',', 10, 'UTF-8'], ]; - foreach($data as $value) { + foreach ($data as $value) { @list($expected, $str, $pattern, $limit, $encoding) = $value; $stringy = __('Stringy')::create($str, $encoding); $result = $stringy->split($pattern, $limit); @@ -655,10 +651,9 @@ \expect($string)->toBeAnInstanceOf(__('Stringy')); } for ($i = 0; $i < count($expected); $i++) { - \expect((string)$result[$i])->toBe($expected[$i]); + \expect((string) $result[$i])->toBe($expected[$i]); } } - }); it('test CollapseWhitespace', function () { @@ -677,14 +672,14 @@ ['', ''], ]; - foreach($data as $value) { + foreach ($data as $value) { @list($expected, $str, $encoding) = $value; { $stringy = __('Stringy')::create($str, $encoding); $result = $stringy->collapseWhitespace(); \expect($result)->toBeAnInstanceOf(__('Stringy')); - \expect((string)$stringy)->toBe($str); - \expect((string)$result)->toBe($expected); + \expect((string) $stringy)->toBe($str); + \expect((string) $result)->toBe($expected); } } }); @@ -703,7 +698,7 @@ ]; it('test indexOf', function () use ($data) { - foreach($data as $value) { + foreach ($data as $value) { @list($expected, $str, $subStr, $offset, $encoding) = $value; $result = __('Stringy')::create($str, $encoding)->indexOf($subStr, $offset); \expect($result)->toBe($expected); @@ -726,17 +721,16 @@ [2, 'foo bar', 'O', false], [1, 'fòô bàř', 'fÒÔ', false, 'UTF-8'], [2, 'fôòô bàř', 'Ô', false, 'UTF-8'], - [2, 'συγγραφέας', 'Σ', false, 'UTF-8'] + [2, 'συγγραφέας', 'Σ', false, 'UTF-8'], ]; - foreach($data as $value) - { + foreach ($data as $value) { @list($expected, $str, $substring, $caseSensitive, $encoding) = $value; $stringy = __('Stringy')::create($str, $encoding); - $result = $stringy->countSubstr($substring, $caseSensitive === true || $caseSensitive === NULL); + $result = $stringy->countSubstr($substring, $caseSensitive === true || $caseSensitive === null); \expect($result)->toBeA('int'); \expect($result)->toBe($expected); - \expect((string)$stringy)->toBe($str); + \expect((string) $stringy)->toBe($str); } }); @@ -753,19 +747,19 @@ ['test=c=c=test', 'TestCCTest', '='], ['string#>with1number', 'string_with1number', '#>'], ['1test2case', '1test2case', '*'], - ['test ύα σase', 'test Σase', ' ύα ', 'UTF-8',], - ['στανιλαcase', 'Στανιλ case', 'α', 'UTF-8',], - ['σashΘcase', 'Σash Case', 'Θ', 'UTF-8'] + ['test ύα σase', 'test Σase', ' ύα ', 'UTF-8'], + ['στανιλαcase', 'Στανιλ case', 'α', 'UTF-8'], + ['σashΘcase', 'Σash Case', 'Θ', 'UTF-8'], ]; - - foreach($data as $value) { + + foreach ($data as $value) { @list($expected, $str, $delimiter, $encoding) = $value; $stringy = __('Stringy')::create($str, $encoding); $result = $stringy->delimit($delimiter); \expect($result)->toBeAnInstanceOf(__('Stringy')); - \expect((string)$stringy)->toBe($str); - \expect((string)$result)->toBe($expected); + \expect((string) $stringy)->toBe($str); + \expect((string) $result)->toBe($expected); } }); @@ -789,20 +783,19 @@ ['background-color', 'backgroundColor'], ['dash-σase', 'dash Σase', 'UTF-8'], ['στανιλ-case', 'Στανιλ case', 'UTF-8'], - ['σash-case', 'Σash Case', 'UTF-8'] + ['σash-case', 'Σash Case', 'UTF-8'], ]; - foreach($data as $value) - { + foreach ($data as $value) { @list($expected, $str, $encoding) = $value; $stringy = __('Stringy')::create($str, $encoding); $result = $stringy->dasherize(); \expect($result)->toBeAnInstanceOf(__('Stringy')); - \expect((string)$stringy)->toBe($str); - \expect((string)$result)->toBe($expected); + \expect((string) $stringy)->toBe($str); + \expect((string) $result)->toBe($expected); } }); - + it('test endsWith', function () { $data = [ [true, 'foo bars', 'o bars'], @@ -817,10 +810,10 @@ [false, 'FÒÔ bàřs', 'fòô bàřs', true, 'UTF-8'], [false, 'fòô bàřs', 'fòô BÀŘS', true, 'UTF-8'], ]; - foreach($data as $value) { + foreach ($data as $value) { @list($expected, $str, $substring, $caseSensitive, $encoding) = $value; $stringy = __('Stringy')::create($str, $encoding); - $result = $stringy->endsWith($substring, $caseSensitive === true || $caseSensitive === NULL); + $result = $stringy->endsWith($substring, $caseSensitive === true || $caseSensitive === null); \expect($result)->toBeA('boolean'); \expect((string) $stringy)->toBe($str); @@ -844,16 +837,15 @@ [false, 'fòô bàřs', [], true, 'UTF-8'], ]; - foreach($data as $value) { + foreach ($data as $value) { @list($expected, $str, $substrings, $caseSensitive, $encoding) = $value; $stringy = __('Stringy')::create($str, $encoding); - $result = $stringy->endsWithAny($substrings, $caseSensitive === true || $caseSensitive === NULL); - + $result = $stringy->endsWithAny($substrings, $caseSensitive === true || $caseSensitive === null); + \expect($result)->toBeA('boolean'); \expect((string) $stringy)->toBe($str); \expect($result)->toBe($expected); } - }); it('test ensureLeft', function () { @@ -869,8 +861,8 @@ ['http://fòôbàř', 'fòôbàř', 'http://', 'UTF-8'], ['http://fòôbàř', 'http://fòôbàř', 'http://', 'UTF-8'], ]; - - foreach($data as $value){ + + foreach ($data as $value) { @list($expected, $str, $substring, $encoding) = $value; $stringy = __('Stringy')::create($str, $encoding); $result = $stringy->ensureLeft($substring); @@ -895,10 +887,10 @@ [false, 'FÒÔ bàřs', 'fòô bàř', true, 'UTF-8'], [false, 'fòô bàřs', 'fòô BÀŘ', true, 'UTF-8'], ]; - foreach($data as $value){ + foreach ($data as $value) { @list($expected, $str, $substring, $caseSensitive, $encoding) = $value; $stringy = _('Stringy')::create($str, $encoding); - $result = $stringy->startsWith($substring, $caseSensitive === true || $caseSensitive === NULL); + $result = $stringy->startsWith($substring, $caseSensitive === true || $caseSensitive === null); \expect($result)->toBeA('boolean'); \expect((string) $stringy)->toBe($str); @@ -920,7 +912,7 @@ ['fòôbàř.com/', 'fòôbàř.com/', '.com/', 'UTF-8'], ]; - foreach($data as $value) { + foreach ($data as $value) { @list($expected, $str, $substring, $encoding) = $value; $stringy = __('Stringy')::create($str, $encoding); $result = $stringy->ensureRight($substring); @@ -947,7 +939,7 @@ ['fòô bàř', 'fòô bàř', 8, 'UTF-8'], ]; - foreach($data as $value) { + foreach ($data as $value) { @list($expected, $str, $n, $encoding) = $value; $stringy = __('Stringy')::create($str, $encoding); $result = $stringy->first($n); diff --git a/spec/TestSpec.php b/spec/TestSpec.php index 70075bb..e3e5876 100644 --- a/spec/TestSpec.php +++ b/spec/TestSpec.php @@ -1,4 +1,5 @@ toEcho('hello world!'); }); - it('测试实例化 hello world!!', function() { + it('测试实例化 hello world!!', function () { expect([_('Test'), 'echoHelloWorld'])->toEcho('hello world!!'); }); @@ -30,13 +31,13 @@ $instance = _('Test'); $params = [ 'a21212' => [1, 2, 3, 4], - '😊☺😀' => ['abab', 'cdcd', 'efef'], - 'daba' => [], + '😊☺😀' => ['abab', 'cdcd', 'efef'], + 'daba' => [], ]; - foreach($params as $method => $args) { - $ret = \call_user_func_array([$instance, $method], $args);; - \expect($ret)->toBe(sprintf('method:%s,count:%d,args:%s', $method, count($args), \implode("-", $args))); + foreach ($params as $method => $args) { + $ret = \call_user_func_array([$instance, $method], $args); + \expect($ret)->toBe(sprintf('method:%s,count:%d,args:%s', $method, count($args), \implode('-', $args))); } }); }); diff --git a/spec/const.php b/spec/const.php index 2b14203..ae4c4d5 100644 --- a/spec/const.php +++ b/spec/const.php @@ -6,4 +6,4 @@ define('NS_EXT_DEFAULT', '\Minbaby\Startup\Ext'); -define('NS_STRINGY', NS_DEFAULT . '\Stringy'); +define('NS_STRINGY', NS_DEFAULT.'\Stringy'); diff --git a/spec/functions.php b/spec/functions.php index c3d24ea..2032f42 100644 --- a/spec/functions.php +++ b/spec/functions.php @@ -5,7 +5,7 @@ function _ns(string $ns = '\\') { global $________; - + if (!empty($_SERVER['MINBABY_TEST_EXT'])) { $ns = str_replace(NS_DEFAULT, NS_EXT_DEFAULT, $ns); } @@ -14,25 +14,28 @@ function _ns(string $ns = '\\') } /** - * @var string $str 类名 + * @var string 类名 + * * @return object 类的实例化对象 */ function _(string $str, array $args = []) { $class = __($str); + return new $class(...$args); } /** - * @var string $str 类名 + * @var string 类名 + * * @return string 带命名空间的完整类名 */ function __(string $str): string { global $________; if (empty($________['ns'])) { - throw new Exception("ns can not empty"); + throw new Exception('ns can not empty'); } - return sprintf('%s\%s', rtrim($________['ns'], SEP_DIR), $str); + return sprintf('%s\%s', rtrim($________['ns'], SEP_DIR), $str); } diff --git a/src/Minbaby/Php/Stringy/Stringy.php b/src/Minbaby/Php/Stringy/Stringy.php index 80e3797..eb26cae 100644 --- a/src/Minbaby/Php/Stringy/Stringy.php +++ b/src/Minbaby/Php/Stringy/Stringy.php @@ -6,7 +6,6 @@ class Stringy implements \Countable, \IteratorAggregate, \ArrayAccess { - protected $str; protected $encoding; @@ -68,6 +67,7 @@ protected function regexEncoding() if ($functionExists) { $args = func_get_args(); + return \call_user_func_array('\mb_regex_encoding', $args); } } @@ -80,8 +80,9 @@ protected function eregReplace($pattern, $replacement, $string, $option = 'msr') } if ($functionExists) { return \mb_ereg_replace($pattern, $replacement, $string, $option); - } else if ($this->supportsEncoding()) { + } elseif ($this->supportsEncoding()) { $option = str_replace('r', '', $option); + return \preg_replace("/$pattern/u$option", $replacement, $string); } } @@ -89,6 +90,7 @@ protected function eregReplace($pattern, $replacement, $string, $option = 'msr') public function trim($chars = null) { $chars = ($chars) ? preg_quote($chars) : '[:space:]'; + return $this->regexReplace("^[$chars]+|[$chars]+\$", ''); } @@ -102,10 +104,12 @@ function ($match) use ($encoding) { if ($match[0] == \mb_strtoupper($match[0], $encoding)) { return \mb_strtolower($match[0], $encoding); } + return \mb_strtoupper($match[0], $encoding); }, $stringy->str ); + return $stringy; } @@ -113,10 +117,11 @@ public function upperCaseFirst() { $first = \mb_substr($this->str, 0, 1, $this->encoding); $rest = \mb_substr($this->str, 1, $this->length() - 1, $this->encoding); - $str = \mb_strtoupper($first, $this->encoding) . $rest; + $str = \mb_strtoupper($first, $this->encoding).$rest; + return static::create($str, $this->encoding); } - + public function length() { return \mb_strlen($this->str, $this->encoding); @@ -135,8 +140,7 @@ public function getIterator() public function chars() { $chars = []; - for($i = 0, $l = $this->length(); $i < $l; $i++) - { + for ($i = 0, $l = $this->length(); $i < $l; $i++) { $chars[] = $this->at($i)->str; } @@ -152,6 +156,7 @@ public function substr($start, $length = null) { $length = $length === null ? $this->length() : $length; $str = \mb_substr($this->str, $start, $length, $this->encoding); + return static::create($str, $this->encoding); } @@ -166,7 +171,7 @@ public function offsetExists($offset) return $length >= abs($offset); } - + public function offsetGet($offset) { $offset = (int) $offset; @@ -174,6 +179,7 @@ public function offsetGet($offset) if (($offset >= 0 && $length <= $offset) || $length < abs($offset)) { throw new \OutOfBoundsException('No character exists at the index'); } + return \mb_substr($this->str, $offset, 1, $this->encoding); } @@ -190,9 +196,9 @@ public function offsetUnset($offset) public function indexOf($needle, $offset = 0) { return \mb_strpos( - $this->str, + $this->str, (string) $needle, - (int) $offset, + (int) $offset, $this->encoding ); } @@ -200,22 +206,22 @@ public function indexOf($needle, $offset = 0) public function indexOfLast($needle, $offset = 0) { return \mb_strrpos( - $this->str, + $this->str, (string) $needle, - (int) $offset, + (int) $offset, $this->encoding ); } - public function append($string) + public function append($string) { - return static::create($this->str . $string, $this->encoding); + return static::create($this->str.$string, $this->encoding); } - public function prepend($string) + public function prepend($string) { - return static::create($string . $this->str, $this->encoding); -} + return static::create($string.$this->str, $this->encoding); + } public function lines() { @@ -223,6 +229,7 @@ public function lines() for ($i = 0; $i < count($array); $i++) { $array[$i] = static::create($array[$i], $this->encoding); } + return $array; } @@ -247,7 +254,7 @@ public function split($pattern, $limit = null) } if ($functionExists) { $array = \mb_split($pattern, $this->str, $limit); - } else if ($this->supportsEncoding()) { + } elseif ($this->supportsEncoding()) { $array = \preg_split("/$pattern/", $this->str, $limit); } $this->regexEncoding($regexEncoding); @@ -257,6 +264,7 @@ public function split($pattern, $limit = null) for ($i = 0; $i < count($array); $i++) { $array[$i] = static::create($array[$i], $this->encoding); } + return $array; } @@ -264,7 +272,8 @@ public function lowerCaseFirst() { $first = \mb_substr($this->str, 0, 1, $this->encoding); $rest = \mb_substr($this->str, 1, $this->length() - 1, $this->encoding); - $str = \mb_strtolower($first, $this->encoding) . $rest; + $str = \mb_strtolower($first, $this->encoding).$rest; + return static::create($str, $this->encoding); } @@ -279,6 +288,7 @@ function ($match) use ($encoding) { if (isset($match[1])) { return \mb_strtoupper($match[1], $encoding); } + return ''; }, $stringy->str @@ -290,18 +300,21 @@ function ($match) use ($encoding) { }, $stringy->str ); + return $stringy; } public function trimLeft($chars = null) { $chars = ($chars) ? preg_quote($chars) : '[:space:]'; + return $this->regexReplace("^[$chars]+", ''); } public function trimRight($chars = null) { $chars = ($chars) ? preg_quote($chars) : '[:space:]'; + return $this->regexReplace("[$chars]+\$", ''); } @@ -316,6 +329,7 @@ public function between($start, $end, $offset = 0) if ($endIndex === false) { return static::create('', $this->encoding); } + return $this->substr($substrIndex, $endIndex - $substrIndex); } @@ -323,9 +337,10 @@ public function contains($needle, $caseSensitive = true) { $encoding = $this->encoding; if ($caseSensitive) { - return (\mb_strpos($this->str, $needle, 0, $encoding) !== false); + return \mb_strpos($this->str, $needle, 0, $encoding) !== false; } - return (\mb_stripos($this->str, $needle, 0, $encoding) !== false); + + return \mb_stripos($this->str, $needle, 0, $encoding) !== false; } public function containsAll($needles, $caseSensitive = true) @@ -338,6 +353,7 @@ public function containsAll($needles, $caseSensitive = true) return false; } } + return true; } @@ -351,6 +367,7 @@ public function containsAny($needles, $caseSensitive = true) return true; } } + return false; } @@ -361,6 +378,7 @@ public function countSubstr($substring, $caseSensitive = true) } $str = \mb_strtoupper($this->str, $this->encoding); $substring = \mb_strtoupper($substring, $this->encoding); + return \mb_substr_count($str, $substring, $this->encoding); } @@ -372,6 +390,7 @@ public function delimit($delimiter) $str = \mb_strtolower($str, $this->encoding); $str = $this->eregReplace('[-_\s]+', $delimiter, $str); $this->regexEncoding($regexEncoding); + return static::create($str, $this->encoding); } @@ -401,6 +420,7 @@ public function endsWith($substring, $caseSensitive = true) $substring = \mb_strtolower($substring, $this->encoding); $endOfStr = \mb_strtolower($endOfStr, $this->encoding); } + return (string) $substring === $endOfStr; } @@ -414,6 +434,7 @@ public function endsWithAny($substrings, $caseSensitive = true) return true; } } + return false; } @@ -421,8 +442,9 @@ public function ensureLeft($substring) { $stringy = static::create($this->str, $this->encoding); if (!$stringy->startsWith($substring)) { - $stringy->str = $substring . $stringy->str; + $stringy->str = $substring.$stringy->str; } + return $stringy; } @@ -434,6 +456,7 @@ public function startsWith($substring, $caseSensitive = true) $substring = \mb_strtolower($substring, $this->encoding); $startOfStr = \mb_strtolower($startOfStr, $this->encoding); } + return (string) $substring === $startOfStr; } @@ -443,6 +466,7 @@ public function ensureRight($substring) if (!$stringy->endsWith($substring)) { $stringy->str .= $substring; } + return $stringy; } @@ -451,8 +475,10 @@ public function first($n) $stringy = static::create($this->str, $this->encoding); if ($n < 0) { $stringy->str = ''; + return $stringy; } + return $stringy->substr(0, $n); } } diff --git a/src/Minbaby/Php/Test.php b/src/Minbaby/Php/Test.php index 2fe6db8..711332a 100644 --- a/src/Minbaby/Php/Test.php +++ b/src/Minbaby/Php/Test.php @@ -1,4 +1,5 @@ trimLeft($chars); @@ -27,4 +28,4 @@ // var_dump((string)$result); } -var_dump(mb_strpos('Str contains foo bar', 'Foo bar', 0, "UTF-8")); +var_dump(mb_strpos('Str contains foo bar', 'Foo bar', 0, 'UTF-8')); From 87537aab7a43c51a533202c01ec72b9828540497 Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Sun, 13 Jan 2019 13:27:42 +0800 Subject: [PATCH 080/126] =?UTF-8?q?[skip=20ci]=20=E6=9B=B4=E6=98=BE?= =?UTF-8?q?=E5=AE=89=E8=A3=85=E8=84=9A=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/init-development.sh | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/scripts/init-development.sh b/scripts/init-development.sh index 0f14cd4..558eb14 100755 --- a/scripts/init-development.sh +++ b/scripts/init-development.sh @@ -11,7 +11,16 @@ export SYSTEM_NAME=`uname` [ "$SYSTEM_NAME" == "Darwin" ] && LIB_BZ2='+bz2=/usr/local/opt/bzip2/' [ "$SYSTEM_NAME" == "Darwin" ] && LIB_ZIP='+zlib=/usr/local/opt/zlib' -phpbrew --debug install --mirror=http://cn2.php.net -j 4 $PHP_VERSION +default $LIB_BZ2 $LIB_ZIP +mb +openssl=/usr/local/opt/openssl/ +# sudo apt install libxml2-dev +# sudo apt install libssh-dev +# sudo apt install libbz2-dev +# sudo apt install libcurl4-openssl-dev +# sudo apt install libmcrypt-dev +# sudo apt install libreadline-dev +# sudo apt install libxslt1-dev +# sudo apt install autoconf + +phpbrew --debug install --mirror=http://cn2.php.net -j 4 $PHP_VERSION +default $LIB_BZ2 $LIB_ZIP +mb # +openssl=/usr/local/opt/openssl/ echo $PHP_VERSION From adc5a119a4a6d35fd32b17946e7e3b6e02c38c6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Sun, 13 Jan 2019 16:07:40 +0800 Subject: [PATCH 081/126] Feature/stringy is alpha (#41) * isalpha * Apply fixes from StyleCI (#42) --- scripts/gdb.sh | 4 ++++ spec/Stringy/StringySpec.php | 24 ++++++++++++++++++++ src/Minbaby/Php/Stringy/Stringy.php | 15 +++++++++++++ src/ext/stringy/stringy.c | 34 +++++++++++++++++++++++++++++ 4 files changed, 77 insertions(+) diff --git a/scripts/gdb.sh b/scripts/gdb.sh index e81bf5a..f1c7c0e 100755 --- a/scripts/gdb.sh +++ b/scripts/gdb.sh @@ -19,3 +19,7 @@ # gdb -c core php # git clone https://github.com/snare/voltron +sudo apt install gdb -f +git clone https://github.com/longld/peda.git ~/peda +echo "source ~/peda/peda.py" >> ~/.gdbinit +echo "DONE! debug your program with gdb and enjoy" \ No newline at end of file diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index 2664764..312f11e 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -949,4 +949,28 @@ \expect((string) $result)->toBe($expected); } }); + + it('test isAlpha', function () { + $data = [ + [true, ''], + [true, 'foobar'], + [false, 'foo bar'], + [false, 'foobar2'], + [true, 'fòôbàř', 'UTF-8'], + [false, 'fòô bàř', 'UTF-8'], + [false, 'fòôbàř2', 'UTF-8'], + [true, 'ҠѨњфгШ', 'UTF-8'], + [false, 'ҠѨњ¨ˆфгШ', 'UTF-8'], + [true, '丹尼爾', 'UTF-8'], + ]; + foreach ($data as $value) { + @list($expected, $str, $encoding) = $value; + $stringy = __('Stringy')::create($str, $encoding); + $result = $stringy->isAlpha(); + + \expect($result)->toBeA('boolean'); + \expect((string) $stringy)->toBe($str); + \expect($result)->toBe($expected); + } + }); }); diff --git a/src/Minbaby/Php/Stringy/Stringy.php b/src/Minbaby/Php/Stringy/Stringy.php index eb26cae..2d23cc9 100644 --- a/src/Minbaby/Php/Stringy/Stringy.php +++ b/src/Minbaby/Php/Stringy/Stringy.php @@ -481,4 +481,19 @@ public function first($n) return $stringy->substr(0, $n); } + + protected function matchesPattern($pattern) + { + $regexEncoding = $this->regexEncoding(); + $this->regexEncoding($this->encoding); + $match = \mb_ereg_match($pattern, $this->str); + $this->regexEncoding($regexEncoding); + + return $match; + } + + public function isAlpha() + { + return $this->matchesPattern('^[[:alpha:]]*$'); + } } diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index 918e790..8f92b8e 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -1776,6 +1776,38 @@ ZEND_BEGIN_ARG_INFO(arginfo_first, 0) ZEND_ARG_INFO(0, substring) ZEND_END_ARG_INFO(); +PHP_METHOD(Stringy, isAlpha) +{ + zval str_val; + ZVAL_STRING(&str_val, "^[[:alpha:]]*$"); + zval func, args[] = { + str_val + }; + ZVAL_STRING(&func, "matchesPattern"); + call_user_function(NULL, getThis(), &func, return_value, 1, args); +} + +PHP_METHOD(Stringy, matchesPattern) +{ + zval *pattern = NULL; + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ZVAL(pattern) + ZEND_PARSE_PARAMETERS_END(); + + zval rv; + zval *str = zend_read_property(stringy_ce, getThis(), ZEND_STRL("str"), 0, &rv); + + zval func, args[] = { + *pattern, + *str, + }; + ZVAL_STRING(&func, "mb_ereg_match"); + call_user_function(NULL, NULL, &func, return_value, 2, args); +} +ZEND_BEGIN_ARG_INFO(arginfo_matchesPattern, 0) + ZEND_ARG_INFO(0, pattern) +ZEND_END_ARG_INFO(); + static zend_function_entry methods[] = { PHP_ME(Stringy, __construct, arginfo___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) PHP_ME(Stringy, __toString, NULL, ZEND_ACC_PUBLIC) @@ -1821,6 +1853,8 @@ static zend_function_entry methods[] = { PHP_ME(Stringy, ensureLeft, arginfo_ensureLeft, ZEND_ACC_PUBLIC) PHP_ME(Stringy, ensureRight, arginfo_ensureRight, ZEND_ACC_PUBLIC) PHP_ME(Stringy, first, arginfo_first, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, isAlpha, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, matchesPattern, arginfo_matchesPattern, ZEND_ACC_PROTECTED) PHP_FE_END }; From 409efbaa10f4689d038ba43f454974b7e1db0f19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Sun, 13 Jan 2019 16:37:46 +0800 Subject: [PATCH 082/126] Feature/stringy isBlank (#43) * stringy-isBlank test+ext+php --- spec/Stringy/StringySpec.php | 26 ++++++++++++++++++++++++++ src/Minbaby/Php/Stringy/Stringy.php | 5 +++++ src/ext/stringy/stringy.c | 12 ++++++++++++ 3 files changed, 43 insertions(+) diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index 312f11e..a65654f 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -967,6 +967,32 @@ @list($expected, $str, $encoding) = $value; $stringy = __('Stringy')::create($str, $encoding); $result = $stringy->isAlpha(); + } + }); + + it('test isBlank', function () { + $data = [ + [true, ''], + [true, ' '], + [true, "\n\t "], + [true, "\n\t \v\f"], + [false, "\n\t a \v\f"], + [false, "\n\t ' \v\f"], + [false, "\n\t 2 \v\f"], + [true, '', 'UTF-8'], + [true, ' ', 'UTF-8'], // no-break space (U+00A0) + [true, '           ', 'UTF-8'], // spaces U+2000 to U+200A + [true, ' ', 'UTF-8'], // narrow no-break space (U+202F) + [true, ' ', 'UTF-8'], // medium mathematical space (U+205F) + [true, ' ', 'UTF-8'], // ideographic space (U+3000) + [false, ' z', 'UTF-8'], + [false, ' 1', 'UTF-8'], + ]; + foreach ($data as $value) + { + @list($expected, $str, $encoding) = $value; + $stringy = __('Stringy')::create($str, $encoding); + $result = $stringy->isBlank(); \expect($result)->toBeA('boolean'); \expect((string) $stringy)->toBe($str); diff --git a/src/Minbaby/Php/Stringy/Stringy.php b/src/Minbaby/Php/Stringy/Stringy.php index 2d23cc9..678a779 100644 --- a/src/Minbaby/Php/Stringy/Stringy.php +++ b/src/Minbaby/Php/Stringy/Stringy.php @@ -496,4 +496,9 @@ public function isAlpha() { return $this->matchesPattern('^[[:alpha:]]*$'); } + + public function isBlank() + { + return $this->matchesPattern('^[[:space:]]*$'); + } } diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index 8f92b8e..71c1219 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -1808,6 +1808,17 @@ ZEND_BEGIN_ARG_INFO(arginfo_matchesPattern, 0) ZEND_ARG_INFO(0, pattern) ZEND_END_ARG_INFO(); +PHP_METHOD(Stringy, isBlank) +{ + zval str_val; + ZVAL_STRING(&str_val, "^[[:space:]]*$"); + zval func, args[] = { + str_val + }; + ZVAL_STRING(&func, "matchesPattern"); + call_user_function(NULL, getThis(), &func, return_value, 1, args); +} + static zend_function_entry methods[] = { PHP_ME(Stringy, __construct, arginfo___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) PHP_ME(Stringy, __toString, NULL, ZEND_ACC_PUBLIC) @@ -1855,6 +1866,7 @@ static zend_function_entry methods[] = { PHP_ME(Stringy, first, arginfo_first, ZEND_ACC_PUBLIC) PHP_ME(Stringy, isAlpha, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, matchesPattern, arginfo_matchesPattern, ZEND_ACC_PROTECTED) + PHP_ME(Stringy, isBlank, NULL, ZEND_ACC_PUBLIC) PHP_FE_END }; From 347cab57787c150ad1acd9056b83bb478741ff45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Sun, 13 Jan 2019 16:54:22 +0800 Subject: [PATCH 083/126] stringy-hasLowerCase (#44) --- spec/Stringy/StringySpec.php | 27 +++++++++++++++++++++++++++ src/Minbaby/Php/Stringy/Stringy.php | 5 +++++ src/ext/stringy/stringy.c | 12 ++++++++++++ 3 files changed, 44 insertions(+) diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index a65654f..e0677af 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -999,4 +999,31 @@ \expect($result)->toBe($expected); } }); + + it('test hasLowerCase', function () { + $data = [ + [false, ''], + [true, 'foobar'], + [false, 'FOO BAR'], + [true, 'fOO BAR'], + [true, 'foO BAR'], + [true, 'FOO BAr'], + [true, 'Foobar'], + [false, 'FÒÔBÀŘ', 'UTF-8'], + [true, 'fòôbàř', 'UTF-8'], + [true, 'fòôbàř2', 'UTF-8'], + [true, 'Fòô bàř', 'UTF-8'], + [true, 'fòôbÀŘ', 'UTF-8'], + ]; + + foreach ($data as $value) { + @list($expected, $str, $encoding) = $value; + $stringy = __('Stringy')::create($str, $encoding); + $result = $stringy->hasLowerCase(); + + \expect($result)->toBeA('boolean'); + \expect((string) $stringy)->toBe($str); + \expect($result)->toBe($expected); + } + }); }); diff --git a/src/Minbaby/Php/Stringy/Stringy.php b/src/Minbaby/Php/Stringy/Stringy.php index 678a779..2a6510f 100644 --- a/src/Minbaby/Php/Stringy/Stringy.php +++ b/src/Minbaby/Php/Stringy/Stringy.php @@ -501,4 +501,9 @@ public function isBlank() { return $this->matchesPattern('^[[:space:]]*$'); } + + public function hasLowerCase() + { + return $this->matchesPattern('.*[[:lower:]]'); + } } diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index 71c1219..29135cf 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -1819,6 +1819,17 @@ PHP_METHOD(Stringy, isBlank) call_user_function(NULL, getThis(), &func, return_value, 1, args); } +PHP_METHOD(Stringy, hasLowerCase) +{ + zval str_val; + ZVAL_STRING(&str_val, ".*[[:lower:]]"); + zval func, args[] = { + str_val + }; + ZVAL_STRING(&func, "matchesPattern"); + call_user_function(NULL, getThis(), &func, return_value, 1, args); +} + static zend_function_entry methods[] = { PHP_ME(Stringy, __construct, arginfo___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) PHP_ME(Stringy, __toString, NULL, ZEND_ACC_PUBLIC) @@ -1867,6 +1878,7 @@ static zend_function_entry methods[] = { PHP_ME(Stringy, isAlpha, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, matchesPattern, arginfo_matchesPattern, ZEND_ACC_PROTECTED) PHP_ME(Stringy, isBlank, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, hasLowerCase, NULL, ZEND_ACC_PUBLIC) PHP_FE_END }; From 6863d61a86571a1d161650d74f6071a8db400f20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Sun, 13 Jan 2019 18:04:12 +0800 Subject: [PATCH 084/126] stringy-html-encode-decode (#45) --- spec/Stringy/StringySpec.php | 42 +++++++++++++++ src/Minbaby/Php/Stringy/Stringy.php | 12 +++++ src/ext/stringy/stringy.c | 80 +++++++++++++++++++++++++++++ 3 files changed, 134 insertions(+) diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index e0677af..7883ecc 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -967,6 +967,10 @@ @list($expected, $str, $encoding) = $value; $stringy = __('Stringy')::create($str, $encoding); $result = $stringy->isAlpha(); + + \expect($result)->toBeA('boolean'); + \expect((string) $stringy)->toBe($str); + \expect($result)->toBe($expected); } }); @@ -1026,4 +1030,42 @@ \expect($result)->toBe($expected); } }); + + it('test htmlDecode', function () { + $data = [ + ['&', '&'], + ['"', '"'], + ["'", ''', ENT_QUOTES], + ['<', '<'], + ['>', '>'], + ]; + foreach($data as $value){ + @list($expected, $str, $flags, $encoding) = $value; + $stringy = __('Stringy')::create($str, $encoding); + $result = $stringy->htmlDecode($flags ?? ENT_COMPAT); + + \expect($stringy)->toBeAnInstanceOf(__('Stringy')); + \expect((string) $stringy)->toBe($str); + \expect((string) $result)->toBe($expected); + } + }); + + it('test htmlEncode', function () { + $data = [ + ['&', '&'], + ['"', '"'], + [''', "'", ENT_QUOTES], + ['<', '<'], + ['>', '>'], + ]; + foreach($data as $value){ + @list($expected, $str, $flags, $encoding) = $value; + $stringy = __('Stringy')::create($str, $encoding); + $result = $stringy->htmlEncode($flags ?? ENT_COMPAT); + + \expect($stringy)->toBeAnInstanceOf(__('Stringy')); + \expect((string) $stringy)->toBe($str); + \expect((string) $result)->toBe($expected); + } + }); }); diff --git a/src/Minbaby/Php/Stringy/Stringy.php b/src/Minbaby/Php/Stringy/Stringy.php index 2a6510f..f0fa5d5 100644 --- a/src/Minbaby/Php/Stringy/Stringy.php +++ b/src/Minbaby/Php/Stringy/Stringy.php @@ -506,4 +506,16 @@ public function hasLowerCase() { return $this->matchesPattern('.*[[:lower:]]'); } + + public function htmlDecode($flags = ENT_COMPAT) + { + $str = html_entity_decode($this->str, $flags, $this->encoding); + return static::create($str, $this->encoding); + } + + public function htmlEncode($flags = ENT_COMPAT) + { + $str = htmlentities($this->str, $flags, $this->encoding); + return static::create($str, $this->encoding); + } } diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index 29135cf..6b86a6b 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -1830,6 +1830,84 @@ PHP_METHOD(Stringy, hasLowerCase) call_user_function(NULL, getThis(), &func, return_value, 1, args); } +PHP_METHOD(Stringy, htmlDecode) +{ + zval *flags = NULL; + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ZVAL(flags); + ZEND_PARSE_PARAMETERS_END(); + + if (flags == NULL) { + ZVAL_STRING(flags, "ENT_COMPAT"); + } + + zval rv; + zval *str = zend_read_property(stringy_ce, getThis(), ZEND_STRL("str"), 0, &rv); + zval *encoding = zend_read_property(stringy_ce, getThis(), ZEND_STRL("encoding"), 0, &rv); + + zval func, args[] = { + *str, + *flags, + *encoding, + }; + ZVAL_STRING(&func, "html_entity_decode"); + call_user_function(NULL, NULL, &func, return_value, 3, args); + + + zval instance; + object_init_ex(&instance, stringy_ce); + zval func_init, args_init[] = { + *return_value, + *encoding, + }; + ZVAL_STRING(&func_init, "__construct"); + call_user_function(NULL, &instance, &func_init, return_value, 2, args_init); + + RETURN_ZVAL(&instance, 0, 1); +} +ZEND_BEGIN_ARG_INFO(arginfo_htmlDecode, 0) + ZEND_ARG_INFO(0, flags) +ZEND_END_ARG_INFO(); + +PHP_METHOD(Stringy, htmlEncode) +{ + zval *flags = NULL; + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ZVAL(flags); + ZEND_PARSE_PARAMETERS_END(); + + if (flags == NULL) { + ZVAL_STRING(flags, "ENT_COMPAT"); + } + + zval rv; + zval *str = zend_read_property(stringy_ce, getThis(), ZEND_STRL("str"), 0, &rv); + zval *encoding = zend_read_property(stringy_ce, getThis(), ZEND_STRL("encoding"), 0, &rv); + + zval func, args[] = { + *str, + *flags, + *encoding, + }; + ZVAL_STRING(&func, "htmlentities"); + call_user_function(NULL, NULL, &func, return_value, 3, args); + + + zval instance; + object_init_ex(&instance, stringy_ce); + zval func_init, args_init[] = { + *return_value, + *encoding, + }; + ZVAL_STRING(&func_init, "__construct"); + call_user_function(NULL, &instance, &func_init, return_value, 2, args_init); + + RETURN_ZVAL(&instance, 0, 1); +} +ZEND_BEGIN_ARG_INFO(arginfo_htmlEncode, 0) + ZEND_ARG_INFO(0, flags) +ZEND_END_ARG_INFO(); + static zend_function_entry methods[] = { PHP_ME(Stringy, __construct, arginfo___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) PHP_ME(Stringy, __toString, NULL, ZEND_ACC_PUBLIC) @@ -1879,6 +1957,8 @@ static zend_function_entry methods[] = { PHP_ME(Stringy, matchesPattern, arginfo_matchesPattern, ZEND_ACC_PROTECTED) PHP_ME(Stringy, isBlank, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, hasLowerCase, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, htmlEncode, arginfo_htmlEncode, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, htmlDecode, arginfo_htmlDecode, ZEND_ACC_PUBLIC) PHP_FE_END }; From a2a3bede28df0f6a140c13762bd7f2133615e059 Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Mon, 14 Jan 2019 09:36:29 +0800 Subject: [PATCH 085/126] =?UTF-8?q?[skip=20ci]=20=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E4=B8=80=E4=B8=8B=E7=8E=AF=E5=A2=83=E5=88=9D=E5=A7=8B=E5=8C=96?= =?UTF-8?q?=E8=84=9A=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/init-development.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/scripts/init-development.sh b/scripts/init-development.sh index 558eb14..e93d2a7 100755 --- a/scripts/init-development.sh +++ b/scripts/init-development.sh @@ -8,8 +8,9 @@ export PHP_VERSION=php-7.1.23 export SYSTEM_NAME=`uname` -[ "$SYSTEM_NAME" == "Darwin" ] && LIB_BZ2='+bz2=/usr/local/opt/bzip2/' -[ "$SYSTEM_NAME" == "Darwin" ] && LIB_ZIP='+zlib=/usr/local/opt/zlib' +[ "$SYSTEM_NAME" == "Darwin" ] && LIB_BZ2='/usr/local/opt/bzip2/' +[ "$SYSTEM_NAME" == "Darwin" ] && LIB_ZIP='/usr/local/opt/zlib' +[ "$SYSTEM_NAME" == "Darwin" ] && LIB_SSL='/usr/local/opt/openssl/' # sudo apt install libxml2-dev # sudo apt install libssh-dev @@ -20,7 +21,7 @@ export SYSTEM_NAME=`uname` # sudo apt install libxslt1-dev # sudo apt install autoconf -phpbrew --debug install --mirror=http://cn2.php.net -j 4 $PHP_VERSION +default $LIB_BZ2 $LIB_ZIP +mb # +openssl=/usr/local/opt/openssl/ +phpbrew --debug install --mirror=http://cn2.php.net -j 4 $PHP_VERSION +default +bz2=$LIB_BZ2 +zlib=$LIB_ZIP +mb +openssl=$LIB_SSL echo $PHP_VERSION From 90dfec2fd0618c863ba56f7d4d9863e8f5fa3520 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Tue, 15 Jan 2019 22:52:19 +0800 Subject: [PATCH 086/126] stringy-hasUpperCase test+ext+php (#46) --- spec/Stringy/StringySpec.php | 28 ++++++++++++++++++++++++++++ src/Minbaby/Php/Stringy/Stringy.php | 5 +++++ src/ext/stringy/stringy.c | 12 ++++++++++++ 3 files changed, 45 insertions(+) diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index 7883ecc..395c123 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -1031,6 +1031,34 @@ } }); + + it('test hasUpperCase', function () { + $data = [ + [false, ''], + [true, 'FOOBAR'], + [false, 'foo bar'], + [true, 'Foo bar'], + [true, 'FOo bar'], + [true, 'foo baR'], + [true, 'fOOBAR'], + [false, 'fòôbàř', 'UTF-8'], + [true, 'FÒÔBÀŘ', 'UTF-8'], + [true, 'FÒÔBÀŘ2', 'UTF-8'], + [true, 'fÒÔ BÀŘ', 'UTF-8'], + [true, 'FÒÔBàř', 'UTF-8'], + ]; + + foreach ($data as $value) { + @list($expected, $str, $encoding) = $value; + $stringy = __('Stringy')::create($str, $encoding); + $result = $stringy->hasUpperCase(); + + \expect($result)->toBeA('boolean'); + \expect((string) $stringy)->toBe($str); + \expect($result)->toBe($expected); + } + }); + it('test htmlDecode', function () { $data = [ ['&', '&'], diff --git a/src/Minbaby/Php/Stringy/Stringy.php b/src/Minbaby/Php/Stringy/Stringy.php index f0fa5d5..a619d45 100644 --- a/src/Minbaby/Php/Stringy/Stringy.php +++ b/src/Minbaby/Php/Stringy/Stringy.php @@ -507,6 +507,11 @@ public function hasLowerCase() return $this->matchesPattern('.*[[:lower:]]'); } + public function hasUpperCase() + { + return $this->matchesPattern('.*[[:upper:]]'); + } + public function htmlDecode($flags = ENT_COMPAT) { $str = html_entity_decode($this->str, $flags, $this->encoding); diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index 6b86a6b..52c2d52 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -1830,6 +1830,17 @@ PHP_METHOD(Stringy, hasLowerCase) call_user_function(NULL, getThis(), &func, return_value, 1, args); } +PHP_METHOD(Stringy, hasUpperCase) +{ + zval str_val; + ZVAL_STRING(&str_val, ".*[[:upper:]]"); + zval func, args[] = { + str_val + }; + ZVAL_STRING(&func, "matchesPattern"); + call_user_function(NULL, getThis(), &func, return_value, 1, args); +} + PHP_METHOD(Stringy, htmlDecode) { zval *flags = NULL; @@ -1957,6 +1968,7 @@ static zend_function_entry methods[] = { PHP_ME(Stringy, matchesPattern, arginfo_matchesPattern, ZEND_ACC_PROTECTED) PHP_ME(Stringy, isBlank, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, hasLowerCase, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, hasUpperCase, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, htmlEncode, arginfo_htmlEncode, ZEND_ACC_PUBLIC) PHP_ME(Stringy, htmlDecode, arginfo_htmlDecode, ZEND_ACC_PUBLIC) PHP_FE_END From e415994b0b0852a5422efa10281aff6a93d8c766 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Thu, 17 Jan 2019 22:06:50 +0800 Subject: [PATCH 087/126] Feature/stringy remove left remove right (#47) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 问题没出处理完成 * stringy-removeLeft,remoeRigh,last,substr --- spec/Stringy/StringySpec.php | 107 ++++++++++++++++++ src/Minbaby/Php/Stringy/Stringy.php | 32 +++++- src/ext/stringy/stringy.c | 168 +++++++++++++++++++++++++++- startup.php | 26 +---- 4 files changed, 303 insertions(+), 30 deletions(-) diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index 395c123..ee02042 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -1096,4 +1096,111 @@ \expect((string) $result)->toBe($expected); } }); + + it('test substr', function () { + $data = [ + ['foo bar', 'foo bar', 0], + ['bar', 'foo bar', 4], + ['bar', 'foo bar', 4, null], + ['o b', 'foo bar', 2, 3], + ['', 'foo bar', 4, 0], + ['fòô bàř', 'fòô bàř', 0, null, 'UTF-8'], + ['bàř', 'fòô bàř', 4, null, 'UTF-8'], + ['ô b', 'fòô bàř', 2, 3, 'UTF-8'], + ['', 'fòô bàř', 4, 0, 'UTF-8'], + ['r', 'foo bar', -1], + ]; + + foreach ($data as $value) { + @list($expected, $str, $start, $length, $encoding) = $value; + $stringy = __('Stringy')::create($str, $encoding); + $result = $stringy->substr($start, $length); + + \expect($stringy)->toBeAnInstanceOf(__('Stringy')); + \expect((string) $stringy)->toBe($str); + \expect((string) $result)->toBe($expected); + } + + }); + + it('test last', function () { + $data = [ + ['', 'foo bar', -5], + ['', 'foo bar', 0], + ['r', 'foo bar', 1], + ['bar', 'foo bar', 3], + ['foo bar', 'foo bar', 7], + ['foo bar', 'foo bar', 8], + ['', 'fòô bàř', -5, 'UTF-8'], + ['', 'fòô bàř', 0, 'UTF-8'], + ['ř', 'fòô bàř', 1, 'UTF-8'], + ['bàř', 'fòô bàř', 3, 'UTF-8'], + ['fòô bàř', 'fòô bàř', 7, 'UTF-8'], + ['fòô bàř', 'fòô bàř', 8, 'UTF-8'], + ]; + + foreach ($data as $value) { + @list($expected, $str, $n, $encoding) = $value; + $stringy = __('Stringy')::create($str, $encoding); + $result = $stringy->last($n); + + \expect($stringy)->toBeAnInstanceOf(__('Stringy')); + \expect((string) $stringy)->toBe($str); + \expect((string) $result)->toBe($expected); + } + }); + + it('test removeLeft', function () { + $data = [ + ['foo bar', 'foo bar', ''], + ['oo bar', 'foo bar', 'f'], + ['bar', 'foo bar', 'foo '], + ['foo bar', 'foo bar', 'oo'], + ['foo bar', 'foo bar', 'oo bar'], + ['oo bar', 'foo bar', __('Stringy')::create('foo bar')->first(1), 'UTF-8'], + ['oo bar', 'foo bar', __('Stringy')::create('foo bar')->at(0), 'UTF-8'], + ['fòô bàř', 'fòô bàř', '', 'UTF-8'], + ['òô bàř', 'fòô bàř', 'f', 'UTF-8'], + ['bàř', 'fòô bàř', 'fòô ', 'UTF-8'], + ['fòô bàř', 'fòô bàř', 'òô', 'UTF-8'], + ['fòô bàř', 'fòô bàř', 'òô bàř', 'UTF-8'] + ]; + foreach($data as $value) + { + @list($expected, $str, $substring, $encoding) = $value; + $stringy = __('Stringy')::create($str, $encoding); + $result = $stringy->removeLeft((string) $substring); + + \expect($stringy)->toBeAnInstanceOf(__('Stringy')); + \expect((string) $stringy)->toBe($str); + \expect((string) $result)->toBe($expected); + } + }); + + it('test removeRight', function () { + $data = [ + ['foo bar', 'foo bar', ''], + ['foo ba', 'foo bar', 'r'], + ['foo', 'foo bar', ' bar'], + ['foo bar', 'foo bar', 'ba'], + ['foo bar', 'foo bar', 'foo ba'], + ['foo ba', 'foo bar', __('Stringy')::create('foo bar')->last(1), 'UTF-8'], + ['foo ba', 'foo bar', __('Stringy')::create('foo bar')->at(6), 'UTF-8'], + ['fòô bàř', 'fòô bàř', '', 'UTF-8'], + ['fòô bà', 'fòô bàř', 'ř', 'UTF-8'], + ['fòô', 'fòô bàř', ' bàř', 'UTF-8'], + ['fòô bàř', 'fòô bàř', 'bà', 'UTF-8'], + ['fòô bàř', 'fòô bàř', 'fòô bà', 'UTF-8'] + ]; + foreach($data as $value) + { + @list($expected, $str, $substring, $encoding) = $value; + $stringy = __('Stringy')::create($str, $encoding); + $result = $stringy->removeRight((string) $substring); + + \expect($stringy)->toBeAnInstanceOf(__('Stringy')); + \expect((string) $stringy)->toBe($str); + \expect((string) $result)->toBe($expected); + } + }); }); diff --git a/src/Minbaby/Php/Stringy/Stringy.php b/src/Minbaby/Php/Stringy/Stringy.php index a619d45..30a9d20 100644 --- a/src/Minbaby/Php/Stringy/Stringy.php +++ b/src/Minbaby/Php/Stringy/Stringy.php @@ -36,7 +36,7 @@ public function getEncoding() return $this->encoding; } - public static function create($str, $encoding) + public static function create($str = '', $encoding = null) { return new static($str, $encoding); } @@ -523,4 +523,34 @@ public function htmlEncode($flags = ENT_COMPAT) $str = htmlentities($this->str, $flags, $this->encoding); return static::create($str, $this->encoding); } + + public function removeLeft($substring) + { + $stringy = static::create($this->str, $this->encoding); + if ($stringy->startsWith($substring)) { + $substringLength = \mb_strlen($substring, $stringy->encoding); + return $stringy->substr($substringLength); + } + return $stringy; + } + + public function removeRight($substring) + { + $stringy = static::create($this->str, $this->encoding); + if ($stringy->endsWith($substring)) { + $substringLength = \mb_strlen($substring, $stringy->encoding); + return $stringy->substr(0, $stringy->length() - $substringLength); + } + return $stringy; + } + + public function last($n) + { + $stringy = static::create($this->str, $this->encoding); + if ($n <= 0) { + $stringy->str = ''; + return $stringy; + } + return $stringy->substr(-$n); + } } diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index 52c2d52..df94de2 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -126,7 +126,7 @@ PHP_METHOD(Stringy, getEncoding) PHP_METHOD(Stringy, create) { - zval instance, *str, *encoding; + zval instance, *str, *encoding = NULL; ZEND_PARSE_PARAMETERS_START(0, 2) Z_PARAM_OPTIONAL @@ -136,6 +136,11 @@ PHP_METHOD(Stringy, create) object_init_ex(&instance, stringy_ce); + if (encoding == NULL) { + encoding = malloc(sizeof(zval)); + ZVAL_STRING(encoding, "UTF-8"); + } + zend_call_method(&instance, stringy_ce, NULL, ZEND_STRL("__construct"), return_value, 2, str, encoding); RETURN_ZVAL(&instance, 1, 0); @@ -311,7 +316,7 @@ ZEND_END_ARG_INFO(); PHP_METHOD(Stringy, substr) { - zval *start, *length; + zval *start, *length = NULL; zval func; ZEND_PARSE_PARAMETERS_START(1, 2) @@ -320,11 +325,11 @@ PHP_METHOD(Stringy, substr) Z_PARAM_ZVAL(length) ZEND_PARSE_PARAMETERS_END(); - if (Z_TYPE_P(length) == IS_NULL) + if (length == NULL) { zval func; ZVAL_STRING(&func, "length"); - call_user_function(NULL, NULL, &func, return_value, 0, NULL); + call_user_function(NULL, getThis(), &func, return_value, 0, NULL); length = return_value; } @@ -1740,6 +1745,7 @@ PHP_METHOD(Stringy, first) ZEND_PARSE_PARAMETERS_END(); if (n == NULL) { + n = malloc(sizeof(zval)); ZVAL_LONG(n, 0); } @@ -1776,6 +1782,49 @@ ZEND_BEGIN_ARG_INFO(arginfo_first, 0) ZEND_ARG_INFO(0, substring) ZEND_END_ARG_INFO(); +PHP_METHOD(Stringy, last) +{ + zval *n = NULL; + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ZVAL(n) + ZEND_PARSE_PARAMETERS_END(); + + if (n == NULL) { + n = malloc(sizeof(zval)); + ZVAL_LONG(n, 0); + } + + zval rv; + zval *str = zend_read_property(stringy_ce, getThis(), ZEND_STRL("str"), 0, &rv); + zval *encoding = zend_read_property(stringy_ce, getThis(), ZEND_STRL("encoding"), 0, &rv); + + zval instance; + object_init_ex(&instance, stringy_ce); + zval func, args[] = { + *str, + *encoding, + }; + ZVAL_STRING(&func, "__construct"); + call_user_function(NULL, &instance, &func, return_value, 2, args); + + zend_long len = Z_LVAL_P(n); + if (len <= 0) { + zend_update_property_string(stringy_ce, &instance, ZEND_STRL("str"), ""); + RETURN_ZVAL(&instance, 0, 1); + } + + ZVAL_LONG(n, -Z_LVAL_P(n)); + + zval args_substr[] = { + *n, + }; + ZVAL_STRING(&func, "substr"); + call_user_function(NULL, &instance, &func, return_value, 1, args_substr); +} +ZEND_BEGIN_ARG_INFO(arginfo_last, 0) + ZEND_ARG_INFO(0, n) +ZEND_END_ARG_INFO(); + PHP_METHOD(Stringy, isAlpha) { zval str_val; @@ -1919,6 +1968,114 @@ ZEND_BEGIN_ARG_INFO(arginfo_htmlEncode, 0) ZEND_ARG_INFO(0, flags) ZEND_END_ARG_INFO(); +PHP_METHOD(Stringy, removeLeft) +{ + zval *substring = NULL; + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ZVAL(substring); + ZEND_PARSE_PARAMETERS_END(); + + zval rv; + zval *str = zend_read_property(stringy_ce, getThis(), ZEND_STRL("str"), 0, &rv); + zval *encoding = zend_read_property(stringy_ce, getThis(), ZEND_STRL("encoding"), 0, &rv); + + zval instance; + object_init_ex(&instance, stringy_ce); + zval func_init, args_init[] = { + *str, + *encoding, + }; + ZVAL_STRING(&func_init, "__construct"); + call_user_function(NULL, &instance, &func_init, return_value, 2, args_init); + + zval func, args[] = { + *substring, + }; + ZVAL_STRING(&func, "startsWith"); + call_user_function(NULL, &instance, &func, return_value, 1, args); + + if (Z_TYPE_P(return_value) == IS_TRUE) { + zval func_strlen, args_strlen[] = { + *substring, + *encoding, + }; + ZVAL_STRING(&func_strlen, "mb_strlen"); + call_user_function(NULL, NULL, &func_strlen, return_value, 2, args_strlen); + + zval func_substr, args_substr[] = { + *return_value, + }; + ZVAL_STRING(&func_substr, "substr"); + call_user_function(NULL, &instance, &func_substr, return_value, 1, args_substr); + return; + } + + RETURN_ZVAL(&instance, 0, 1); +} +ZEND_BEGIN_ARG_INFO(arginfo_removeLeft, 0) + ZEND_ARG_INFO(0, substring) +ZEND_END_ARG_INFO(); + +PHP_METHOD(Stringy, removeRight) +{ + zval *substring = NULL; + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ZVAL(substring); + ZEND_PARSE_PARAMETERS_END(); + + zval rv; + zval *str = zend_read_property(stringy_ce, getThis(), ZEND_STRL("str"), 0, &rv); + zval *encoding = zend_read_property(stringy_ce, getThis(), ZEND_STRL("encoding"), 0, &rv); + + zval instance; + object_init_ex(&instance, stringy_ce); + zval func_init, args_init[] = { + *str, + *encoding, + }; + ZVAL_STRING(&func_init, "__construct"); + call_user_function(NULL, &instance, &func_init, return_value, 2, args_init); + + zval func, args[] = { + *substring, + }; + ZVAL_STRING(&func, "endsWith"); + call_user_function(NULL, &instance, &func, return_value, 1, args); + + if (Z_TYPE_P(return_value) == IS_TRUE) { + zval func_strlen, args_strlen[] = { + *substring, + *encoding, + }; + ZVAL_STRING(&func_strlen, "mb_strlen"); + call_user_function(NULL, NULL, &func_strlen, return_value, 2, args_strlen); + size_t substing_len = Z_LVAL_P(return_value); + + zval func_len; + ZVAL_STRING(&func_len, "length"); + call_user_function(NULL, getThis(), &func_len, return_value, 0, NULL); + size_t len = Z_LVAL_P(return_value); + + + zval zero; + zval second; + ZVAL_LONG(&zero, 0); + ZVAL_LONG(&second, len - substing_len); + zval func_substr, args_substr[] = { + zero, + second, + }; + ZVAL_STRING(&func_substr, "substr"); + call_user_function(NULL, getThis(), &func_substr, return_value, 2, args_substr); + return; + } + + RETURN_ZVAL(&instance, 0, 1); +} +ZEND_BEGIN_ARG_INFO(arginfo_removeRight, 0) + ZEND_ARG_INFO(0, substring) +ZEND_END_ARG_INFO(); + static zend_function_entry methods[] = { PHP_ME(Stringy, __construct, arginfo___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) PHP_ME(Stringy, __toString, NULL, ZEND_ACC_PUBLIC) @@ -1964,6 +2121,7 @@ static zend_function_entry methods[] = { PHP_ME(Stringy, ensureLeft, arginfo_ensureLeft, ZEND_ACC_PUBLIC) PHP_ME(Stringy, ensureRight, arginfo_ensureRight, ZEND_ACC_PUBLIC) PHP_ME(Stringy, first, arginfo_first, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, last, arginfo_last, ZEND_ACC_PUBLIC) PHP_ME(Stringy, isAlpha, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, matchesPattern, arginfo_matchesPattern, ZEND_ACC_PROTECTED) PHP_ME(Stringy, isBlank, NULL, ZEND_ACC_PUBLIC) @@ -1971,6 +2129,8 @@ static zend_function_entry methods[] = { PHP_ME(Stringy, hasUpperCase, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, htmlEncode, arginfo_htmlEncode, ZEND_ACC_PUBLIC) PHP_ME(Stringy, htmlDecode, arginfo_htmlDecode, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, removeLeft, arginfo_removeLeft, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, removeRight, arginfo_removeRight, ZEND_ACC_PUBLIC) PHP_FE_END }; diff --git a/startup.php b/startup.php index 0cedf64..c1a248c 100644 --- a/startup.php +++ b/startup.php @@ -4,28 +4,4 @@ _ns(NS_STRINGY); -$data = [ - ['foo bar ', ' foo bar '], - ['foo bar', ' foo bar'], - ['foo bar ', 'foo bar '], - ["foo bar \n\t", "\n\t foo bar \n\t"], - ['fòô bàř ', ' fòô bàř '], - ['fòô bàř', ' fòô bàř'], - ['fòô bàř ', 'fòô bàř '], - ['foo bar', '--foo bar', '-'], - ['fòô bàř', 'òòfòô bàř', 'ò', 'UTF-8'], - ["fòô bàř \n\t", "\n\t fòô bàř \n\t", null, 'UTF-8'], - ['fòô ', ' fòô ', null, 'UTF-8'], // narrow no-break space (U+202F) - ['fòô  ', '  fòô  ', null, 'UTF-8'], // medium mathematical space (U+205F) - ['fòô', '           fòô', null, 'UTF-8'], // spaces U+2000 to U+200A -]; - -foreach ($data as $value) { - @list($expected, $str, $chars, $encoding) = $value; - $stringy = __('Stringy')::create($str, $encoding); - $result = $stringy->trimLeft($chars); - - // var_dump((string)$result); -} - -var_dump(mb_strpos('Str contains foo bar', 'Foo bar', 0, 'UTF-8')); +var_dump(__('Stringy')::create("a")); From cd50bd37476f49a1f6e1b3e7e5041811f6b64f7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Thu, 17 Jan 2019 22:56:19 +0800 Subject: [PATCH 088/126] stringy-humanize (#48) --- spec/Stringy/StringySpec.php | 18 ++++++++++++ src/Minbaby/Php/Stringy/Stringy.php | 6 ++++ src/ext/stringy/stringy.c | 45 +++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+) diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index ee02042..9040f09 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -1203,4 +1203,22 @@ \expect((string) $result)->toBe($expected); } }); + + it('test humanize', function () { + $data = [ + ['Author', 'author_id'], + ['Test user', ' _test_user_'], + ['Συγγραφέας', ' συγγραφέας_id ', 'UTF-8'] + ]; + + foreach($data as $value) { + @list($expected, $str, $encoding) = $value; + $stringy = __('Stringy')::create($str, $encoding); + $result = $stringy->humanize(); + + \expect($stringy)->toBeAnInstanceOf(__('Stringy')); + \expect((string) $stringy)->toBe($str); + \expect((string) $result)->toBe($expected); + } + }); }); diff --git a/src/Minbaby/Php/Stringy/Stringy.php b/src/Minbaby/Php/Stringy/Stringy.php index 30a9d20..e295710 100644 --- a/src/Minbaby/Php/Stringy/Stringy.php +++ b/src/Minbaby/Php/Stringy/Stringy.php @@ -553,4 +553,10 @@ public function last($n) } return $stringy->substr(-$n); } + + public function humanize() + { + $str = str_replace(['_id', '_'], ['', ' '], $this->str); + return static::create($str, $this->encoding)->trim()->upperCaseFirst(); + } } diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index df94de2..62ebbf7 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -2076,6 +2076,50 @@ ZEND_BEGIN_ARG_INFO(arginfo_removeRight, 0) ZEND_ARG_INFO(0, substring) ZEND_END_ARG_INFO(); +PHP_METHOD(Stringy, humanize) +{ + zval rv; + zval *str = zend_read_property(stringy_ce, getThis(), ZEND_STRL("str"), 0, &rv); + zval *encoding = zend_read_property(stringy_ce, getThis(), ZEND_STRL("encoding"), 0, &rv); + + zval search; + array_init(&search); + add_next_index_string(&search, "_id"); + add_next_index_string(&search, "_"); + + zval repalce; + array_init(&repalce); + add_next_index_string(&repalce, ""); + add_next_index_string(&repalce, " "); + + zval func, args[] = { + search, + repalce, + *str, + }; + ZVAL_STRING(&func, "str_replace"); + call_user_function(NULL, NULL, &func, return_value, 3, args); + + zval instance; + object_init_ex(&instance, stringy_ce); + zval func_construct, args_construct[] = { + *return_value, + *encoding, + }; + ZVAL_STRING(&func_construct, "__construct"); + call_user_function(NULL, &instance, &func_construct, return_value, 2, args_construct); + + zval func_trim; + ZVAL_STRING(&func_trim, "trim"); + call_user_function(NULL, &instance, &func_trim, return_value, 0, NULL); + + zval func_upperCaseFirst; + ZVAL_STRING(&func_upperCaseFirst, "upperCaseFirst"); + call_user_function(NULL, return_value, &func_upperCaseFirst, return_value, 0, NULL); + + RETURN_ZVAL(return_value, 0, 1); +} + static zend_function_entry methods[] = { PHP_ME(Stringy, __construct, arginfo___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) PHP_ME(Stringy, __toString, NULL, ZEND_ACC_PUBLIC) @@ -2131,6 +2175,7 @@ static zend_function_entry methods[] = { PHP_ME(Stringy, htmlDecode, arginfo_htmlDecode, ZEND_ACC_PUBLIC) PHP_ME(Stringy, removeLeft, arginfo_removeLeft, ZEND_ACC_PUBLIC) PHP_ME(Stringy, removeRight, arginfo_removeRight, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, humanize, NULL, ZEND_ACC_PUBLIC) PHP_FE_END }; From d80636028d9ff2b0f2c14442c7c8e59ad86d1ff8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Fri, 18 Jan 2019 23:05:20 +0800 Subject: [PATCH 089/126] stringy-insert (#49) --- spec/Stringy/StringySpec.php | 23 ++++++++++ src/Minbaby/Php/Stringy/Stringy.php | 13 ++++++ src/ext/stringy/stringy.c | 68 +++++++++++++++++++++++++++++ 3 files changed, 104 insertions(+) diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index 9040f09..2753ea6 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -1221,4 +1221,27 @@ \expect((string) $result)->toBe($expected); } }); + + it('test insert', function () { + $data = [ + ['foo bar', 'oo bar', 'f', 0], + ['foo bar', 'f bar', 'oo', 1], + ['f bar', 'f bar', 'oo', 20], + ['foo bar', 'foo ba', 'r', 6], + ['fòôbàř', 'fòôbř', 'à', 4, 'UTF-8'], + ['fòô bàř', 'òô bàř', 'f', 0, 'UTF-8'], + ['fòô bàř', 'f bàř', 'òô', 1, 'UTF-8'], + ['fòô bàř', 'fòô bà', 'ř', 6, 'UTF-8'] + ]; + foreach($data as $value) { + @list($expected, $str, $substring, $index, $encoding) = $value; + $stringy = __('Stringy')::create($str, $encoding); + $result = $stringy->insert($substring, $index); + + \expect($stringy)->toBeAnInstanceOf(__('Stringy')); + \expect((string) $stringy)->toBe($str); + \expect((string) $result)->toBe($expected); + + } + }); }); diff --git a/src/Minbaby/Php/Stringy/Stringy.php b/src/Minbaby/Php/Stringy/Stringy.php index e295710..2c1f260 100644 --- a/src/Minbaby/Php/Stringy/Stringy.php +++ b/src/Minbaby/Php/Stringy/Stringy.php @@ -559,4 +559,17 @@ public function humanize() $str = str_replace(['_id', '_'], ['', ' '], $this->str); return static::create($str, $this->encoding)->trim()->upperCaseFirst(); } + + public function insert($substring, $index) + { + $stringy = static::create($this->str, $this->encoding); + if ($index > $stringy->length()) { + return $stringy; + } + $start = \mb_substr($stringy->str, 0, $index, $stringy->encoding); + $end = \mb_substr($stringy->str, $index, $stringy->length(), $stringy->encoding); + $stringy->str = $start . $substring . $end; + return $stringy; + } + } diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index 62ebbf7..4fb8b27 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -2120,6 +2120,73 @@ PHP_METHOD(Stringy, humanize) RETURN_ZVAL(return_value, 0, 1); } +PHP_METHOD(Stringy, insert) +{ + zval *substring, *index; + ZEND_PARSE_PARAMETERS_START(2, 2) + Z_PARAM_ZVAL(substring) + Z_PARAM_ZVAL(index) + ZEND_PARSE_PARAMETERS_END(); + + zval rv; + zval *str = zend_read_property(stringy_ce, getThis(), ZEND_STRL("str"), 0, &rv); + zval *encoding = zend_read_property(stringy_ce, getThis(), ZEND_STRL("encoding"), 0, &rv); + + zval instance; + object_init_ex(&instance, stringy_ce); + zval func, args[] = { + *str, + *encoding, + }; + ZVAL_STRING(&func, "__construct"); + call_user_function(NULL, &instance, &func, return_value, 2, args); + + + zval len; + zval func_length; + ZVAL_STRING(&func_length, "length"); + call_user_function(NULL, &instance, &func_length, &len, 0, NULL); + + if (Z_LVAL_P(index) > Z_LVAL(len)) { + RETURN_ZVAL(&instance, 0, 1); + } + + zval zero; + ZVAL_LONG(&zero, 0); + + zval start; + zval func_substr1, args_substr1[] = { + *str, + zero, + *index, + *encoding, + }; + ZVAL_STRING(&func_substr1, "mb_substr"); + call_user_function(NULL, NULL, &func_substr1, &start, 4, args_substr1); + + zval end; + zval func_substr2, args_substr2[] = { + *str, + *index, + len, + *encoding, + }; + ZVAL_STRING(&func_substr2, "mb_substr"); + call_user_function(NULL, NULL, &func_substr2, &end, 4, args_substr2); + + zval ret; + concat_function(&ret, &start, substring); + concat_function(&ret, &ret, &end); + + zend_update_property(stringy_ce, &instance, ZEND_STRL("str"), &ret); + + RETURN_ZVAL(&instance, 0, 1); +} +ZEND_BEGIN_ARG_INFO(arginfo_insert, 0) + ZEND_ARG_INFO(0, substring) + ZEND_ARG_INFO(0, index) +ZEND_END_ARG_INFO(); + static zend_function_entry methods[] = { PHP_ME(Stringy, __construct, arginfo___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) PHP_ME(Stringy, __toString, NULL, ZEND_ACC_PUBLIC) @@ -2176,6 +2243,7 @@ static zend_function_entry methods[] = { PHP_ME(Stringy, removeLeft, arginfo_removeLeft, ZEND_ACC_PUBLIC) PHP_ME(Stringy, removeRight, arginfo_removeRight, ZEND_ACC_PUBLIC) PHP_ME(Stringy, humanize, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, insert, arginfo_insert, ZEND_ACC_PUBLIC) PHP_FE_END }; From 550ed93b91f1f2fbc3a3ad0dad60b16c365c60f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Fri, 18 Jan 2019 23:30:26 +0800 Subject: [PATCH 090/126] stringy/{length,isUpperCase,isLowerCase,isHexadecimal,isAlphanumeric} (#50) --- spec/Stringy/StringySpec.php | 118 ++++++++++++++++++++++++++++ src/Minbaby/Php/Stringy/Stringy.php | 19 +++++ src/ext/stringy/stringy.c | 48 +++++++++++ 3 files changed, 185 insertions(+) diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index 2753ea6..33ead23 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -1244,4 +1244,122 @@ } }); + + it('test isAlphanumeric', function () { + $data = [ + [true, ''], + [true, 'foobar1'], + [false, 'foo bar'], + [false, 'foobar2"'], + [false, "\nfoobar\n"], + [true, 'fòôbàř1', 'UTF-8'], + [false, 'fòô bàř', 'UTF-8'], + [false, 'fòôbàř2"', 'UTF-8'], + [true, 'ҠѨњфгШ', 'UTF-8'], + [false, 'ҠѨњ¨ˆфгШ', 'UTF-8'], + [true, '丹尼爾111', 'UTF-8'], + [true, 'دانيال1', 'UTF-8'], + [false, 'دانيال1 ', 'UTF-8'] + ]; + foreach($data as $value) { + @list($expected, $str, $encoding) = $value; + $stringy = __('Stringy')::create($str, $encoding); + $result = $stringy->isAlphanumeric(); + + \expect($result)->toBeA('boolean'); + \expect((string) $stringy)->toBe($str); + \expect((bool) $result)->toBe($expected); + } + }); + + it('test isHexadecimal', function () { + $data = [ + [true, ''], + [true, 'abcdef'], + [true, 'ABCDEF'], + [true, '0123456789'], + [true, '0123456789AbCdEf'], + [false, '0123456789x'], + [false, 'ABCDEFx'], + [true, 'abcdef', 'UTF-8'], + [true, 'ABCDEF', 'UTF-8'], + [true, '0123456789', 'UTF-8'], + [true, '0123456789AbCdEf', 'UTF-8'], + [false, '0123456789x', 'UTF-8'], + [false, 'ABCDEFx', 'UTF-8'], + ]; + foreach($data as $value) { + @list($expected, $str, $encoding) = $value; + $stringy = __('Stringy')::create($str, $encoding); + $result = $stringy->isHexadecimal(); + + \expect($result)->toBeA('boolean'); + \expect((string) $stringy)->toBe($str); + \expect((bool) $result)->toBe($expected); + } + }); + + + it('test isLowerCase', function () { + $data = [ + [true, ''], + [true, 'foobar'], + [false, 'foo bar'], + [false, 'Foobar'], + [true, 'fòôbàř', 'UTF-8'], + [false, 'fòôbàř2', 'UTF-8'], + [false, 'fòô bàř', 'UTF-8'], + [false, 'fòôbÀŘ', 'UTF-8'], + ]; + foreach($data as $value) { + @list($expected, $str, $encoding) = $value; + $stringy = __('Stringy')::create($str, $encoding); + $result = $stringy->isLowerCase(); + + \expect($result)->toBeA('boolean'); + \expect((string) $stringy)->toBe($str); + \expect((bool) $result)->toBe($expected); + } + }); + + it('test isUpperCase', function () { + $data = [ + [true, ''], + [true, 'FOOBAR'], + [false, 'FOO BAR'], + [false, 'fOOBAR'], + [true, 'FÒÔBÀŘ', 'UTF-8'], + [false, 'FÒÔBÀŘ2', 'UTF-8'], + [false, 'FÒÔ BÀŘ', 'UTF-8'], + [false, 'FÒÔBàř', 'UTF-8'], + ]; + foreach($data as $value) { + @list($expected, $str, $encoding) = $value; + $stringy = __('Stringy')::create($str, $encoding); + $result = $stringy->isUpperCase(); + + \expect($result)->toBeA('boolean'); + \expect((string) $stringy)->toBe($str); + \expect((bool) $result)->toBe($expected); + } + }); + + it('test length', function () { + $data = [ + [11, ' foo bar '], + [1, 'f'], + [0, ''], + [7, 'fòô bàř', 'UTF-8'] + ]; + + foreach($data as $value) { + @list($expected, $str, $encoding) = $value; + $stringy = __('Stringy')::create($str, $encoding); + $result = $stringy->length(); + + \expect($result)->toBeA('int'); + \expect((string) $stringy)->toBe($str); + \expect((int) $result)->toBe($expected); + } + }); }); diff --git a/src/Minbaby/Php/Stringy/Stringy.php b/src/Minbaby/Php/Stringy/Stringy.php index 2c1f260..72166a4 100644 --- a/src/Minbaby/Php/Stringy/Stringy.php +++ b/src/Minbaby/Php/Stringy/Stringy.php @@ -572,4 +572,23 @@ public function insert($substring, $index) return $stringy; } + public function isAlphanumeric() + { + return $this->matchesPattern('^[[:alnum:]]*$'); + } + + public function isHexadecimal() + { + return $this->matchesPattern('^[[:xdigit:]]*$'); + } + + public function isLowerCase() + { + return $this->matchesPattern('^[[:lower:]]*$'); + } + + public function isUpperCase() + { + return $this->matchesPattern('^[[:upper:]]*$'); + } } diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index 4fb8b27..716d3c6 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -2187,6 +2187,50 @@ ZEND_BEGIN_ARG_INFO(arginfo_insert, 0) ZEND_ARG_INFO(0, index) ZEND_END_ARG_INFO(); +PHP_METHOD(Stringy, isAlphanumeric) +{ + zval str_val; + ZVAL_STRING(&str_val, "^[[:alnum:]]*$"); + zval func, args[] = { + str_val + }; + ZVAL_STRING(&func, "matchesPattern"); + call_user_function(NULL, getThis(), &func, return_value, 1, args); +} + +PHP_METHOD(Stringy, isLowerCase) +{ + zval str_val; + ZVAL_STRING(&str_val, "^[[:lower:]]*$"); + zval func, args[] = { + str_val + }; + ZVAL_STRING(&func, "matchesPattern"); + call_user_function(NULL, getThis(), &func, return_value, 1, args); +} + +PHP_METHOD(Stringy, isUpperCase) +{ + zval str_val; + ZVAL_STRING(&str_val, "^[[:upper:]]*$"); + zval func, args[] = { + str_val + }; + ZVAL_STRING(&func, "matchesPattern"); + call_user_function(NULL, getThis(), &func, return_value, 1, args); +} + +PHP_METHOD(Stringy, isHexadecimal) +{ + zval str_val; + ZVAL_STRING(&str_val, "^[[:xdigit:]]*$"); + zval func, args[] = { + str_val + }; + ZVAL_STRING(&func, "matchesPattern"); + call_user_function(NULL, getThis(), &func, return_value, 1, args); +} + static zend_function_entry methods[] = { PHP_ME(Stringy, __construct, arginfo___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) PHP_ME(Stringy, __toString, NULL, ZEND_ACC_PUBLIC) @@ -2234,6 +2278,10 @@ static zend_function_entry methods[] = { PHP_ME(Stringy, first, arginfo_first, ZEND_ACC_PUBLIC) PHP_ME(Stringy, last, arginfo_last, ZEND_ACC_PUBLIC) PHP_ME(Stringy, isAlpha, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, isAlphanumeric, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, isHexadecimal, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, isLowerCase, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, isUpperCase, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, matchesPattern, arginfo_matchesPattern, ZEND_ACC_PROTECTED) PHP_ME(Stringy, isBlank, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, hasLowerCase, NULL, ZEND_ACC_PUBLIC) From e60e73006b22ca914cb43c10185948f50a0c0290 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Sat, 19 Jan 2019 23:49:24 +0800 Subject: [PATCH 091/126] stringy-isJson (#51) --- spec/Stringy/StringySpec.php | 35 +++++++++++++++++++++++++++++ src/Minbaby/Php/Stringy/Stringy.php | 9 ++++++++ src/ext/stringy/stringy.c | 30 +++++++++++++++++++++++++ 3 files changed, 74 insertions(+) diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index 33ead23..ad202b3 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -1362,4 +1362,39 @@ \expect((int) $result)->toBe($expected); } }); + + it('test isJson', function () { + $data = [ + [false, ''], + [false, ' '], + [true, 'null'], + [true, 'true'], + [true, 'false'], + [true, '[]'], + [true, '{}'], + [true, '123'], + [true, '{"foo": "bar"}'], + [false, '{"foo":"bar",}'], + [false, '{"foo"}'], + [true, '["foo"]'], + [false, '{"foo": "bar"]'], + [true, '123', 'UTF-8'], + [true, '{"fòô": "bàř"}', 'UTF-8'], + [false, '{"fòô":"bàř",}', 'UTF-8'], + [false, '{"fòô"}', 'UTF-8'], + [false, '["fòô": "bàř"]', 'UTF-8'], + [true, '["fòô"]', 'UTF-8'], + [false, '{"fòô": "bàř"]', 'UTF-8'], + ]; + foreach($data as $value) { + @list($expected, $str, $encoding) = $value; + $stringy = __('Stringy')::create($str, $encoding); + $result = $stringy->isJson(); + + \expect($result)->toBeA('boolean'); + \expect((string) $stringy)->toBe($str); + \expect((bool) $result)->toBe($expected); + } + + }); }); diff --git a/src/Minbaby/Php/Stringy/Stringy.php b/src/Minbaby/Php/Stringy/Stringy.php index 72166a4..cee9e9b 100644 --- a/src/Minbaby/Php/Stringy/Stringy.php +++ b/src/Minbaby/Php/Stringy/Stringy.php @@ -591,4 +591,13 @@ public function isUpperCase() { return $this->matchesPattern('^[[:upper:]]*$'); } + + public function isJson() + { + if (!$this->length()) { + return false; + } + json_decode($this->str); + return (json_last_error() === JSON_ERROR_NONE); + } } diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index 716d3c6..e778a16 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -2231,6 +2231,35 @@ PHP_METHOD(Stringy, isHexadecimal) call_user_function(NULL, getThis(), &func, return_value, 1, args); } +PHP_METHOD(Stringy, isJson) +{ + zval func; + ZVAL_STRING(&func, "length"); + call_user_function(NULL, getThis(), &func, return_value, 0, NULL); + if (Z_LVAL_P(return_value) <= 0) { + RETURN_BOOL(0); + } + + zval rv; + zval *str = zend_read_property(stringy_ce, getThis(), ZEND_STRL("str"), 0, &rv); + + zval func_json_decode, args[] = { + *str, + }; + ZVAL_STRING(&func_json_decode, "json_decode"); + call_user_function(NULL, NULL, &func_json_decode, return_value, 1, args); + + ZVAL_STRING(&func, "json_last_error"); + call_user_function(NULL, NULL, &func, return_value, 0, NULL); + + zval *json_error_none = zend_get_constant_str(ZEND_STRL("JSON_ERROR_NONE")); + + if (Z_LVAL_P(json_error_none) == Z_LVAL_P(return_value)) { + RETURN_BOOL(1); + } + RETURN_BOOL(0); +} + static zend_function_entry methods[] = { PHP_ME(Stringy, __construct, arginfo___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) PHP_ME(Stringy, __toString, NULL, ZEND_ACC_PUBLIC) @@ -2292,6 +2321,7 @@ static zend_function_entry methods[] = { PHP_ME(Stringy, removeRight, arginfo_removeRight, ZEND_ACC_PUBLIC) PHP_ME(Stringy, humanize, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, insert, arginfo_insert, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, isJson, NULL, ZEND_ACC_PUBLIC) PHP_FE_END }; From 0324bc382c4baa3f95a05a1a2eec88640e617836 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Wed, 6 Feb 2019 00:25:34 +0800 Subject: [PATCH 092/126] stringy-isSerialized php+ext+test (#52) --- .vscode/c_cpp_properties.json | 2 +- kahlan-config.php | 4 +-- spec/Stringy/StringySpec.php | 28 ++++++++++++++++++ spec/functions.php | 5 ++++ src/Minbaby/Php/Stringy/Stringy.php | 5 ++++ src/ext/stringy/stringy.c | 44 +++++++++++++++++++++++++++++ 6 files changed, 85 insertions(+), 3 deletions(-) diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index dafe320..5e0a595 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -16,7 +16,7 @@ "name": "Mac", "includePath": [ "${workspaceFolder}/**", - "~/.phpbrew/build/php-7.1.17/**" + "~/.phpbrew/build/php-7.1.23/**" ], "defines": [], "compilerPath": "/usr/bin/gcc", diff --git a/kahlan-config.php b/kahlan-config.php index a6b0d51..6cfdff0 100644 --- a/kahlan-config.php +++ b/kahlan-config.php @@ -3,6 +3,6 @@ /** @var \Kahlan\Cli\CommandLine $commandLine */ $commandLine = $this->commandLine(); -// $commandLine->option('reporter', 'default', 'verbose'); +$commandLine->option('reporter', 'default', 'verbose'); $commandLine->option('ff', 'default', 1); -$commandLine->option('clover', 'default', 'coverage.xml'); +isset($_SERVER['CI']) && $_SERVER['CI'] === true && $commandLine->option('clover', 'default', 'coverage.xml'); diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index ad202b3..88a9a9b 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -2,6 +2,11 @@ namespace Minbaby\Startup\Spec\Stringy; +use function Kahlan\context; +use function Kahlan\it; +use function Kahlan\describe; + + \describe('Stringy Test', function () { \beforeAll(function () { _ns(NS_STRINGY); @@ -1397,4 +1402,27 @@ } }); + + context('test isSerialized', function () { + $data = [ + [false, ''], + [true, 'a:1:{s:3:"foo";s:3:"bar";}'], + [false, 'a:1:{s:3:"foo";s:3:"bar"}'], + [true, serialize(['foo' => 'bar'])], + [true, 'a:1:{s:5:"fòô";s:5:"bàř";}', 'UTF-8'], + [false, 'a:1:{s:5:"fòô";s:5:"bàř"}', 'UTF-8'], + [true, serialize(['fòô' => 'bár']), 'UTF-8'], + ]; + foreach($data as $key => $value) { + it(__formatMessage($key, $value), function () use ($value) { + @list($expected, $str, $encoding) = $value; + $stringy = __('Stringy')::create($str, $encoding); + $result = $stringy->isSerialized(); + + \expect($result)->toBeA('boolean'); + \expect((string) $stringy)->toBe($str); + \expect((bool) $result)->toBe($expected); + }); + } + }); }); diff --git a/spec/functions.php b/spec/functions.php index 2032f42..b4dad63 100644 --- a/spec/functions.php +++ b/spec/functions.php @@ -39,3 +39,8 @@ function __(string $str): string return sprintf('%s\%s', rtrim($________['ns'], SEP_DIR), $str); } + +function __formatMessage(string $message, array $data): string +{ + return sprintf('%s: ==> %s <==', $message, json_encode($data)); +} diff --git a/src/Minbaby/Php/Stringy/Stringy.php b/src/Minbaby/Php/Stringy/Stringy.php index cee9e9b..d48121b 100644 --- a/src/Minbaby/Php/Stringy/Stringy.php +++ b/src/Minbaby/Php/Stringy/Stringy.php @@ -600,4 +600,9 @@ public function isJson() json_decode($this->str); return (json_last_error() === JSON_ERROR_NONE); } + + public function isSerialized() + { + return $this->str === 'b:0;' || @unserialize($this->str) !== false; + } } diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index e778a16..2459bf4 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -2260,6 +2260,49 @@ PHP_METHOD(Stringy, isJson) RETURN_BOOL(0); } +PHP_METHOD(Stringy, isSerialized) +{ + zval empty_object_serialized; + ZVAL_STRING(&empty_object_serialized, "b:0;"); + + zval rv; + zval *str = zend_read_property(stringy_ce, getThis(), ZEND_STRL("str"), 0, &rv); + + if (Z_TYPE_P(str) == Z_TYPE(empty_object_serialized) && Z_STR_P(str) == Z_STR(empty_object_serialized)) + { + RETURN_TRUE; + } + zval func; + + zval error_level; + ZVAL_STRING(&func, "error_reporting"); + zval new_error_level; + ZVAL_LONG(&new_error_level, 0); + zval args_error_reporting[] = { + new_error_level, + }; + call_user_function(NULL, NULL, &func, &error_level, 1, args_error_reporting); + + zval args[] = { + *str, + }; + ZVAL_STRING(&func, "unserialize"); + call_user_function(NULL, NULL, &func, return_value, 1, args); + + zval reset_error_level; + zval args_reset[] = { + error_level, + }; + ZVAL_STRING(&func, "error_reporting"); + call_user_function(NULL, NULL, &func, &reset_error_level, 1, args_reset); + + if (Z_TYPE_P(return_value) != IS_FALSE) { + RETURN_TRUE; + } + + RETURN_FALSE; +} + static zend_function_entry methods[] = { PHP_ME(Stringy, __construct, arginfo___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) PHP_ME(Stringy, __toString, NULL, ZEND_ACC_PUBLIC) @@ -2322,6 +2365,7 @@ static zend_function_entry methods[] = { PHP_ME(Stringy, humanize, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, insert, arginfo_insert, ZEND_ACC_PUBLIC) PHP_ME(Stringy, isJson, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, isSerialized, NULL, ZEND_ACC_PUBLIC) PHP_FE_END }; From 8c435623dd8d52ef85d973a1b37345c1510b1978 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Thu, 7 Feb 2019 17:19:53 +0800 Subject: [PATCH 093/126] Feature/stringy is base64 php+ext+test (#53) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * stringy-isBase64 * fix unknown type name ‘bool’ --- config.m4 | 1 + spec/Stringy/StringySpec.php | 25 +++++++++++++++++++ src/Minbaby/Php/Stringy/Stringy.php | 5 ++++ src/ext/functions.c | 10 ++++++++ src/ext/functions.h | 2 ++ src/ext/stringy/stringy.c | 38 +++++++++++++++++++++-------- src/ext/stringy/stringy.h | 10 ++++++++ 7 files changed, 81 insertions(+), 10 deletions(-) diff --git a/config.m4 b/config.m4 index 9a25795..5d45a77 100644 --- a/config.m4 +++ b/config.m4 @@ -60,6 +60,7 @@ if test "$PHP_STARTUP" != "no"; then dnl PHP_SUBST(STARTUP_SHARED_LIBADD) source="startup.c \ + src/ext/functions.c \ src/ext/test.class.c \ src/ext/stringy/stringy.c"; diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index 88a9a9b..fd8f627 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -1425,4 +1425,29 @@ }); } }); + + context('test isBase64', function () { + $data = [ + [false, ' '], + [true, ''], + [true, base64_encode('FooBar') ], + [true, base64_encode(' ') ], + [true, base64_encode('FÒÔBÀŘ') ], + [true, base64_encode('συγγραφέας') ], + [false, 'Foobar'], + ]; + + foreach($data as $key => $value) { + it(__formatMessage($key, $value), function () use ($value) { + list($expected, $str) = $value; + + $stringy = __('Stringy')::create($str); + $result = $stringy->isBase64(); + + \expect($result)->toBeA('boolean'); + \expect((string) $stringy)->toBe($str); + \expect((bool) $result)->toBe($expected); + }); + } + }); }); diff --git a/src/Minbaby/Php/Stringy/Stringy.php b/src/Minbaby/Php/Stringy/Stringy.php index d48121b..c5d708b 100644 --- a/src/Minbaby/Php/Stringy/Stringy.php +++ b/src/Minbaby/Php/Stringy/Stringy.php @@ -605,4 +605,9 @@ public function isSerialized() { return $this->str === 'b:0;' || @unserialize($this->str) !== false; } + + public function isBase64() + { + return (base64_encode(base64_decode($this->str, true)) === $this->str); + } } diff --git a/src/ext/functions.c b/src/ext/functions.c index d6f83a1..347226d 100644 --- a/src/ext/functions.c +++ b/src/ext/functions.c @@ -5,3 +5,13 @@ // void php_startup_register_functions(zend_function_entry *entry) // { // } + +bool zval_str_equal(zval *first, zval *second) +{ + + if (Z_TYPE_P(first) == Z_TYPE_P(second) && zend_string_equals(Z_STR_P(first), Z_STR_P(second))) { + return true; + } + + return false; +} diff --git a/src/ext/functions.h b/src/ext/functions.h index c134d61..4e89ea4 100644 --- a/src/ext/functions.h +++ b/src/ext/functions.h @@ -1,9 +1,11 @@ #ifndef STARTUP_FUNCTIONS_H #define STARTUP_FUNCTIONS_H +#include "stdbool.h" #include "php.h" #include "common.h" #include "ext/standard/php_standard.h" // void php_startup_register_functions(zend_function_entry *zend_function_entry); +bool zval_equal(zval *first, zval *second); #endif diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index 2459bf4..9938dca 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -1,14 +1,4 @@ #include "stringy.h" -#include "php.h" -#include "../common.h" -#include "ext/standard/php_standard.h" -#include "Zend/zend_exceptions.h" -#include "ext/spl/spl_exceptions.h" -#include "ext/spl/spl_iterators.h" -#include "ext/mbstring/mbstring.h" -#include "zend_interfaces.h" -#include "zend_closures.h" -#include "ext/spl/spl_array.h" zend_class_entry *stringy_ce; @@ -2303,6 +2293,33 @@ PHP_METHOD(Stringy, isSerialized) RETURN_FALSE; } +PHP_METHOD(Stringy, isBase64) +{ + zval rv; + zval *str = zend_read_property(stringy_ce, getThis(), ZEND_STRL("str"), 0, &rv); + + zval z_true; + ZVAL_BOOL(&z_true, IS_TRUE); + zval func, args[] = { + *str, + z_true, + }; + ZVAL_STRING(&func, "base64_decode"); + call_user_function(NULL, NULL, &func, return_value, 2, args); + + zval args_decode[] = { + *return_value, + }; + ZVAL_STRING(&func, "base64_encode"); + call_user_function(NULL, NULL, &func, return_value, 1, args_decode); + + if (zval_str_equal(return_value, str)) { + RETURN_TRUE; + } + + RETURN_FALSE; +} + static zend_function_entry methods[] = { PHP_ME(Stringy, __construct, arginfo___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) PHP_ME(Stringy, __toString, NULL, ZEND_ACC_PUBLIC) @@ -2366,6 +2383,7 @@ static zend_function_entry methods[] = { PHP_ME(Stringy, insert, arginfo_insert, ZEND_ACC_PUBLIC) PHP_ME(Stringy, isJson, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, isSerialized, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, isBase64, NULL, ZEND_ACC_PUBLIC) PHP_FE_END }; diff --git a/src/ext/stringy/stringy.h b/src/ext/stringy/stringy.h index 41d739a..ef5c756 100644 --- a/src/ext/stringy/stringy.h +++ b/src/ext/stringy/stringy.h @@ -2,6 +2,16 @@ #define STARTUP_STRINGY_STRINGY_H #include "php.h" +#include "../common.h" +#include "../functions.h" +#include "ext/standard/php_standard.h" +#include "Zend/zend_exceptions.h" +#include "ext/spl/spl_exceptions.h" +#include "ext/spl/spl_iterators.h" +#include "ext/mbstring/mbstring.h" +#include "zend_interfaces.h" +#include "zend_closures.h" +#include "ext/spl/spl_array.h" #define PHP_STARTUP_STRINGY_NS(cls) PHP_STARTUP_NS_NAME "Stringy\\" #cls From d5e7e64f9ae059e9fab2f7acd42749af1059452f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Mon, 25 Feb 2019 23:13:54 +0800 Subject: [PATCH 094/126] Feature/stringy longest common (#54) --- Makefile.frag | 29 +++ config.m4 | 32 +++- scripts/fetch.php | 2 + scripts/subtree.sh | 5 + scripts/test.sh | 4 +- spec/Stringy/StringySpec.php | 85 +++++++++ spec/functions.php | 18 +- src/Minbaby/Php/Stringy/Stringy.php | 68 +++++++ src/ext/common.h | 7 + src/ext/functions.c | 62 +++++- src/ext/functions.h | 10 +- src/ext/stringy/stringy.c | 282 ++++++++++++++++++++++++++++ src/ext/test.class.c | 2 +- thirdParty/rxi-log/LICENSE | 19 ++ thirdParty/rxi-log/README.md | 70 +++++++ thirdParty/rxi-log/src/log.c | 136 ++++++++++++++ thirdParty/rxi-log/src/log.h | 35 ++++ 17 files changed, 848 insertions(+), 18 deletions(-) create mode 100644 Makefile.frag create mode 100755 scripts/subtree.sh create mode 100644 thirdParty/rxi-log/LICENSE create mode 100644 thirdParty/rxi-log/README.md create mode 100644 thirdParty/rxi-log/src/log.c create mode 100644 thirdParty/rxi-log/src/log.h diff --git a/Makefile.frag b/Makefile.frag new file mode 100644 index 0000000..232a926 --- /dev/null +++ b/Makefile.frag @@ -0,0 +1,29 @@ +ext-subtree: + ./scripts/subtree.sh + +ext-fetch: + ./scripts/fetch.php + +ext-prepare: + echo "prepare..." + phpize && ./configure --enable-debug + +ext-clean: + echo "clean..." + make clean && phpize --clean + +ext-build: + ./scripts/build.sh + +ext-test: + # echo "disable ext startup.so" + phpbrew ext disable startup + MINBABY_TEST_EXT=0 php ./vendor/bin/kahlan + +ext-test-ext: + # echo "enable ext start.so" + phpbrew ext enable startup + MINBABY_TEST_EXT=1 php ./vendor/bin/kahlan + +ext-first:ext-prepare ext-build ext-test ext-test-ext + @echo 1 diff --git a/config.m4 b/config.m4 index 5d45a77..5759bdf 100644 --- a/config.m4 +++ b/config.m4 @@ -17,6 +17,13 @@ PHP_ARG_ENABLE(startup, whether to enable startup support, dnl Make sure that the comment is aligned: [ --enable-startup Enable startup support]) +if test -z "$PHP_DEBUG"; then + AC_ARG_ENABLE(debug, + [--enable-debug compile with debugging system], + [PHP_DEBUG=$enableval], [PHP_DEBUG=no] + ) +fi + if test "$PHP_STARTUP" != "no"; then dnl Write more examples of tests here... @@ -65,11 +72,24 @@ if test "$PHP_STARTUP" != "no"; then src/ext/stringy/stringy.c"; PHP_NEW_EXTENSION(startup, $source, $ext_shared,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1) -fi -if test -z "$PHP_DEBUG"; then - AC_ARG_ENABLE(debug, - [--enable-debug compile with debugging system], - [PHP_DEBUG=$enableval], [PHP_DEBUG=no] - ) + dnl configure can't use ".." as a source filename, so we make a link here + # ln -sf $ext_srcdir/../common $ext_srcdir + # ln -sf $ext_srcdir/../deps $ext_srcdir + # ln -sf ./thirdParty/rxi-log include/rxi-log + + dnl add common include path + PHP_ADD_INCLUDE(thirdParty/rxi-log/src) + + # PHP_ADD_SOURCES(thirdParty/rxi-log/src) + + PHP_ADD_MAKEFILE_FRAGMENT fi + +if test "$PHP_DEBUG" != "no"; then + dnl 是,则设置 C 语言宏指令 + AC_DEFINE(PHP_DEBUG, 1, [Include debugging support in ext1]) + AC_DEFINE(PHP_EXT_DEBUG, 1, [Include debugging support in ext]) + fi + + diff --git a/scripts/fetch.php b/scripts/fetch.php index dc98a3c..83a389a 100755 --- a/scripts/fetch.php +++ b/scripts/fetch.php @@ -16,6 +16,7 @@ 'phptrace' => 'https://github.com/Qihoo360/phptrace', 'php-memcached' => 'https://github.com/php-memcached-dev/php-memcached', 'swoole' => 'https://github.com/swoole/swoole-src', + 'async-ext' => 'https://github.com/swoole/async-ext.git', 'pthreads' => 'https://github.com/krakjoe/pthreads', 'SeasLog' => 'https://github.com/SeasX/SeasLog', 'phpdbg' => 'https://github.com/krakjoe/phpdbg', @@ -24,6 +25,7 @@ 'php-git' => 'https://github.com/libgit2/php-git', 'AOP' => 'https://github.com/AOP-PHP/AOP', 'xdeubg' => 'https://github.com/xdebug/xdebug.git', + 'apcu' => 'https://github.com/krakjoe/apcu.git', ]; // PHPBREW_ROOT/build/php-7.1.17/ext/ diff --git a/scripts/subtree.sh b/scripts/subtree.sh new file mode 100755 index 0000000..899caa1 --- /dev/null +++ b/scripts/subtree.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +set -e -x + +git subtree pull --prefix=src/ext/thirdParty/rxi-log https://github.com/rxi/log.c master --squash diff --git a/scripts/test.sh b/scripts/test.sh index 616683f..793270d 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -8,9 +8,9 @@ pwd # echo "disable ext startup.so" phpbrew ext disable startup export MINBABY_TEST_EXT=0 -./vendor/bin/kahlan --coverage=1 --clover=coverage.xml +./vendor/bin/kahlan # echo "enable ext start.so" phpbrew ext enable startup export MINBABY_TEST_EXT=1 -./vendor/bin/kahlan --coverage=1 --clover=coverage.xml +./vendor/bin/kahlan diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index fd8f627..508a2f3 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -1450,4 +1450,89 @@ }); } }); + + context('test longestCommonPrefix', function () { + $data = [ + ['foo', 'foobar', 'foo bar'], + ['foo bar', 'foo bar', 'foo bar'], + ['f', 'foo bar', 'far boo'], + ['', 'toy car', 'foo bar'], + ['', 'foo bar', ''], + ['fòô', 'fòôbar', 'fòô bar', 'UTF-8'], + ['fòô bar', 'fòô bar', 'fòô bar', 'UTF-8'], + ['fò', 'fòô bar', 'fòr bar', 'UTF-8'], + ['', 'toy car', 'fòô bar', 'UTF-8'], + ['', 'fòô bar', '', 'UTF-8'], + ]; + + foreach($data as $key => $value) { + it(__formatMessage($key, $value), function () use ($value) { + @list($expected, $str, $otherStr, $encoding) = $value; + + $stringy = __('Stringy')::create($str); + $result = $stringy->longestCommonPrefix($otherStr); + + \expect($stringy)->toBeAnInstanceOf(__('Stringy')); + \expect((string) $stringy)->toBe($str); + \expect((string) $result)->toBe($expected); + }); + } + }); + + context('test longestCommonSuffix', function () { + $data = [ + ['bar', 'foobar', 'foo bar'], + ['foo bar', 'foo bar', 'foo bar'], + ['ar', 'foo bar', 'boo far'], + ['', 'foo bad', 'foo bar'], + ['', 'foo bar', ''], + ['bàř', 'fòôbàř', 'fòô bàř', 'UTF-8'], + ['fòô bàř', 'fòô bàř', 'fòô bàř', 'UTF-8'], + [' bàř', 'fòô bàř', 'fòr bàř', 'UTF-8'], + ['', 'toy car', 'fòô bàř', 'UTF-8'], + ['', 'fòô bàř', '', 'UTF-8'], + ]; + + foreach($data as $key => $value) { + it(__formatMessage($key, $value), function () use ($value) { + @list($expected, $str, $otherStr, $encoding) = $value; + + $stringy = __('Stringy')::create($str); + $result = $stringy->longestCommonSuffix($otherStr); + + \expect($stringy)->toBeAnInstanceOf(__('Stringy')); + \expect((string) $stringy)->toBe($str); + \expect((string) $result)->toBe($expected); + }); + } + }); + + xcontext('test longestCommonSubstring', function () { + $data = [ + // ['ff', 'aff', 'ff'], + // ['foo', 'foobar', 'foo bar'], + // ['foo bar', 'foo bar', 'foo bar'], + // ['oo ', 'foo bar', 'boo far'], + // ['foo ba', 'foo bad', 'foo bar'], + // ['', 'foo bar', ''], + // ['fòô', 'fòôbàř', 'fòô bàř', 'UTF-8'], + // ['fòô bàř', 'fòô bàř', 'fòô bàř', 'UTF-8'], + [' bàř', 'fòô bàř', 'fòr bàř', 'UTF-8'], + [' ', 'toy car', 'fòô bàř', 'UTF-8'], + ['', 'fòô bàř', '', 'UTF-8'], + ]; + + foreach($data as $key => $value) { + it(__formatMessage($key, $value), function () use ($value) { + @list($expected, $str, $otherStr, $encoding) = $value; + + $stringy = __('Stringy')::create($str); + $result = $stringy->longestCommonSubstring($otherStr); + + \expect($stringy)->toBeAnInstanceOf(__('Stringy')); + \expect((string) $stringy)->toBe($str); + \expect((string) $result)->toBe($expected); + }); + } + }); }); diff --git a/spec/functions.php b/spec/functions.php index b4dad63..1d7e352 100644 --- a/spec/functions.php +++ b/spec/functions.php @@ -42,5 +42,21 @@ function __(string $str): string function __formatMessage(string $message, array $data): string { - return sprintf('%s: ==> %s <==', $message, json_encode($data)); + return sprintf('%s: ==> %s <==', $message, json_encode($data, JSON_UNESCAPED_UNICODE)); +} + +function __debug_array(array $arr): string +{ + $i = $j = 0; + + $ret = ''; + for ($i = 0; $i < count($arr); $i++) { + for ($j = 0; $j < count($arr[$i]); $j++) { + $ret .= " ($i, $j) "; + } + $ret .= "\n"; + } + $ret .= "\n"; + + return $ret; } diff --git a/src/Minbaby/Php/Stringy/Stringy.php b/src/Minbaby/Php/Stringy/Stringy.php index c5d708b..1470c19 100644 --- a/src/Minbaby/Php/Stringy/Stringy.php +++ b/src/Minbaby/Php/Stringy/Stringy.php @@ -610,4 +610,72 @@ public function isBase64() { return (base64_encode(base64_decode($this->str, true)) === $this->str); } + + public function longestCommonPrefix($otherStr) + { + $encoding = $this->encoding; + $maxLength = min($this->length(), \mb_strlen($otherStr, $encoding)); + $longestCommonPrefix = ''; + for ($i = 0; $i < $maxLength; $i++) { + $char = \mb_substr($this->str, $i, 1, $encoding); + if ($char == \mb_substr($otherStr, $i, 1, $encoding)) { + $longestCommonPrefix .= $char; + } else { + break; + } + } + return static::create($longestCommonPrefix, $encoding); + } + + public function longestCommonSuffix($otherStr) + { + $encoding = $this->encoding; + $maxLength = min($this->length(), \mb_strlen($otherStr, $encoding)); + $longestCommonSuffix = ''; + for ($i = 1; $i <= $maxLength; $i++) { + $char = \mb_substr($this->str, -$i, 1, $encoding); + if ($char == \mb_substr($otherStr, -$i, 1, $encoding)) { + $longestCommonSuffix = $char . $longestCommonSuffix; + } else { + break; + } + } + return static::create($longestCommonSuffix, $encoding); + } + + public function longestCommonSubstring($otherStr) + { + // Uses dynamic programming to solve + // http://en.wikipedia.org/wiki/Longest_common_substring_problem + $encoding = $this->encoding; + $stringy = static::create($this->str, $encoding); + $strLength = $stringy->length(); + $otherLength = \mb_strlen($otherStr, $encoding); + // Return if either string is empty + if ($strLength == 0 || $otherLength == 0) { + $stringy->str = ''; + return $stringy; + } + $len = 0; + $end = 0; + $table = array_fill(0, $strLength + 1, + array_fill(0, $otherLength + 1, 0)); + for ($i = 1; $i <= $strLength; $i++) { + for ($j = 1; $j <= $otherLength; $j++) { + $strChar = \mb_substr($stringy->str, $i - 1, 1, $encoding); + $otherChar = \mb_substr($otherStr, $j - 1, 1, $encoding); + if ($strChar == $otherChar) { + $table[$i][$j] = $table[$i - 1][$j - 1] + 1; + if ($table[$i][$j] > $len) { + $len = $table[$i][$j]; + $end = $i; + } + } else { + $table[$i][$j] = 0; + } + } + } + $stringy->str = \mb_substr($stringy->str, $end - $len, $len, $encoding); + return $stringy; + } } diff --git a/src/ext/common.h b/src/ext/common.h index 0d2dc7d..f1040b2 100644 --- a/src/ext/common.h +++ b/src/ext/common.h @@ -1,6 +1,13 @@ #ifndef STARTUP_COMMON_H #define STARTUP_COMMON_H +#if !defined(PHP_EXT_DEBUG) +#define PHP_EXT_DEBUG 0 +#endif // PHP_EXT_DEBUG + #define PHP_STARTUP_NS_NAME "Minbaby\\Startup\\Ext\\" +#define LOG_LEVEL_INFO 1; +#define LOG_LEVEL_INFO_NAME "info"; + #endif diff --git a/src/ext/functions.c b/src/ext/functions.c index 347226d..5e28e31 100644 --- a/src/ext/functions.c +++ b/src/ext/functions.c @@ -1,17 +1,67 @@ #include "functions.h" -#define XXX(zend_function_entry, len) {len = sizeof(zend_function_entry) / sizeof(zend_function_entry[0]);} -// void php_startup_register_functions(zend_function_entry *entry) -// { -// } +int strsplit (const char *str, char *parts[], const char *delimiter) { + char *pch; + int i = 0; + char *copy = NULL, *tmp = NULL; + + copy = strdup(str); + if (! copy) + goto bad; + + pch = strtok(copy, delimiter); + + tmp = strdup(pch); + if (! tmp) + goto bad; + + parts[i++] = tmp; + + while (pch) { + pch = strtok(NULL, delimiter); + if (NULL == pch) break; + + tmp = strdup(pch); + if (! tmp) + goto bad; + + parts[i++] = tmp; + } + + free(copy); + return i; + + bad: + free(copy); + for (int j = 0; j < i; j++) + free(parts[j]); + return -1; +} bool zval_str_equal(zval *first, zval *second) { - if (Z_TYPE_P(first) == Z_TYPE_P(second) && zend_string_equals(Z_STR_P(first), Z_STR_P(second))) { return true; } - return false; } + +bool m_array_set(zval *array, const char *key, zval *value) +{ + +} + +zval m_array_get(zval *array, const char *key) +{ + zval ret; + if (Z_TYPE_P(array) != IS_ARRAY) { + return ret; + } + + char *x[1]; + + strsplit(key, x, "."); + + return ret; +} diff --git a/src/ext/functions.h b/src/ext/functions.h index 4e89ea4..7fc26af 100644 --- a/src/ext/functions.h +++ b/src/ext/functions.h @@ -5,7 +5,13 @@ #include "php.h" #include "common.h" #include "ext/standard/php_standard.h" +#include "log.h" -// void php_startup_register_functions(zend_function_entry *zend_function_entry); -bool zval_equal(zval *first, zval *second); +int strsplit (const char *, char *[], const char *); + +bool zval_str_equal(zval *first, zval *second); + +zval m_array_get(zval *array, const char *key); + +bool m_array_set(zval *array, const char *key, zval *value); #endif diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index 9938dca..c1bf219 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -2320,6 +2320,285 @@ PHP_METHOD(Stringy, isBase64) RETURN_FALSE; } +PHP_METHOD(Stringy, longestCommonPrefix) +{ + zval *otherStr; + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ZVAL(otherStr) + ZEND_PARSE_PARAMETERS_END(); + + zval rv; + zval *encoding = zend_read_property(stringy_ce, getThis(), ZEND_STRL("encoding"), 0, &rv); + + zval func; + ZVAL_STRING(&func, "length"); + call_user_function(NULL, getThis(), &func, return_value, 0, NULL); + size_t length = Z_LVAL_P(return_value); + + zval args_mb_strlen[] = { + *otherStr, + *encoding, + }; + ZVAL_STRING(&func, "mb_strlen"); + call_user_function(NULL, NULL, &func, return_value, 2, args_mb_strlen); + size_t mb_strlen_length = Z_LVAL_P(return_value); + + size_t maxLength = MIN(length, mb_strlen_length); + + zval longestCommonPrefix, i_tmp, const_substr_len, ret_first, ret_second; + ZVAL_EMPTY_STRING(&longestCommonPrefix); + zval *str = zend_read_property(stringy_ce, getThis(), ZEND_STRL("str"), 0, &rv); + ZVAL_LONG(&const_substr_len, 1); + + for(int i = 0; i < maxLength; i++) { + ZVAL_LONG(&i_tmp, i); + zval args_mb_substr[] = { + *str, + i_tmp, + const_substr_len, + *encoding, + }; + ZVAL_STRING(&func, "mb_substr"); + call_user_function(NULL, NULL, &func, &ret_first, 4, args_mb_substr); + + zval args_mb_substr2[] = { + *otherStr, + i_tmp, + const_substr_len, + *encoding, + }; + ZVAL_STRING(&func, "mb_substr"); + call_user_function(NULL, NULL, &func, &ret_second, 4, args_mb_substr2); + + if (zend_string_equals(Z_STR(ret_first), Z_STR(ret_second)) == false) { + break; + } + + concat_function(&longestCommonPrefix, &longestCommonPrefix, &ret_first); + } + + zval instance; + object_init_ex(&instance, stringy_ce); + + zval args_const[] = { + longestCommonPrefix, + *encoding, + }; + ZVAL_STRING(&func, "__construct"); + call_user_function(NULL, &instance, &func, return_value, 2, args_const); + + RETURN_ZVAL(&instance, 0, 1); +} +ZEND_BEGIN_ARG_INFO(arginfo_longestCommonPrefix, 0) + ZEND_ARG_INFO(0, otherStr) +ZEND_END_ARG_INFO(); + +PHP_METHOD(Stringy, longestCommonSuffix) +{ + zval *otherStr; + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ZVAL(otherStr) + ZEND_PARSE_PARAMETERS_END(); + + zval rv; + zval *encoding = zend_read_property(stringy_ce, getThis(), ZEND_STRL("encoding"), 0, &rv); + + zval func; + ZVAL_STRING(&func, "length"); + call_user_function(NULL, getThis(), &func, return_value, 0, NULL); + size_t length = Z_LVAL_P(return_value); + + zval args_mb_strlen[] = { + *otherStr, + *encoding, + }; + ZVAL_STRING(&func, "mb_strlen"); + call_user_function(NULL, NULL, &func, return_value, 2, args_mb_strlen); + size_t mb_strlen_length = Z_LVAL_P(return_value); + + size_t maxLength = MIN(length, mb_strlen_length); + + zval longestCommonSuffix, i_tmp, const_substr_len, ret_first, ret_second; + ZVAL_EMPTY_STRING(&longestCommonSuffix); + zval *str = zend_read_property(stringy_ce, getThis(), ZEND_STRL("str"), 0, &rv); + ZVAL_LONG(&const_substr_len, 1); + + for(int i = 1; i <= maxLength; i++) { + ZVAL_LONG(&i_tmp, -i); + zval args_mb_substr[] = { + *str, + i_tmp, + const_substr_len, + *encoding, + }; + ZVAL_STRING(&func, "mb_substr"); + call_user_function(NULL, NULL, &func, &ret_first, 4, args_mb_substr); + + zval args_mb_substr2[] = { + *otherStr, + i_tmp, + const_substr_len, + *encoding, + }; + ZVAL_STRING(&func, "mb_substr"); + call_user_function(NULL, NULL, &func, &ret_second, 4, args_mb_substr2); + + if (zend_string_equals(Z_STR(ret_first), Z_STR(ret_second)) == false) { + break; + } + zval tmp; + concat_function(&tmp, &ret_first, &longestCommonSuffix); + longestCommonSuffix = tmp; + } + + zval instance; + object_init_ex(&instance, stringy_ce); + + zval args_const[] = { + longestCommonSuffix, + *encoding, + }; + ZVAL_STRING(&func, "__construct"); + call_user_function(NULL, &instance, &func, return_value, 2, args_const); + + RETURN_ZVAL(&instance, 0, 1); +} +ZEND_BEGIN_ARG_INFO(arginfo_longestCommonSuffix, 0) + ZEND_ARG_INFO(0, otherStr) +ZEND_END_ARG_INFO(); + +PHP_METHOD(Stringy, longestCommonSubstring) +{ + // Uses dynamic programming to solve + // http://en.wikipedia.org/wiki/Longest_common_substring_problem + + zval *otherStr; + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ZVAL(otherStr) + ZEND_PARSE_PARAMETERS_END(); + + zval rv; + zval *encoding = zend_read_property(stringy_ce, getThis(), ZEND_STRL("encoding"), 0, &rv); + zval *str = zend_read_property(stringy_ce, getThis(), ZEND_STRL("str"), 0, &rv); + + zval instance, func; + object_init_ex(&instance, stringy_ce); + + zval args_const[] = { + *str, + *encoding, + }; + ZVAL_STRING(&func, "__construct"); + call_user_function(NULL, &instance, &func, return_value, 2, args_const); + + zval strLen; + ZVAL_STRING(&func, "length"); + call_user_function(NULL, &instance, &func, &strLen, 0, NULL); + + zval otherLength, args_mb_strlen[] = { + *otherStr, + *encoding, + }; + ZVAL_STRING(&func, "mb_strlen"); + call_user_function(NULL, NULL, &func, &otherLength, 2, args_mb_strlen); + + if (Z_LVAL(strLen) == 0 || Z_LVAL(otherLength) == 0) { + zend_update_property_stringl(stringy_ce, &instance, ZEND_STRL("str"), ZEND_STRL("")); + RETURN_ZVAL(&instance, 0, 1); + } + + zval len, end, table, tmp, zero; + ZVAL_LONG(&len, 0); + ZVAL_LONG(&end, 0); + ZVAL_LONG(&zero, 0); + ZVAL_LONG(&otherLength, Z_LVAL(otherLength)+1); + ZVAL_LONG(&strLen, Z_LVAL(strLen)+1); + array_init(&table); + + zval args_array_fill[] = { + zero, + otherLength, + zero, + }; + ZVAL_STRING(&func, "array_fill"); + call_user_function(NULL, NULL, &func, return_value, 3, args_array_fill); + + zval args_array_fill2[] = { + zero, + strLen, + *return_value, + }; + call_user_function(NULL, NULL, &func, &table, 3, args_array_fill2); + + zval strChar, otherChar, i_tmp, j_tmp, const_substr_len; + ZVAL_LONG(&const_substr_len, 1); + for(int i = 1; i < Z_LVAL(strLen); i++) { + ZVAL_LONG(&i_tmp, i - 1); + zval args_mb_strlen[] = { + *str, + i_tmp, + const_substr_len, + *encoding, + }; + ZVAL_STRING(&func, "mb_substr"); + call_user_function(NULL, NULL, &func, &strChar, 4, args_mb_strlen); + + zend_array *ht = Z_ARRVAL(table); + for(int j = 1; j < Z_LVAL(otherLength); j++) { + ZVAL_LONG(&j_tmp, j - 1); + zval args_mb_strlen2[] = { + *otherStr, + j_tmp, + const_substr_len, + *encoding, + }; + ZVAL_STRING(&func, "mb_substr"); + call_user_function(NULL, NULL, &func, &otherChar, 4, args_mb_strlen2); + + zval *tmp = zend_hash_index_find(ht, i); + if (zend_string_equals(Z_STR(otherChar), Z_STR(strChar))) { + zval *tmp2 = zend_hash_index_find(ht, i - 1); + tmp2 = zend_hash_index_find(Z_ARRVAL_P(tmp2), j - 1); + zval value; + ZVAL_LONG(&value, Z_LVAL_P(tmp2) + 1); + + zval_add_ref(&value); + zend_hash_index_update(Z_ARR_P(tmp), j, &value); + + if (Z_LVAL(value) > Z_LVAL(len)) { + ZVAL_LONG(&len, Z_LVAL(value)); + ZVAL_LONG(&end, i); + } + } else { + zval_add_ref(&zero); + zend_hash_index_update(Z_ARR_P(tmp), j, &zero); + } + + zval_add_ref(tmp); + zend_hash_index_update(ht, j, tmp); + } + } + + zval end_len; + ZVAL_LONG(&end_len, Z_LVAL(end) - Z_LVAL(len)); + + zval args_mb_strlen3[] = { + *str, + end_len, + len, + *encoding, + }; + ZVAL_STRING(&func, "mb_substr"); + call_user_function(NULL, NULL, &func, return_value, 4, args_mb_strlen3); + + zend_update_property(stringy_ce, &instance, ZEND_STRL("str"), return_value); + + RETURN_ZVAL(&instance, 0, 1); +} +ZEND_BEGIN_ARG_INFO(arginfo_longestCommonSubstring, 0) + ZEND_ARG_INFO(0, otherStr) +ZEND_END_ARG_INFO(); + static zend_function_entry methods[] = { PHP_ME(Stringy, __construct, arginfo___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) PHP_ME(Stringy, __toString, NULL, ZEND_ACC_PUBLIC) @@ -2384,6 +2663,9 @@ static zend_function_entry methods[] = { PHP_ME(Stringy, isJson, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, isSerialized, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, isBase64, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, longestCommonPrefix, arginfo_longestCommonPrefix, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, longestCommonSuffix, arginfo_longestCommonSuffix, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, longestCommonSubstring, arginfo_longestCommonSubstring, ZEND_ACC_PUBLIC) PHP_FE_END }; diff --git a/src/ext/test.class.c b/src/ext/test.class.c index 320aefb..860a9b0 100644 --- a/src/ext/test.class.c +++ b/src/ext/test.class.c @@ -7,7 +7,7 @@ PHP_METHOD(Test, helloworld) if (zend_parse_parameters_none() == FAILURE ) { return; } - + php_printf("hello world!"); RETVAL_NULL(); } diff --git a/thirdParty/rxi-log/LICENSE b/thirdParty/rxi-log/LICENSE new file mode 100644 index 0000000..7e3bf17 --- /dev/null +++ b/thirdParty/rxi-log/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2017 rxi + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/thirdParty/rxi-log/README.md b/thirdParty/rxi-log/README.md new file mode 100644 index 0000000..a5b7e88 --- /dev/null +++ b/thirdParty/rxi-log/README.md @@ -0,0 +1,70 @@ +# log.c +A simple logging library implemented in C99 + +![screenshot](https://cloud.githubusercontent.com/assets/3920290/23831970/a2415e96-0723-11e7-9886-f8f5d2de60fe.png) + + +## Usage +**[log.c](src/log.c?raw=1)** and **[log.h](src/log.h?raw=1)** should be dropped +into an existing project and compiled along with it. The library provides 6 +function-like macros for logging: + +```c +log_trace(const char *fmt, ...); +log_debug(const char *fmt, ...); +log_info(const char *fmt, ...); +log_warn(const char *fmt, ...); +log_error(const char *fmt, ...); +log_fatal(const char *fmt, ...); +``` + +Each function takes a printf format string followed by additional arguments: + +```c +log_trace("Hello %s", "world") +``` + +Resulting in a line with the given format printed to stderr: + +``` +20:18:26 TRACE src/main.c:11: Hello world +``` + + +#### log_set_quiet(int enable) +Quiet-mode can be enabled by passing `1` to the `log_set_quiet()` function. +While this mode is enabled the library will not output anything to stderr, but +will continue to write to the file if one is set. + + +#### log_set_level(int level) +The current logging level can be set by using the `log_set_level()` function. +All logs below the given level will be ignored. By default the level is +`LOG_TRACE`, such that nothing is ignored. + + +#### log_set_fp(FILE *fp) +A file pointer where the log should be written can be provided to the library by +using the `log_set_fp()` function. The data written to the file output is +of the following format: + +``` +2047-03-11 20:18:26 TRACE src/main.c:11: Hello world +``` + + +#### log_set_lock(log_LockFn fn) +If the log will be written to from multiple threads a lock function can be set. +The function is passed a `udata` value (set by `log_set_udata()`) and the +integer `1` if the lock should be acquired or `0` if the lock should be +released. + + +#### LOG_USE_COLOR +If the library is compiled with `-DLOG_USE_COLOR` ANSI color escape codes will +be used when printing. + + +## License +This library is free software; you can redistribute it and/or modify it under +the terms of the MIT license. See [LICENSE](LICENSE) for details. diff --git a/thirdParty/rxi-log/src/log.c b/thirdParty/rxi-log/src/log.c new file mode 100644 index 0000000..2e183b0 --- /dev/null +++ b/thirdParty/rxi-log/src/log.c @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2017 rxi + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#include "log.h" + +static struct { + void *udata; + log_LockFn lock; + FILE *fp; + int level; + int quiet; +} L; + + +static const char *level_names[] = { + "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL" +}; + +#ifdef LOG_USE_COLOR +static const char *level_colors[] = { + "\x1b[94m", "\x1b[36m", "\x1b[32m", "\x1b[33m", "\x1b[31m", "\x1b[35m" +}; +#endif + + +static void lock(void) { + if (L.lock) { + L.lock(L.udata, 1); + } +} + + +static void unlock(void) { + if (L.lock) { + L.lock(L.udata, 0); + } +} + + +void log_set_udata(void *udata) { + L.udata = udata; +} + + +void log_set_lock(log_LockFn fn) { + L.lock = fn; +} + + +void log_set_fp(FILE *fp) { + L.fp = fp; +} + + +void log_set_level(int level) { + L.level = level; +} + + +void log_set_quiet(int enable) { + L.quiet = enable ? 1 : 0; +} + + +void log_log(int level, const char *file, int line, const char *fmt, ...) { + if (level < L.level) { + return; + } + + /* Acquire lock */ + lock(); + + /* Get current time */ + time_t t = time(NULL); + struct tm *lt = localtime(&t); + + /* Log to stderr */ + if (!L.quiet) { + va_list args; + char buf[16]; + buf[strftime(buf, sizeof(buf), "%H:%M:%S", lt)] = '\0'; +#ifdef LOG_USE_COLOR + fprintf( + stderr, "%s %s%-5s\x1b[0m \x1b[90m%s:%d:\x1b[0m ", + buf, level_colors[level], level_names[level], file, line); +#else + fprintf(stderr, "%s %-5s %s:%d: ", buf, level_names[level], file, line); +#endif + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); + fprintf(stderr, "\n"); + fflush(stderr); + } + + /* Log to file */ + if (L.fp) { + va_list args; + char buf[32]; + buf[strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", lt)] = '\0'; + fprintf(L.fp, "%s %-5s %s:%d: ", buf, level_names[level], file, line); + va_start(args, fmt); + vfprintf(L.fp, fmt, args); + va_end(args); + fprintf(L.fp, "\n"); + fflush(L.fp); + } + + /* Release lock */ + unlock(); +} diff --git a/thirdParty/rxi-log/src/log.h b/thirdParty/rxi-log/src/log.h new file mode 100644 index 0000000..77bf087 --- /dev/null +++ b/thirdParty/rxi-log/src/log.h @@ -0,0 +1,35 @@ +/** + * Copyright (c) 2017 rxi + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MIT license. See `log.c` for details. + */ + +#ifndef LOG_H +#define LOG_H + +#include +#include + +#define LOG_VERSION "0.1.0" + +typedef void (*log_LockFn)(void *udata, int lock); + +enum { EXT_LOG_TRACE, EXT_LOG_DEBUG, EXT_LOG_INFO, EXT_LOG_WARN, EXT_LOG_ERROR, EXT_LOG_FATAL }; + +#define log_trace(...) log_log(EXT_LOG_TRACE, __FILE__, __LINE__, __VA_ARGS__) +#define log_debug(...) log_log(EXT_LOG_DEBUG, __FILE__, __LINE__, __VA_ARGS__) +#define log_info(...) log_log(EXT_LOG_INFO, __FILE__, __LINE__, __VA_ARGS__) +#define log_warn(...) log_log(EXT_LOG_WARN, __FILE__, __LINE__, __VA_ARGS__) +#define log_error(...) log_log(EXT_LOG_ERROR, __FILE__, __LINE__, __VA_ARGS__) +#define log_fatal(...) log_log(EXT_LOG_FATAL, __FILE__, __LINE__, __VA_ARGS__) + +void log_set_udata(void *udata); +void log_set_lock(log_LockFn fn); +void log_set_fp(FILE *fp); +void log_set_level(int level); +void log_set_quiet(int enable); + +void log_log(int level, const char *file, int line, const char *fmt, ...); + +#endif From a1e43b5c7c7de4228219662127d08482558fba80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Sun, 3 Mar 2019 18:34:13 +0800 Subject: [PATCH 095/126] Feature/pad (#55) * pad * pad * fix --- spec/Stringy/StringySpec.php | 121 ++++++++++++ src/Minbaby/Php/Stringy/Stringy.php | 50 +++++ src/ext/stringy/stringy.c | 289 ++++++++++++++++++++++++++++ 3 files changed, 460 insertions(+) diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index 508a2f3..eac1087 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -1535,4 +1535,125 @@ }); } }); + + context('test pad', function () { + $data = [ + // length <= str + ['foo bar', 'foo bar', -1], + ['foo bar', 'foo bar', 7], + ['fòô bàř', 'fòô bàř', 7, ' ', 'right', 'UTF-8'], + // right + ['foo bar ', 'foo bar', 9], + ['foo bar_*', 'foo bar', 9, '_*', 'right'], + ['fòô bàř¬ø¬', 'fòô bàř', 10, '¬ø', 'right', 'UTF-8'], + // left + [' foo bar', 'foo bar', 9, ' ', 'left'], + ['_*foo bar', 'foo bar', 9, '_*', 'left'], + ['¬ø¬fòô bàř', 'fòô bàř', 10, '¬ø', 'left', 'UTF-8'], + // both + ['foo bar ', 'foo bar', 8, ' ', 'both'], + ['¬fòô bàř¬ø', 'fòô bàř', 10, '¬ø', 'both', 'UTF-8'], + ['¬øfòô bàř¬øÿ', 'fòô bàř', 12, '¬øÿ', 'both', 'UTF-8'] + ]; + + foreach($data as $key => $value) { + it(__formatMessage($key, $value), function () use ($value) { + @list($expected, $str, $length, $padStr, $padType, $encoding) = $value; + + $padType = $padType ?? 'right'; + + $padStr = $padStr ?? ' '; + + $stringy = __('Stringy')::create($str, $encoding); + $result = $stringy->pad($length, $padStr, $padType); + + \expect($stringy)->toBeAnInstanceOf(__('Stringy')); + \expect((string) $stringy)->toBe($str); + \expect((string) $result)->toBe($expected); + }); + } + }); + + context('test padLeft', function () { + $data = [ + [' foo bar', 'foo bar', 9], + ['_*foo bar', 'foo bar', 9, '_*'], + ['_*_foo bar', 'foo bar', 10, '_*'], + [' fòô bàř', 'fòô bàř', 9, ' ', 'UTF-8'], + ['¬øfòô bàř', 'fòô bàř', 9, '¬ø', 'UTF-8'], + ['¬ø¬fòô bàř', 'fòô bàř', 10, '¬ø', 'UTF-8'], + ['¬ø¬øfòô bàř', 'fòô bàř', 11, '¬ø', 'UTF-8'], + ]; + + foreach($data as $key => $value) { + it(__formatMessage($key, $value), function () use ($value) { + @list($expected, $str, $length, $padStr, $encoding) = $value; + + $padStr = $padStr ?? ' '; + + $stringy = __('Stringy')::create($str, $encoding); + $result = $stringy->padLeft($length, $padStr); + + \expect($stringy)->toBeAnInstanceOf(__('Stringy')); + \expect((string) $stringy)->toBe($str); + \expect((string) $result)->toBe($expected); + }); + } + }); + context('test padRight', function () { + $data = [ + ['foo bar ', 'foo bar', 9], + ['foo bar_*', 'foo bar', 9, '_*'], + ['foo bar_*_', 'foo bar', 10, '_*'], + ['fòô bàř ', 'fòô bàř', 9, ' ', 'UTF-8'], + ['fòô bàř¬ø', 'fòô bàř', 9, '¬ø', 'UTF-8'], + ['fòô bàř¬ø¬', 'fòô bàř', 10, '¬ø', 'UTF-8'], + ['fòô bàř¬ø¬ø', 'fòô bàř', 11, '¬ø', 'UTF-8'], + ]; + + foreach($data as $key => $value) { + it(__formatMessage($key, $value), function () use ($value) { + @list($expected, $str, $length, $padStr, $encoding) = $value; + + $padStr = $padStr ?? ' '; + + $stringy = __('Stringy')::create($str, $encoding); + $result = $stringy->padRight($length, $padStr); + + \expect($stringy)->toBeAnInstanceOf(__('Stringy')); + \expect((string) $stringy)->toBe($str); + \expect((string) $result)->toBe($expected); + }); + } + }); + context('test padBoth', function () { + $data = [ + ['foo bar ', 'foo bar', 8], + [' foo bar ', 'foo bar', 9, ' '], + ['fòô bàř ', 'fòô bàř', 8, ' ', 'UTF-8'], + [' fòô bàř ', 'fòô bàř', 9, ' ', 'UTF-8'], + ['fòô bàř¬', 'fòô bàř', 8, '¬ø', 'UTF-8'], + ['¬fòô bàř¬', 'fòô bàř', 9, '¬ø', 'UTF-8'], + ['¬fòô bàř¬ø', 'fòô bàř', 10, '¬ø', 'UTF-8'], + ['¬øfòô bàř¬ø', 'fòô bàř', 11, '¬ø', 'UTF-8'], + ['¬fòô bàř¬ø', 'fòô bàř', 10, '¬øÿ', 'UTF-8'], + ['¬øfòô bàř¬ø', 'fòô bàř', 11, '¬øÿ', 'UTF-8'], + ['¬øfòô bàř¬øÿ', 'fòô bàř', 12, '¬øÿ', 'UTF-8'] + ]; + + foreach($data as $key => $value) { + it(__formatMessage($key, $value), function () use ($value) { + @list($expected, $str, $length, $padStr, $encoding) = $value; + + $padStr = $padStr ?? ' '; + + $stringy = __('Stringy')::create($str, $encoding); + $result = $stringy->padBoth($length, $padStr); + + \expect($stringy)->toBeAnInstanceOf(__('Stringy')); + \expect((string) $stringy)->toBe($str); + \expect((string) $result)->toBe($expected); + }); + } + }); }); diff --git a/src/Minbaby/Php/Stringy/Stringy.php b/src/Minbaby/Php/Stringy/Stringy.php index 1470c19..a6a6ecc 100644 --- a/src/Minbaby/Php/Stringy/Stringy.php +++ b/src/Minbaby/Php/Stringy/Stringy.php @@ -678,4 +678,54 @@ public function longestCommonSubstring($otherStr) $stringy->str = \mb_substr($stringy->str, $end - $len, $len, $encoding); return $stringy; } + + public function pad($length, $padStr = ' ', $padType = 'right') + { + if (!in_array($padType, ['left', 'right', 'both'])) { + throw new InvalidArgumentException('Pad expects $padType ' . + "to be one of 'left', 'right' or 'both'"); + } + switch ($padType) { + case 'left': + return $this->padLeft($length, $padStr); + case 'right': + return $this->padRight($length, $padStr); + default: + return $this->padBoth($length, $padStr); + } + } + + public function padBoth($length, $padStr = ' ') + { + $padding = $length - $this->length(); + return $this->applyPadding(floor($padding / 2), ceil($padding / 2), + $padStr); + } + + public function padLeft($length, $padStr = ' ') + { + return $this->applyPadding($length - $this->length(), 0, $padStr); + } + + public function padRight($length, $padStr = ' ') + { + return $this->applyPadding(0, $length - $this->length(), $padStr); + } + + protected function applyPadding($left = 0, $right = 0, $padStr = ' ') + { + $stringy = static::create($this->str, $this->encoding); + $length = \mb_strlen($padStr, $stringy->encoding); + $strLength = $stringy->length(); + $paddedLength = $strLength + $left + $right; + if (!$length || $paddedLength <= $strLength) { + return $stringy; + } + $leftPadding = \mb_substr(str_repeat($padStr, ceil($left / $length)), 0, + $left, $stringy->encoding); + $rightPadding = \mb_substr(str_repeat($padStr, ceil($right / $length)), + 0, $right, $stringy->encoding); + $stringy->str = $leftPadding . $stringy->str . $rightPadding; + return $stringy; + } } diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index c1bf219..941fc3f 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -2599,6 +2599,290 @@ ZEND_BEGIN_ARG_INFO(arginfo_longestCommonSubstring, 0) ZEND_ARG_INFO(0, otherStr) ZEND_END_ARG_INFO(); +PHP_METHOD(Stringy, pad) +{ + zval *length, *padStr, *padType; + ZEND_PARSE_PARAMETERS_START(1, 3) + Z_PARAM_ZVAL(length) + Z_PARAM_OPTIONAL + Z_PARAM_ZVAL(padStr) + Z_PARAM_ZVAL(padType) + ZEND_PARSE_PARAMETERS_END(); + + if (padStr == NULL) { + padStr = malloc(sizeof(zval)); + ZVAL_STRING(padStr, " "); + } + + if (padType == NULL) { + padType = malloc(sizeof(zval)); + ZVAL_STRING(padType, "right"); + } + + zval left, right, both; + ZVAL_STRING(&left, "left"); + ZVAL_STRING(&right, "right"); + ZVAL_STRING(&both, "both"); + + zval func; + + if (zval_str_equal(&left, padType)) { + ZVAL_STRING(&func, "padLeft"); + } else if (zval_str_equal(&right, padType) == 1) { + ZVAL_STRING(&func, "padRight"); + } else if (zval_str_equal(&both, padType) == 1) { + ZVAL_STRING(&func, "padBoth"); + } else { + zend_throw_exception_ex( + spl_ce_InvalidArgumentException, + 0, + "Pad expects %s to be one of 'left', 'right' or 'both'", + Z_STRVAL_P(padType) + ); + } + + zval args[] = { + *length, + *padStr + }; + + call_user_function(NULL, getThis(), &func, return_value, 2, args); +} +ZEND_BEGIN_ARG_INFO(arginfo_pad, 0) + ZEND_ARG_INFO(0, length) + ZEND_ARG_INFO(0, padStr) + ZEND_ARG_INFO(0, padType) +ZEND_END_ARG_INFO(); + +PHP_METHOD(Stringy, applyPadding) +{ + zval *left, *right, *padStr; + ZEND_PARSE_PARAMETERS_START(0, 3) + Z_PARAM_OPTIONAL + Z_PARAM_ZVAL(left); + Z_PARAM_ZVAL(right); + Z_PARAM_ZVAL(padStr); + ZEND_PARSE_PARAMETERS_END(); + + zval rv, zero; + zval *str = zend_read_property(stringy_ce, getThis(), ZEND_STRL("str"), 1, &rv); + zval *encoding = zend_read_property(stringy_ce, getThis(), ZEND_STRL("encoding"), 1, &rv); + + ZVAL_LONG(&zero, 0); + + if (left == NULL) { + left = malloc(sizeof(zval)); + ZVAL_LONG(left, 0); + } + + if (Z_TYPE_P(left) != IS_LONG) { + convert_to_long(left); + } + + if (right == NULL) { + right = malloc(sizeof(zval)); + ZVAL_LONG(right, 0); + } + + if (Z_TYPE_P(right) != IS_LONG) { + convert_to_long(right); + } + + if (padStr == NULL) { + padStr = malloc(sizeof(zval)); + ZVAL_STRING(padStr, " "); + } + + zval stringy; + object_init_ex(&stringy, stringy_ce); + zval func, args[] = { + *str, + *encoding, + }; + ZVAL_STRING(&func, "__construct"); + call_user_function(NULL, &stringy, &func, return_value, 2, args); + + zval length; + zval args_mb_strlen[] = { + *padStr, + *encoding, + }; + ZVAL_STRING(&func, "mb_strlen"); + call_user_function(NULL, NULL, &func, &length, 2, args_mb_strlen); + + zval strLength; + ZVAL_STRING(&func, "length"); + call_user_function(NULL, &stringy, &func, return_value, 0, NULL); + + zval paddedLength; + ZVAL_LONG(&paddedLength, Z_LVAL(strLength) + Z_LVAL_P(left) + Z_LVAL_P(right)); + + if (Z_TYPE(length) == IS_FALSE || Z_LVAL(paddedLength) <= Z_LVAL(strLength)) { + RETURN_ZVAL(&stringy, 0, 1); + } + + zval str_repeat_0; + zval str_repeat_0_val; + ZVAL_LONG(&str_repeat_0_val, ceil(Z_LVAL_P(left)/(float)Z_LVAL(length))); + zval args_str_repeat[] = { + *padStr, + str_repeat_0_val, + }; + ZVAL_STRING(&func, "str_repeat"); + call_user_function(NULL, NULL, &func, &str_repeat_0, 2, args_str_repeat); + + zval leftPadding; + zval args_leftPadding[] = { + str_repeat_0, + zero, + *left, + *encoding, + }; + ZVAL_STRING(&func, "mb_substr"); + call_user_function(NULL, NULL, &func, &leftPadding, 4, args_leftPadding); + + zval str_repeat_1; + zval str_repeat_1_val; + ZVAL_LONG(&str_repeat_1_val, ceil(Z_LVAL_P(right)/(float)Z_LVAL(length))); + zval args_str_repeat_1[] = { + *padStr, + str_repeat_1_val, + }; + ZVAL_STRING(&func, "str_repeat"); + call_user_function(NULL, NULL, &func, &str_repeat_1, 2, args_str_repeat_1); + + zval rightPadding; + zval args_rightPadding[] = { + str_repeat_1, + zero, + *right, + *encoding, + }; + ZVAL_STRING(&func, "mb_substr"); + call_user_function(NULL, NULL, &func, &rightPadding, 4, args_rightPadding); + + zval x; + concat_function(&x, &leftPadding, str); + concat_function(&x, &x, &rightPadding); + + RETURN_ZVAL(&x, 0, 1); +} +ZEND_BEGIN_ARG_INFO(arginfo_applyPadding, 0) + ZEND_ARG_INFO(0, left) + ZEND_ARG_INFO(0, right) + ZEND_ARG_INFO(0, padStr) +ZEND_END_ARG_INFO(); + +PHP_METHOD(Stringy, padLeft) +{ + zval *length, *padStr; + ZEND_PARSE_PARAMETERS_START(1, 2) + Z_PARAM_ZVAL(length) + Z_PARAM_OPTIONAL + Z_PARAM_ZVAL(padStr) + ZEND_PARSE_PARAMETERS_END(); + + if (padStr == NULL) { + padStr = malloc(sizeof(zval)); + ZVAL_STRING(padStr, " "); + } + + zval zero; + ZVAL_LONG(&zero, 0); + + zval func; + ZVAL_STRING(&func, "length"); + call_user_function(NULL, getThis(), &func, return_value, 0, NULL); + + zval first; + ZVAL_LONG(&first, Z_LVAL_P(length) - Z_LVAL_P(return_value)); + zval args[] = { + first, + zero, + *padStr, + }; + ZVAL_STRING(&func, "applyPadding"); + call_user_function(NULL, getThis(), &func, return_value, 3, args); +} +ZEND_BEGIN_ARG_INFO(arginfo_padLeft, 0) + ZEND_ARG_INFO(0, length) + ZEND_ARG_INFO(0, padStr) +ZEND_END_ARG_INFO(); + +PHP_METHOD(Stringy, padRight) +{ + zval *length, *padStr; + ZEND_PARSE_PARAMETERS_START(1, 2) + Z_PARAM_ZVAL(length) + Z_PARAM_OPTIONAL + Z_PARAM_ZVAL(padStr) + ZEND_PARSE_PARAMETERS_END(); + + if (padStr == NULL) { + padStr = malloc(sizeof(zval)); + ZVAL_STRING(padStr, " "); + } + + zval zero; + ZVAL_LONG(&zero, 0); + + zval func; + ZVAL_STRING(&func, "length"); + call_user_function(NULL, getThis(), &func, return_value, 0, NULL); + + zval value; + ZVAL_LONG(&value, Z_LVAL_P(length) - Z_LVAL_P(return_value)); + zval args[] = { + zero, + value, + *padStr, + }; + ZVAL_STRING(&func, "applyPadding"); + call_user_function(NULL, getThis(), &func, return_value, 3, args); +} +ZEND_BEGIN_ARG_INFO(arginfo_padRight, 0) + ZEND_ARG_INFO(0, length) + ZEND_ARG_INFO(0, padStr) +ZEND_END_ARG_INFO(); + +PHP_METHOD(Stringy, padBoth) +{ + zval *length, *padStr; + ZEND_PARSE_PARAMETERS_START(1, 2) + Z_PARAM_ZVAL(length) + Z_PARAM_OPTIONAL + Z_PARAM_ZVAL(padStr) + ZEND_PARSE_PARAMETERS_END(); + + if (padStr == NULL) { + padStr = malloc(sizeof(zval)); + ZVAL_STRING(padStr, " "); + } + + zval func; + ZVAL_STRING(&func, "length"); + call_user_function(NULL, getThis(), &func, return_value, 0, NULL); + + zval value; + ZVAL_LONG(&value, Z_LVAL_P(length) - Z_LVAL_P(return_value)); + + zval first, second; + ZVAL_LONG(&first, floor(Z_LVAL(value) / 2.0)); + ZVAL_LONG(&second, ceil(Z_LVAL(value) / 2.0);) + + zval args[] = { + first, + second, + *padStr, + }; + ZVAL_STRING(&func, "applyPadding"); + call_user_function(NULL, getThis(), &func, return_value, 3, args); +} +ZEND_BEGIN_ARG_INFO(arginfo_padBoth, 0) + ZEND_ARG_INFO(0, length) + ZEND_ARG_INFO(0, padStr) +ZEND_END_ARG_INFO(); + static zend_function_entry methods[] = { PHP_ME(Stringy, __construct, arginfo___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) PHP_ME(Stringy, __toString, NULL, ZEND_ACC_PUBLIC) @@ -2666,6 +2950,11 @@ static zend_function_entry methods[] = { PHP_ME(Stringy, longestCommonPrefix, arginfo_longestCommonPrefix, ZEND_ACC_PUBLIC) PHP_ME(Stringy, longestCommonSuffix, arginfo_longestCommonSuffix, ZEND_ACC_PUBLIC) PHP_ME(Stringy, longestCommonSubstring, arginfo_longestCommonSubstring, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, pad, arginfo_pad, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, padLeft, arginfo_padLeft, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, padRight, arginfo_padRight, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, padBoth, arginfo_padBoth, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, applyPadding, arginfo_applyPadding, ZEND_ACC_PUBLIC) PHP_FE_END }; From 67fc07f7fa6b9defaceb1573ae3965ab7d05a16a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Wed, 20 Mar 2019 20:56:18 +0800 Subject: [PATCH 096/126] Feature/repeat+ replace (#57) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix 特殊数据修复 * repeat * replace --- spec/Stringy/StringySpec.php | 58 ++++++++++++ src/Minbaby/Php/Stringy/Stringy.php | 11 +++ src/ext/stringy/stringy.c | 132 +++++++++++++++++++++------- 3 files changed, 171 insertions(+), 30 deletions(-) diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index eac1087..8e74226 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -1656,4 +1656,62 @@ }); } }); + + context('test repeat', function () { + $data = [ + ['', 'foo', 0], + ['foo', 'foo', 1], + ['foofoo', 'foo', 2], + ['foofoofoo', 'foo', 3], + ['fòô', 'fòô', 1, 'UTF-8'], + ['fòôfòô', 'fòô', 2, 'UTF-8'], + ['fòôfòôfòô', 'fòô', 3, 'UTF-8'] + ]; + foreach ($data as $key => $value) { + it(__formatMessage($key, $value), function () use ($value) { + @list($expected, $str, $multiplier, $encoding) = $value; + + $stringy = __('Stringy')::create($str, $encoding); + $result = $stringy->repeat($multiplier); + + \expect($stringy)->toBeAnInstanceOf(__('Stringy')); + \expect((string) $stringy)->toBe($str); + \expect((string) $result)->toBe($expected); + }); + } + }); + + context('test replace', function () { + $data = [ + ['', '', '', ''], + ['foo', '', '', 'foo'], + ['foo', '\s', '\s', 'foo'], + ['foo bar', 'foo bar', '', ''], + ['foo bar', 'foo bar', 'f(o)o', '\1'], + ['\1 bar', 'foo bar', 'foo', '\1'], + ['bar', 'foo bar', 'foo ', ''], + ['far bar', 'foo bar', 'foo', 'far'], + ['bar bar', 'foo bar foo bar', 'foo ', ''], + ['', '', '', '', 'UTF-8'], + ['fòô', '', '', 'fòô', 'UTF-8'], + ['fòô', '\s', '\s', 'fòô', 'UTF-8'], + ['fòô bàř', 'fòô bàř', '', '', 'UTF-8'], + ['bàř', 'fòô bàř', 'fòô ', '', 'UTF-8'], + ['far bàř', 'fòô bàř', 'fòô', 'far', 'UTF-8'], + ['bàř bàř', 'fòô bàř fòô bàř', 'fòô ', '', 'UTF-8'], + ]; + + foreach($data as $key => $value) { + it(__formatMessage($key, $value), function () use ($value) { + @list($expected, $str, $search, $replacement, $encoding) = $value; + + $stringy = __('Stringy')::create($str, $encoding); + $result = $stringy->replace($search, $replacement); + + \expect($stringy)->toBeAnInstanceOf(__('Stringy')); + \expect((string) $stringy)->toBe($str); + \expect((string) $result)->toBe($expected); + }); + } + }); }); diff --git a/src/Minbaby/Php/Stringy/Stringy.php b/src/Minbaby/Php/Stringy/Stringy.php index a6a6ecc..6bf550f 100644 --- a/src/Minbaby/Php/Stringy/Stringy.php +++ b/src/Minbaby/Php/Stringy/Stringy.php @@ -728,4 +728,15 @@ protected function applyPadding($left = 0, $right = 0, $padStr = ' ') $stringy->str = $leftPadding . $stringy->str . $rightPadding; return $stringy; } + + public function repeat($multiplier) + { + $repeated = str_repeat($this->str, $multiplier); + return static::create($repeated, $this->encoding); + } + + public function replace($search, $replacement) + { + return $this->regexReplace(preg_quote($search), $replacement); + } } diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index 941fc3f..d483275 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -2724,42 +2724,52 @@ PHP_METHOD(Stringy, applyPadding) zval str_repeat_0; zval str_repeat_0_val; ZVAL_LONG(&str_repeat_0_val, ceil(Z_LVAL_P(left)/(float)Z_LVAL(length))); - zval args_str_repeat[] = { - *padStr, - str_repeat_0_val, - }; - ZVAL_STRING(&func, "str_repeat"); - call_user_function(NULL, NULL, &func, &str_repeat_0, 2, args_str_repeat); + zval leftPadding; + if (Z_LVAL(str_repeat_0_val) >=0) + { + zval args_str_repeat[] = { + *padStr, + str_repeat_0_val, + }; + ZVAL_STRING(&func, "str_repeat"); + call_user_function(NULL, NULL, &func, &str_repeat_0, 2, args_str_repeat); - zval leftPadding; - zval args_leftPadding[] = { - str_repeat_0, - zero, - *left, - *encoding, - }; - ZVAL_STRING(&func, "mb_substr"); - call_user_function(NULL, NULL, &func, &leftPadding, 4, args_leftPadding); + zval args_leftPadding[] = { + str_repeat_0, + zero, + *left, + *encoding, + }; + ZVAL_STRING(&func, "mb_substr"); + call_user_function(NULL, NULL, &func, &leftPadding, 4, args_leftPadding); + } else { + ZVAL_STRING(&leftPadding, ""); + } zval str_repeat_1; zval str_repeat_1_val; ZVAL_LONG(&str_repeat_1_val, ceil(Z_LVAL_P(right)/(float)Z_LVAL(length))); - zval args_str_repeat_1[] = { - *padStr, - str_repeat_1_val, - }; - ZVAL_STRING(&func, "str_repeat"); - call_user_function(NULL, NULL, &func, &str_repeat_1, 2, args_str_repeat_1); + zval rightPadding; + if (Z_LVAL(str_repeat_1_val) >=0) + { + zval args_str_repeat_1[] = { + *padStr, + str_repeat_1_val, + }; + ZVAL_STRING(&func, "str_repeat"); + call_user_function(NULL, NULL, &func, &str_repeat_1, 2, args_str_repeat_1); - zval rightPadding; - zval args_rightPadding[] = { - str_repeat_1, - zero, - *right, - *encoding, - }; - ZVAL_STRING(&func, "mb_substr"); - call_user_function(NULL, NULL, &func, &rightPadding, 4, args_rightPadding); + zval args_rightPadding[] = { + str_repeat_1, + zero, + *right, + *encoding, + }; + ZVAL_STRING(&func, "mb_substr"); + call_user_function(NULL, NULL, &func, &rightPadding, 4, args_rightPadding); + } else { + ZVAL_STRING(&rightPadding, ""); + } zval x; concat_function(&x, &leftPadding, str); @@ -2883,6 +2893,66 @@ ZEND_BEGIN_ARG_INFO(arginfo_padBoth, 0) ZEND_ARG_INFO(0, padStr) ZEND_END_ARG_INFO(); +PHP_METHOD(Stringy, repeat) +{ + zval *multilpier; + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ZVAL(multilpier) + ZEND_PARSE_PARAMETERS_END(); + + zval rv; + zval *str = zend_read_property(stringy_ce, getThis(), ZEND_STRL("str"), 0, &rv); + zval *encoding = zend_read_property(stringy_ce, getThis(), ZEND_STRL("encoding"), 0, &rv); + zval func, args[] = { + *str, + *multilpier, + }; + ZVAL_STRING(&func, "str_repeat"); + call_user_function(NULL, NULL, &func, return_value, 2, args); + + zval instance; + object_init_ex(&instance, stringy_ce); + + zval args_construct[] = { + *return_value, + *encoding, + }; + ZVAL_STRING(&func, "__construct"); + call_user_function(NULL, &instance, &func, return_value, 2, args_construct); + + RETURN_ZVAL(&instance, 0, 1); +} +ZEND_BEGIN_ARG_INFO(arginfo_repeat, 0) + ZEND_ARG_INFO(0, multiplier) +ZEND_END_ARG_INFO(); + +PHP_METHOD(Stringy, replace) +{ + zval *search, *replacement; + ZEND_PARSE_PARAMETERS_START(2, 2) + Z_PARAM_ZVAL(search) + Z_PARAM_ZVAL(replacement) + ZEND_PARSE_PARAMETERS_END(); + + zval func, delimiter; + ZVAL_STRING(&func, "preg_quote"); + zval args[] = { + *search, + }; + call_user_function(NULL, NULL, &func, return_value, 1, args); + + ZVAL_STRING(&func, "regexReplace"); + zval args_regex[] = { + *return_value, + *replacement, + }; + call_user_function(NULL, getThis(), &func, return_value, 2, args_regex); +} +ZEND_BEGIN_ARG_INFO(arginfo_replace, 0) + ZEND_ARG_INFO(0, search) + ZEND_ARG_INFO(0, replacement) +ZEND_END_ARG_INFO(); + static zend_function_entry methods[] = { PHP_ME(Stringy, __construct, arginfo___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) PHP_ME(Stringy, __toString, NULL, ZEND_ACC_PUBLIC) @@ -2955,6 +3025,8 @@ static zend_function_entry methods[] = { PHP_ME(Stringy, padRight, arginfo_padRight, ZEND_ACC_PUBLIC) PHP_ME(Stringy, padBoth, arginfo_padBoth, ZEND_ACC_PUBLIC) PHP_ME(Stringy, applyPadding, arginfo_applyPadding, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, repeat, arginfo_repeat, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, replace, arginfo_replace, ZEND_ACC_PUBLIC) PHP_FE_END }; From 043902c1ddcb43a0f6c111d78c0e061cb5422e91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Tue, 7 May 2019 20:42:11 +0800 Subject: [PATCH 097/126] Feature/to (#58) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * update * 卡住了,不知道为啥 * 找到问题了,因为key可能为空 * ok * 体力活,休息一下 * update * update * coding use clion * 搞不定,放弃 * 有bug,需要处理 * update shel * 终于搞定了这部分,主要还是不熟悉导致一些基础问题不能一眼看出来 --- .clang | 6 + .gitignore | 10 + scripts/init-development.sh | 14 +- spec/Stringy/StringySpec.php | 43 +- src/Minbaby/Php/Stringy/Stringy.php | 211 +++++ src/ext/functions.c | 4 +- src/ext/functions.h | 2 +- src/ext/stringy/stringy.c | 1142 +++++++++++++++++++++++++++ startup.php | 44 +- thirdParty/rxi-log/LICENSE | 19 - thirdParty/rxi-log/README.md | 70 -- thirdParty/rxi-log/src/log.c | 136 ---- thirdParty/rxi-log/src/log.h | 35 - 13 files changed, 1427 insertions(+), 309 deletions(-) create mode 100644 .clang delete mode 100644 thirdParty/rxi-log/LICENSE delete mode 100644 thirdParty/rxi-log/README.md delete mode 100644 thirdParty/rxi-log/src/log.c delete mode 100644 thirdParty/rxi-log/src/log.h diff --git a/.clang b/.clang new file mode 100644 index 0000000..cae8aca --- /dev/null +++ b/.clang @@ -0,0 +1,6 @@ +-I/home/minbaby-debain/.phpbrew/php/php-7.1.23/include/php +-I/home/minbaby-debain/.phpbrew/php/php-7.1.23/include/php/main +-I/home/minbaby-debain/.phpbrew/php/php-7.1.23/include/php/TSRM +-I/home/minbaby-debain/.phpbrew/php/php-7.1.23/include/php/Zend +-I/home/minbaby-debain/.phpbrew/php/php-7.1.23/include/php/ext +-I/home/minbaby-debain/.phpbrew/php/php-7.1.23/include/php/ext/date/lib \ No newline at end of file diff --git a/.gitignore b/.gitignore index 2917c43..a2a1b76 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ .deps *.lo *.la +*.so .libs acinclude.m4 aclocal.m4 @@ -47,3 +48,12 @@ GPATH /.gdb_history peda-session-php.txt /coverage.xml +/.vscode/ipch + +#clion +/.idea/ +CMakeCache.txt +/CMakeFiles/ +/cmake-build-debug/ +cmake_install.cmake +php_ext_startup.cbp \ No newline at end of file diff --git a/scripts/init-development.sh b/scripts/init-development.sh index e93d2a7..5ab9d37 100755 --- a/scripts/init-development.sh +++ b/scripts/init-development.sh @@ -9,7 +9,7 @@ export PHP_VERSION=php-7.1.23 export SYSTEM_NAME=`uname` [ "$SYSTEM_NAME" == "Darwin" ] && LIB_BZ2='/usr/local/opt/bzip2/' -[ "$SYSTEM_NAME" == "Darwin" ] && LIB_ZIP='/usr/local/opt/zlib' +[ "$SYSTEM_NAME" == "Darwin" ] && LIB_ZIP='/usr/local/opt/zlib/' [ "$SYSTEM_NAME" == "Darwin" ] && LIB_SSL='/usr/local/opt/openssl/' # sudo apt install libxml2-dev @@ -21,7 +21,17 @@ export SYSTEM_NAME=`uname` # sudo apt install libxslt1-dev # sudo apt install autoconf -phpbrew --debug install --mirror=http://cn2.php.net -j 4 $PHP_VERSION +default +bz2=$LIB_BZ2 +zlib=$LIB_ZIP +mb +openssl=$LIB_SSL +phpbrew --debug install \ + --mirror=http://cn2.php.net -j 4 \ + $PHP_VERSION \ + +default \ + +bz2=$LIB_BZ2 \ + +zlib=$LIB_ZIP \ + +mb \ + +openssl=$LIB_SSL +intl \ + +mysql \ + +pdo \ + +xml echo $PHP_VERSION diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index 8e74226..bb64978 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -661,7 +661,7 @@ } }); - it('test CollapseWhitespace', function () { + xit('test CollapseWhitespace', function () { $data = [ ['foo bar', ' foo bar '], ['test string', 'test string'], @@ -1714,4 +1714,45 @@ }); } }); + + context('test toAsiic', function () { + $data = [ + ['foo bar', 'fòô bàř'], + [' TEST ', ' ŤÉŚŢ '], + ['f = z = 3', 'φ = ź = 3'], + ['perevirka', 'перевірка'], + ['lysaya gora', 'лысая гора'], + ['user@host', 'user@host'], + ['shchuka', 'щука'], + ['', '漢字'], + ['xin chao the gioi', 'xin chào thế giới'], + ['XIN CHAO THE GIOI', 'XIN CHÀO THẾ GIỚI'], + ['dam phat chet luon', 'đấm phát chết luôn'], + [' ', ' '], // no-break space (U+00A0) + [' ', '           '], // spaces U+2000 to U+200A + [' ', ' '], // narrow no-break space (U+202F) + [' ', ' '], // medium mathematical space (U+205F) + [' ', ' '], // ideographic space (U+3000) + ['', '𐍉'], // some uncommon, unsupported character (U+10349) + ['𐍉', '𐍉', 'en', false], + ['aouAOU', 'äöüÄÖÜ'], + ['aeoeueAEOEUE', 'äöüÄÖÜ', 'de'], + ['aeoeueAEOEUE', 'äöüÄÖÜ', 'de_DE'] + ]; + + foreach ($data as $key => $value) { + it(__formatMessage($key, $value), function () use ($value) { + @list($expected, $str, $language, $removeUnsupported) = $value; + $language = $language ?? 'en'; + $removeUnsupported = $removeUnsupported ?? true; + + $stringy = __('Stringy')::create($str); + $result = $stringy->toAscii($language, $removeUnsupported); + + \expect($stringy)->toBeAnInstanceOf(__('Stringy')); + \expect((string) $stringy)->toBe($str); + \expect((string) $result)->toBe($expected); + }); + } + }); }); diff --git a/src/Minbaby/Php/Stringy/Stringy.php b/src/Minbaby/Php/Stringy/Stringy.php index 6bf550f..24b3838 100644 --- a/src/Minbaby/Php/Stringy/Stringy.php +++ b/src/Minbaby/Php/Stringy/Stringy.php @@ -739,4 +739,215 @@ public function replace($search, $replacement) { return $this->regexReplace(preg_quote($search), $replacement); } + + public function toAscii($language = 'en', $removeUnsupported = true) + { + $str = $this->str; + $langSpecific = $this->langSpecificCharsArray($language); + if (!empty($langSpecific)) { + $str = str_replace($langSpecific[0], $langSpecific[1], $str); + } + foreach ($this->charsArray() as $key => $value) { + $str = str_replace($value, $key, $str); + } + if ($removeUnsupported) { + $str = preg_replace('/[^\x20-\x7E]/u', '', $str); + } + return static::create($str, $this->encoding); + } + + protected static function langSpecificCharsArray($language = 'en') + { + $split = preg_split('/[-_]/', $language); + $language = strtolower($split[0]); + static $charsArray = []; + if (isset($charsArray[$language])) { + return $charsArray[$language]; + } + $languageSpecific = [ + 'de' => [ + ['ä', 'ö', 'ü', 'Ä', 'Ö', 'Ü' ], + ['ae', 'oe', 'ue', 'AE', 'OE', 'UE'], + ], + 'bg' => [ + ['х', 'Х', 'щ', 'Щ', 'ъ', 'Ъ', 'ь', 'Ь'], + ['h', 'H', 'sht', 'SHT', 'a', 'А', 'y', 'Y'] + ] + ]; + if (isset($languageSpecific[$language])) { + $charsArray[$language] = $languageSpecific[$language]; + } else { + $charsArray[$language] = []; + } + return $charsArray[$language]; + } + + protected function charsArray() + { + static $charsArray; + if (isset($charsArray)) return $charsArray; + return $charsArray = [ + '0' => ['°', '₀', '۰', '0'], + '1' => ['¹', '₁', '۱', '1'], + '2' => ['²', '₂', '۲', '2'], + '3' => ['³', '₃', '۳', '3'], + '4' => ['⁴', '₄', '۴', '٤', '4'], + '5' => ['⁵', '₅', '۵', '٥', '5'], + '6' => ['⁶', '₆', '۶', '٦', '6'], + '7' => ['⁷', '₇', '۷', '7'], + '8' => ['⁸', '₈', '۸', '8'], + '9' => ['⁹', '₉', '۹', '9'], + 'a' => ['à', 'á', 'ả', 'ã', 'ạ', 'ă', 'ắ', 'ằ', 'ẳ', 'ẵ', + 'ặ', 'â', 'ấ', 'ầ', 'ẩ', 'ẫ', 'ậ', 'ā', 'ą', 'å', + 'α', 'ά', 'ἀ', 'ἁ', 'ἂ', 'ἃ', 'ἄ', 'ἅ', 'ἆ', 'ἇ', + 'ᾀ', 'ᾁ', 'ᾂ', 'ᾃ', 'ᾄ', 'ᾅ', 'ᾆ', 'ᾇ', 'ὰ', 'ά', + 'ᾰ', 'ᾱ', 'ᾲ', 'ᾳ', 'ᾴ', 'ᾶ', 'ᾷ', 'а', 'أ', 'အ', + 'ာ', 'ါ', 'ǻ', 'ǎ', 'ª', 'ა', 'अ', 'ا', 'a', 'ä'], + 'b' => ['б', 'β', 'ب', 'ဗ', 'ბ', 'b'], + 'c' => ['ç', 'ć', 'č', 'ĉ', 'ċ', 'c'], + 'd' => ['ď', 'ð', 'đ', 'ƌ', 'ȡ', 'ɖ', 'ɗ', 'ᵭ', 'ᶁ', 'ᶑ', + 'д', 'δ', 'د', 'ض', 'ဍ', 'ဒ', 'დ', 'd'], + 'e' => ['é', 'è', 'ẻ', 'ẽ', 'ẹ', 'ê', 'ế', 'ề', 'ể', 'ễ', + 'ệ', 'ë', 'ē', 'ę', 'ě', 'ĕ', 'ė', 'ε', 'έ', 'ἐ', + 'ἑ', 'ἒ', 'ἓ', 'ἔ', 'ἕ', 'ὲ', 'έ', 'е', 'ё', 'э', + 'є', 'ə', 'ဧ', 'ေ', 'ဲ', 'ე', 'ए', 'إ', 'ئ', 'e'], + 'f' => ['ф', 'φ', 'ف', 'ƒ', 'ფ', 'f'], + 'g' => ['ĝ', 'ğ', 'ġ', 'ģ', 'г', 'ґ', 'γ', 'ဂ', 'გ', 'گ', + 'g'], + 'h' => ['ĥ', 'ħ', 'η', 'ή', 'ح', 'ه', 'ဟ', 'ှ', 'ჰ', 'h'], + 'i' => ['í', 'ì', 'ỉ', 'ĩ', 'ị', 'î', 'ï', 'ī', 'ĭ', 'į', + 'ı', 'ι', 'ί', 'ϊ', 'ΐ', 'ἰ', 'ἱ', 'ἲ', 'ἳ', 'ἴ', + 'ἵ', 'ἶ', 'ἷ', 'ὶ', 'ί', 'ῐ', 'ῑ', 'ῒ', 'ΐ', 'ῖ', + 'ῗ', 'і', 'ї', 'и', 'ဣ', 'ိ', 'ီ', 'ည်', 'ǐ', 'ი', + 'इ', 'ی', 'i'], + 'j' => ['ĵ', 'ј', 'Ј', 'ჯ', 'ج', 'j'], + 'k' => ['ķ', 'ĸ', 'к', 'κ', 'Ķ', 'ق', 'ك', 'က', 'კ', 'ქ', + 'ک', 'k'], + 'l' => ['ł', 'ľ', 'ĺ', 'ļ', 'ŀ', 'л', 'λ', 'ل', 'လ', 'ლ', + 'l'], + 'm' => ['м', 'μ', 'م', 'မ', 'მ', 'm'], + 'n' => ['ñ', 'ń', 'ň', 'ņ', 'ʼn', 'ŋ', 'ν', 'н', 'ن', 'န', + 'ნ', 'n'], + 'o' => ['ó', 'ò', 'ỏ', 'õ', 'ọ', 'ô', 'ố', 'ồ', 'ổ', 'ỗ', + 'ộ', 'ơ', 'ớ', 'ờ', 'ở', 'ỡ', 'ợ', 'ø', 'ō', 'ő', + 'ŏ', 'ο', 'ὀ', 'ὁ', 'ὂ', 'ὃ', 'ὄ', 'ὅ', 'ὸ', 'ό', + 'о', 'و', 'θ', 'ို', 'ǒ', 'ǿ', 'º', 'ო', 'ओ', 'o', + 'ö'], + 'p' => ['п', 'π', 'ပ', 'პ', 'پ', 'p'], + 'q' => ['ყ', 'q'], + 'r' => ['ŕ', 'ř', 'ŗ', 'р', 'ρ', 'ر', 'რ', 'r'], + 's' => ['ś', 'š', 'ş', 'с', 'σ', 'ș', 'ς', 'س', 'ص', 'စ', + 'ſ', 'ს', 's'], + 't' => ['ť', 'ţ', 'т', 'τ', 'ț', 'ت', 'ط', 'ဋ', 'တ', 'ŧ', + 'თ', 'ტ', 't'], + 'u' => ['ú', 'ù', 'ủ', 'ũ', 'ụ', 'ư', 'ứ', 'ừ', 'ử', 'ữ', + 'ự', 'û', 'ū', 'ů', 'ű', 'ŭ', 'ų', 'µ', 'у', 'ဉ', + 'ု', 'ူ', 'ǔ', 'ǖ', 'ǘ', 'ǚ', 'ǜ', 'უ', 'उ', 'u', + 'ў', 'ü'], + 'v' => ['в', 'ვ', 'ϐ', 'v'], + 'w' => ['ŵ', 'ω', 'ώ', 'ဝ', 'ွ', 'w'], + 'x' => ['χ', 'ξ', 'x'], + 'y' => ['ý', 'ỳ', 'ỷ', 'ỹ', 'ỵ', 'ÿ', 'ŷ', 'й', 'ы', 'υ', + 'ϋ', 'ύ', 'ΰ', 'ي', 'ယ', 'y'], + 'z' => ['ź', 'ž', 'ż', 'з', 'ζ', 'ز', 'ဇ', 'ზ', 'z'], + 'aa' => ['ع', 'आ', 'آ'], + 'ae' => ['æ', 'ǽ'], + 'ai' => ['ऐ'], + 'ch' => ['ч', 'ჩ', 'ჭ', 'چ'], + 'dj' => ['ђ', 'đ'], + 'dz' => ['џ', 'ძ'], + 'ei' => ['ऍ'], + 'gh' => ['غ', 'ღ'], + 'ii' => ['ई'], + 'ij' => ['ij'], + 'kh' => ['х', 'خ', 'ხ'], + 'lj' => ['љ'], + 'nj' => ['њ'], + 'oe' => ['œ', 'ؤ'], + 'oi' => ['ऑ'], + 'oii' => ['ऒ'], + 'ps' => ['ψ'], + 'sh' => ['ш', 'შ', 'ش'], + 'shch' => ['щ'], + 'ss' => ['ß'], + 'sx' => ['ŝ'], + 'th' => ['þ', 'ϑ', 'ث', 'ذ', 'ظ'], + 'ts' => ['ц', 'ც', 'წ'], + 'uu' => ['ऊ'], + 'ya' => ['я'], + 'yu' => ['ю'], + 'zh' => ['ж', 'ჟ', 'ژ'], + '(c)' => ['©'], + 'A' => ['Á', 'À', 'Ả', 'Ã', 'Ạ', 'Ă', 'Ắ', 'Ằ', 'Ẳ', 'Ẵ', + 'Ặ', 'Â', 'Ấ', 'Ầ', 'Ẩ', 'Ẫ', 'Ậ', 'Å', 'Ā', 'Ą', + 'Α', 'Ά', 'Ἀ', 'Ἁ', 'Ἂ', 'Ἃ', 'Ἄ', 'Ἅ', 'Ἆ', 'Ἇ', + 'ᾈ', 'ᾉ', 'ᾊ', 'ᾋ', 'ᾌ', 'ᾍ', 'ᾎ', 'ᾏ', 'Ᾰ', 'Ᾱ', + 'Ὰ', 'Ά', 'ᾼ', 'А', 'Ǻ', 'Ǎ', 'A', 'Ä'], + 'B' => ['Б', 'Β', 'ब', 'B'], + 'C' => ['Ç','Ć', 'Č', 'Ĉ', 'Ċ', 'C'], + 'D' => ['Ď', 'Ð', 'Đ', 'Ɖ', 'Ɗ', 'Ƌ', 'ᴅ', 'ᴆ', 'Д', 'Δ', + 'D'], + 'E' => ['É', 'È', 'Ẻ', 'Ẽ', 'Ẹ', 'Ê', 'Ế', 'Ề', 'Ể', 'Ễ', + 'Ệ', 'Ë', 'Ē', 'Ę', 'Ě', 'Ĕ', 'Ė', 'Ε', 'Έ', 'Ἐ', + 'Ἑ', 'Ἒ', 'Ἓ', 'Ἔ', 'Ἕ', 'Έ', 'Ὲ', 'Е', 'Ё', 'Э', + 'Є', 'Ə', 'E'], + 'F' => ['Ф', 'Φ', 'F'], + 'G' => ['Ğ', 'Ġ', 'Ģ', 'Г', 'Ґ', 'Γ', 'G'], + 'H' => ['Η', 'Ή', 'Ħ', 'H'], + 'I' => ['Í', 'Ì', 'Ỉ', 'Ĩ', 'Ị', 'Î', 'Ï', 'Ī', 'Ĭ', 'Į', + 'İ', 'Ι', 'Ί', 'Ϊ', 'Ἰ', 'Ἱ', 'Ἳ', 'Ἴ', 'Ἵ', 'Ἶ', + 'Ἷ', 'Ῐ', 'Ῑ', 'Ὶ', 'Ί', 'И', 'І', 'Ї', 'Ǐ', 'ϒ', + 'I'], + 'J' => ['J'], + 'K' => ['К', 'Κ', 'K'], + 'L' => ['Ĺ', 'Ł', 'Л', 'Λ', 'Ļ', 'Ľ', 'Ŀ', 'ल', 'L'], + 'M' => ['М', 'Μ', 'M'], + 'N' => ['Ń', 'Ñ', 'Ň', 'Ņ', 'Ŋ', 'Н', 'Ν', 'N'], + 'O' => ['Ó', 'Ò', 'Ỏ', 'Õ', 'Ọ', 'Ô', 'Ố', 'Ồ', 'Ổ', 'Ỗ', + 'Ộ', 'Ơ', 'Ớ', 'Ờ', 'Ở', 'Ỡ', 'Ợ', 'Ø', 'Ō', 'Ő', + 'Ŏ', 'Ο', 'Ό', 'Ὀ', 'Ὁ', 'Ὂ', 'Ὃ', 'Ὄ', 'Ὅ', 'Ὸ', + 'Ό', 'О', 'Θ', 'Ө', 'Ǒ', 'Ǿ', 'O', 'Ö'], + 'P' => ['П', 'Π', 'P'], + 'Q' => ['Q'], + 'R' => ['Ř', 'Ŕ', 'Р', 'Ρ', 'Ŗ', 'R'], + 'S' => ['Ş', 'Ŝ', 'Ș', 'Š', 'Ś', 'С', 'Σ', 'S'], + 'T' => ['Ť', 'Ţ', 'Ŧ', 'Ț', 'Т', 'Τ', 'T'], + 'U' => ['Ú', 'Ù', 'Ủ', 'Ũ', 'Ụ', 'Ư', 'Ứ', 'Ừ', 'Ử', 'Ữ', + 'Ự', 'Û', 'Ū', 'Ů', 'Ű', 'Ŭ', 'Ų', 'У', 'Ǔ', 'Ǖ', + 'Ǘ', 'Ǚ', 'Ǜ', 'U', 'Ў', 'Ü'], + 'V' => ['В', 'V'], + 'W' => ['Ω', 'Ώ', 'Ŵ', 'W'], + 'X' => ['Χ', 'Ξ', 'X'], + 'Y' => ['Ý', 'Ỳ', 'Ỷ', 'Ỹ', 'Ỵ', 'Ÿ', 'Ῠ', 'Ῡ', 'Ὺ', 'Ύ', + 'Ы', 'Й', 'Υ', 'Ϋ', 'Ŷ', 'Y'], + 'Z' => ['Ź', 'Ž', 'Ż', 'З', 'Ζ', 'Z'], + 'AE' => ['Æ', 'Ǽ'], + 'Ch' => ['Ч'], + 'Dj' => ['Ђ'], + 'Dz' => ['Џ'], + 'Gx' => ['Ĝ'], + 'Hx' => ['Ĥ'], + 'Ij' => ['IJ'], + 'Jx' => ['Ĵ'], + 'Kh' => ['Х'], + 'Lj' => ['Љ'], + 'Nj' => ['Њ'], + 'Oe' => ['Œ'], + 'Ps' => ['Ψ'], + 'Sh' => ['Ш'], + 'Shch' => ['Щ'], + 'Ss' => ['ẞ'], + 'Th' => ['Þ'], + 'Ts' => ['Ц'], + 'Ya' => ['Я'], + 'Yu' => ['Ю'], + 'Zh' => ['Ж'], + ' ' => ["\xC2\xA0", "\xE2\x80\x80", "\xE2\x80\x81", + "\xE2\x80\x82", "\xE2\x80\x83", "\xE2\x80\x84", + "\xE2\x80\x85", "\xE2\x80\x86", "\xE2\x80\x87", + "\xE2\x80\x88", "\xE2\x80\x89", "\xE2\x80\x8A", + "\xE2\x80\xAF", "\xE2\x81\x9F", "\xE3\x80\x80", + "\xEF\xBE\xA0"], + ]; + } } diff --git a/src/ext/functions.c b/src/ext/functions.c index 5e28e31..5867994 100644 --- a/src/ext/functions.c +++ b/src/ext/functions.c @@ -1,7 +1,6 @@ #include "functions.h" - -int strsplit (const char *str, char *parts[], const char *delimiter) { +int strsplit(const char *str, char *parts[], const char *delimiter) { char *pch; int i = 0; char *copy = NULL, *tmp = NULL; @@ -31,7 +30,6 @@ int strsplit (const char *str, char *parts[], const char *delimiter) { free(copy); return i; - bad: free(copy); for (int j = 0; j < i; j++) diff --git a/src/ext/functions.h b/src/ext/functions.h index 7fc26af..690ad98 100644 --- a/src/ext/functions.h +++ b/src/ext/functions.h @@ -5,7 +5,7 @@ #include "php.h" #include "common.h" #include "ext/standard/php_standard.h" -#include "log.h" +//#include "log.h" int strsplit (const char *, char *[], const char *); diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index d483275..539e16c 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -2953,6 +2953,1145 @@ ZEND_BEGIN_ARG_INFO(arginfo_replace, 0) ZEND_ARG_INFO(0, replacement) ZEND_END_ARG_INFO(); +PHP_METHOD(Stringy, toAscii) +{ + zval *language, *removeUnsupported; + ZEND_PARSE_PARAMETERS_START(0, 2) + Z_PARAM_OPTIONAL + Z_PARAM_ZVAL(language) + Z_PARAM_ZVAL(removeUnsupported) + ZEND_PARSE_PARAMETERS_END(); + + if (language == NULL) { + language = (zval *) malloc(sizeof(zval)); + ZVAL_STRING(language, "en"); + } + + if (removeUnsupported == NULL) { + removeUnsupported = (zval *) malloc(sizeof(zval)); + ZVAL_BOOL(removeUnsupported, IS_TRUE); + } + + zval rv; + zval *str = zend_read_property(stringy_ce, getThis(), ZEND_STRL("str"), 0, &rv); + zval tmp = *str; + + zval func, args[] = { + *language + }; + ZVAL_STRING(&func, "langSpecificCharsArray"); + call_user_function(NULL, getThis(), &func, return_value, 1, args); + + zval chars; + if (zend_array_count(Z_ARRVAL_P(return_value)) > 0) { + zval args_preg_replace_1[] = { + *zend_hash_index_find(Z_ARRVAL_P(return_value), 0), + *zend_hash_index_find(Z_ARRVAL_P(return_value), 1), + *str, + }; + ZVAL_STRING(&func, "str_replace"); + call_user_function(NULL, NULL, &func, &tmp, 3, args_preg_replace_1); + } + + ZVAL_STRING(&func, "charsArray"); + call_user_function(NULL, getThis(), &func, &chars, 0, NULL); + + zval *value; + zend_string *key; + zval x; + ulong idx; + + ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL(chars), idx, key, value) { + if (!key) { + key = zend_long_to_str(idx); + } + ZVAL_NEW_STR(&x, key); + + zval args_preg_replace_2[] = { + *value, + x, + tmp, + }; + ZVAL_STRING(&func, "str_replace"); + + call_user_function(NULL, NULL, &func, &tmp, 3, args_preg_replace_2); + } ZEND_HASH_FOREACH_END(); + + if (Z_TYPE_P(removeUnsupported) == IS_TRUE) { + zval pattern, replacement; + ZVAL_STRING(&pattern, "/[^\x20-\x7E]/u"); + ZVAL_STRING(&replacement, ""); + + zval args_preg_replace_3[] = { + pattern, + replacement, + tmp, + }; + ZVAL_STRING(&func, "preg_replace"); + call_user_function(NULL, NULL, &func, &tmp, 3, args_preg_replace_3); + } + + zval instance; + object_init_ex(&instance, stringy_ce); + + zval *encoding = zend_read_property(stringy_ce, getThis(), ZEND_STRL("encoding"), 0, &rv); + + zval args_construct[] = { + tmp, + *encoding, + }; + ZVAL_STRING(&func, "__construct"); + call_user_function(NULL, &instance, &func, return_value, 2, args_construct); + + RETURN_ZVAL(&instance, 0, 1); +} +ZEND_BEGIN_ARG_INFO(arginfo_toAscii, 0) + ZEND_ARG_INFO(0, language) + ZEND_ARG_INFO(0, removeUnsupported) +ZEND_END_ARG_INFO(); + +//TODO: 先实现再说 +PHP_METHOD(Stringy, charsArray) +{ + zval ret; + array_init(&ret); + + zval tb_0; + array_init(&tb_0); + char* th_0_arr[] = {"°", "₀", "۰", "0"}; + for(int i = 0; i < 4; i++) { + add_next_index_string(&tb_0, th_0_arr[i]); + } + add_assoc_zval(&ret, "0", &tb_0); + + zval tb_1; + array_init(&tb_1); + char* th_1_arr[] = {"¹", "₁", "۱", "1"}; + for(int i = 0; i < 4; i++) { + add_next_index_string(&tb_1, th_1_arr[i]); + } + add_assoc_zval(&ret, "1", &tb_1); + + zval tb_2; + array_init(&tb_2); + char* th_2_arr[] = {"²", "₂", "۲", "2"}; + for(int i = 0; i < 4; i++) { + add_next_index_string(&tb_2, th_2_arr[i]); + } + add_assoc_zval(&ret, "2", &tb_2); + + zval tb_3; + array_init(&tb_3); + char* th_3_arr[] = {"³", "₃", "۳", "3"}; + for(int i = 0; i < 4; i++) { + add_next_index_string(&tb_3, th_3_arr[i]); + } + add_assoc_zval(&ret, "3", &tb_3); + + zval tb_4; + array_init(&tb_4); + char* th_4_arr[] = {"⁴", "₄", "۴", "٤", "4"}; + for(int i = 0; i < 5; i++) { + add_next_index_string(&tb_4, th_4_arr[i]); + } + add_assoc_zval(&ret, "4", &tb_4); + + zval tb_5; + array_init(&tb_5); + char* th_5_arr[] = {"⁵", "₅", "۵", "٥", "5"}; + for(int i = 0; i < 5; i++) { + add_next_index_string(&tb_5, th_5_arr[i]); + } + add_assoc_zval(&ret, "5", &tb_5); + + zval tb_6; + array_init(&tb_6); + char* th_6_arr[] = {"⁶", "₆", "۶", "٦", "6"}; + for(int i = 0; i < 5; i++) { + add_next_index_string(&tb_6, th_6_arr[i]); + } + add_assoc_zval(&ret, "5", &tb_6); + + zval tb_7; + array_init(&tb_7); + char* th_7_arr[] = {"⁷", "₇", "۷", "7"}; + for(int i = 0; i < 4; i++) { + add_next_index_string(&tb_7, th_7_arr[i]); + } + add_assoc_zval(&ret, "7", &tb_7); + + zval tb_8; + array_init(&tb_8); + char* th_8_arr[] = {"⁸", "₈", "۸", "8"}; + for(int i = 0; i < 4; i++) { + add_next_index_string(&tb_8, th_8_arr[i]); + } + add_assoc_zval(&ret, "8", &tb_8); + + zval tb_9; + array_init(&tb_9); + char* th_9_arr[] = {"⁹", "₉", "۹", "9"}; + for(int i = 0; i < 4; i++) { + add_next_index_string(&tb_9, th_9_arr[i]); + } + add_assoc_zval(&ret, "9", &tb_9); + + zval tb_a; + array_init(&tb_a); + char* th_a_arr[] = {"à", "á", "ả", "ã", "ạ", "ă", "ắ", "ằ", "ẳ", "ẵ", + "ặ", "â", "ấ", "ầ", "ẩ", "ẫ", "ậ", "ā", "ą", "å", + "α", "ά", "ἀ", "ἁ", "ἂ", "ἃ", "ἄ", "ἅ", "ἆ", "ἇ", + "ᾀ", "ᾁ", "ᾂ", "ᾃ", "ᾄ", "ᾅ", "ᾆ", "ᾇ", "ὰ", "ά", + "ᾰ", "ᾱ", "ᾲ", "ᾳ", "ᾴ", "ᾶ", "ᾷ", "а", "أ", "အ", + "ာ", "ါ", "ǻ", "ǎ", "ª", "ა", "अ", "ا", "a", "ä"}; + for(int i = 0; i < 60; i++) { + add_next_index_string(&tb_a, th_a_arr[i]); + } + add_assoc_zval(&ret, "a", &tb_a); + + zval tb_b; + array_init(&tb_b); + char* th_b_arr[] = {"б", "β", "ب", "ဗ", "ბ", "b"}; + for(int i = 0; i < 6; i++) { + add_next_index_string(&tb_b, th_b_arr[i]); + } + add_assoc_zval(&ret, "b", &tb_b); + + zval tb_c; + array_init(&tb_c); + char* th_c_arr[] = {"ç", "ć", "č", "ĉ", "ċ", "c"}; + for(int i = 0; i < 6; i++) { + add_next_index_string(&tb_c, th_c_arr[i]); + } + add_assoc_zval(&ret, "c", &tb_c); + + zval tb_d; + array_init(&tb_d); + char* th_d_arr[] = {"ď", "ð", "đ", "ƌ", "ȡ", "ɖ", "ɗ", "ᵭ", "ᶁ", "ᶑ", + "д", "δ", "د", "ض", "ဍ", "ဒ", "დ", "d"}; + for(int i = 0; i < 18; i++) { + add_next_index_string(&tb_d, th_d_arr[i]); + } + add_assoc_zval(&ret, "d", &tb_d); + + zval tb_e; + array_init(&tb_e); + char* th_e_arr[] = {"é", "è", "ẻ", "ẽ", "ẹ", "ê", "ế", "ề", "ể", "ễ", + "ệ", "ë", "ē", "ę", "ě", "ĕ", "ė", "ε", "έ", "ἐ", + "ἑ", "ἒ", "ἓ", "ἔ", "ἕ", "ὲ", "έ", "е", "ё", "э", + "є", "ə", "ဧ", "ေ", "ဲ", "ე", "ए", "إ", "ئ", "e"}; + for(int i = 0; i < 40; i++) { + add_next_index_string(&tb_e, th_e_arr[i]); + } + add_assoc_zval(&ret, "e", &tb_e); + + zval tb_f; + array_init(&tb_f); + char* th_f_arr[] = {"ф", "φ", "ف", "ƒ", "ფ", "f"}; + for(int i = 0; i < 6; i++) { + add_next_index_string(&tb_f, th_f_arr[i]); + } + add_assoc_zval(&ret, "f", &tb_f); + + zval tb_g; + array_init(&tb_g); + char* th_g_arr[] = {"ĝ", "ğ", "ġ", "ģ", "г", "ґ", "γ", "ဂ", "გ", "گ", + "g"}; + for(int i = 0; i < 11; i++) { + add_next_index_string(&tb_g, th_g_arr[i]); + } + add_assoc_zval(&ret, "g", &tb_g); + + zval tb_h; + array_init(&tb_h); + char* th_h_arr[] = {"ĥ", "ħ", "η", "ή", "ح", "ه", "ဟ", "ှ", "ჰ", "h"}; + for(int i = 0; i < 10; i++) { + add_next_index_string(&tb_h, th_h_arr[i]); + } + add_assoc_zval(&ret, "h", &tb_h); + + zval tb_i; + array_init(&tb_i); + char* th_i_arr[] = {"í", "ì", "ỉ", "ĩ", "ị", "î", "ï", "ī", "ĭ", "į", + "ı", "ι", "ί", "ϊ", "ΐ", "ἰ", "ἱ", "ἲ", "ἳ", "ἴ", + "ἵ", "ἶ", "ἷ", "ὶ", "ί", "ῐ", "ῑ", "ῒ", "ΐ", "ῖ", + "ῗ", "і", "ї", "и", "ဣ", "ိ", "ီ", "ည်", "ǐ", "ი", + "इ", "ی", "i"}; + for(int i = 0; i < 43; i++) { + add_next_index_string(&tb_i, th_i_arr[i]); + } + add_assoc_zval(&ret, "i", &tb_i); + + zval tb_j; + array_init(&tb_j); + char* th_j_arr[] = {"ĵ", "ј", "Ј", "ჯ", "ج", "j"}; + for(int i = 0; i < 6; i++) { + add_next_index_string(&tb_j, th_j_arr[i]); + } + add_assoc_zval(&ret, "j", &tb_j); + + zval tb_k; + array_init(&tb_k); + char* th_k_arr[] = {"ķ", "ĸ", "к", "κ", "Ķ", "ق", "ك", "က", "კ", "ქ", + "ک", "k"}; + for(int i = 0; i < 12; i++) { + add_next_index_string(&tb_k, th_k_arr[i]); + } + add_assoc_zval(&ret, "k", &tb_k); + + zval tb_l; + array_init(&tb_l); + char* th_l_arr[] = {"ł", "ľ", "ĺ", "ļ", "ŀ", "л", "λ", "ل", "လ", "ლ", + "l"}; + for(int i = 0; i < 11; i++) { + add_next_index_string(&tb_l, th_l_arr[i]); + } + add_assoc_zval(&ret, "l", &tb_l); + + zval tb_m; + array_init(&tb_m); + char* th_m_arr[] = {"м", "μ", "م", "မ", "მ", "m"}; + for(int i = 0; i < 6; i++) { + add_next_index_string(&tb_m, th_m_arr[i]); + } + add_assoc_zval(&ret, "m", &tb_m); + + zval tb_n; + array_init(&tb_n); + char* th_n_arr[] = {"ñ", "ń", "ň", "ņ", "ʼn", "ŋ", "ν", "н", "ن", "န", + "ნ", "n"}; + for(int i = 0; i < 12; i++) { + add_next_index_string(&tb_n, th_n_arr[i]); + } + add_assoc_zval(&ret, "n", &tb_n); + + zval tb_o; + array_init(&tb_o); + char* th_o_arr[] = {"ó", "ò", "ỏ", "õ", "ọ", "ô", "ố", "ồ", "ổ", "ỗ", + "ộ", "ơ", "ớ", "ờ", "ở", "ỡ", "ợ", "ø", "ō", "ő", + "ŏ", "ο", "ὀ", "ὁ", "ὂ", "ὃ", "ὄ", "ὅ", "ὸ", "ό", + "о", "و", "θ", "ို", "ǒ", "ǿ", "º", "ო", "ओ", "o", + "ö"}; + for(int i = 0; i < 41; i++) { + add_next_index_string(&tb_o, th_o_arr[i]); + } + add_assoc_zval(&ret, "o", &tb_o); + + zval tb_p; + array_init(&tb_p); + char* th_p_arr[] = {"п", "π", "ပ", "პ", "پ", "p"}; + for(int i = 0; i < 6; i++) { + add_next_index_string(&tb_p, th_p_arr[i]); + } + add_assoc_zval(&ret, "p", &tb_p); + + zval tb_q; + array_init(&tb_q); + char* th_q_arr[] = {"ყ", "q"}; + for(int i = 0; i < 2; i++) { + add_next_index_string(&tb_q, th_q_arr[i]); + } + add_assoc_zval(&ret, "q", &tb_q); + + zval tb_r; + array_init(&tb_r); + char* th_r_arr[] = {"ŕ", "ř", "ŗ", "р", "ρ", "ر", "რ", "r"}; + for(int i = 0; i < 8; i++) { + add_next_index_string(&tb_r, th_r_arr[i]); + } + add_assoc_zval(&ret, "r", &tb_r); + + zval tb_s; + array_init(&tb_s); + char* th_s_arr[] = {"ś", "š", "ş", "с", "σ", "ș", "ς", "س", "ص", "စ", + "ſ", "ს", "s"}; + for(int i = 0; i < 13; i++) { + add_next_index_string(&tb_s, th_s_arr[i]); + } + add_assoc_zval(&ret, "s", &tb_s); + + zval tb_tt; + array_init(&tb_tt); + char* th_t_arr[] = {"ť", "ţ", "т", "τ", "ț", "ت", "ط", "ဋ", "တ", "ŧ", + "თ", "ტ", "t"}; + for(int i = 0; i < 13; i++) { + add_next_index_string(&tb_tt, th_t_arr[i]); + } + add_assoc_zval(&ret, "t", &tb_tt); + + zval tb_u; + array_init(&tb_u); + char* th_u_arr[] = {"ú", "ù", "ủ", "ũ", "ụ", "ư", "ứ", "ừ", "ử", "ữ", + "ự", "û", "ū", "ů", "ű", "ŭ", "ų", "µ", "у", "ဉ", + "ု", "ူ", "ǔ", "ǖ", "ǘ", "ǚ", "ǜ", "უ", "उ", "u", + "ў", "ü"}; + for(int i = 0; i < 32; i++) { + add_next_index_string(&tb_u, th_u_arr[i]); + } + add_assoc_zval(&ret, "u", &tb_u); + + zval tb_v; + array_init(&tb_v); + char* th_v_arr[] = {"в", "ვ", "ϐ", "v"}; + for(int i = 0; i < 4; i++) { + add_next_index_string(&tb_v, th_v_arr[i]); + } + add_assoc_zval(&ret, "v", &tb_v); + + zval tb_w; + array_init(&tb_w); + char* th_w_arr[] = {"ŵ", "ω", "ώ", "ဝ", "ွ", "w"}; + for(int i = 0; i < 6; i++) { + add_next_index_string(&tb_w, th_w_arr[i]); + } + add_assoc_zval(&ret, "w", &tb_w); + + zval tb_x; + array_init(&tb_x); + char* th_x_arr[] = {"χ", "ξ", "x"}; + for(int i = 0; i < 3; i++) { + add_next_index_string(&tb_x, th_x_arr[i]); + } + add_assoc_zval(&ret, "x", &tb_x); + + zval tb_y; + array_init(&tb_y); + char* th_y_arr[] = {"ý", "ỳ", "ỷ", "ỹ", "ỵ", "ÿ", "ŷ", "й", "ы", "υ", + "ϋ", "ύ", "ΰ", "ي", "ယ", "y"}; + for(int i = 0; i < 16; i++) { + add_next_index_string(&tb_y, th_y_arr[i]); + } + add_assoc_zval(&ret, "y", &tb_y); + + zval tb_z; + array_init(&tb_z); + char* th_z_arr[] = {"ź", "ž", "ż", "з", "ζ", "ز", "ဇ", "ზ", "z"}; + for(int i = 0; i < 9; i++) { + add_next_index_string(&tb_z, th_z_arr[i]); + } + add_assoc_zval(&ret, "z", &tb_z); + + zval tb_aa; + array_init(&tb_aa); + char* th_aa_arr[] = {"ع", "आ", "آ"}; + for(int i = 0; i < 3; i++) { + add_next_index_string(&tb_aa, th_aa_arr[i]); + } + add_assoc_zval(&ret, "aa", &tb_aa); + + zval tb_ae; + array_init(&tb_ae); + char* th_ae_arr[] = {"æ", "ǽ"}; + for(int i = 0; i < 2; i++) { + add_next_index_string(&tb_ae, th_ae_arr[i]); + } + add_assoc_zval(&ret, "aa", &tb_ae); + + zval tb_ai; + array_init(&tb_ai); + char* th_ai_arr[] = {"ऐ"}; + for(int i = 0; i < 1; i++) { + add_next_index_string(&tb_ai, th_ai_arr[i]); + } + add_assoc_zval(&ret, "ai", &tb_ai); + + zval tb_ch; + array_init(&tb_ch); + char* th_ch_arr[] = {"ч", "ჩ", "ჭ", "چ"}; + for(int i = 0; i < 4; i++) { + add_next_index_string(&tb_ch, th_ch_arr[i]); + } + add_assoc_zval(&ret, "ch", &tb_ch); + + zval tb_dj; + array_init(&tb_dj); + char* th_dj_arr[] = {"ђ", "đ"}; + for(int i = 0; i < 2; i++) { + add_next_index_string(&tb_dj, th_dj_arr[i]); + } + add_assoc_zval(&ret, "dj", &tb_dj); + + zval tb_dz; + array_init(&tb_dz); + char* th_dz_arr[] = {"џ", "ძ"}; + for(int i = 0; i < 2; i++) { + add_next_index_string(&tb_dz, th_dz_arr[i]); + } + add_assoc_zval(&ret, "dz", &tb_dz); + + zval tb_ei; + array_init(&tb_ei); + char* th_ei_arr[] = {"ऍ"}; + for(int i = 0; i < 1; i++) { + add_next_index_string(&tb_ei, th_ei_arr[i]); + } + add_assoc_zval(&ret, "ei", &tb_ei); + + zval tb_gh; + array_init(&tb_gh); + char* th_gh_arr[] = {"غ", "ღ"}; + for(int i = 0; i < 2; i++) { + add_next_index_string(&tb_gh, th_gh_arr[i]); + } + add_assoc_zval(&ret, "gh", &tb_gh); + + zval tb_ii; + array_init(&tb_ii); + char* th_ii_arr[] = {"ई"}; + for(int i = 0; i < 1; i++) { + add_next_index_string(&tb_ii, th_ii_arr[i]); + } + add_assoc_zval(&ret, "ii", &tb_ii); + + zval tb_kh; + array_init(&tb_kh); + char* th_kh_arr[] = {"х", "خ", "ხ"}; + for(int i = 0; i < 3; i++) { + add_next_index_string(&tb_kh, th_kh_arr[i]); + } + add_assoc_zval(&ret, "kh", &tb_kh); + + zval tb_ij; + array_init(&tb_ij); + char* th_ij_arr[] = {"ij"}; + for(int i = 0; i < 1; i++) { + add_next_index_string(&tb_ij, th_ij_arr[i]); + } + add_assoc_zval(&ret, "ij", &tb_ij); + + zval tb_lj; + array_init(&tb_lj); + char* th_lj_arr[] = {"љ"}; + for(int i = 0; i < 1; i++) { + add_next_index_string(&tb_lj, th_lj_arr[i]); + } + add_assoc_zval(&ret, "lj", &tb_lj); + + zval tb_nj; + array_init(&tb_nj); + char* th_nj_arr[] = {"њ"}; + for(int i = 0; i < 1; i++) { + add_next_index_string(&tb_nj, th_nj_arr[i]); + } + add_assoc_zval(&ret, "nj", &tb_nj); + + zval tb_oe; + array_init(&tb_oe); + char* th_oe_arr[] = {"œ", "ؤ"}; + for(int i = 0; i < 2; i++) { + add_next_index_string(&tb_oe, th_oe_arr[i]); + } + add_assoc_zval(&ret, "oe", &tb_oe); + + zval tb_oi; + array_init(&tb_oi); + char* th_oi_arr[] = {"ऑ"}; + for(int i = 0; i < 1; i++) { + add_next_index_string(&tb_oi, th_oi_arr[i]); + } + add_assoc_zval(&ret, "oi", &tb_oi); + + zval tb_oii; + array_init(&tb_oii); + char* th_oii_arr[] = {"ऒ"}; + for(int i = 0; i < 1; i++) { + add_next_index_string(&tb_oii, th_oii_arr[i]); + } + add_assoc_zval(&ret, "oii", &tb_oii); + + zval tb_ps; + array_init(&tb_ps); + char* th_ps_arr[] = {"ψ"}; + for(int i = 0; i < 1; i++) { + add_next_index_string(&tb_ps, th_ps_arr[i]); + } + add_assoc_zval(&ret, "ps", &tb_ps); + + zval tb_sh; + array_init(&tb_sh); + char* th_sh_arr[] = {"ш", "შ", "ش"}; + for(int i = 0; i < 3; i++) { + add_next_index_string(&tb_sh, th_sh_arr[i]); + } + add_assoc_zval(&ret, "sh", &tb_sh); + + zval tb_shch; + array_init(&tb_shch); + char* th_shch_arr[] = {"щ"}; + for(int i = 0; i < 1; i++) { + add_next_index_string(&tb_shch, th_shch_arr[i]); + } + add_assoc_zval(&ret, "shch", &tb_shch); + + zval tb_ss; + array_init(&tb_ss); + char* th_ss_arr[] = {"ß"}; + for(int i = 0; i < 1; i++) { + add_next_index_string(&tb_ss, th_ss_arr[i]); + } + add_assoc_zval(&ret, "ss", &tb_ss); + + zval tb_sx; + array_init(&tb_sx); + char* th_sx_arr[] = {"ŝ"}; + for(int i = 0; i < 1; i++) { + add_next_index_string(&tb_sx, th_sx_arr[i]); + } + add_assoc_zval(&ret, "sx", &tb_sx); + + zval tb_th; + array_init(&tb_th); + char* th_th_arr[] = {"þ", "ϑ", "ث", "ذ", "ظ"}; + for(int i = 0; i < 5; i++) { + add_next_index_string(&tb_th, th_th_arr[i]); + } + add_assoc_zval(&ret, "th", &tb_th); + + zval tb_ts; + array_init(&tb_ts); + char* th_ts_arr[] = {"ц", "ც", "წ"}; + for(int i = 0; i < 3; i++) { + add_next_index_string(&tb_ts, th_ts_arr[i]); + } + add_assoc_zval(&ret, "ts", &tb_ts); + + zval tb_uu; + array_init(&tb_uu); + char* th_uu_arr[] = {"ऊ"}; + for(int i = 0; i < 1; i++) { + add_next_index_string(&tb_uu, th_uu_arr[i]); + } + add_assoc_zval(&ret, "uu", &tb_uu); + + zval tb_ya; + array_init(&tb_ya); + char* th_ya_arr[] = {"я"}; + for(int i = 0; i < 1; i++) { + add_next_index_string(&tb_ya, th_ya_arr[i]); + } + add_assoc_zval(&ret, "ya", &tb_ya); + + zval tb_yu; + array_init(&tb_yu); + char* th_yu_arr[] = {"ю"}; + for(int i = 0; i < 1; i++) { + add_next_index_string(&tb_yu, th_yu_arr[i]); + } + add_assoc_zval(&ret, "yu", &tb_yu); + + zval tb_zh; + array_init(&tb_zh); + char* th_zh_arr[] = {"ж", "ჟ", "ژ"}; + for(int i = 0; i < 3; i++) { + add_next_index_string(&tb_zh, th_zh_arr[i]); + } + add_assoc_zval(&ret, "zh", &tb_zh); + + zval tb_ccc; + array_init(&tb_ccc); + char* th_ccc_arr[] = {"©"}; + for(int i = 0; i < 1; i++) { + add_next_index_string(&tb_ccc, th_ccc_arr[i]); + } + add_assoc_zval(&ret, "(c)", &tb_ccc); + + zval tb_A; + array_init(&tb_A); + char* th_A_arr[] = {"Á", "À", "Ả", "Ã", "Ạ", "Ă", "Ắ", "Ằ", "Ẳ", "Ẵ", + "Ặ", "Â", "Ấ", "Ầ", "Ẩ", "Ẫ", "Ậ", "Å", "Ā", "Ą", + "Α", "Ά", "Ἀ", "Ἁ", "Ἂ", "Ἃ", "Ἄ", "Ἅ", "Ἆ", "Ἇ", + "ᾈ", "ᾉ", "ᾊ", "ᾋ", "ᾌ", "ᾍ", "ᾎ", "ᾏ", "Ᾰ", "Ᾱ", + "Ὰ", "Ά", "ᾼ", "А", "Ǻ", "Ǎ", "A", "Ä"}; + for(int i = 0; i < 48; i++) { + add_next_index_string(&tb_A, th_A_arr[i]); + } + add_assoc_zval(&ret, "A", &tb_A); + + zval tb_B; + array_init(&tb_B); + char* th_B_arr[] = {"Б", "Β", "ब", "B"}; + for(int i = 0; i < 4; i++) { + add_next_index_string(&tb_B, th_B_arr[i]); + } + add_assoc_zval(&ret, "B", &tb_B); + + zval tb_C; + array_init(&tb_C); + char* th_C_arr[] = {"Ç", "Ć", "Č", "Ĉ", "Ċ", "C"}; + for(int i = 0; i < 6; i++) { + add_next_index_string(&tb_C, th_C_arr[i]); + } + add_assoc_zval(&ret, "C", &tb_C); + + zval tb_D; + array_init(&tb_D); + char* th_D_arr[] = {"Ď", "Ð", "Đ", "Ɖ", "Ɗ", "Ƌ", "ᴅ", "ᴆ", "Д", "Δ", + "D"}; + for(int i = 0; i < 11; i++) { + add_next_index_string(&tb_D, th_D_arr[i]); + } + add_assoc_zval(&ret, "D", &tb_D); + + zval tb_E; + array_init(&tb_E); + char* th_E_arr[] = {"É", "È", "Ẻ", "Ẽ", "Ẹ", "Ê", "Ế", "Ề", "Ể", "Ễ", + "Ệ", "Ë", "Ē", "Ę", "Ě", "Ĕ", "Ė", "Ε", "Έ", "Ἐ", + "Ἑ", "Ἒ", "Ἓ", "Ἔ", "Ἕ", "Έ", "Ὲ", "Е", "Ё", "Э", + "Є", "Ə", "E"}; + for(int i = 0; i < 33; i++) { + add_next_index_string(&tb_E, th_E_arr[i]); + } + add_assoc_zval(&ret, "E", &tb_E); + + zval tb_F; + array_init(&tb_F); + char* th_F_arr[] = {"Ф", "Φ", "F"}; + for(int i = 0; i < 3; i++) { + add_next_index_string(&tb_F, th_F_arr[i]); + } + add_assoc_zval(&ret, "F", &tb_F); + + zval tb_G; + array_init(&tb_G); + char* th_G_arr[] = {"Ğ", "Ġ", "Ģ", "Г", "Ґ", "Γ", "G"}; + for(int i = 0; i < 7; i++) { + add_next_index_string(&tb_G, th_G_arr[i]); + } + add_assoc_zval(&ret, "G", &tb_G); + + zval tb_H; + array_init(&tb_H); + char* th_H_arr[] = {"Η", "Ή", "Ħ", "H"}; + for(int i = 0; i < 4; i++) { + add_next_index_string(&tb_H, th_H_arr[i]); + } + add_assoc_zval(&ret, "H", &tb_H); + + zval tb_I; + array_init(&tb_I); + char* th_I_arr[] = {"Í", "Ì", "Ỉ", "Ĩ", "Ị", "Î", "Ï", "Ī", "Ĭ", "Į", + "İ", "Ι", "Ί", "Ϊ", "Ἰ", "Ἱ", "Ἳ", "Ἴ", "Ἵ", "Ἶ", + "Ἷ", "Ῐ", "Ῑ", "Ὶ", "Ί", "И", "І", "Ї", "Ǐ", "ϒ", + "I"}; + for(int i = 0; i < 31; i++) { + add_next_index_string(&tb_I, th_I_arr[i]); + } + add_assoc_zval(&ret, "I", &tb_I); + + zval tb_J; + array_init(&tb_J); + char* th_J_arr[] = {"J"}; + for(int i = 0; i < 1; i++) { + add_next_index_string(&tb_J, th_J_arr[i]); + } + add_assoc_zval(&ret, "J", &tb_J); + + zval tb_K; + array_init(&tb_K); + char* th_K_arr[] = {"К", "Κ", "K"}; + for(int i = 0; i < 3; i++) { + add_next_index_string(&tb_K, th_K_arr[i]); + } + add_assoc_zval(&ret, "K", &tb_K); + + zval tb_L; + array_init(&tb_L); + char* th_L_arr[] = {"Ĺ", "Ł", "Л", "Λ", "Ļ", "Ľ", "Ŀ", "ल", "L"}; + for(int i = 0; i < 9; i++) { + add_next_index_string(&tb_L, th_L_arr[i]); + } + add_assoc_zval(&ret, "L", &tb_L); + + zval tb_M; + array_init(&tb_M); + char* th_M_arr[] = {"М", "Μ", "M"}; + for(int i = 0; i < 3; i++) { + add_next_index_string(&tb_M, th_M_arr[i]); + } + add_assoc_zval(&ret, "M", &tb_M); + + zval tb_N; + array_init(&tb_N); + char* th_N_arr[] = {"Ń", "Ñ", "Ň", "Ņ", "Ŋ", "Н", "Ν", "N"}; + for(int i = 0; i < 8; i++) { + add_next_index_string(&tb_N, th_N_arr[i]); + } + add_assoc_zval(&ret, "N", &tb_N); + + zval tb_O; + array_init(&tb_O); + char* th_O_arr[] = {"Ó", "Ò", "Ỏ", "Õ", "Ọ", "Ô", "Ố", "Ồ", "Ổ", "Ỗ", + "Ộ", "Ơ", "Ớ", "Ờ", "Ở", "Ỡ", "Ợ", "Ø", "Ō", "Ő", + "Ŏ", "Ο", "Ό", "Ὀ", "Ὁ", "Ὂ", "Ὃ", "Ὄ", "Ὅ", "Ὸ", + "Ό", "О", "Θ", "Ө", "Ǒ", "Ǿ", "O", "Ö"}; + for(int i = 0; i < 38; i++) { + add_next_index_string(&tb_O, th_O_arr[i]); + } + add_assoc_zval(&ret, "O", &tb_O); + + zval tb_P; + array_init(&tb_P); + char* th_P_arr[] = {"П", "Π", "P"}; + for(int i = 0; i < 3; i++) { + add_next_index_string(&tb_P, th_P_arr[i]); + } + add_assoc_zval(&ret, "P", &tb_P); + + zval tb_Q; + array_init(&tb_Q); + char* th_Q_arr[] = {"Q"}; + for(int i = 0; i < 1; i++) { + add_next_index_string(&tb_Q, th_Q_arr[i]); + } + add_assoc_zval(&ret, "Q", &tb_Q); + + zval tb_R; + array_init(&tb_R); + char* th_R_arr[] = {"Ř", "Ŕ", "Р", "Ρ", "Ŗ", "R"}; + for(int i = 0; i < 6; i++) { + add_next_index_string(&tb_R, th_R_arr[i]); + } + add_assoc_zval(&ret, "R", &tb_R); + + zval tb_S; + array_init(&tb_S); + char* th_S_arr[] = {"Ş", "Ŝ", "Ș", "Š", "Ś", "С", "Σ", "S"}; + for(int i = 0; i < 8; i++) { + add_next_index_string(&tb_S, th_S_arr[i]); + } + add_assoc_zval(&ret, "S", &tb_S); + + zval tb_T; + array_init(&tb_T); + char* th_T_arr[] = {"Ť", "Ţ", "Ŧ", "Ț", "Т", "Τ", "T"}; + for(int i = 0; i < 7; i++) { + add_next_index_string(&tb_T, th_T_arr[i]); + } + add_assoc_zval(&ret, "T", &tb_T); + + zval tb_U; + array_init(&tb_U); + char* th_U_arr[] = {"Ú", "Ù", "Ủ", "Ũ", "Ụ", "Ư", "Ứ", "Ừ", "Ử", "Ữ", + "Ự", "Û", "Ū", "Ů", "Ű", "Ŭ", "Ų", "У", "Ǔ", "Ǖ", + "Ǘ", "Ǚ", "Ǜ", "U", "Ў", "Ü"}; + for(int i = 0; i < 26; i++) { + add_next_index_string(&tb_U, th_U_arr[i]); + } + add_assoc_zval(&ret, "U", &tb_U); + + zval tb_V; + array_init(&tb_V); + char* th_V_arr[] = {"В", "V"}; + for(int i = 0; i < 2; i++) { + add_next_index_string(&tb_V, th_V_arr[i]); + } + add_assoc_zval(&ret, "V", &tb_V); + + zval tb_W; + array_init(&tb_W); + char* th_W_arr[] = {"Ω", "Ώ", "Ŵ", "W"}; + for(int i = 0; i < 4; i++) { + add_next_index_string(&tb_W, th_W_arr[i]); + } + add_assoc_zval(&ret, "W", &tb_W); + + zval tb_X; + array_init(&tb_X); + char* th_X_arr[] = {"Χ", "Ξ", "X"}; + for(int i = 0; i < 3; i++) { + add_next_index_string(&tb_X, th_X_arr[i]); + } + add_assoc_zval(&ret, "X", &tb_X); + + zval tb_Y; + array_init(&tb_Y); + char* th_Y_arr[] = {"Ý", "Ỳ", "Ỷ", "Ỹ", "Ỵ", "Ÿ", "Ῠ", "Ῡ", "Ὺ", "Ύ", + "Ы", "Й", "Υ", "Ϋ", "Ŷ", "Y"}; + for(int i = 0; i < 16; i++) { + add_next_index_string(&tb_Y, th_Y_arr[i]); + } + add_assoc_zval(&ret, "Y", &tb_Y); + + zval tb_Z; + array_init(&tb_Z); + char* th_Z_arr[] = {"Ź", "Ž", "Ż", "З", "Ζ", "Z"}; + for(int i = 0; i < 6; i++) { + add_next_index_string(&tb_Z, th_Z_arr[i]); + } + add_assoc_zval(&ret, "Z", &tb_Z); + + zval tb_AE; + array_init(&tb_AE); + char* th_AE_arr[] = {"Æ", "Ǽ"}; + for(int i = 0; i < 2; i++) { + add_next_index_string(&tb_AE, th_AE_arr[i]); + } + add_assoc_zval(&ret, "AE", &tb_AE); + + zval tb_Ch; + array_init(&tb_Ch); + char* th_Ch_arr[] = {"Ч"}; + for(int i = 0; i < 1; i++) { + add_next_index_string(&tb_Ch, th_Ch_arr[i]); + } + add_assoc_zval(&ret, "Ch", &tb_Ch); + + zval tb_Dj; + array_init(&tb_Dj); + char* th_Dj_arr[] = {"Ђ"}; + for(int i = 0; i < 1; i++) { + add_next_index_string(&tb_Dj, th_Dj_arr[i]); + } + add_assoc_zval(&ret, "Dj", &tb_Dj); + + zval tb_Dz; + array_init(&tb_Dz); + char* th_Dz_arr[] = {"Џ"}; + for(int i = 0; i < 1; i++) { + add_next_index_string(&tb_Dz, th_Dz_arr[i]); + } + add_assoc_zval(&ret, "Dz", &tb_Dz); + + zval tb_Gx; + array_init(&tb_Gx); + char* th_Gx_arr[] = {"Ĝ"}; + for(int i = 0; i < 1; i++) { + add_next_index_string(&tb_Gx, th_Gx_arr[i]); + } + add_assoc_zval(&ret, "Gx", &tb_Gx); + + zval tb_Hx; + array_init(&tb_Hx); + char* th_Hx_arr[] = {"Ĥ"}; + for(int i = 0; i < 1; i++) { + add_next_index_string(&tb_Hx, th_Hx_arr[i]); + } + add_assoc_zval(&ret, "Hx", &tb_Hx); + + zval tb_Ij; + array_init(&tb_Ij); + char* th_Ij_arr[] = {"IJ"}; + for(int i = 0; i < 1; i++) { + add_next_index_string(&tb_Ij, th_Ij_arr[i]); + } + add_assoc_zval(&ret, "Ij", &tb_Ij); + + zval tb_Jx; + array_init(&tb_Jx); + char* th_Jx_arr[] = {"Ĵ"}; + for(int i = 0; i < 1; i++) { + add_next_index_string(&tb_Jx, th_Jx_arr[i]); + } + add_assoc_zval(&ret, "Jx", &tb_Jx); + + zval tb_Kh; + array_init(&tb_Kh); + char* th_Kh_arr[] = {"Х"}; + for(int i = 0; i < 1; i++) { + add_next_index_string(&tb_Kh, th_Kh_arr[i]); + } + add_assoc_zval(&ret, "Kh", &tb_Kh); + + zval tb_Lj; + array_init(&tb_Lj); + char* th_Lj_arr[] = {"Љ"}; + for(int i = 0; i < 1; i++) { + add_next_index_string(&tb_Lj, th_Lj_arr[i]); + } + add_assoc_zval(&ret, "Lj", &tb_Lj); + + zval tb_Nj; + array_init(&tb_Nj); + char* th_Nj_arr[] = {"Њ"}; + for(int i = 0; i < 1; i++) { + add_next_index_string(&tb_Nj, th_Nj_arr[i]); + } + add_assoc_zval(&ret, "Nj", &tb_Nj); + + zval tb_Oe; + array_init(&tb_Oe); + char* th_Oe_arr[] = {"Œ"}; + for(int i = 0; i < 1; i++) { + add_next_index_string(&tb_Oe, th_Oe_arr[i]); + } + add_assoc_zval(&ret, "Oe", &tb_Oe); + + zval tb_Ps; + array_init(&tb_Ps); + char* th_Ps_arr[] = {"Ψ"}; + for(int i = 0; i < 1; i++) { + add_next_index_string(&tb_Ps, th_Ps_arr[i]); + } + add_assoc_zval(&ret, "Ps", &tb_Ps); + + zval tb_Sh; + array_init(&tb_Sh); + char* th_Sh_arr[] = {"Ш"}; + for(int i = 0; i < 1; i++) { + add_next_index_string(&tb_Sh, th_Sh_arr[i]); + } + add_assoc_zval(&ret, "Sh", &tb_Sh); + + zval tb_Shch; + array_init(&tb_Shch); + char* th_Shch_arr[] = {"Щ"}; + for(int i = 0; i < 1; i++) { + add_next_index_string(&tb_Shch, th_Shch_arr[i]); + } + add_assoc_zval(&ret, "Shch", &tb_Shch); + + zval tb_Ss; + array_init(&tb_Ss); + char* th_Ss_arr[] = {"ẞ"}; + for(int i = 0; i < 1; i++) { + add_next_index_string(&tb_Ss, th_Ss_arr[i]); + } + add_assoc_zval(&ret, "Ss", &tb_Ss); + + zval tb_Th; + array_init(&tb_Th); + char* th_Th_arr[] = {"Þ"}; + for(int i = 0; i < 1; i++) { + add_next_index_string(&tb_Th, th_Th_arr[i]); + } + add_assoc_zval(&ret, "Th", &tb_Th); + + zval tb_Ts; + array_init(&tb_Ts); + char* th_Ts_arr[] = {"Ц"}; + for(int i = 0; i < 1; i++) { + add_next_index_string(&tb_Ts, th_Ts_arr[i]); + } + add_assoc_zval(&ret, "Ts", &tb_Ts); + + zval tb_Ya; + array_init(&tb_Ya); + char* th_Ya_arr[] = {"Я"}; + for(int i = 0; i < 1; i++) { + add_next_index_string(&tb_Ya, th_Ya_arr[i]); + } + add_assoc_zval(&ret, "Ya", &tb_Ya); + + zval tb_Yu; + array_init(&tb_Yu); + char* th_Yu_arr[] = {"Yu"}; + for(int i = 0; i < 1; i++) { + add_next_index_string(&tb_Yu, th_Yu_arr[i]); + } + add_assoc_zval(&ret, "Yu", &tb_Yu); + + zval tb_Zh; + array_init(&tb_Zh); + char* th_Zh_arr[] = {"Ж"}; + for(int i = 0; i < 1; i++) { + add_next_index_string(&tb_Zh, th_Zh_arr[i]); + } + add_assoc_zval(&ret, "Zh", &tb_Zh); + + zval tb_empty; + array_init(&tb_empty); + char* th_empty_arr[] = {"\xC2\xA0", "\xE2\x80\x80", "\xE2\x80\x81", + "\xE2\x80\x82", "\xE2\x80\x83", "\xE2\x80\x84", + "\xE2\x80\x85", "\xE2\x80\x86", "\xE2\x80\x87", + "\xE2\x80\x88", "\xE2\x80\x89", "\xE2\x80\x8A", + "\xE2\x80\xAF", "\xE2\x81\x9F", "\xE3\x80\x80", + "\xEF\xBE\xA0"}; + for(int i = 0; i < 16; i++) { + add_next_index_string(&tb_empty, th_empty_arr[i]); + } + add_assoc_zval(&ret, " ", &tb_empty); + + RETURN_ZVAL(&ret, 0, 0); +} + +PHP_METHOD(Stringy, langSpecificCharsArray) +{ + zval *language; + ZEND_PARSE_PARAMETERS_START(0, 1) + Z_PARAM_OPTIONAL + Z_PARAM_ZVAL(language) + ZEND_PARSE_PARAMETERS_END(); + + if (language == NULL) { + language = malloc(sizeof(zval)); + ZVAL_STRING(language, "en"); + } + + zval reg; + ZVAL_STRING(®, "/[-_]/"); + zval func, args[] = { + reg, + *language, + }; + ZVAL_STRING(&func, "preg_split"); + call_user_function(NULL, NULL, &func, return_value, 2, args); + + zval args_strtolower[] = { + *zend_hash_index_find(Z_ARRVAL_P(return_value), (zend_long) 0), + }; + ZVAL_STRING(&func, "strtolower"); + call_user_function(NULL, NULL, &func, return_value, 1, args_strtolower); + + zval languageSpecific; + array_init(&languageSpecific); + + zval tb_0; + array_init(&tb_0); + char* th_0_arr[6] = {"ä", "ö", "ü", "Ä", "Ö", "Ü"}; + for(int i = 0; i < 6; i++) { + add_next_index_string(&tb_0, th_0_arr[i]); + } + + zval tb_1; + array_init(&tb_1); + char* th_1_arr[6] = {"ae", "oe", "ue", "AE", "OE", "UE"}; + for(int i = 0; i < 6; i++) { + add_next_index_string(&tb_1, th_1_arr[i]); + } + + zval val_0; + array_init(&val_0); + add_next_index_zval(&val_0, &tb_0); + add_next_index_zval(&val_0, &tb_1); + + add_assoc_zval(&languageSpecific, "de", &val_0); + + zval tb_1_0; + array_init(&tb_1_0); + char* th_1_0_arr[8] = {"х", "Х", "щ", "Щ", "ъ", "Ъ", "ь", "Ь"}; + for(int i = 0; i < 8; i++) { + add_next_index_string(&tb_1_0, th_1_0_arr[i]); + } + + zval tb_1_1; + array_init(&tb_1_1); + char* th_1_1_arr[8] = {"h", "H", "sht", "SHT", "a", "А", "y", "Y"}; + for(int i = 0; i < 8; i++) { + add_next_index_string(&tb_1_1, th_1_1_arr[i]); + } + + zval val_1; + array_init(&val_1); + add_next_index_zval(&val_1, &tb_0); + add_next_index_zval(&val_1, &tb_1); + + add_assoc_zval(&languageSpecific, "bg", &val_1); + + zval ret; + zend_string *key = Z_STR_P(return_value); + if (zend_hash_exists(Z_ARRVAL(languageSpecific), key)) { + ret = *zend_hash_find(Z_ARR(languageSpecific), key); + } else { + array_init(&ret); + } + + RETURN_ZVAL(&ret, 0, 1); +} +ZEND_BEGIN_ARG_INFO(arginfo_langSpecificCharsArray, 0) + ZEND_ARG_INFO(0, language) +ZEND_END_ARG_INFO(); + + static zend_function_entry methods[] = { PHP_ME(Stringy, __construct, arginfo___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) PHP_ME(Stringy, __toString, NULL, ZEND_ACC_PUBLIC) @@ -3027,6 +4166,9 @@ static zend_function_entry methods[] = { PHP_ME(Stringy, applyPadding, arginfo_applyPadding, ZEND_ACC_PUBLIC) PHP_ME(Stringy, repeat, arginfo_repeat, ZEND_ACC_PUBLIC) PHP_ME(Stringy, replace, arginfo_replace, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, toAscii, arginfo_toAscii, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, charsArray, NULL, ZEND_ACC_PROTECTED) + PHP_ME(Stringy, langSpecificCharsArray, arginfo_langSpecificCharsArray, ZEND_ACC_PROTECTED) PHP_FE_END }; diff --git a/startup.php b/startup.php index 3ef19e8..8bb7294 100644 --- a/startup.php +++ b/startup.php @@ -5,47 +5,7 @@ include __DIR__.'/vendor/autoload.php'; - $function = 'confirm_'.$module.'_compiled'; - if (extension_loaded($module)) { - $str = $function($module); - } else { - $str = "Module $module is not compiled into PHP"; - } - echo "$str\n"; -} +_ns(NS_STRINGY); -function handleClass() -{ - if (class_exists('myclass')) { - echo 'myclass exists'; - } else { - echo 'myclass exists'; - } - $class = new myclass(); - var_dump($class); - $class->abab(); -} - -function checkExt() -{ - global $br, $module; - if (!extension_loaded('startup')) { - dl('startup.'.PHP_SHLIB_SUFFIX); - } - $module = 'startup'; - $functions = get_extension_funcs($module); - echo "Functions available in the test extension:$br\n"; - foreach ($functions as $func) { - echo $func."$br\n"; - } - echo "$br\n"; -} - -function main() -{ - $instance = new Minbaby\Ext\Test(); - echo $instance->xab(); -} - -main(); +__('Stringy')::create("afdsafsd")->toAscii(); \ No newline at end of file diff --git a/thirdParty/rxi-log/LICENSE b/thirdParty/rxi-log/LICENSE deleted file mode 100644 index 7e3bf17..0000000 --- a/thirdParty/rxi-log/LICENSE +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2017 rxi - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/thirdParty/rxi-log/README.md b/thirdParty/rxi-log/README.md deleted file mode 100644 index a5b7e88..0000000 --- a/thirdParty/rxi-log/README.md +++ /dev/null @@ -1,70 +0,0 @@ -# log.c -A simple logging library implemented in C99 - -![screenshot](https://cloud.githubusercontent.com/assets/3920290/23831970/a2415e96-0723-11e7-9886-f8f5d2de60fe.png) - - -## Usage -**[log.c](src/log.c?raw=1)** and **[log.h](src/log.h?raw=1)** should be dropped -into an existing project and compiled along with it. The library provides 6 -function-like macros for logging: - -```c -log_trace(const char *fmt, ...); -log_debug(const char *fmt, ...); -log_info(const char *fmt, ...); -log_warn(const char *fmt, ...); -log_error(const char *fmt, ...); -log_fatal(const char *fmt, ...); -``` - -Each function takes a printf format string followed by additional arguments: - -```c -log_trace("Hello %s", "world") -``` - -Resulting in a line with the given format printed to stderr: - -``` -20:18:26 TRACE src/main.c:11: Hello world -``` - - -#### log_set_quiet(int enable) -Quiet-mode can be enabled by passing `1` to the `log_set_quiet()` function. -While this mode is enabled the library will not output anything to stderr, but -will continue to write to the file if one is set. - - -#### log_set_level(int level) -The current logging level can be set by using the `log_set_level()` function. -All logs below the given level will be ignored. By default the level is -`LOG_TRACE`, such that nothing is ignored. - - -#### log_set_fp(FILE *fp) -A file pointer where the log should be written can be provided to the library by -using the `log_set_fp()` function. The data written to the file output is -of the following format: - -``` -2047-03-11 20:18:26 TRACE src/main.c:11: Hello world -``` - - -#### log_set_lock(log_LockFn fn) -If the log will be written to from multiple threads a lock function can be set. -The function is passed a `udata` value (set by `log_set_udata()`) and the -integer `1` if the lock should be acquired or `0` if the lock should be -released. - - -#### LOG_USE_COLOR -If the library is compiled with `-DLOG_USE_COLOR` ANSI color escape codes will -be used when printing. - - -## License -This library is free software; you can redistribute it and/or modify it under -the terms of the MIT license. See [LICENSE](LICENSE) for details. diff --git a/thirdParty/rxi-log/src/log.c b/thirdParty/rxi-log/src/log.c deleted file mode 100644 index 2e183b0..0000000 --- a/thirdParty/rxi-log/src/log.c +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (c) 2017 rxi - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -#include -#include -#include -#include -#include - -#include "log.h" - -static struct { - void *udata; - log_LockFn lock; - FILE *fp; - int level; - int quiet; -} L; - - -static const char *level_names[] = { - "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL" -}; - -#ifdef LOG_USE_COLOR -static const char *level_colors[] = { - "\x1b[94m", "\x1b[36m", "\x1b[32m", "\x1b[33m", "\x1b[31m", "\x1b[35m" -}; -#endif - - -static void lock(void) { - if (L.lock) { - L.lock(L.udata, 1); - } -} - - -static void unlock(void) { - if (L.lock) { - L.lock(L.udata, 0); - } -} - - -void log_set_udata(void *udata) { - L.udata = udata; -} - - -void log_set_lock(log_LockFn fn) { - L.lock = fn; -} - - -void log_set_fp(FILE *fp) { - L.fp = fp; -} - - -void log_set_level(int level) { - L.level = level; -} - - -void log_set_quiet(int enable) { - L.quiet = enable ? 1 : 0; -} - - -void log_log(int level, const char *file, int line, const char *fmt, ...) { - if (level < L.level) { - return; - } - - /* Acquire lock */ - lock(); - - /* Get current time */ - time_t t = time(NULL); - struct tm *lt = localtime(&t); - - /* Log to stderr */ - if (!L.quiet) { - va_list args; - char buf[16]; - buf[strftime(buf, sizeof(buf), "%H:%M:%S", lt)] = '\0'; -#ifdef LOG_USE_COLOR - fprintf( - stderr, "%s %s%-5s\x1b[0m \x1b[90m%s:%d:\x1b[0m ", - buf, level_colors[level], level_names[level], file, line); -#else - fprintf(stderr, "%s %-5s %s:%d: ", buf, level_names[level], file, line); -#endif - va_start(args, fmt); - vfprintf(stderr, fmt, args); - va_end(args); - fprintf(stderr, "\n"); - fflush(stderr); - } - - /* Log to file */ - if (L.fp) { - va_list args; - char buf[32]; - buf[strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", lt)] = '\0'; - fprintf(L.fp, "%s %-5s %s:%d: ", buf, level_names[level], file, line); - va_start(args, fmt); - vfprintf(L.fp, fmt, args); - va_end(args); - fprintf(L.fp, "\n"); - fflush(L.fp); - } - - /* Release lock */ - unlock(); -} diff --git a/thirdParty/rxi-log/src/log.h b/thirdParty/rxi-log/src/log.h deleted file mode 100644 index 77bf087..0000000 --- a/thirdParty/rxi-log/src/log.h +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Copyright (c) 2017 rxi - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the MIT license. See `log.c` for details. - */ - -#ifndef LOG_H -#define LOG_H - -#include -#include - -#define LOG_VERSION "0.1.0" - -typedef void (*log_LockFn)(void *udata, int lock); - -enum { EXT_LOG_TRACE, EXT_LOG_DEBUG, EXT_LOG_INFO, EXT_LOG_WARN, EXT_LOG_ERROR, EXT_LOG_FATAL }; - -#define log_trace(...) log_log(EXT_LOG_TRACE, __FILE__, __LINE__, __VA_ARGS__) -#define log_debug(...) log_log(EXT_LOG_DEBUG, __FILE__, __LINE__, __VA_ARGS__) -#define log_info(...) log_log(EXT_LOG_INFO, __FILE__, __LINE__, __VA_ARGS__) -#define log_warn(...) log_log(EXT_LOG_WARN, __FILE__, __LINE__, __VA_ARGS__) -#define log_error(...) log_log(EXT_LOG_ERROR, __FILE__, __LINE__, __VA_ARGS__) -#define log_fatal(...) log_log(EXT_LOG_FATAL, __FILE__, __LINE__, __VA_ARGS__) - -void log_set_udata(void *udata); -void log_set_lock(log_LockFn fn); -void log_set_fp(FILE *fp); -void log_set_level(int level); -void log_set_quiet(int enable); - -void log_log(int level, const char *file, int line, const char *fmt, ...); - -#endif From 98dc4c0e3c0ae9238860ecd3c74afc1590b22910 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Wed, 8 May 2019 20:46:15 +0800 Subject: [PATCH 098/126] toSpaces (#59) --- spec/Stringy/StringySpec.php | 25 +++++++++++ src/Minbaby/Php/Stringy/Stringy.php | 7 ++++ src/ext/stringy/stringy.c | 64 +++++++++++++++++++++++++---- startup.php | 2 +- 4 files changed, 89 insertions(+), 9 deletions(-) diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index bb64978..d4431be 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -1755,4 +1755,29 @@ }); } }); + + context('test toSpaces', function () { + $data = [ + [' foo bar ', ' foo bar '], + [' foo bar ', ' foo bar ', 5], + [' foo bar ', ' foo bar ', 2], + ['foobar', ' foo bar ', 0], + [" foo\n bar", " foo\n bar"], + [" fòô\n bàř", " fòô\n bàř"] + ]; + + foreach ($data as $key => $value) { + it(__formatMessage($key, $value), function () use ($value) { + @list($expected, $str, $tabLength) = $value; + $tabLength = $tabLength ?? 4; + + $stringy = __('Stringy')::create($str); + $result = $stringy->toSpaces($tabLength); + + \expect($stringy)->toBeAnInstanceOf(__('Stringy')); + \expect((string) $stringy)->toBe($str); + \expect((string) $result)->toBe($expected); + }); + } + }); }); diff --git a/src/Minbaby/Php/Stringy/Stringy.php b/src/Minbaby/Php/Stringy/Stringy.php index 24b3838..21656e1 100644 --- a/src/Minbaby/Php/Stringy/Stringy.php +++ b/src/Minbaby/Php/Stringy/Stringy.php @@ -950,4 +950,11 @@ protected function charsArray() "\xEF\xBE\xA0"], ]; } + + public function toSpaces($tabLength = 4) + { + $spaces = str_repeat(' ', $tabLength); + $str = str_replace("\t", $spaces, $this->str); + return static::create($str, $this->encoding); + } } diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index 539e16c..577afa8 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -2252,13 +2252,13 @@ PHP_METHOD(Stringy, isJson) PHP_METHOD(Stringy, isSerialized) { - zval empty_object_serialized; - ZVAL_STRING(&empty_object_serialized, "b:0;"); + zval str_object_serialized; + ZVAL_STRING(&str_object_serialized, "b:0;"); zval rv; zval *str = zend_read_property(stringy_ce, getThis(), ZEND_STRL("str"), 0, &rv); - if (Z_TYPE_P(str) == Z_TYPE(empty_object_serialized) && Z_STR_P(str) == Z_STR(empty_object_serialized)) + if (Z_TYPE_P(str) == Z_TYPE(str_object_serialized) && Z_STR_P(str) == Z_STR(str_object_serialized)) { RETURN_TRUE; } @@ -3988,18 +3988,18 @@ PHP_METHOD(Stringy, charsArray) } add_assoc_zval(&ret, "Zh", &tb_Zh); - zval tb_empty; - array_init(&tb_empty); - char* th_empty_arr[] = {"\xC2\xA0", "\xE2\x80\x80", "\xE2\x80\x81", + zval tb_str; + array_init(&tb_str); + char* th_str_arr[] = {"\xC2\xA0", "\xE2\x80\x80", "\xE2\x80\x81", "\xE2\x80\x82", "\xE2\x80\x83", "\xE2\x80\x84", "\xE2\x80\x85", "\xE2\x80\x86", "\xE2\x80\x87", "\xE2\x80\x88", "\xE2\x80\x89", "\xE2\x80\x8A", "\xE2\x80\xAF", "\xE2\x81\x9F", "\xE3\x80\x80", "\xEF\xBE\xA0"}; for(int i = 0; i < 16; i++) { - add_next_index_string(&tb_empty, th_empty_arr[i]); + add_next_index_string(&tb_str, th_str_arr[i]); } - add_assoc_zval(&ret, " ", &tb_empty); + add_assoc_zval(&ret, " ", &tb_str); RETURN_ZVAL(&ret, 0, 0); } @@ -4091,6 +4091,53 @@ ZEND_BEGIN_ARG_INFO(arginfo_langSpecificCharsArray, 0) ZEND_ARG_INFO(0, language) ZEND_END_ARG_INFO(); +PHP_METHOD(Stringy, toSpaces) +{ + zval * tabLength; + ZEND_PARSE_PARAMETERS_START(0, 1) + Z_PARAM_ZVAL(tabLength) + ZEND_PARSE_PARAMETERS_END(); + + zval rv; + zval * str = zend_read_property(stringy_ce, getThis(), ZEND_STRL("str"), 0, &rv); + zval * encoding = zend_read_property(stringy_ce, getThis(), ZEND_STRL("encoding"), 1, &rv); + + zval tmp_str; + ZVAL_STRING(&tmp_str, " "); + + convert_to_long(tabLength); + zval func, args[] = { + tmp_str, + *tabLength, + }; + ZVAL_STRING(&func, "str_repeat"); + call_user_function(NULL, NULL, &func, return_value, 2, args); + + ZVAL_STRING(&tmp_str, "\t"); + zval args_str_replace[] = { + tmp_str, + *return_value, + *str, + }; + ZVAL_STRING(&func, "str_replace"); + call_user_function(NULL, NULL, &func, return_value, 3, args_str_replace); + + zval instance; + object_init_ex(&instance, stringy_ce); + + zval args_construct[] = { + *return_value, + *encoding, + }; + ZVAL_STRING(&func, "__construct"); + call_user_function(NULL, &instance, &func, return_value, 2, args_construct); + + RETURN_ZVAL(&instance, 0, 1); +} +ZEND_BEGIN_ARG_INFO(arginfo_toSpaces, 0) + ZEND_ARG_INFO(0, tabLength) +ZEND_END_ARG_INFO(); + static zend_function_entry methods[] = { PHP_ME(Stringy, __construct, arginfo___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) @@ -4169,6 +4216,7 @@ static zend_function_entry methods[] = { PHP_ME(Stringy, toAscii, arginfo_toAscii, ZEND_ACC_PUBLIC) PHP_ME(Stringy, charsArray, NULL, ZEND_ACC_PROTECTED) PHP_ME(Stringy, langSpecificCharsArray, arginfo_langSpecificCharsArray, ZEND_ACC_PROTECTED) + PHP_ME(Stringy, toSpaces, arginfo_toSpaces, ZEND_ACC_PUBLIC) PHP_FE_END }; diff --git a/startup.php b/startup.php index 8bb7294..ac4408e 100644 --- a/startup.php +++ b/startup.php @@ -8,4 +8,4 @@ _ns(NS_STRINGY); -__('Stringy')::create("afdsafsd")->toAscii(); \ No newline at end of file +echo __('Stringy')::create("afds\tafsd")->toSpaces(); From d3abc6169087653a4a165933b5e336dc9182cda8 Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Sun, 12 May 2019 13:12:56 +0800 Subject: [PATCH 099/126] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ext/stringy/stringy.c | 1135 +++++++------------------------------ src/ext/stringy/stringy.h | 4 + 2 files changed, 194 insertions(+), 945 deletions(-) diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index 577afa8..59db5cf 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -2,8 +2,8 @@ zend_class_entry *stringy_ce; -// @TODO: 这个地方似乎用法有问题,全是动态调用本类的方法,这个思路是是面向对象的用法,理论上这个地方应该把公用的地方提取成公共方法。 -// @TODO: 先把这个写完,然后去学习一下其他项目,然后再来优化这个地方的代码,先跑起来 +// @TODO: 这个地方似乎用法有问题,全是动态调用本类的方法,这个思路是是面向对象的用法,理论上这个地方应该把公用的地方提取成公共方法。 +// @TODO: 先把这个写完,然后去学习一下其他项目,然后再来优化这个地方的代码,先跑起来 ///* don't forget to free the zvals */ //zval_ptr_dtor(&retval_ptr); //zval_dtor(&function_name); @@ -75,7 +75,7 @@ PHP_METHOD(Stringy, __construct) encoding = ""; } - // 这里需要加一下了逻辑, 如果这里需要判断 encoding 是否支持, 不支持话,就用默认的编码 + // 这里需要加一下了逻辑, 如果这里需要判断 encoding 是否支持, 不支持话,就用默认的编码 ZVAL_STRING(&func, "mb_list_encodings"); call_user_function(NULL, NULL, &func, return_value, 0, NULL); @@ -198,7 +198,7 @@ ZEND_ARG_INFO(0, offset) ZEND_END_ARG_INFO() /*{{{ int indexOf($needle, $offset = 0) - TODO: 这个和上个重复率太高,暂时不知道怎么优化 + TODO: 这个和上个重复率太高,暂时不知道怎么优化 }}}*/ PHP_METHOD(Stringy, indexOf) { @@ -949,7 +949,7 @@ static void preg_replace_callback_handler(INTERNAL_FUNCTION_PARAMETERS) zval *first = zend_hash_index_find(Z_ARRVAL_P(arr), 1); // php_var_dump(arr, 1); // php_var_dump(first, 1); - //TODO: 不知道这里如何模拟 php 里边的use, 这里先写死了 + //TODO: 不知道这里如何模拟 php 里边的use, 这里先写死了 zval encoding; ZVAL_STRING(&encoding, "UTF-8"); zval func, args[] = { @@ -974,7 +974,7 @@ static void preg_replace_callback_2_handler(INTERNAL_FUNCTION_PARAMETERS) zval *first = zend_hash_index_find(Z_ARRVAL_P(arr), 0); - //TODO: 不知道这里如何模拟 php 里边的use, 这里先写死了 + //TODO: 不知道这里如何模拟 php 里边的use, 这里先写死了 zval encoding; ZVAL_STRING(&encoding, "UTF-8"); zval func, args[] = { @@ -3055,951 +3055,196 @@ PHP_METHOD(Stringy, charsArray) { zval ret; array_init(&ret); - - zval tb_0; - array_init(&tb_0); - char* th_0_arr[] = {"°", "₀", "۰", "0"}; - for(int i = 0; i < 4; i++) { - add_next_index_string(&tb_0, th_0_arr[i]); - } - add_assoc_zval(&ret, "0", &tb_0); - - zval tb_1; - array_init(&tb_1); - char* th_1_arr[] = {"¹", "₁", "۱", "1"}; - for(int i = 0; i < 4; i++) { - add_next_index_string(&tb_1, th_1_arr[i]); - } - add_assoc_zval(&ret, "1", &tb_1); - - zval tb_2; - array_init(&tb_2); - char* th_2_arr[] = {"²", "₂", "۲", "2"}; - for(int i = 0; i < 4; i++) { - add_next_index_string(&tb_2, th_2_arr[i]); - } - add_assoc_zval(&ret, "2", &tb_2); - - zval tb_3; - array_init(&tb_3); - char* th_3_arr[] = {"³", "₃", "۳", "3"}; - for(int i = 0; i < 4; i++) { - add_next_index_string(&tb_3, th_3_arr[i]); - } - add_assoc_zval(&ret, "3", &tb_3); - - zval tb_4; - array_init(&tb_4); - char* th_4_arr[] = {"⁴", "₄", "۴", "٤", "4"}; - for(int i = 0; i < 5; i++) { - add_next_index_string(&tb_4, th_4_arr[i]); - } - add_assoc_zval(&ret, "4", &tb_4); - - zval tb_5; - array_init(&tb_5); - char* th_5_arr[] = {"⁵", "₅", "۵", "٥", "5"}; - for(int i = 0; i < 5; i++) { - add_next_index_string(&tb_5, th_5_arr[i]); - } - add_assoc_zval(&ret, "5", &tb_5); - - zval tb_6; - array_init(&tb_6); - char* th_6_arr[] = {"⁶", "₆", "۶", "٦", "6"}; - for(int i = 0; i < 5; i++) { - add_next_index_string(&tb_6, th_6_arr[i]); - } - add_assoc_zval(&ret, "5", &tb_6); - - zval tb_7; - array_init(&tb_7); - char* th_7_arr[] = {"⁷", "₇", "۷", "7"}; - for(int i = 0; i < 4; i++) { - add_next_index_string(&tb_7, th_7_arr[i]); - } - add_assoc_zval(&ret, "7", &tb_7); - - zval tb_8; - array_init(&tb_8); - char* th_8_arr[] = {"⁸", "₈", "۸", "8"}; - for(int i = 0; i < 4; i++) { - add_next_index_string(&tb_8, th_8_arr[i]); - } - add_assoc_zval(&ret, "8", &tb_8); - - zval tb_9; - array_init(&tb_9); - char* th_9_arr[] = {"⁹", "₉", "۹", "9"}; - for(int i = 0; i < 4; i++) { - add_next_index_string(&tb_9, th_9_arr[i]); - } - add_assoc_zval(&ret, "9", &tb_9); - - zval tb_a; - array_init(&tb_a); - char* th_a_arr[] = {"à", "á", "ả", "ã", "ạ", "ă", "ắ", "ằ", "ẳ", "ẵ", - "ặ", "â", "ấ", "ầ", "ẩ", "ẫ", "ậ", "ā", "ą", "å", - "α", "ά", "ἀ", "ἁ", "ἂ", "ἃ", "ἄ", "ἅ", "ἆ", "ἇ", - "ᾀ", "ᾁ", "ᾂ", "ᾃ", "ᾄ", "ᾅ", "ᾆ", "ᾇ", "ὰ", "ά", - "ᾰ", "ᾱ", "ᾲ", "ᾳ", "ᾴ", "ᾶ", "ᾷ", "а", "أ", "အ", - "ာ", "ါ", "ǻ", "ǎ", "ª", "ა", "अ", "ا", "a", "ä"}; - for(int i = 0; i < 60; i++) { - add_next_index_string(&tb_a, th_a_arr[i]); - } - add_assoc_zval(&ret, "a", &tb_a); - - zval tb_b; - array_init(&tb_b); - char* th_b_arr[] = {"б", "β", "ب", "ဗ", "ბ", "b"}; - for(int i = 0; i < 6; i++) { - add_next_index_string(&tb_b, th_b_arr[i]); - } - add_assoc_zval(&ret, "b", &tb_b); - - zval tb_c; - array_init(&tb_c); - char* th_c_arr[] = {"ç", "ć", "č", "ĉ", "ċ", "c"}; - for(int i = 0; i < 6; i++) { - add_next_index_string(&tb_c, th_c_arr[i]); - } - add_assoc_zval(&ret, "c", &tb_c); - - zval tb_d; - array_init(&tb_d); - char* th_d_arr[] = {"ď", "ð", "đ", "ƌ", "ȡ", "ɖ", "ɗ", "ᵭ", "ᶁ", "ᶑ", - "д", "δ", "د", "ض", "ဍ", "ဒ", "დ", "d"}; - for(int i = 0; i < 18; i++) { - add_next_index_string(&tb_d, th_d_arr[i]); - } - add_assoc_zval(&ret, "d", &tb_d); - - zval tb_e; - array_init(&tb_e); - char* th_e_arr[] = {"é", "è", "ẻ", "ẽ", "ẹ", "ê", "ế", "ề", "ể", "ễ", - "ệ", "ë", "ē", "ę", "ě", "ĕ", "ė", "ε", "έ", "ἐ", - "ἑ", "ἒ", "ἓ", "ἔ", "ἕ", "ὲ", "έ", "е", "ё", "э", - "є", "ə", "ဧ", "ေ", "ဲ", "ე", "ए", "إ", "ئ", "e"}; - for(int i = 0; i < 40; i++) { - add_next_index_string(&tb_e, th_e_arr[i]); - } - add_assoc_zval(&ret, "e", &tb_e); - - zval tb_f; - array_init(&tb_f); - char* th_f_arr[] = {"ф", "φ", "ف", "ƒ", "ფ", "f"}; - for(int i = 0; i < 6; i++) { - add_next_index_string(&tb_f, th_f_arr[i]); - } - add_assoc_zval(&ret, "f", &tb_f); - - zval tb_g; - array_init(&tb_g); - char* th_g_arr[] = {"ĝ", "ğ", "ġ", "ģ", "г", "ґ", "γ", "ဂ", "გ", "گ", - "g"}; - for(int i = 0; i < 11; i++) { - add_next_index_string(&tb_g, th_g_arr[i]); - } - add_assoc_zval(&ret, "g", &tb_g); - - zval tb_h; - array_init(&tb_h); - char* th_h_arr[] = {"ĥ", "ħ", "η", "ή", "ح", "ه", "ဟ", "ှ", "ჰ", "h"}; - for(int i = 0; i < 10; i++) { - add_next_index_string(&tb_h, th_h_arr[i]); - } - add_assoc_zval(&ret, "h", &tb_h); - - zval tb_i; - array_init(&tb_i); - char* th_i_arr[] = {"í", "ì", "ỉ", "ĩ", "ị", "î", "ï", "ī", "ĭ", "į", - "ı", "ι", "ί", "ϊ", "ΐ", "ἰ", "ἱ", "ἲ", "ἳ", "ἴ", - "ἵ", "ἶ", "ἷ", "ὶ", "ί", "ῐ", "ῑ", "ῒ", "ΐ", "ῖ", - "ῗ", "і", "ї", "и", "ဣ", "ိ", "ီ", "ည်", "ǐ", "ი", - "इ", "ی", "i"}; - for(int i = 0; i < 43; i++) { - add_next_index_string(&tb_i, th_i_arr[i]); - } - add_assoc_zval(&ret, "i", &tb_i); - - zval tb_j; - array_init(&tb_j); - char* th_j_arr[] = {"ĵ", "ј", "Ј", "ჯ", "ج", "j"}; - for(int i = 0; i < 6; i++) { - add_next_index_string(&tb_j, th_j_arr[i]); - } - add_assoc_zval(&ret, "j", &tb_j); - - zval tb_k; - array_init(&tb_k); - char* th_k_arr[] = {"ķ", "ĸ", "к", "κ", "Ķ", "ق", "ك", "က", "კ", "ქ", - "ک", "k"}; - for(int i = 0; i < 12; i++) { - add_next_index_string(&tb_k, th_k_arr[i]); - } - add_assoc_zval(&ret, "k", &tb_k); - - zval tb_l; - array_init(&tb_l); - char* th_l_arr[] = {"ł", "ľ", "ĺ", "ļ", "ŀ", "л", "λ", "ل", "လ", "ლ", - "l"}; - for(int i = 0; i < 11; i++) { - add_next_index_string(&tb_l, th_l_arr[i]); - } - add_assoc_zval(&ret, "l", &tb_l); - - zval tb_m; - array_init(&tb_m); - char* th_m_arr[] = {"м", "μ", "م", "မ", "მ", "m"}; - for(int i = 0; i < 6; i++) { - add_next_index_string(&tb_m, th_m_arr[i]); - } - add_assoc_zval(&ret, "m", &tb_m); - - zval tb_n; - array_init(&tb_n); - char* th_n_arr[] = {"ñ", "ń", "ň", "ņ", "ʼn", "ŋ", "ν", "н", "ن", "န", - "ნ", "n"}; - for(int i = 0; i < 12; i++) { - add_next_index_string(&tb_n, th_n_arr[i]); - } - add_assoc_zval(&ret, "n", &tb_n); - - zval tb_o; - array_init(&tb_o); - char* th_o_arr[] = {"ó", "ò", "ỏ", "õ", "ọ", "ô", "ố", "ồ", "ổ", "ỗ", - "ộ", "ơ", "ớ", "ờ", "ở", "ỡ", "ợ", "ø", "ō", "ő", - "ŏ", "ο", "ὀ", "ὁ", "ὂ", "ὃ", "ὄ", "ὅ", "ὸ", "ό", - "о", "و", "θ", "ို", "ǒ", "ǿ", "º", "ო", "ओ", "o", - "ö"}; - for(int i = 0; i < 41; i++) { - add_next_index_string(&tb_o, th_o_arr[i]); - } - add_assoc_zval(&ret, "o", &tb_o); - - zval tb_p; - array_init(&tb_p); - char* th_p_arr[] = {"п", "π", "ပ", "პ", "پ", "p"}; - for(int i = 0; i < 6; i++) { - add_next_index_string(&tb_p, th_p_arr[i]); - } - add_assoc_zval(&ret, "p", &tb_p); - - zval tb_q; - array_init(&tb_q); - char* th_q_arr[] = {"ყ", "q"}; - for(int i = 0; i < 2; i++) { - add_next_index_string(&tb_q, th_q_arr[i]); - } - add_assoc_zval(&ret, "q", &tb_q); - zval tb_r; - array_init(&tb_r); - char* th_r_arr[] = {"ŕ", "ř", "ŗ", "р", "ρ", "ر", "რ", "r"}; - for(int i = 0; i < 8; i++) { - add_next_index_string(&tb_r, th_r_arr[i]); - } - add_assoc_zval(&ret, "r", &tb_r); - - zval tb_s; - array_init(&tb_s); - char* th_s_arr[] = {"ś", "š", "ş", "с", "σ", "ș", "ς", "س", "ص", "စ", - "ſ", "ს", "s"}; - for(int i = 0; i < 13; i++) { - add_next_index_string(&tb_s, th_s_arr[i]); - } - add_assoc_zval(&ret, "s", &tb_s); - - zval tb_tt; - array_init(&tb_tt); - char* th_t_arr[] = {"ť", "ţ", "т", "τ", "ț", "ت", "ط", "ဋ", "တ", "ŧ", - "თ", "ტ", "t"}; - for(int i = 0; i < 13; i++) { - add_next_index_string(&tb_tt, th_t_arr[i]); - } - add_assoc_zval(&ret, "t", &tb_tt); - - zval tb_u; - array_init(&tb_u); - char* th_u_arr[] = {"ú", "ù", "ủ", "ũ", "ụ", "ư", "ứ", "ừ", "ử", "ữ", - "ự", "û", "ū", "ů", "ű", "ŭ", "ų", "µ", "у", "ဉ", - "ု", "ူ", "ǔ", "ǖ", "ǘ", "ǚ", "ǜ", "უ", "उ", "u", - "ў", "ü"}; - for(int i = 0; i < 32; i++) { - add_next_index_string(&tb_u, th_u_arr[i]); - } - add_assoc_zval(&ret, "u", &tb_u); - - zval tb_v; - array_init(&tb_v); - char* th_v_arr[] = {"в", "ვ", "ϐ", "v"}; - for(int i = 0; i < 4; i++) { - add_next_index_string(&tb_v, th_v_arr[i]); - } - add_assoc_zval(&ret, "v", &tb_v); - - zval tb_w; - array_init(&tb_w); - char* th_w_arr[] = {"ŵ", "ω", "ώ", "ဝ", "ွ", "w"}; - for(int i = 0; i < 6; i++) { - add_next_index_string(&tb_w, th_w_arr[i]); - } - add_assoc_zval(&ret, "w", &tb_w); - - zval tb_x; - array_init(&tb_x); - char* th_x_arr[] = {"χ", "ξ", "x"}; - for(int i = 0; i < 3; i++) { - add_next_index_string(&tb_x, th_x_arr[i]); - } - add_assoc_zval(&ret, "x", &tb_x); - - zval tb_y; - array_init(&tb_y); - char* th_y_arr[] = {"ý", "ỳ", "ỷ", "ỹ", "ỵ", "ÿ", "ŷ", "й", "ы", "υ", - "ϋ", "ύ", "ΰ", "ي", "ယ", "y"}; - for(int i = 0; i < 16; i++) { - add_next_index_string(&tb_y, th_y_arr[i]); - } - add_assoc_zval(&ret, "y", &tb_y); - - zval tb_z; - array_init(&tb_z); - char* th_z_arr[] = {"ź", "ž", "ż", "з", "ζ", "ز", "ဇ", "ზ", "z"}; - for(int i = 0; i < 9; i++) { - add_next_index_string(&tb_z, th_z_arr[i]); - } - add_assoc_zval(&ret, "z", &tb_z); - - zval tb_aa; - array_init(&tb_aa); - char* th_aa_arr[] = {"ع", "आ", "آ"}; - for(int i = 0; i < 3; i++) { - add_next_index_string(&tb_aa, th_aa_arr[i]); - } - add_assoc_zval(&ret, "aa", &tb_aa); - - zval tb_ae; - array_init(&tb_ae); - char* th_ae_arr[] = {"æ", "ǽ"}; - for(int i = 0; i < 2; i++) { - add_next_index_string(&tb_ae, th_ae_arr[i]); - } - add_assoc_zval(&ret, "aa", &tb_ae); - - zval tb_ai; - array_init(&tb_ai); - char* th_ai_arr[] = {"ऐ"}; - for(int i = 0; i < 1; i++) { - add_next_index_string(&tb_ai, th_ai_arr[i]); - } - add_assoc_zval(&ret, "ai", &tb_ai); - - zval tb_ch; - array_init(&tb_ch); - char* th_ch_arr[] = {"ч", "ჩ", "ჭ", "چ"}; - for(int i = 0; i < 4; i++) { - add_next_index_string(&tb_ch, th_ch_arr[i]); - } - add_assoc_zval(&ret, "ch", &tb_ch); - - zval tb_dj; - array_init(&tb_dj); - char* th_dj_arr[] = {"ђ", "đ"}; - for(int i = 0; i < 2; i++) { - add_next_index_string(&tb_dj, th_dj_arr[i]); - } - add_assoc_zval(&ret, "dj", &tb_dj); - - zval tb_dz; - array_init(&tb_dz); - char* th_dz_arr[] = {"џ", "ძ"}; - for(int i = 0; i < 2; i++) { - add_next_index_string(&tb_dz, th_dz_arr[i]); - } - add_assoc_zval(&ret, "dz", &tb_dz); - - zval tb_ei; - array_init(&tb_ei); - char* th_ei_arr[] = {"ऍ"}; - for(int i = 0; i < 1; i++) { - add_next_index_string(&tb_ei, th_ei_arr[i]); - } - add_assoc_zval(&ret, "ei", &tb_ei); - - zval tb_gh; - array_init(&tb_gh); - char* th_gh_arr[] = {"غ", "ღ"}; - for(int i = 0; i < 2; i++) { - add_next_index_string(&tb_gh, th_gh_arr[i]); - } - add_assoc_zval(&ret, "gh", &tb_gh); - - zval tb_ii; - array_init(&tb_ii); - char* th_ii_arr[] = {"ई"}; - for(int i = 0; i < 1; i++) { - add_next_index_string(&tb_ii, th_ii_arr[i]); - } - add_assoc_zval(&ret, "ii", &tb_ii); - - zval tb_kh; - array_init(&tb_kh); - char* th_kh_arr[] = {"х", "خ", "ხ"}; - for(int i = 0; i < 3; i++) { - add_next_index_string(&tb_kh, th_kh_arr[i]); - } - add_assoc_zval(&ret, "kh", &tb_kh); - - zval tb_ij; - array_init(&tb_ij); - char* th_ij_arr[] = {"ij"}; - for(int i = 0; i < 1; i++) { - add_next_index_string(&tb_ij, th_ij_arr[i]); - } - add_assoc_zval(&ret, "ij", &tb_ij); - - zval tb_lj; - array_init(&tb_lj); - char* th_lj_arr[] = {"љ"}; - for(int i = 0; i < 1; i++) { - add_next_index_string(&tb_lj, th_lj_arr[i]); - } - add_assoc_zval(&ret, "lj", &tb_lj); - - zval tb_nj; - array_init(&tb_nj); - char* th_nj_arr[] = {"њ"}; - for(int i = 0; i < 1; i++) { - add_next_index_string(&tb_nj, th_nj_arr[i]); - } - add_assoc_zval(&ret, "nj", &tb_nj); - - zval tb_oe; - array_init(&tb_oe); - char* th_oe_arr[] = {"œ", "ؤ"}; - for(int i = 0; i < 2; i++) { - add_next_index_string(&tb_oe, th_oe_arr[i]); - } - add_assoc_zval(&ret, "oe", &tb_oe); - - zval tb_oi; - array_init(&tb_oi); - char* th_oi_arr[] = {"ऑ"}; - for(int i = 0; i < 1; i++) { - add_next_index_string(&tb_oi, th_oi_arr[i]); - } - add_assoc_zval(&ret, "oi", &tb_oi); - - zval tb_oii; - array_init(&tb_oii); - char* th_oii_arr[] = {"ऒ"}; - for(int i = 0; i < 1; i++) { - add_next_index_string(&tb_oii, th_oii_arr[i]); - } - add_assoc_zval(&ret, "oii", &tb_oii); - - zval tb_ps; - array_init(&tb_ps); - char* th_ps_arr[] = {"ψ"}; - for(int i = 0; i < 1; i++) { - add_next_index_string(&tb_ps, th_ps_arr[i]); - } - add_assoc_zval(&ret, "ps", &tb_ps); - - zval tb_sh; - array_init(&tb_sh); - char* th_sh_arr[] = {"ш", "შ", "ش"}; - for(int i = 0; i < 3; i++) { - add_next_index_string(&tb_sh, th_sh_arr[i]); - } - add_assoc_zval(&ret, "sh", &tb_sh); - - zval tb_shch; - array_init(&tb_shch); - char* th_shch_arr[] = {"щ"}; - for(int i = 0; i < 1; i++) { - add_next_index_string(&tb_shch, th_shch_arr[i]); - } - add_assoc_zval(&ret, "shch", &tb_shch); - - zval tb_ss; - array_init(&tb_ss); - char* th_ss_arr[] = {"ß"}; - for(int i = 0; i < 1; i++) { - add_next_index_string(&tb_ss, th_ss_arr[i]); - } - add_assoc_zval(&ret, "ss", &tb_ss); + char str_arr[STRINNGY_ROW_COUNT][STRINNGY_COLUM_COUNT][10] = { + {"°", "₀", "۰", "0"}, + {"¹", "₁", "۱", "1"}, + {"²", "₂", "۲", "2"}, + {"³", "₃", "۳", "3"}, + {"⁴", "₄", "۴", "٤", "4"}, + {"⁵", "₅", "۵", "٥", "5"}, + {"⁶", "₆", "۶", "٦", "6"}, + {"⁷", "₇", "۷", "7"}, + {"⁸", "₈", "۸", "8"}, + {"⁹", "₉", "۹", "9"}, + {"à", "á", "ả", "ã", "ạ", "ă", "ắ", "ằ", "ẳ", "ẵ", + "ặ", "â", "ấ", "ầ", "ẩ", "ẫ", "ậ", "ā", "ą", "å", + "α", "ά", "ἀ", "ἁ", "ἂ", "ἃ", "ἄ", "ἅ", "ἆ", "ἇ", + "ᾀ", "ᾁ", "ᾂ", "ᾃ", "ᾄ", "ᾅ", "ᾆ", "ᾇ", "ὰ", "ά", + "ᾰ", "ᾱ", "ᾲ", "ᾳ", "ᾴ", "ᾶ", "ᾷ", "а", "أ", "အ", + "ာ", "ါ", "ǻ", "ǎ", "ª", "ა", "अ", "ا", "a", "ä"}, + {"б", "β", "ب", "ဗ", "ბ", "b"}, + {"ç", "ć", "č", "ĉ", "ċ", "c"}, + {"ď", "ð", "đ", "ƌ", "ȡ", "ɖ", "ɗ", "ᵭ", "ᶁ", "ᶑ", + "д", "δ", "د", "ض", "ဍ", "ဒ", "დ", "d"}, + {"é", "è", "ẻ", "ẽ", "ẹ", "ê", "ế", "ề", "ể", "ễ", + "ệ", "ë", "ē", "ę", "ě", "ĕ", "ė", "ε", "έ", "ἐ", + "ἑ", "ἒ", "ἓ", "ἔ", "ἕ", "ὲ", "έ", "е", "ё", "э", + "є", "ə", "ဧ", "ေ", "ဲ", "ე", "ए", "إ", "ئ", "e"}, + {"ф", "φ", "ف", "ƒ", "ფ", "f"}, + {"ĝ", "ğ", "ġ", "ģ", "г", "ґ", "γ", "ဂ", "გ", "گ", + "g"}, + {"ĥ", "ħ", "η", "ή", "ح", "ه", "ဟ", "ှ", "ჰ", "h"}, + {"í", "ì", "ỉ", "ĩ", "ị", "î", "ï", "ī", "ĭ", "į", + "ı", "ι", "ί", "ϊ", "ΐ", "ἰ", "ἱ", "ἲ", "ἳ", "ἴ", + "ἵ", "ἶ", "ἷ", "ὶ", "ί", "ῐ", "ῑ", "ῒ", "ΐ", "ῖ", + "ῗ", "і", "ї", "и", "ဣ", "ိ", "ီ", "ည်", "ǐ", "ი", + "इ", "ی", "i"}, + {"ĵ", "ј", "Ј", "ჯ", "ج", "j"}, + {"ķ", "ĸ", "к", "κ", "Ķ", "ق", "ك", "က", "კ", "ქ", + "ک", "k"}, + {"ł", "ľ", "ĺ", "ļ", "ŀ", "л", "λ", "ل", "လ", "ლ", + "l"}, + {"м", "μ", "م", "မ", "მ", "m"}, + {"ñ", "ń", "ň", "ņ", "ʼn", "ŋ", "ν", "н", "ن", "န", + "ნ", "n"}, + {"ó", "ò", "ỏ", "õ", "ọ", "ô", "ố", "ồ", "ổ", "ỗ", + "ộ", "ơ", "ớ", "ờ", "ở", "ỡ", "ợ", "ø", "ō", "ő", + "ŏ", "ο", "ὀ", "ὁ", "ὂ", "ὃ", "ὄ", "ὅ", "ὸ", "ό", + "о", "و", "θ", "ို", "ǒ", "ǿ", "º", "ო", "ओ", "o", + "ö"}, + {"п", "π", "ပ", "პ", "پ", "p"}, + {"ყ", "q"}, + {"ŕ", "ř", "ŗ", "р", "ρ", "ر", "რ", "r"}, + {"ś", "š", "ş", "с", "σ", "ș", "ς", "س", "ص", "စ", + "ſ", "ს", "s"}, + {"ť", "ţ", "т", "τ", "ț", "ت", "ط", "ဋ", "တ", "ŧ", + "თ", "ტ", "t"}, + {"ú", "ù", "ủ", "ũ", "ụ", "ư", "ứ", "ừ", "ử", "ữ", + "ự", "û", "ū", "ů", "ű", "ŭ", "ų", "µ", "у", "ဉ", + "ု", "ူ", "ǔ", "ǖ", "ǘ", "ǚ", "ǜ", "უ", "उ", "u", + "ў", "ü"}, + {"в", "ვ", "ϐ", "v"}, + {"ŵ", "ω", "ώ", "ဝ", "ွ", "w"}, + {"χ", "ξ", "x"}, + {"ý", "ỳ", "ỷ", "ỹ", "ỵ", "ÿ", "ŷ", "й", "ы", "υ", + "ϋ", "ύ", "ΰ", "ي", "ယ", "y"}, + {"ź", "ž", "ż", "з", "ζ", "ز", "ဇ", "ზ", "z"}, + {"ع", "आ", "آ"}, + {"æ", "ǽ"}, + {"ऐ"}, + {"ч", "ჩ", "ჭ", "چ"}, + {"ђ", "đ"}, + {"џ", "ძ"}, + {"ऍ"}, + {"غ", "ღ"}, + {"ई"}, + {"х", "خ", "ხ"}, + {"ij"}, + {"љ"}, + {"њ"}, + {"œ", "ؤ"}, + {"ऑ"}, + {"ऒ"}, + {"ψ"}, + {"ш", "შ", "ش"}, + {"щ"}, + {"ß"}, + {"ŝ"}, + {"þ", "ϑ", "ث", "ذ", "ظ"}, + {"ц", "ც", "წ"}, + {"ऊ"}, + {"я"}, + {"ю"}, + {"ж", "ჟ", "ژ"}, + {"©"}, + {"Á", "À", "Ả", "Ã", "Ạ", "Ă", "Ắ", "Ằ", "Ẳ", "Ẵ", + "Ặ", "Â", "Ấ", "Ầ", "Ẩ", "Ẫ", "Ậ", "Å", "Ā", "Ą", + "Α", "Ά", "Ἀ", "Ἁ", "Ἂ", "Ἃ", "Ἄ", "Ἅ", "Ἆ", "Ἇ", + "ᾈ", "ᾉ", "ᾊ", "ᾋ", "ᾌ", "ᾍ", "ᾎ", "ᾏ", "Ᾰ", "Ᾱ", + "Ὰ", "Ά", "ᾼ", "А", "Ǻ", "Ǎ", "A", "Ä"}, + {"Б", "Β", "ब", "B"}, + {"Ç", "Ć", "Č", "Ĉ", "Ċ", "C"}, + {"Ď", "Ð", "Đ", "Ɖ", "Ɗ", "Ƌ", "ᴅ", "ᴆ", "Д", "Δ", + "D"}, + {"É", "È", "Ẻ", "Ẽ", "Ẹ", "Ê", "Ế", "Ề", "Ể", "Ễ", + "Ệ", "Ë", "Ē", "Ę", "Ě", "Ĕ", "Ė", "Ε", "Έ", "Ἐ", + "Ἑ", "Ἒ", "Ἓ", "Ἔ", "Ἕ", "Έ", "Ὲ", "Е", "Ё", "Э", + "Є", "Ə", "E"}, + {"Ф", "Φ", "F"}, + {"Ğ", "Ġ", "Ģ", "Г", "Ґ", "Γ", "G"}, + {"Η", "Ή", "Ħ", "H"}, + {"Í", "Ì", "Ỉ", "Ĩ", "Ị", "Î", "Ï", "Ī", "Ĭ", "Į", + "İ", "Ι", "Ί", "Ϊ", "Ἰ", "Ἱ", "Ἳ", "Ἴ", "Ἵ", "Ἶ", + "Ἷ", "Ῐ", "Ῑ", "Ὶ", "Ί", "И", "І", "Ї", "Ǐ", "ϒ", + "I"}, + {"J"}, + {"К", "Κ", "K"}, + {"Ĺ", "Ł", "Л", "Λ", "Ļ", "Ľ", "Ŀ", "ल", "L"}, + {"М", "Μ", "M"}, + {"Ń", "Ñ", "Ň", "Ņ", "Ŋ", "Н", "Ν", "N"}, + {"Ó", "Ò", "Ỏ", "Õ", "Ọ", "Ô", "Ố", "Ồ", "Ổ", "Ỗ", + "Ộ", "Ơ", "Ớ", "Ờ", "Ở", "Ỡ", "Ợ", "Ø", "Ō", "Ő", + "Ŏ", "Ο", "Ό", "Ὀ", "Ὁ", "Ὂ", "Ὃ", "Ὄ", "Ὅ", "Ὸ", + "Ό", "О", "Θ", "Ө", "Ǒ", "Ǿ", "O", "Ö"}, + {"П", "Π", "P"}, + {"Q"}, + {"Ř", "Ŕ", "Р", "Ρ", "Ŗ", "R"}, + {"Ş", "Ŝ", "Ș", "Š", "Ś", "С", "Σ", "S"}, + {"Ť", "Ţ", "Ŧ", "Ț", "Т", "Τ", "T"}, + {"Ú", "Ù", "Ủ", "Ũ", "Ụ", "Ư", "Ứ", "Ừ", "Ử", "Ữ", + "Ự", "Û", "Ū", "Ů", "Ű", "Ŭ", "Ų", "У", "Ǔ", "Ǖ", + "Ǘ", "Ǚ", "Ǜ", "U", "Ў", "Ü"}, + {"В", "V"}, + {"Ω", "Ώ", "Ŵ", "W"}, + {"Χ", "Ξ", "X"}, + {"Ý", "Ỳ", "Ỷ", "Ỹ", "Ỵ", "Ÿ", "Ῠ", "Ῡ", "Ὺ", "Ύ", + "Ы", "Й", "Υ", "Ϋ", "Ŷ", "Y"}, + {"Ź", "Ž", "Ż", "З", "Ζ", "Z"}, + {"Æ", "Ǽ"}, + {"Ч"}, + {"Ђ"}, + {"Џ"}, + {"Ĝ"}, + {"Ĥ"}, + {"IJ"}, + {"Ĵ"}, + {"Х"}, + {"Љ"}, + {"Њ"}, + {"Œ"}, + {"Ψ"}, + {"Ш"}, + {"Щ"}, + {"ẞ"}, + {"Þ"}, + {"Ц"}, + {"Я"}, + {"Yu"}, + {"Ж"}, + {"\xC2\xA0", "\xE2\x80\x80", "\xE2\x80\x81", + "\xE2\x80\x82", "\xE2\x80\x83", "\xE2\x80\x84", + "\xE2\x80\x85", "\xE2\x80\x86", "\xE2\x80\x87", + "\xE2\x80\x88", "\xE2\x80\x89", "\xE2\x80\x8A", + "\xE2\x80\xAF", "\xE2\x81\x9F", "\xE3\x80\x80", + "\xEF\xBE\xA0"}, + }; - zval tb_sx; - array_init(&tb_sx); - char* th_sx_arr[] = {"ŝ"}; - for(int i = 0; i < 1; i++) { - add_next_index_string(&tb_sx, th_sx_arr[i]); - } - add_assoc_zval(&ret, "sx", &tb_sx); - - zval tb_th; - array_init(&tb_th); - char* th_th_arr[] = {"þ", "ϑ", "ث", "ذ", "ظ"}; - for(int i = 0; i < 5; i++) { - add_next_index_string(&tb_th, th_th_arr[i]); - } - add_assoc_zval(&ret, "th", &tb_th); - - zval tb_ts; - array_init(&tb_ts); - char* th_ts_arr[] = {"ц", "ც", "წ"}; - for(int i = 0; i < 3; i++) { - add_next_index_string(&tb_ts, th_ts_arr[i]); - } - add_assoc_zval(&ret, "ts", &tb_ts); - - zval tb_uu; - array_init(&tb_uu); - char* th_uu_arr[] = {"ऊ"}; - for(int i = 0; i < 1; i++) { - add_next_index_string(&tb_uu, th_uu_arr[i]); - } - add_assoc_zval(&ret, "uu", &tb_uu); - - zval tb_ya; - array_init(&tb_ya); - char* th_ya_arr[] = {"я"}; - for(int i = 0; i < 1; i++) { - add_next_index_string(&tb_ya, th_ya_arr[i]); - } - add_assoc_zval(&ret, "ya", &tb_ya); - - zval tb_yu; - array_init(&tb_yu); - char* th_yu_arr[] = {"ю"}; - for(int i = 0; i < 1; i++) { - add_next_index_string(&tb_yu, th_yu_arr[i]); - } - add_assoc_zval(&ret, "yu", &tb_yu); - - zval tb_zh; - array_init(&tb_zh); - char* th_zh_arr[] = {"ж", "ჟ", "ژ"}; - for(int i = 0; i < 3; i++) { - add_next_index_string(&tb_zh, th_zh_arr[i]); - } - add_assoc_zval(&ret, "zh", &tb_zh); - - zval tb_ccc; - array_init(&tb_ccc); - char* th_ccc_arr[] = {"©"}; - for(int i = 0; i < 1; i++) { - add_next_index_string(&tb_ccc, th_ccc_arr[i]); - } - add_assoc_zval(&ret, "(c)", &tb_ccc); - - zval tb_A; - array_init(&tb_A); - char* th_A_arr[] = {"Á", "À", "Ả", "Ã", "Ạ", "Ă", "Ắ", "Ằ", "Ẳ", "Ẵ", - "Ặ", "Â", "Ấ", "Ầ", "Ẩ", "Ẫ", "Ậ", "Å", "Ā", "Ą", - "Α", "Ά", "Ἀ", "Ἁ", "Ἂ", "Ἃ", "Ἄ", "Ἅ", "Ἆ", "Ἇ", - "ᾈ", "ᾉ", "ᾊ", "ᾋ", "ᾌ", "ᾍ", "ᾎ", "ᾏ", "Ᾰ", "Ᾱ", - "Ὰ", "Ά", "ᾼ", "А", "Ǻ", "Ǎ", "A", "Ä"}; - for(int i = 0; i < 48; i++) { - add_next_index_string(&tb_A, th_A_arr[i]); - } - add_assoc_zval(&ret, "A", &tb_A); + char str[STRINNGY_ROW_COUNT][5] = { + "0", "1", "2","3","4", "5", "6", "7", "8", "9", + "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", + "aa", "ae", "ai", "ch", "dj", "dz", "ei", "gh", "ii", "kh", "ij", "lj", "nj", "oe", "oi", "oii", "ps", "sh", "shch", "ss", "sx", "th", "ts", "uu", "ya", "yu", "zh", "(c)", + "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", + "AE", "Ch", "Dj", "Dz", "Gx", "Hx", "Ij", "Jx", "Kh", "Lj", "Nj", "Oe", "Ps", "Sh", "Shch", "Ss", "Th", "Ts", "Ya", "Yu", "Zh", " ", + }; - zval tb_B; - array_init(&tb_B); - char* th_B_arr[] = {"Б", "Β", "ब", "B"}; - for(int i = 0; i < 4; i++) { - add_next_index_string(&tb_B, th_B_arr[i]); - } - add_assoc_zval(&ret, "B", &tb_B); + for (size_t i = 0; i < STRINNGY_ROW_COUNT; i++) + { + zval tmp; + array_init(&tmp); - zval tb_C; - array_init(&tb_C); - char* th_C_arr[] = {"Ç", "Ć", "Č", "Ĉ", "Ċ", "C"}; - for(int i = 0; i < 6; i++) { - add_next_index_string(&tb_C, th_C_arr[i]); + for (size_t j = 0; j < STRINNGY_COLUM_COUNT; j++) + { + if (strlen(str_arr[i][j]) == 0) { + break; + } + + add_next_index_string(&tmp, str_arr[i][j]); + } + + add_assoc_zval(&ret, str[i], &tmp); } - add_assoc_zval(&ret, "C", &tb_C); - zval tb_D; - array_init(&tb_D); - char* th_D_arr[] = {"Ď", "Ð", "Đ", "Ɖ", "Ɗ", "Ƌ", "ᴅ", "ᴆ", "Д", "Δ", - "D"}; - for(int i = 0; i < 11; i++) { - add_next_index_string(&tb_D, th_D_arr[i]); - } - add_assoc_zval(&ret, "D", &tb_D); - - zval tb_E; - array_init(&tb_E); - char* th_E_arr[] = {"É", "È", "Ẻ", "Ẽ", "Ẹ", "Ê", "Ế", "Ề", "Ể", "Ễ", - "Ệ", "Ë", "Ē", "Ę", "Ě", "Ĕ", "Ė", "Ε", "Έ", "Ἐ", - "Ἑ", "Ἒ", "Ἓ", "Ἔ", "Ἕ", "Έ", "Ὲ", "Е", "Ё", "Э", - "Є", "Ə", "E"}; - for(int i = 0; i < 33; i++) { - add_next_index_string(&tb_E, th_E_arr[i]); - } - add_assoc_zval(&ret, "E", &tb_E); - - zval tb_F; - array_init(&tb_F); - char* th_F_arr[] = {"Ф", "Φ", "F"}; - for(int i = 0; i < 3; i++) { - add_next_index_string(&tb_F, th_F_arr[i]); - } - add_assoc_zval(&ret, "F", &tb_F); - - zval tb_G; - array_init(&tb_G); - char* th_G_arr[] = {"Ğ", "Ġ", "Ģ", "Г", "Ґ", "Γ", "G"}; - for(int i = 0; i < 7; i++) { - add_next_index_string(&tb_G, th_G_arr[i]); - } - add_assoc_zval(&ret, "G", &tb_G); - - zval tb_H; - array_init(&tb_H); - char* th_H_arr[] = {"Η", "Ή", "Ħ", "H"}; - for(int i = 0; i < 4; i++) { - add_next_index_string(&tb_H, th_H_arr[i]); - } - add_assoc_zval(&ret, "H", &tb_H); - - zval tb_I; - array_init(&tb_I); - char* th_I_arr[] = {"Í", "Ì", "Ỉ", "Ĩ", "Ị", "Î", "Ï", "Ī", "Ĭ", "Į", - "İ", "Ι", "Ί", "Ϊ", "Ἰ", "Ἱ", "Ἳ", "Ἴ", "Ἵ", "Ἶ", - "Ἷ", "Ῐ", "Ῑ", "Ὶ", "Ί", "И", "І", "Ї", "Ǐ", "ϒ", - "I"}; - for(int i = 0; i < 31; i++) { - add_next_index_string(&tb_I, th_I_arr[i]); - } - add_assoc_zval(&ret, "I", &tb_I); - - zval tb_J; - array_init(&tb_J); - char* th_J_arr[] = {"J"}; - for(int i = 0; i < 1; i++) { - add_next_index_string(&tb_J, th_J_arr[i]); - } - add_assoc_zval(&ret, "J", &tb_J); - - zval tb_K; - array_init(&tb_K); - char* th_K_arr[] = {"К", "Κ", "K"}; - for(int i = 0; i < 3; i++) { - add_next_index_string(&tb_K, th_K_arr[i]); - } - add_assoc_zval(&ret, "K", &tb_K); - - zval tb_L; - array_init(&tb_L); - char* th_L_arr[] = {"Ĺ", "Ł", "Л", "Λ", "Ļ", "Ľ", "Ŀ", "ल", "L"}; - for(int i = 0; i < 9; i++) { - add_next_index_string(&tb_L, th_L_arr[i]); - } - add_assoc_zval(&ret, "L", &tb_L); - - zval tb_M; - array_init(&tb_M); - char* th_M_arr[] = {"М", "Μ", "M"}; - for(int i = 0; i < 3; i++) { - add_next_index_string(&tb_M, th_M_arr[i]); - } - add_assoc_zval(&ret, "M", &tb_M); - - zval tb_N; - array_init(&tb_N); - char* th_N_arr[] = {"Ń", "Ñ", "Ň", "Ņ", "Ŋ", "Н", "Ν", "N"}; - for(int i = 0; i < 8; i++) { - add_next_index_string(&tb_N, th_N_arr[i]); - } - add_assoc_zval(&ret, "N", &tb_N); - - zval tb_O; - array_init(&tb_O); - char* th_O_arr[] = {"Ó", "Ò", "Ỏ", "Õ", "Ọ", "Ô", "Ố", "Ồ", "Ổ", "Ỗ", - "Ộ", "Ơ", "Ớ", "Ờ", "Ở", "Ỡ", "Ợ", "Ø", "Ō", "Ő", - "Ŏ", "Ο", "Ό", "Ὀ", "Ὁ", "Ὂ", "Ὃ", "Ὄ", "Ὅ", "Ὸ", - "Ό", "О", "Θ", "Ө", "Ǒ", "Ǿ", "O", "Ö"}; - for(int i = 0; i < 38; i++) { - add_next_index_string(&tb_O, th_O_arr[i]); - } - add_assoc_zval(&ret, "O", &tb_O); - - zval tb_P; - array_init(&tb_P); - char* th_P_arr[] = {"П", "Π", "P"}; - for(int i = 0; i < 3; i++) { - add_next_index_string(&tb_P, th_P_arr[i]); - } - add_assoc_zval(&ret, "P", &tb_P); - - zval tb_Q; - array_init(&tb_Q); - char* th_Q_arr[] = {"Q"}; - for(int i = 0; i < 1; i++) { - add_next_index_string(&tb_Q, th_Q_arr[i]); - } - add_assoc_zval(&ret, "Q", &tb_Q); - - zval tb_R; - array_init(&tb_R); - char* th_R_arr[] = {"Ř", "Ŕ", "Р", "Ρ", "Ŗ", "R"}; - for(int i = 0; i < 6; i++) { - add_next_index_string(&tb_R, th_R_arr[i]); - } - add_assoc_zval(&ret, "R", &tb_R); - - zval tb_S; - array_init(&tb_S); - char* th_S_arr[] = {"Ş", "Ŝ", "Ș", "Š", "Ś", "С", "Σ", "S"}; - for(int i = 0; i < 8; i++) { - add_next_index_string(&tb_S, th_S_arr[i]); - } - add_assoc_zval(&ret, "S", &tb_S); - - zval tb_T; - array_init(&tb_T); - char* th_T_arr[] = {"Ť", "Ţ", "Ŧ", "Ț", "Т", "Τ", "T"}; - for(int i = 0; i < 7; i++) { - add_next_index_string(&tb_T, th_T_arr[i]); - } - add_assoc_zval(&ret, "T", &tb_T); - - zval tb_U; - array_init(&tb_U); - char* th_U_arr[] = {"Ú", "Ù", "Ủ", "Ũ", "Ụ", "Ư", "Ứ", "Ừ", "Ử", "Ữ", - "Ự", "Û", "Ū", "Ů", "Ű", "Ŭ", "Ų", "У", "Ǔ", "Ǖ", - "Ǘ", "Ǚ", "Ǜ", "U", "Ў", "Ü"}; - for(int i = 0; i < 26; i++) { - add_next_index_string(&tb_U, th_U_arr[i]); - } - add_assoc_zval(&ret, "U", &tb_U); - - zval tb_V; - array_init(&tb_V); - char* th_V_arr[] = {"В", "V"}; - for(int i = 0; i < 2; i++) { - add_next_index_string(&tb_V, th_V_arr[i]); - } - add_assoc_zval(&ret, "V", &tb_V); - - zval tb_W; - array_init(&tb_W); - char* th_W_arr[] = {"Ω", "Ώ", "Ŵ", "W"}; - for(int i = 0; i < 4; i++) { - add_next_index_string(&tb_W, th_W_arr[i]); - } - add_assoc_zval(&ret, "W", &tb_W); - - zval tb_X; - array_init(&tb_X); - char* th_X_arr[] = {"Χ", "Ξ", "X"}; - for(int i = 0; i < 3; i++) { - add_next_index_string(&tb_X, th_X_arr[i]); - } - add_assoc_zval(&ret, "X", &tb_X); - - zval tb_Y; - array_init(&tb_Y); - char* th_Y_arr[] = {"Ý", "Ỳ", "Ỷ", "Ỹ", "Ỵ", "Ÿ", "Ῠ", "Ῡ", "Ὺ", "Ύ", - "Ы", "Й", "Υ", "Ϋ", "Ŷ", "Y"}; - for(int i = 0; i < 16; i++) { - add_next_index_string(&tb_Y, th_Y_arr[i]); - } - add_assoc_zval(&ret, "Y", &tb_Y); - - zval tb_Z; - array_init(&tb_Z); - char* th_Z_arr[] = {"Ź", "Ž", "Ż", "З", "Ζ", "Z"}; - for(int i = 0; i < 6; i++) { - add_next_index_string(&tb_Z, th_Z_arr[i]); - } - add_assoc_zval(&ret, "Z", &tb_Z); - - zval tb_AE; - array_init(&tb_AE); - char* th_AE_arr[] = {"Æ", "Ǽ"}; - for(int i = 0; i < 2; i++) { - add_next_index_string(&tb_AE, th_AE_arr[i]); - } - add_assoc_zval(&ret, "AE", &tb_AE); - - zval tb_Ch; - array_init(&tb_Ch); - char* th_Ch_arr[] = {"Ч"}; - for(int i = 0; i < 1; i++) { - add_next_index_string(&tb_Ch, th_Ch_arr[i]); - } - add_assoc_zval(&ret, "Ch", &tb_Ch); - - zval tb_Dj; - array_init(&tb_Dj); - char* th_Dj_arr[] = {"Ђ"}; - for(int i = 0; i < 1; i++) { - add_next_index_string(&tb_Dj, th_Dj_arr[i]); - } - add_assoc_zval(&ret, "Dj", &tb_Dj); - - zval tb_Dz; - array_init(&tb_Dz); - char* th_Dz_arr[] = {"Џ"}; - for(int i = 0; i < 1; i++) { - add_next_index_string(&tb_Dz, th_Dz_arr[i]); - } - add_assoc_zval(&ret, "Dz", &tb_Dz); - - zval tb_Gx; - array_init(&tb_Gx); - char* th_Gx_arr[] = {"Ĝ"}; - for(int i = 0; i < 1; i++) { - add_next_index_string(&tb_Gx, th_Gx_arr[i]); - } - add_assoc_zval(&ret, "Gx", &tb_Gx); - - zval tb_Hx; - array_init(&tb_Hx); - char* th_Hx_arr[] = {"Ĥ"}; - for(int i = 0; i < 1; i++) { - add_next_index_string(&tb_Hx, th_Hx_arr[i]); - } - add_assoc_zval(&ret, "Hx", &tb_Hx); - - zval tb_Ij; - array_init(&tb_Ij); - char* th_Ij_arr[] = {"IJ"}; - for(int i = 0; i < 1; i++) { - add_next_index_string(&tb_Ij, th_Ij_arr[i]); - } - add_assoc_zval(&ret, "Ij", &tb_Ij); - - zval tb_Jx; - array_init(&tb_Jx); - char* th_Jx_arr[] = {"Ĵ"}; - for(int i = 0; i < 1; i++) { - add_next_index_string(&tb_Jx, th_Jx_arr[i]); - } - add_assoc_zval(&ret, "Jx", &tb_Jx); - - zval tb_Kh; - array_init(&tb_Kh); - char* th_Kh_arr[] = {"Х"}; - for(int i = 0; i < 1; i++) { - add_next_index_string(&tb_Kh, th_Kh_arr[i]); - } - add_assoc_zval(&ret, "Kh", &tb_Kh); - - zval tb_Lj; - array_init(&tb_Lj); - char* th_Lj_arr[] = {"Љ"}; - for(int i = 0; i < 1; i++) { - add_next_index_string(&tb_Lj, th_Lj_arr[i]); - } - add_assoc_zval(&ret, "Lj", &tb_Lj); - - zval tb_Nj; - array_init(&tb_Nj); - char* th_Nj_arr[] = {"Њ"}; - for(int i = 0; i < 1; i++) { - add_next_index_string(&tb_Nj, th_Nj_arr[i]); - } - add_assoc_zval(&ret, "Nj", &tb_Nj); - - zval tb_Oe; - array_init(&tb_Oe); - char* th_Oe_arr[] = {"Œ"}; - for(int i = 0; i < 1; i++) { - add_next_index_string(&tb_Oe, th_Oe_arr[i]); - } - add_assoc_zval(&ret, "Oe", &tb_Oe); - - zval tb_Ps; - array_init(&tb_Ps); - char* th_Ps_arr[] = {"Ψ"}; - for(int i = 0; i < 1; i++) { - add_next_index_string(&tb_Ps, th_Ps_arr[i]); - } - add_assoc_zval(&ret, "Ps", &tb_Ps); - - zval tb_Sh; - array_init(&tb_Sh); - char* th_Sh_arr[] = {"Ш"}; - for(int i = 0; i < 1; i++) { - add_next_index_string(&tb_Sh, th_Sh_arr[i]); - } - add_assoc_zval(&ret, "Sh", &tb_Sh); - - zval tb_Shch; - array_init(&tb_Shch); - char* th_Shch_arr[] = {"Щ"}; - for(int i = 0; i < 1; i++) { - add_next_index_string(&tb_Shch, th_Shch_arr[i]); - } - add_assoc_zval(&ret, "Shch", &tb_Shch); - - zval tb_Ss; - array_init(&tb_Ss); - char* th_Ss_arr[] = {"ẞ"}; - for(int i = 0; i < 1; i++) { - add_next_index_string(&tb_Ss, th_Ss_arr[i]); - } - add_assoc_zval(&ret, "Ss", &tb_Ss); - - zval tb_Th; - array_init(&tb_Th); - char* th_Th_arr[] = {"Þ"}; - for(int i = 0; i < 1; i++) { - add_next_index_string(&tb_Th, th_Th_arr[i]); - } - add_assoc_zval(&ret, "Th", &tb_Th); - - zval tb_Ts; - array_init(&tb_Ts); - char* th_Ts_arr[] = {"Ц"}; - for(int i = 0; i < 1; i++) { - add_next_index_string(&tb_Ts, th_Ts_arr[i]); - } - add_assoc_zval(&ret, "Ts", &tb_Ts); - - zval tb_Ya; - array_init(&tb_Ya); - char* th_Ya_arr[] = {"Я"}; - for(int i = 0; i < 1; i++) { - add_next_index_string(&tb_Ya, th_Ya_arr[i]); - } - add_assoc_zval(&ret, "Ya", &tb_Ya); - - zval tb_Yu; - array_init(&tb_Yu); - char* th_Yu_arr[] = {"Yu"}; - for(int i = 0; i < 1; i++) { - add_next_index_string(&tb_Yu, th_Yu_arr[i]); - } - add_assoc_zval(&ret, "Yu", &tb_Yu); - - zval tb_Zh; - array_init(&tb_Zh); - char* th_Zh_arr[] = {"Ж"}; - for(int i = 0; i < 1; i++) { - add_next_index_string(&tb_Zh, th_Zh_arr[i]); - } - add_assoc_zval(&ret, "Zh", &tb_Zh); - - zval tb_str; - array_init(&tb_str); - char* th_str_arr[] = {"\xC2\xA0", "\xE2\x80\x80", "\xE2\x80\x81", - "\xE2\x80\x82", "\xE2\x80\x83", "\xE2\x80\x84", - "\xE2\x80\x85", "\xE2\x80\x86", "\xE2\x80\x87", - "\xE2\x80\x88", "\xE2\x80\x89", "\xE2\x80\x8A", - "\xE2\x80\xAF", "\xE2\x81\x9F", "\xE3\x80\x80", - "\xEF\xBE\xA0"}; - for(int i = 0; i < 16; i++) { - add_next_index_string(&tb_str, th_str_arr[i]); - } - add_assoc_zval(&ret, " ", &tb_str); RETURN_ZVAL(&ret, 0, 0); } diff --git a/src/ext/stringy/stringy.h b/src/ext/stringy/stringy.h index ef5c756..8302d65 100644 --- a/src/ext/stringy/stringy.h +++ b/src/ext/stringy/stringy.h @@ -15,6 +15,10 @@ #define PHP_STARTUP_STRINGY_NS(cls) PHP_STARTUP_NS_NAME "Stringy\\" #cls +#define STRINNGY_ROW_COUNT 112 + +#define STRINNGY_COLUM_COUNT 60 + extern zend_class_entry *stringy_ce; void php_startup_register_stringy(); From be5ec58d5a3769d15893d8f6d5ceb965744a221f Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Sat, 22 Jun 2019 11:19:44 +0800 Subject: [PATCH 100/126] fix test --- scripts/fetch.php | 1 + src/ext/stringy/stringy.c | 1 + 2 files changed, 2 insertions(+) diff --git a/scripts/fetch.php b/scripts/fetch.php index 83a389a..ffddce2 100755 --- a/scripts/fetch.php +++ b/scripts/fetch.php @@ -26,6 +26,7 @@ 'AOP' => 'https://github.com/AOP-PHP/AOP', 'xdeubg' => 'https://github.com/xdebug/xdebug.git', 'apcu' => 'https://github.com/krakjoe/apcu.git', + // 'swoole-pgsql' => 'git@github.com:swoole/ext-postgresql.git', ]; // PHPBREW_ROOT/build/php-7.1.17/ext/ diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index 59db5cf..35bc04f 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -3340,6 +3340,7 @@ PHP_METHOD(Stringy, toSpaces) { zval * tabLength; ZEND_PARSE_PARAMETERS_START(0, 1) + Z_PARAM_OPTIONAL Z_PARAM_ZVAL(tabLength) ZEND_PARSE_PARAMETERS_END(); From 65431992660ad7b0c699708423c94b3dbe6ecddf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Sat, 22 Jun 2019 12:34:08 +0800 Subject: [PATCH 101/126] underscored (#60) underscored --- spec/Stringy/StringySpec.php | 34 +++++++++++++++++++++++++++++ src/Minbaby/Php/Stringy/Stringy.php | 5 +++++ src/ext/stringy/stringy.c | 12 ++++++++++ 3 files changed, 51 insertions(+) diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index d4431be..bf1f6d7 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -1780,4 +1780,38 @@ }); } }); + + context('test underscored', function () { + $data = [ + ['test_case', 'testCase'], + ['test_case', 'Test-Case'], + ['test_case', 'test case'], + ['test_case', 'test -case'], + ['_test_case', '-test - case'], + ['test_case', 'test_case'], + ['test_c_test', ' test c test'], + ['test_u_case', 'TestUCase'], + ['test_c_c_test', 'TestCCTest'], + ['string_with1number', 'string_with1number'], + ['string_with_2_2_numbers', 'String-with_2_2 numbers'], + ['1test2case', '1test2case'], + ['yes_we_can', 'yesWeCan'], + ['test_σase', 'test Σase', 'UTF-8'], + ['στανιλ_case', 'Στανιλ case', 'UTF-8'], + ['σash_case', 'Σash Case', 'UTF-8'] + ]; + + foreach ($data as $key => $value) { + it(__formatMessage($key, $value), function () use ($value) { + @list($expected, $str, $encoding) = $value; + + $stringy = __('Stringy')::create($str, $encoding); + $result = $stringy->underscored(); + + \expect($stringy)->toBeAnInstanceOf(__('Stringy')); + \expect((string) $stringy)->toBe($str); + \expect((string) $result)->toBe($expected); + }); + } + }); }); diff --git a/src/Minbaby/Php/Stringy/Stringy.php b/src/Minbaby/Php/Stringy/Stringy.php index 21656e1..5857b7d 100644 --- a/src/Minbaby/Php/Stringy/Stringy.php +++ b/src/Minbaby/Php/Stringy/Stringy.php @@ -957,4 +957,9 @@ public function toSpaces($tabLength = 4) $str = str_replace("\t", $spaces, $this->str); return static::create($str, $this->encoding); } + + public function underscored() + { + return $this->delimit('_'); + } } diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index 35bc04f..aa22cf7 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -3384,6 +3384,17 @@ ZEND_BEGIN_ARG_INFO(arginfo_toSpaces, 0) ZEND_ARG_INFO(0, tabLength) ZEND_END_ARG_INFO(); +PHP_METHOD(Stringy, underscored) +{ + zval delimit; + ZVAL_STRING(&delimit, "_"); + zval func, args[] = { + delimit, + }; + ZVAL_STRING(&func, "delimit"); + call_user_function(NULL, getThis(), &func, return_value, 1, args); +} + static zend_function_entry methods[] = { PHP_ME(Stringy, __construct, arginfo___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) @@ -3463,6 +3474,7 @@ static zend_function_entry methods[] = { PHP_ME(Stringy, charsArray, NULL, ZEND_ACC_PROTECTED) PHP_ME(Stringy, langSpecificCharsArray, arginfo_langSpecificCharsArray, ZEND_ACC_PROTECTED) PHP_ME(Stringy, toSpaces, arginfo_toSpaces, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, underscored, NULL, ZEND_ACC_PUBLIC) PHP_FE_END }; From e2d601a88269d9bfd075eaf7b73c5c263f7fde6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Tue, 25 Jun 2019 22:34:34 +0800 Subject: [PATCH 102/126] =?UTF-8?q?=E5=AE=8C=E6=88=90=20(#61)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- spec/Stringy/StringySpec.php | 23 +++++++++++++++++++++++ src/Minbaby/Php/Stringy/Stringy.php | 6 ++++++ src/ext/stringy/stringy.c | 28 ++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+) diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index bf1f6d7..cf318fa 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -1814,4 +1814,27 @@ }); } }); + + context('test toUpperCase', function () { + $data = [ + ['FOO BAR', 'foo bar'], + [' FOO_BAR ', ' FOO_bar '], + ['FÒÔ BÀŘ', 'fòô bàř', 'UTF-8'], + [' FÒÔ_BÀŘ ', ' FÒÔ_bàř ', 'UTF-8'], + ['ΑΥΤΟΚΊΝΗΤΟ', 'αυτοκίνητο', 'UTF-8'], + ]; + + foreach ($data as $key => $value) { + it(__formatMessage($key, $value), function () use ($value) { + @list($expected, $str, $encoding) = $value; + + $stringy = __('Stringy')::create($str, $encoding); + $result = $stringy->toUpperCase(); + + \expect($stringy)->toBeAnInstanceOf(__('Stringy')); + \expect((string) $stringy)->toBe($str); + \expect((string) $result)->toBe($expected); + }); + } + }); }); diff --git a/src/Minbaby/Php/Stringy/Stringy.php b/src/Minbaby/Php/Stringy/Stringy.php index 5857b7d..5d0e8cf 100644 --- a/src/Minbaby/Php/Stringy/Stringy.php +++ b/src/Minbaby/Php/Stringy/Stringy.php @@ -962,4 +962,10 @@ public function underscored() { return $this->delimit('_'); } + + public function toUpperCase() + { + $str = \mb_strtoupper($this->str, $this->encoding); + return static::create($str, $this->encoding); + } } diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index aa22cf7..3e7dcc2 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -3395,6 +3395,33 @@ PHP_METHOD(Stringy, underscored) call_user_function(NULL, getThis(), &func, return_value, 1, args); } +PHP_METHOD(Stringy, toUpperCase) +{ + zval rv; + zval *str = zend_read_property(stringy_ce, getThis(), ZEND_STRL("str"), 0, &rv); + zval *encoding = zend_read_property(stringy_ce, getThis(), ZEND_STRL("encoding"), 1, &rv); + + + zval func, args[] = { + *str, + *encoding, + }; + ZVAL_STRING(&func, "mb_strtoupper"); + call_user_function(NULL, NULL, &func, return_value, 2, args); + + zval instance; + object_init_ex(&instance, stringy_ce); + + zval args_construct[] = { + *return_value, + *encoding, + }; + ZVAL_STRING(&func, "__construct"); + call_user_function(NULL, &instance, &func, return_value, 2, args_construct); + + RETURN_ZVAL(&instance, 0, 1); +} + static zend_function_entry methods[] = { PHP_ME(Stringy, __construct, arginfo___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) @@ -3475,6 +3502,7 @@ static zend_function_entry methods[] = { PHP_ME(Stringy, langSpecificCharsArray, arginfo_langSpecificCharsArray, ZEND_ACC_PROTECTED) PHP_ME(Stringy, toSpaces, arginfo_toSpaces, ZEND_ACC_PUBLIC) PHP_ME(Stringy, underscored, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, toUpperCase, NULL, ZEND_ACC_PUBLIC) PHP_FE_END }; From 27ad9b3dc91c802e2c29e2dc730ec78d11ba49b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Wed, 24 Jul 2019 20:24:32 +0800 Subject: [PATCH 103/126] truncate (#62) --- .vscode/settings.json | 7 +++- spec/Stringy/StringySpec.php | 42 +++++++++++++++++++ src/Minbaby/Php/Stringy/Stringy.php | 14 +++++++ src/ext/stringy/stringy.c | 63 +++++++++++++++++++++++++++++ 4 files changed, 125 insertions(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index f2f49eb..a0e2daa 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,11 @@ { "files.associations": { - "*.h": "c" + "*.inc": "php", + "*.h": "c", + "__locale": "c", + "__string": "c", + "string": "c", + "string_view": "c" }, "editor.mouseWheelZoom": false, "files.autoSave": "onFocusChange", diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index cf318fa..c39309e 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -1837,4 +1837,46 @@ }); } }); + + context('test truncate', function () { + $data = [ + ['Test foo bar', 'Test foo bar', 12], + ['Test foo ba', 'Test foo bar', 11], + ['Test foo', 'Test foo bar', 8], + ['Test fo', 'Test foo bar', 7], + ['Test', 'Test foo bar', 4], + ['Test foo bar', 'Test foo bar', 12, '...'], + ['Test foo...', 'Test foo bar', 11, '...'], + ['Test ...', 'Test foo bar', 8, '...'], + ['Test...', 'Test foo bar', 7, '...'], + ['T...', 'Test foo bar', 4, '...'], + ['Test fo....', 'Test foo bar', 11, '....'], + ['Test fòô bàř', 'Test fòô bàř', 12, '', 'UTF-8'], + ['Test fòô bà', 'Test fòô bàř', 11, '', 'UTF-8'], + ['Test fòô', 'Test fòô bàř', 8, '', 'UTF-8'], + ['Test fò', 'Test fòô bàř', 7, '', 'UTF-8'], + ['Test', 'Test fòô bàř', 4, '', 'UTF-8'], + ['Test fòô bàř', 'Test fòô bàř', 12, 'ϰϰ', 'UTF-8'], + ['Test fòô ϰϰ', 'Test fòô bàř', 11, 'ϰϰ', 'UTF-8'], + ['Test fϰϰ', 'Test fòô bàř', 8, 'ϰϰ', 'UTF-8'], + ['Test ϰϰ', 'Test fòô bàř', 7, 'ϰϰ', 'UTF-8'], + ['Teϰϰ', 'Test fòô bàř', 4, 'ϰϰ', 'UTF-8'], + ['What are your pl...', 'What are your plans today?', 19, '...'] + ]; + + foreach ($data as $key => $value) { + it(__formatMessage($key, $value), function () use ($value) { + @list($expected, $str, $length, $substring, $encoding) = $value; + + $substring = $substring ?? ''; + + $stringy = __('Stringy')::create($str, $encoding); + $result = $stringy->truncate($length, $substring); + + \expect($stringy)->toBeAnInstanceOf(__('Stringy')); + \expect((string) $stringy)->toBe($str); + \expect((string) $result)->toBe($expected); + }); + } + }); }); diff --git a/src/Minbaby/Php/Stringy/Stringy.php b/src/Minbaby/Php/Stringy/Stringy.php index 5d0e8cf..fe56c6e 100644 --- a/src/Minbaby/Php/Stringy/Stringy.php +++ b/src/Minbaby/Php/Stringy/Stringy.php @@ -968,4 +968,18 @@ public function toUpperCase() $str = \mb_strtoupper($this->str, $this->encoding); return static::create($str, $this->encoding); } + + public function truncate($length, $substring = '') + { + $stringy = static::create($this->str, $this->encoding); + if ($length >= $stringy->length()) { + return $stringy; + } + // Need to further trim the string so we can append the substring + $substringLength = \mb_strlen($substring, $stringy->encoding); + $length = $length - $substringLength; + $truncated = \mb_substr($stringy->str, 0, $length, $stringy->encoding); + $stringy->str = $truncated . $substring; + return $stringy; + } } diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index 3e7dcc2..f5493bb 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -3422,6 +3422,68 @@ PHP_METHOD(Stringy, toUpperCase) RETURN_ZVAL(&instance, 0, 1); } +PHP_METHOD(Stringy, truncate) +{ + zval *len, *substring; + ZEND_PARSE_PARAMETERS_START(2, 2) + Z_PARAM_ZVAL(len); + Z_PARAM_ZVAL(substring); + ZEND_PARSE_PARAMETERS_END(); + + zval rv; + zval *encoding = zend_read_property(stringy_ce, getThis(), ZEND_STRL("encoding"), 0, &rv); + zval *str = zend_read_property(stringy_ce, getThis(), ZEND_STRL("str"), 0, &rv); + + zval object; + object_init_ex(&object, stringy_ce); + zval method, args[] = { + *str, + *substring, + }; + ZVAL_STRING(&method, "__construct"); + call_user_function(NULL, &object, &method, return_value, 2, args); + + ZVAL_STRING(&method, "length"); + call_user_function(NULL, getThis(), &method, return_value, 0, NULL); + + if (Z_LVAL_P(len) >= Z_LVAL_P(return_value)) { + RETURN_ZVAL(&object, 0, 0); + } + + zval *strNew = zend_read_property(stringy_ce, &object, ZEND_STRL("str"), 0, &rv); + zval args_mb_string[] = { + *substring, + *encoding, + }; + ZVAL_STRING(&method, "mb_strlen"); + call_user_function(NULL, NULL, &method, return_value, 1, args_mb_string); + + size_t substringLength = Z_LVAL_P(return_value); + size_t length = Z_LVAL_P(len); + length = length - substringLength; + + zval zero, zvalLen; + ZVAL_LONG(&zero, 0); + ZVAL_LONG(&zvalLen, length); + zval args_mb_substr[] = { + *strNew, + zero, + zvalLen, + *encoding, + }; + ZVAL_STRING(&method, "mb_substr"); + call_user_function(NULL, NULL, &method, return_value, 4, args_mb_substr); + + zval newVal; + concat_function(&newVal, return_value, substring); + zend_update_property(stringy_ce, &object, ZEND_STRL("str"), &newVal); + + RETURN_ZVAL(&object, 0, 1); +} +ZEND_BEGIN_ARG_INFO(arginfo_truncate, 0) + ZEND_ARG_INFO(0, length) + ZEND_ARG_INFO(0, substring) +ZEND_END_ARG_INFO(); static zend_function_entry methods[] = { PHP_ME(Stringy, __construct, arginfo___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) @@ -3503,6 +3565,7 @@ static zend_function_entry methods[] = { PHP_ME(Stringy, toSpaces, arginfo_toSpaces, ZEND_ACC_PUBLIC) PHP_ME(Stringy, underscored, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, toUpperCase, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, truncate, arginfo_truncate, ZEND_ACC_PUBLIC) PHP_FE_END }; From 9e4daae73cde16fce13a6ba18118e4c97ffb38a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Wed, 24 Jul 2019 23:23:31 +0800 Subject: [PATCH 104/126] =?UTF-8?q?=E6=90=9E=E5=AE=9A=20(#63)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- spec/Stringy/StringySpec.php | 24 ++++++++++++++++++++++- src/Minbaby/Php/Stringy/Stringy.php | 6 ++++++ src/ext/stringy/stringy.c | 30 +++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 1 deletion(-) diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index c39309e..10e34e3 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -6,7 +6,6 @@ use function Kahlan\it; use function Kahlan\describe; - \describe('Stringy Test', function () { \beforeAll(function () { _ns(NS_STRINGY); @@ -1879,4 +1878,27 @@ }); } }); + + context('test toTitleCase', function () { + $data = [ + ['Foo Bar', 'foo bar'], + [' Foo_Bar ', ' foo_bar '], + ['Fòô Bàř', 'fòô bàř', 'UTF-8'], + [' Fòô_Bàř ', ' fòô_bàř ', 'UTF-8'], + ['Αυτοκίνητο Αυτοκίνητο', 'αυτοκίνητο αυτοκίνητο', 'UTF-8'], + ]; + + foreach ($data as $key => $value) { + it(__formatMessage($key, $value), function () use ($value) { + @list($expected, $str, $encoding) = $value; + + $stringy = __('Stringy')::create($str, $encoding); + $result = $stringy->toTitleCase(); + + \expect($stringy)->toBeAnInstanceOf(__('Stringy')); + \expect((string) $stringy)->toBe($str); + \expect((string) $result)->toBe($expected); + }); + } + }); }); diff --git a/src/Minbaby/Php/Stringy/Stringy.php b/src/Minbaby/Php/Stringy/Stringy.php index fe56c6e..57a3aaf 100644 --- a/src/Minbaby/Php/Stringy/Stringy.php +++ b/src/Minbaby/Php/Stringy/Stringy.php @@ -982,4 +982,10 @@ public function truncate($length, $substring = '') $stringy->str = $truncated . $substring; return $stringy; } + + public function toTitleCase() + { + $str = \mb_convert_case($this->str, \MB_CASE_TITLE, $this->encoding); + return static::create($str, $this->encoding); + } } diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index f5493bb..d53c310 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -3485,6 +3485,35 @@ ZEND_BEGIN_ARG_INFO(arginfo_truncate, 0) ZEND_ARG_INFO(0, substring) ZEND_END_ARG_INFO(); +PHP_METHOD(Stringy, toTitleCase) +{ + zval *str, *encoding, rv; + str = zend_read_property(stringy_ce, getThis(), ZEND_STRL("str"), 0, &rv); + encoding = zend_read_property(stringy_ce, getThis(), ZEND_STRL("encoding"), 0, &rv); + + // ZVAL_STRING(&const_mb_case_title, "MB_CASE_TITLE"); + zval *const_mb_case_title = zend_get_constant_str(ZEND_STRL("MB_CASE_TITLE")); + + zval method, args[] = { + *str, + *const_mb_case_title, + *encoding, + }; + ZVAL_STRING(&method, "mb_convert_case"); + call_user_function(NULL, NULL, &method, return_value, 3, args); + + zval obj; + object_init_ex(&obj, stringy_ce); + zval args_construct[] = { + *return_value, + *encoding, + }; + ZVAL_STRING(&method, "__construct"); + call_user_function(NULL, &obj, &method, return_value, 2, args_construct); + + RETURN_ZVAL(&obj, 0, 1); +} + static zend_function_entry methods[] = { PHP_ME(Stringy, __construct, arginfo___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) PHP_ME(Stringy, __toString, NULL, ZEND_ACC_PUBLIC) @@ -3566,6 +3595,7 @@ static zend_function_entry methods[] = { PHP_ME(Stringy, underscored, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, toUpperCase, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, truncate, arginfo_truncate, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, toTitleCase, NULL, ZEND_ACC_PUBLIC) PHP_FE_END }; From 872b0ba2c778475479496a771d35885916712e20 Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Tue, 7 Apr 2020 14:21:50 +0800 Subject: [PATCH 105/126] add drone --- .drone.yml | 50 +++++++++++++++++++++++++++++ spec/Stringy/StringySpec.php | 25 +++++++++++++++ src/Minbaby/Php/Stringy/Stringy.php | 7 ++++ src/ext/stringy/stringy.c | 50 +++++++++++++++++++++++++++++ 4 files changed, 132 insertions(+) create mode 100644 .drone.yml diff --git a/.drone.yml b/.drone.yml new file mode 100644 index 0000000..ff8109f --- /dev/null +++ b/.drone.yml @@ -0,0 +1,50 @@ +--- +kind: pipeline +type: docker +name: php-ext-startup test + +steps: + - name: install vendor + image: composer:1 + commands: + - php -v + - composer install -vvv --profile --no-interaction --prefer-source + - name: build-ext(7.1) + image: php:7.1-cli + commands: + - php -v + - ./vendor/bin/kahlan + - phpize && ./configure && make && make install + - cp .circleci/docker-php-ext-startup.ini /usr/local/etc/php/conf.d/ + - ./vendor/bin/kahlan + - name: build-ext(7.2) + image: php:7.2-cli + commands: + - php -v + - ./vendor/bin/kahlan + - phpize && ./configure && make && make install + - cp .circleci/docker-php-ext-startup.ini /usr/local/etc/php/conf.d/ + - ./vendor/bin/kahlan + - name: build-ext(7.3) + image: php:7.3-cli + commands: + - php -v + - ./vendor/bin/kahlan + - phpize && ./configure && make && make install + - cp .circleci/docker-php-ext-startup.ini /usr/local/etc/php/conf.d/ + - ./vendor/bin/kahlan + # - name: build-ext(7.4) + # image: php:7.4-cli + # commands: + # - php -v + # - ./vendor/bin/kahlan + # - phpize && ./configure && make && make install + # - cp .circleci/docker-php-ext-startup.ini /usr/local/etc/php/conf.d/ + # - ./vendor/bin/kahlan + - name: send-wechat + image: erguotou/drone-instant-access + settings: + channel: + from_secret: CHANNEL + head: Drone Build Status + body: "${DRONE_BUILD_STATUS} at ${DRONE_REPO_BRANCH} branch" diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index 10e34e3..681cf9f 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -1901,4 +1901,29 @@ }); } }); + + context('test toTabs', function () { + $data = [ + [' foo bar ', ' foo bar '], + [' foo bar ', ' foo bar ', 5], + [' foo bar ', ' foo bar ', 2], + [" foo\n bar", " foo\n bar"], + [" fòô\n bàř", " fòô\n bàř"] + ]; + + foreach ($data as $key => $value) { + it(__formatMessage($key, $value), function () use ($value) { + @list($expected, $str, $tabLength) = $value; + $tabLength = $tabLength ?? 4; + + $stringy = __('Stringy')::create($str); + $result = $stringy->toTabs($tabLength); + + \expect($stringy)->toBeAnInstanceOf(__('Stringy')); + \expect((string) $stringy)->toBe($str); + \expect((string) $result)->toBe($expected); + }); + } + + }); }); diff --git a/src/Minbaby/Php/Stringy/Stringy.php b/src/Minbaby/Php/Stringy/Stringy.php index 57a3aaf..1336408 100644 --- a/src/Minbaby/Php/Stringy/Stringy.php +++ b/src/Minbaby/Php/Stringy/Stringy.php @@ -988,4 +988,11 @@ public function toTitleCase() $str = \mb_convert_case($this->str, \MB_CASE_TITLE, $this->encoding); return static::create($str, $this->encoding); } + + public function toTabs($tabLength = 4) + { + $spaces = str_repeat(' ', $tabLength); + $str = str_replace($spaces, "\t", $this->str); + return static::create($str, $this->encoding); + } } diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index d53c310..d8e0165 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -3514,6 +3514,55 @@ PHP_METHOD(Stringy, toTitleCase) RETURN_ZVAL(&obj, 0, 1); } +PHP_METHOD(Stringy, toTabs) +{ + zval *tabLength; + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ZVAL(tabLength) + ZEND_PARSE_PARAMETERS_END(); + + if (tabLength == NULL) { + tabLength = malloc(sizeof(zval)); + ZVAL_LONG(tabLength, 4); + } + + zval empty; + ZVAL_STRING(&empty, " "); + + zval func, args[] = { + empty, + *tabLength + }; + ZVAL_STRING(&func, "str_repeat"); + call_user_function(NULL, NULL, &func, return_value, 2, args); + + zval *str, *encoding, rv; + str = zend_read_property(stringy_ce, getThis(), ZEND_STRL("str"), 0, &rv); + encoding = zend_read_property(stringy_ce, getThis(), ZEND_STRL("encoding"), 0, &rv); + + zval tab; + ZVAL_STRING(&tab, "\t"); + + zval args_str_replace[] = { + *return_value, + tab, + *str + }; + ZVAL_STRING(&func, "str_replace"); + call_user_function(NULL, NULL, &func, return_value, 3, args_str_replace); + + zval obj; + object_init_ex(&obj, stringy_ce); + zval args_construct[] = { + *return_value, + *encoding, + }; + ZVAL_STRING(&func, "__construct"); + call_user_function(NULL, &obj, &func, return_value, 2, args_construct); + + RETURN_ZVAL(&obj, 0, 1); +} + static zend_function_entry methods[] = { PHP_ME(Stringy, __construct, arginfo___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) PHP_ME(Stringy, __toString, NULL, ZEND_ACC_PUBLIC) @@ -3596,6 +3645,7 @@ static zend_function_entry methods[] = { PHP_ME(Stringy, toUpperCase, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, truncate, arginfo_truncate, ZEND_ACC_PUBLIC) PHP_ME(Stringy, toTitleCase, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, toTabs, NULL, ZEND_ACC_PUBLIC) PHP_FE_END }; From 98fd00b734fb4b38052dacd9850f3ab6ed1c28ea Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Tue, 7 Apr 2020 14:27:36 +0800 Subject: [PATCH 106/126] update lib --- composer.lock | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/composer.lock b/composer.lock index e77ea92..1dde26d 100644 --- a/composer.lock +++ b/composer.lock @@ -9,20 +9,20 @@ "packages-dev": [ { "name": "kahlan/kahlan", - "version": "4.4.0", + "version": "4.7.2", "source": { "type": "git", "url": "https://github.com/kahlan/kahlan.git", - "reference": "6a2f0d1dd1a45b518010bf8d2a3a9bae9e1bd7a9" + "reference": "025114b7f13985abceff3ba0e28cca71cb0d40e8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/kahlan/kahlan/zipball/6a2f0d1dd1a45b518010bf8d2a3a9bae9e1bd7a9", - "reference": "6a2f0d1dd1a45b518010bf8d2a3a9bae9e1bd7a9", + "url": "https://api.github.com/repos/kahlan/kahlan/zipball/025114b7f13985abceff3ba0e28cca71cb0d40e8", + "reference": "025114b7f13985abceff3ba0e28cca71cb0d40e8", "shasum": "", "mirrors": [ { - "url": "https://dl.laravel-china.org/%package%/%reference%.%type%", + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", "preferred": true } ] @@ -31,7 +31,7 @@ "php": ">=5.5" }, "require-dev": { - "squizlabs/php_codesniffer": "^3.3" + "squizlabs/php_codesniffer": "^3.4" }, "bin": [ "bin/kahlan" @@ -65,7 +65,7 @@ "testing", "unit test" ], - "time": "2018-12-01T00:19:49+00:00" + "time": "2020-01-25T16:39:06+00:00" } ], "aliases": [], @@ -77,5 +77,6 @@ "php": "^7.0", "ext-json": "*" }, - "platform-dev": [] + "platform-dev": [], + "plugin-api-version": "1.1.0" } From cc829c2ea37d6fd2b22a5705bce6f166f2914c5a Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Tue, 7 Apr 2020 14:48:31 +0800 Subject: [PATCH 107/126] update --- .drone.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.drone.yml b/.drone.yml index ff8109f..c61f669 100644 --- a/.drone.yml +++ b/.drone.yml @@ -47,4 +47,4 @@ steps: channel: from_secret: CHANNEL head: Drone Build Status - body: "${DRONE_BUILD_STATUS} at ${DRONE_REPO_BRANCH} branch" + body: "[${DRONE_REPO}] ${DRONE_BUILD_STATUS} at ${DRONE_REPO_BRANCH} branch" From 2412a14601616b16b090d9345623a3aecb1212f0 Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Tue, 7 Apr 2020 18:44:34 +0800 Subject: [PATCH 108/126] toSpaces --- .drone.yml | 2 +- scripts/test.sh | 2 ++ spec/Stringy/StringySpec.php | 23 +++++++++++++++++++++++ src/Minbaby/Php/Stringy/Stringy.php | 7 +++++++ src/ext/stringy/stringy.c | 26 ++++++++++++++++++++++++++ 5 files changed, 59 insertions(+), 1 deletion(-) diff --git a/.drone.yml b/.drone.yml index c61f669..abd1a9e 100644 --- a/.drone.yml +++ b/.drone.yml @@ -46,5 +46,5 @@ steps: settings: channel: from_secret: CHANNEL - head: Drone Build Status + head: "[${DRONE_REPO}] Build Status" body: "[${DRONE_REPO}] ${DRONE_BUILD_STATUS} at ${DRONE_REPO_BRANCH} branch" diff --git a/scripts/test.sh b/scripts/test.sh index 793270d..bbb2194 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -14,3 +14,5 @@ export MINBABY_TEST_EXT=0 phpbrew ext enable startup export MINBABY_TEST_EXT=1 ./vendor/bin/kahlan + +export MINBABY_TEST_EXT=0 diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index 681cf9f..8289d49 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -1924,6 +1924,29 @@ \expect((string) $result)->toBe($expected); }); } + }); + + context('test toLowerCase', function () { + $data = [ + ['foo bar', 'FOO BAR'], + [' foo_bar ', ' FOO_bar '], + ['fòô bàř', 'FÒÔ BÀŘ', 'UTF-8'], + [' fòô_bàř ', ' FÒÔ_bàř ', 'UTF-8'], + ['αυτοκίνητο', 'ΑΥΤΟΚΊΝΗΤΟ', 'UTF-8'], + ]; + + foreach ($data as $key => $value) { + it(__formatMessage($key, $value), function () use ($value) { + @list($expected, $str, $tabLength) = $value; + $tabLength = $tabLength ?? 4; + + $stringy = __('Stringy')::create($str); + $result = $stringy->toLowerCase($tabLength); + \expect($stringy)->toBeAnInstanceOf(__('Stringy')); + \expect((string) $stringy)->toBe($str); + \expect((string) $result)->toBe($expected); + }); + } }); }); diff --git a/src/Minbaby/Php/Stringy/Stringy.php b/src/Minbaby/Php/Stringy/Stringy.php index 1336408..bcabef9 100644 --- a/src/Minbaby/Php/Stringy/Stringy.php +++ b/src/Minbaby/Php/Stringy/Stringy.php @@ -995,4 +995,11 @@ public function toTabs($tabLength = 4) $str = str_replace($spaces, "\t", $this->str); return static::create($str, $this->encoding); } + + public function toLowerCase() + { + $str = \mb_strtolower($this->str, $this->encoding); + + return static::create($str, $this->encoding); + } } diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index d8e0165..2df4af0 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -3563,6 +3563,31 @@ PHP_METHOD(Stringy, toTabs) RETURN_ZVAL(&obj, 0, 1); } +PHP_METHOD(Stringy, toLowerCase) +{ + zval *str, *encoding, rv; + str = zend_read_property(stringy_ce, getThis(), ZEND_STRL("str"), 0, &rv); + encoding = zend_read_property(stringy_ce, getThis(), ZEND_STRL("encoding"), 0, &rv); + + zval func = {}; + ZVAL_STRING(&func, "mb_strtolower"); + zval args_str_to_lower[] = { + *str, + }; + call_user_function(NULL, NULL, &func, return_value, 1, args_str_to_lower); + + zval obj; + object_init_ex(&obj, stringy_ce); + zval args_construct[] = { + *return_value, + *encoding, + }; + ZVAL_STRING(&func, "__construct"); + call_user_function(NULL, &obj, &func, return_value, 2, args_construct); + + RETURN_ZVAL(&obj, 0, 1); +} + static zend_function_entry methods[] = { PHP_ME(Stringy, __construct, arginfo___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) PHP_ME(Stringy, __toString, NULL, ZEND_ACC_PUBLIC) @@ -3646,6 +3671,7 @@ static zend_function_entry methods[] = { PHP_ME(Stringy, truncate, arginfo_truncate, ZEND_ACC_PUBLIC) PHP_ME(Stringy, toTitleCase, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, toTabs, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, toLowerCase, NULL, ZEND_ACC_PUBLIC) PHP_FE_END }; From fbda8e47bf0673270b4ba5e1726606e5cbbb5cca Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Tue, 7 Apr 2020 18:53:33 +0800 Subject: [PATCH 109/126] test drone env --- .drone.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.drone.yml b/.drone.yml index abd1a9e..d820302 100644 --- a/.drone.yml +++ b/.drone.yml @@ -47,4 +47,4 @@ steps: channel: from_secret: CHANNEL head: "[${DRONE_REPO}] Build Status" - body: "[${DRONE_REPO}] ${DRONE_BUILD_STATUS} at ${DRONE_REPO_BRANCH} branch" + body: "[${DRONE_REPO}] ${DRONE_BUILD_STATUS} at ${DRONE_BRANCH} branch" From efe0b057c94c176e8be46c483e7cba7957d222dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Sun, 5 Jul 2020 12:55:07 +0800 Subject: [PATCH 110/126] =?UTF-8?q?=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/c_cpp_properties.json | 4 +- .vscode/settings.json | 14 +- README.MD | 20 + composer.json | 23 + docs/README.md | 26 + kahlan-config.php | 6 +- scripts/build.sh | 5 +- scripts/init-development.sh | 45 +- scripts/prepare.sh | 1 - scripts/resources/icu-config | 765 ++++++++++++++++++++++++++++ scripts/subtree.sh | 5 - spec/Stringy/StringySpec.php | 33 ++ src/Minbaby/Php/Stringy/Stringy.php | 23 + src/ext/stringy/stringy.c | 63 +++ 14 files changed, 1001 insertions(+), 32 deletions(-) create mode 100644 docs/README.md create mode 100755 scripts/resources/icu-config delete mode 100755 scripts/subtree.sh diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index 5e0a595..60ba042 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -4,7 +4,7 @@ "name": "Linux", "includePath": [ "${workspaceFolder}/**", - "~/.phpbrew/build/php-7.1.23/**" + "~/.phpbrew/build/php-7.1.33/**" ], "defines": [], "compilerPath": "/usr/bin/gcc", @@ -16,7 +16,7 @@ "name": "Mac", "includePath": [ "${workspaceFolder}/**", - "~/.phpbrew/build/php-7.1.23/**" + "~/.phpbrew/build/php-7.1.33/**" ], "defines": [], "compilerPath": "/usr/bin/gcc", diff --git a/.vscode/settings.json b/.vscode/settings.json index a0e2daa..a7c201e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -5,7 +5,17 @@ "__locale": "c", "__string": "c", "string": "c", - "string_view": "c" + "string_view": "c", + "array": "c", + "initializer_list": "c", + "utility": "c", + "sstream": "c", + "istream": "c", + "ostream": "c", + "functional": "c", + "tuple": "c", + "type_traits": "c", + "random": "c" }, "editor.mouseWheelZoom": false, "files.autoSave": "onFocusChange", @@ -19,5 +29,5 @@ "**/CVS": true, "**/.DS_Store": true }, - "editor.minimap.enabled": false + "editor.minimap.enabled": true } diff --git a/README.MD b/README.MD index ddf7c0f..8457008 100644 --- a/README.MD +++ b/README.MD @@ -28,6 +28,26 @@ 2. 查看 `src/Minbaby/` 目录下的 php 实现 3. 查看 `src/ext` 目录下的 c 实现 +## 常用命令 + +1. 测试所有 + +```bash +composer run test +``` + +2. 测试 php 部分代码 + +```bash +composer run test-php +``` + +3. 测试 ext 部分代码 + +```bash +composer run test-ext +``` + ## TODO - [ ] [stringy](https://github.com/danielstjules/Stringy) diff --git a/composer.json b/composer.json index 66fe082..3b5e936 100644 --- a/composer.json +++ b/composer.json @@ -29,5 +29,28 @@ }, "require-dev": { "kahlan/kahlan": "^4.3" + }, + "scripts": { + "init-dev": "./scripts/init-development.sh", + "prepare": "./scripts/prepare.sh", + "build": "./scripts/build.sh", + "test": [ + "@test-php", + "@test-ext" + ], + "test-php": [ + "phpbrew ext disable startup", + "MINBABY_TEST_EXT=0 ./vendor/bin/kahlan" + ], + "test-ext": [ + "@build", + "phpbrew ext enable startup", + "MINBABY_TEST_EXT=1 ./vendor/bin/kahlan" + ], + "test-ext-vagrind": [ + "@build", + "phpbrew ext enable startup", + "MINBABY_TEST_EXT=1 USE_ZEND_ALLOC=0 valgrind --log-file=/tmp/valgrind.log php ./vendor/bin/kahlan" + ] } } diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..75d539b --- /dev/null +++ b/docs/README.md @@ -0,0 +1,26 @@ +# 一些备忘操作 + +## 数组操作 + +|php语法|c语法(arr是zval*)|说明| +|-|-|-| +|$arr = array() |array_init(arr)|初始化一个新数组, 还有其他方式| +|$arr[] = NULL| add_next_index_null(arr)|| +|$arr[] = 42|add_next_index_long(arr, 42)|| +|$arr[] = true|add_next_index_bool(arr, 1)|| +|$arr[] = 3.14|add_next_index_double(arr, 3.14)|| +|$arr[] = 'foo'|add_next_index_string(arr, "foo", 1)|| +|$arr[] = $myvar|add_next_index_zval(arr, myvar)|| +|$arr[0] = NULL|add_index_null(arr, 0)|| +|$arr[1] = 42|add_index_long(arr, 1, 42)|| +|$arr[2] = true|add_index_bool(arr, 2, 1)|| +|$arr[3] = 3.14|add_index_double(arr, 3, 3.14)|| +|$arr[5] = $myvar|add_index_zval(arr, 5, myvar)|| +|$arr['abc'] = NULL|add_assoc_null(arr, "abc")|| +|$arr['def'] = 711|add_assoc_long(arr, "def", 711)|| +|$arr['ghi'] = true|add_assoc_bool(arr, "ghi", 1)|???| +|$arr['jkl'] = 1.44|add_assoc_double(arr, "jkl", 1.44)|| +|$arr['mno'] = 'baz'|add_assoc_string(arr, "mno", "baz", 1)|| +|$arr['pqr'] = $myvar|add_assoc_zval(arr, "pqr", myvar)|| + +参考:https://hongweipeng.com/index.php/archives/1014/ \ No newline at end of file diff --git a/kahlan-config.php b/kahlan-config.php index 6cfdff0..4d2e5d4 100644 --- a/kahlan-config.php +++ b/kahlan-config.php @@ -3,6 +3,8 @@ /** @var \Kahlan\Cli\CommandLine $commandLine */ $commandLine = $this->commandLine(); -$commandLine->option('reporter', 'default', 'verbose'); $commandLine->option('ff', 'default', 1); -isset($_SERVER['CI']) && $_SERVER['CI'] === true && $commandLine->option('clover', 'default', 'coverage.xml'); +if (isset($_SERVER['CI']) && $_SERVER['CI'] === true) { + $commandLine->option('clover', 'default', 'coverage.xml'); + $commandLine->option('reporter', 'default', 'verbose'); +} diff --git a/scripts/build.sh b/scripts/build.sh index f7af8b3..91cc53f 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -1,7 +1,6 @@ #!/usr/bin/env bash set -e -set -x pwd @@ -12,5 +11,5 @@ rm -f $PHPBREW_ROOT/php/$PHPBREW_PHP/var/db/start.ini echo "build" make && make install -echo "enabled startup" -phpbrew ext enable startup +# echo "enabled startup" +# phpbrew ext enable startup diff --git a/scripts/init-development.sh b/scripts/init-development.sh index 5ab9d37..f0d84c1 100755 --- a/scripts/init-development.sh +++ b/scripts/init-development.sh @@ -4,31 +4,42 @@ set -e -x export PATH=/usr/bin:$PATH -export PHP_VERSION=php-7.1.23 +export PHP_VERSION=php-7.1.33 export SYSTEM_NAME=`uname` -[ "$SYSTEM_NAME" == "Darwin" ] && LIB_BZ2='/usr/local/opt/bzip2/' -[ "$SYSTEM_NAME" == "Darwin" ] && LIB_ZIP='/usr/local/opt/zlib/' -[ "$SYSTEM_NAME" == "Darwin" ] && LIB_SSL='/usr/local/opt/openssl/' - -# sudo apt install libxml2-dev -# sudo apt install libssh-dev -# sudo apt install libbz2-dev -# sudo apt install libcurl4-openssl-dev -# sudo apt install libmcrypt-dev -# sudo apt install libreadline-dev -# sudo apt install libxslt1-dev -# sudo apt install autoconf +export SCRIPT_DIR=`dirname $0` + +[ "$SYSTEM_NAME" == "Darwin" ] && LIB_BZ2='=/usr/local/opt/bzip2/' +[ "$SYSTEM_NAME" == "Darwin" ] && LIB_ZIP='=/usr/local/opt/zlib/' +[ "$SYSTEM_NAME" == "Darwin" ] && LIB_SSL='=/usr/local/opt/openssl/' + +if [ ! -x "$(command -v icu-config)" ]; then + sudo cp $SCRIPT_DIR/resources/icu-config /usr/bin/icu-config +fi + +if [ "$SYSTEM_NAME" == "Linux" ]; then + sudo apt install \ + libxml2-dev \ + libssh-dev \ + libbz2-dev \ + libcurl4-openssl-dev \ + libmcrypt-dev \ + libreadline-dev \ + libxslt1-dev \ + autoconf \ + valgrind +fi phpbrew --debug install \ - --mirror=http://cn2.php.net -j 4 \ + -j 4 \ $PHP_VERSION \ +default \ - +bz2=$LIB_BZ2 \ - +zlib=$LIB_ZIP \ + +bz2$LIB_BZ2 \ + +zlib$LIB_ZIP \ +mb \ - +openssl=$LIB_SSL +intl \ + +openssl$LIB_SSL \ + +intl \ +mysql \ +pdo \ +xml diff --git a/scripts/prepare.sh b/scripts/prepare.sh index 1b272db..262d843 100755 --- a/scripts/prepare.sh +++ b/scripts/prepare.sh @@ -1,7 +1,6 @@ #!/usr/bin/env bash set -e -set -x echo "prepare..." phpize && ./configure --enable-debug diff --git a/scripts/resources/icu-config b/scripts/resources/icu-config new file mode 100755 index 0000000..077d64b --- /dev/null +++ b/scripts/resources/icu-config @@ -0,0 +1,765 @@ +#!/bin/sh +## -*-sh-*- +#set -x +# BEGIN of icu-config-top +# Copyright (C) 2016 and later: Unicode, Inc. and others. +# License & terms of use: http://www.unicode.org/copyright.html +#****************************************************************************** +# Copyright (C) 1999-2013, International Business Machines +# Corporation and others. All Rights Reserved. +#****************************************************************************** +# This script is designed to aid configuration of ICU. +# rpath links a library search path right into the binaries. +# +# Note: it's preferred to use the .pc files rather than icu-config. +# + +### END of icu-config-top + +## Zero out prefix. +execprefix= +prefix= + + +loaddefs() +{ + +# Following from icu/icu4c/source/config/Makefile.inc +# Copyright (C) 2016 and later: Unicode, Inc. and others. +# License & terms of use: http://www.unicode.org/copyright.html +## -*-makefile-*- +#****************************************************************************** +# Copyright (C) 1999-2014, International Business Machines +# Corporation and others. All Rights Reserved. +#****************************************************************************** +# This Makefile.inc is designed to be included into projects which make use +# of the ICU. + +# CONTENTS OF THIS FILE +# 1). Base configuration information and linkage +# 2). Variables giving access to ICU tools +# 3). Host information +# 4). Compiler flags and settings +# 5). Data Packaging directives +# 6). Include of platform make fragment (mh-* file) + +################################################################## +# +# *1* base configuration information and linkage +# +################################################################## +# The PREFIX is the base of where ICU is installed. +# Inside this directory you should find bin, lib, include/unicode, +# etc. If ICU is not installed in this directory, you must change the +# following line. There should exist ${prefix}/include/unicode/utypes.h +# for example. +default_prefix="/usr" +if [ "x${prefix}" = "x" ]; then prefix="$default_prefix"; fi +exec_prefix="${prefix}" +libdir="${prefix}/lib/x86_64-linux-gnu" +libexecdir="${prefix}/lib/icu" +bindir="${exec_prefix}/bin" +datarootdir="${prefix}/share" +datadir="${datarootdir}" +sbindir="${exec_prefix}/sbin" + +# about the ICU version +VERSION="66.1" +UNICODE_VERSION="13.0" + +# The prefix for ICU libraries, normally 'icu' +ICUPREFIX="icu" +PACKAGE="icu" +LIBICU="lib${ICUPREFIX}" + +# Static library prefix and file extension +STATIC_PREFIX="s" +LIBSICU="lib${STATIC_PREFIX}${ICUPREFIX}" +A="a" + +# Suffix at the end of libraries. Usually empty. +ICULIBSUFFIX="" +# ICULIBSUFFIX_VERSION is non-empty if it is to contain a library +# version. For example, if it is 21, it means libraries are named +# libicuuc21.so for example. + +# rpath links a library search path right into the binaries. +## mh-files MUST NOT override RPATHLDFLAGS unless they provide +## equivalent '#SH#' lines for icu-config fixup +default_ENABLE_RPATH="NO" +if [ "x${ENABLE_RPATH}" = "x" ]; then ENABLE_RPATH="$default_ENABLE_RPATH"; fi +RPATHLDFLAGS="${LD_RPATH}${LD_RPATH_PRE}${libdir}" + +# icu-config version of above 'if': +case "x$ENABLE_RPATH" in +x[yY]*) + ENABLE_RPATH=YES + RPATHLDFLAGS="${LD_RPATH}${LD_RPATH_PRE}${libdir}" + ;; + +x[nN]*) + ENABLE_RPATH=NO + RPATHLDFLAGS="" + ;; + +x) + ENABLE_RPATH=NO + RPATHLDFLAGS="" + ;; + +*) + echo $0: Unknown --enable-rpath value ${ENABLE_RPATH} 1>&2 + exit 3 + ;; +esac + +# Name flexibility for the library naming scheme. Any modifications should +# be made in the mh- file for the specific platform. +DATA_STUBNAME="data" +COMMON_STUBNAME="uc" +I18N_STUBNAME="i18n" +LAYOUTEX_STUBNAME="lx" +IO_STUBNAME="io" +TOOLUTIL_STUBNAME="tu" +CTESTFW_STUBNAME="test" + + +### To link your application with ICU: +# 1. use LDFLAGS, CFLAGS, etc from above +# 2. link with ${ICULIBS} +# 3. optionally, add one or more of: +# - ${ICULIBS_I18N} - i18n library, formatting, etc. +# - ${ICULIBS_ICUIO} - ICU stdio equivalent library + +ICULIBS_COMMON="-l${ICUPREFIX}uc${ICULIBSUFFIX}${ICULIBSUFFIX_VERSION}" +ICULIBS_DATA="-l${ICUPREFIX}${DATA_STUBNAME}${ICULIBSUFFIX}${ICULIBSUFFIX_VERSION}" +ICULIBS_I18N="-l${ICUPREFIX}${I18N_STUBNAME}${ICULIBSUFFIX}${ICULIBSUFFIX_VERSION}" +ICULIBS_TOOLUTIL="-l${ICUPREFIX}tu${ICULIBSUFFIX}${ICULIBSUFFIX_VERSION}" +ICULIBS_CTESTFW="-l${ICUPREFIX}ctestfw${ICULIBSUFFIX}${ICULIBSUFFIX_VERSION}" +ICULIBS_ICUIO="-l${ICUPREFIX}io${ICULIBSUFFIX}${ICULIBSUFFIX_VERSION}" +ICULIBS_OBSOLETE="-l${ICUPREFIX}obsolete${ICULIBSUFFIX}${ICULIBSUFFIX_VERSION}" +ICULIBS_LAYOUTEX="-l${ICUPREFIX}lx${ICULIBSUFFIX}${ICULIBSUFFIX_VERSION}" +ICULIBS_BASE="-L${libdir}" + +# for icu-config to test with +ICULIBS_COMMON_LIB_NAME="${LIBICU}${COMMON_STUBNAME}${ICULIBSUFFIX}${ICULIBSUFFIX_VERSION}.${SO}" +ICULIBS_COMMON_LIB_NAME_A="${LIBICU}${COMMON_STUBNAME}${ICULIBSUFFIX}.${A}" + +# ICULIBS is the set of libraries your application should link +# with usually. Many applications will want to add ${ICULIBS_I18N} as well. +ICULIBS="${ICULIBS_BASE} ${ICULIBS_I18N} ${ICULIBS_COMMON} ${ICULIBS_DATA} " + +# Proper echo newline handling is needed in icu-config +ECHO_N="-n" +ECHO_C="" +# Not currently being used but good to have for proper tab handling +ECHO_T="" + +################################################################## +# +# *2* access to ICU tools +# +################################################################## +# Environment variable to set a runtime search path +# (Overridden when necessary in -mh files) +LDLIBRARYPATH_ENVVAR="LD_LIBRARY_PATH" + +# Versioned target for a shared library +## FINAL_SO_TARGET = ${SO_TARGET}.${SO_TARGET_VERSION} +## MIDDLE_SO_TARGET = ${SO_TARGET}.${SO_TARGET_VERSION_MAJOR} + +# Access to important ICU tools. +# Use as follows: ${INVOKE} ${GENRB} arguments .. +INVOKE="${LDLIBRARYPATH_ENVVAR}=${libdir}:$$${LDLIBRARYPATH_ENVVAR} ${LEAK_CHECKER}" +GENCCODE="${sbindir}/genccode" +ICUPKG="${sbindir}/icupkg" +GENCMN="${sbindir}/gencmn" +GENRB="${bindir}/genrb" +PKGDATA="${bindir}/pkgdata" + +# moved here because of dependencies +pkgdatadir="${datadir}/${PACKAGE}${ICULIBSUFFIX}/${VERSION}" +pkglibdir="${libdir}/${PACKAGE}${ICULIBSUFFIX}/${VERSION}" + +################################################################## +# +# *3* Information about the host +# +################################################################## + +# Information about the host that 'configure' was run on. +host="x86_64-pc-linux-gnu" +host_alias="" +host_cpu="x86_64" +host_vendor="pc" +host_os="linux-gnu" +# Our platform canonical name (as determined by configure) +# this is a #define value (i.e. U_XXXX or XXXX) +platform="U_LINUX" + +################################################################## +# +# *4* compiler flags and misc. options +# +################################################################## +AR="ar" +# initial tab keeps it out of the shell version. +ARFLAGS=" ${ARFLAGS}" +CC="gcc" +CPP="gcc -E" +CFLAGS="" +CPPFLAGS="-I${prefix}/include" +CXXFLAGS="-std=c++11" +CXX="g++" +DEFAULT_MODE="dll" +DEFS="-DPACKAGE_NAME=\"ICU\" -DPACKAGE_TARNAME=\"International\ Components\ for\ Unicode\" -DPACKAGE_VERSION=\"66.1\" -DPACKAGE_STRING=\"ICU\ 66.1\" -DPACKAGE_BUGREPORT=\"http://icu-project.org/bugs\" -DPACKAGE_URL=\"http://icu-project.org\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DSIZEOF_VOID_P=8 -DHAVE_LIBM=1 -DHAVE_ELF_H=1 -DHAVE_DLFCN_H=1 -DHAVE_DLOPEN=1 -DHAVE_GETTIMEOFDAY=1 -DHAVE_LIBPTHREAD=1 -DHAVE_INTTYPES_H=1 -DHAVE_DIRENT_H=1 -DHAVE_WCHAR_H=1 -DSIZEOF_WCHAR_T=4 " +# use a consistent INSTALL +INSTALL="${SHELL} ${pkgdatadir}/install-sh -c" +INSTALL_DATA="${INSTALL} -m 644" +INSTALL_PROGRAM="${INSTALL}" +INSTALL_SCRIPT="${INSTALL}" +LDFLAGS="${RPATHLDFLAGS}" +LIBS="-lpthread -ldl -lm " +LIB_M="" +LIB_VERSION="66.1" +LIB_VERSION_MAJOR="66" +MKINSTALLDIRS="${SHELL} ${pkgdatadir}/mkinstalldirs" +RANLIB="ranlib" +RMV="rm -rf" +SHELL="/bin/bash" +SHLIB_c="${CC} ${DEFS} ${CPPFLAGS} ${CFLAGS} ${LDFLAGS} -shared" +SHLIB_cc="${CXX} ${DEFS} ${CPPFLAGS} ${CXXFLAGS} ${LDFLAGS} -shared" +U_IS_BIG_ENDIAN="0" +includedir="${prefix}/include/x86_64-linux-gnu" +infodir="${prefix}/share/info" +localstatedir="/var" +mandir="${prefix}/share/man" +oldincludedir="/usr/include" +program_transform_name="s,x,x," +sharedstatedir="${prefix}/com" +sysconfdir="/etc" +INSTALL_L="${INSTALL_DATA}" + +# for derivative builds - don't bother with VERBOSE/NONVERBOSE SILENT_COMPILE + +################################################################## +# +# *5* packaging options and directories +# +################################################################## + +# The basename of the ICU data file (i.e. icudt21b ) +ICUDATA_CHAR="l" +ICUDATA_NAME="icudt66l" + +# Defaults for pkgdata's mode and directories +# The default data dir changes depending on what packaging mode +# is being used +if [ "x$PKGDATA_MODE" = "x" ]; +then +PKGDATA_MODE="dll" +fi + +case "$PKGDATA_MODE" in +common) +ICUDATA_DIR="${pkgdatadir}" +ICUPKGDATA_DIR="${ICUDATA_DIR}" +;; +dll) +ICUDATA_DIR="${pkgdatadir}" +ICUPKGDATA_DIR="${libdir}" +;; +*) +ICUDATA_DIR="${pkgdatadir}" +ICUPKGDATA_DIR="${ICUDATA_DIR}" +;; + +esac + +GENCCODE_ASSEMBLY="-a gcc" + +################################################################## +# +# *6* Inclusion of platform make fragment (mh-* file) +# +################################################################## +# The mh- file ("make fragment") for the platform is included here. +# It may override the above settings. +# It is put last so that the mh-file can override anything. +# The selfcheck is just a sanity check that this makefile is +# parseable. The mh fragment is only included if this does not occur. + +# Following from ./config/mh-linux +## -*-makefile-*- +## Copyright (C) 2016 and later: Unicode, Inc. and others. +## License & terms of use: http://www.unicode.org/copyright.html +## Linux-specific setup +## Copyright (c) 1999-2013, International Business Machines Corporation and +## others. All Rights Reserved. + +## Commands to generate dependency files +GEN_DEPS_c="${CC} -E -MM ${DEFS} ${CPPFLAGS}" +GEN_DEPS_cc="${CXX} -E -MM ${DEFS} ${CPPFLAGS} ${CXXFLAGS}" + +## Flags for position independent code +SHAREDLIBCFLAGS="-fPIC" +SHAREDLIBCXXFLAGS="-fPIC" +SHAREDLIBCPPFLAGS="-DPIC" + +## Additional flags when building libraries and with threads +THREADSCPPFLAGS="-D_REENTRANT" +LIBCPPFLAGS="" + +## Compiler switch to embed a runtime search path +LD_RPATH="-Wl,-zorigin,-rpath,\$\$ORIGIN " +LD_RPATH_PRE="-Wl,-rpath," + +## These are the library specific LDFLAGS +LDFLAGSICUDT="-nodefaultlibs -nostdlib" + +## Compiler switch to embed a library name +# The initial tab in the next line is to prevent icu-config from reading it. +# We can't depend on MIDDLE_SO_TARGET being set. +LD_SONAME= + +## Shared library options +LD_SOOPTIONS="-Wl,-Bsymbolic" + +## Shared object suffix +SO="so" +## Non-shared intermediate object suffix +STATIC_O="ao" + +## Compilation rules + +## Dependency rules + +## Versioned libraries rules + +## Bind internal references + +# LDflags that pkgdata will use +BIR_LDFLAGS="-Wl,-Bsymbolic" + +# Dependencies [i.e. map files] for the final library +BIR_DEPS="" + +## Remove shared library 's' +STATIC_PREFIX_WHEN_USED="" +STATIC_PREFIX="" + +## End Linux-specific setup + +## -*-sh-*- +## BEGIN of icu-config-bottom. +## Copyright (C) 2016 and later: Unicode, Inc. and others. +## License & terms of use: http://www.unicode.org/copyright.html +## Copyright (c) 2002-2013, International Business Machines Corporation and +## others. All Rights Reserved. + +ICUUC_FILE="${libdir}/${ICULIBS_COMMON_LIB_NAME}" +ICUUC_FILE_A="${libdir}/${ICULIBS_COMMON_LIB_NAME_A}" + +# echo ENABLE RPATH $ENABLE_RPATH and RPATHLDFLAGS=${RPATH_LDFLAGS} +if [ "x$PKGDATA_MODE" = "x" ]; then + PKGDATA_MODE=dll +fi + +} + +## The actual code of icu-config goes here. + +ME=`basename "$0"` + +allflags() +{ + echo " --noverify Don't verify that ICU is actually installed." + echo " --bindir Print binary directory path (bin)" + echo " --cc Print C compiler used [CC]" + echo " --cflags Print C compiler flags [CFLAGS]" + echo " --cflags-dynamic Print additional C flags for" + echo " building shared libraries." + echo " --cppflags Print C Preprocessor flags [CPPFLAGS]" + echo " --cppflags-dynamic Print additional C Preprocessor flags for" + echo " building shared libraries." + echo " --cppflags-searchpath Print only -I include directives (-Iinclude)" + echo " --cxx Print C++ compiler used [CXX]" + echo " --cxxflags Print C++ compiler flags [CXXFLAGS]" + echo " --cxxflags-dynamic Print additional C++ flags for" + echo " building shared libraries." + echo " --detect-prefix Attempt to detect prefix based on PATH" + echo " --exec-prefix Print prefix for executables (/bin)" + echo " --exists Return with 0 status if ICU exists else fail" + echo " --help, -?, --usage Print this message" + echo " --icudata Print shortname of ICU data file (icudt21l)" + echo " --icudata-install-dir Print path to install data to - use as --install option to pkgdata(1)" + echo " --icudata-mode Print default ICU pkgdata mode (dll) - use as --mode option to pkgdata(1)." + echo " --icudatadir Print path to packaged archive data. Can set as [ICU_DATA]" + echo " --invoke Print commands to invoke an ICU program" + echo " --invoke= Print commands to invoke an ICU program named (ex: genrb)" + echo " --ldflags Print -L search path and -l libraries to link with ICU [LDFLAGS]. This is for the data, uc (common), and i18n libraries only. " + echo " --ldflags-libsonly Same as --ldflags, but only the -l directives" + echo " --ldflags-searchpath Print only -L (search path) directive" + echo " --ldflags-system Print only system libs ICU links with (-lpthread, -lm)" + echo " --ldflags-icuio Print ICU icuio link directive. Use in addition to --ldflags " + echo " --ldflags-obsolete Print ICU obsolete link directive. Use in addition to --ldflags. (requires icuapps/obsolete to be built and installed.) " + echo " --mandir Print manpage (man) path" + echo " --prefix Print PREFIX to icu install (/usr/local)" + echo " --prefix=XXX Set prefix to XXX for remainder of command" + echo " --sbindir Print system binary path (sbin) " + echo " --shared-datadir Print shared data (share) path. This is NOT the ICU data dir." + echo " --shlib-c Print the command to compile and build C shared libraries with ICU" + echo " --shlib-cc Print the command to compile and build C++ shared libraries with ICU" + echo " --sysconfdir Print system config (etc) path" + echo " --unicode-version Print version of Unicode data used in ICU ($UNICODE_VERSION)" + echo " --version Print ICU version ($VERSION)" + echo " --incfile Print path to Makefile.inc" + echo " --incpkgdatafile Print path to pkgdata.inc (for -O option of pkgdata)" + echo " --install Print path to install-sh" + echo " --mkinstalldirs Print path to mkinstalldirs" +} + +## Print the normal usage message +shortusage() +{ + echo "usage: ${ME} " `allflags | cut -c-25 | sed -e 's%.*%[ & ]%'` +} + + +usage() +{ + echo "${ME}: icu-config: ICU configuration helper script" + echo + echo "The most commonly used options will be --cflags, --cxxflags, --cppflags, and --ldflags." + echo 'Example (in make): CPFLAGS=$(shell icu-config --cppflags)' + echo ' LDFLAGS=$(shell icu-config --ldflags)' + echo " (etc).." + echo + echo "Usage:" + allflags + + echo + echo " [Brackets] show MAKE variable equivalents, (parenthesis) show example output" + echo + echo "Copyright (c) 2002-2013, International Business Machines Corporation and others. All Rights Reserved." + echo + echo "NOTE: Please consider using the pkg-config (.pc) files instead of icu-config." + echo " See: " +} + +## Check the sanity of current variables +sanity() +{ + if [ ! -f "${ICUUC_FILE}" -a ! -f "${ICUUC_FILE_A}" ] && [ ${IGNORE_ICUUC_FILE_CHECK} = "no" ] && [ ${SANITY} = "sane" ]; + then + echo "### $ME: Can't find ${ICUUC_FILE} - ICU prefix is wrong." 1>&2 + echo "### Try the --prefix= option " 1>&2 + echo "### or --detect-prefix" 1>&2 + echo "### (If you want to disable this check, use the --noverify option)" 1>&2 + echo "### $ME: Exitting." 1>&2 + exit 2 + fi +} + +## Main starts here. + +if [ $# -lt 1 ]; then + shortusage + exit 1 +fi + +# For certain options (e.g. --detect-prefix) don't check for icuuc library file. + +IGNORE_ICUUC_FILE_CHECK="no"; + +SANITY="sane" + +case "$1" in +--noverify) + SANITY="nosanity" + shift + ;; +esac + +case "$1" in +*prefix*) + IGNORE_ICUUC_FILE_CHECK="yes" + ;; +esac + +# Load our variables from autoconf +# ALWAYS load twice because of dependencies +loaddefs +loaddefs + +if [ $# -gt 0 -a $1 = "--selfcheck" ]; +then + echo "passed" + exit + # EXIT for self check +fi + +sanity + +while [ $# -gt 0 ]; +do + arg="$1" + var=`echo $arg | sed -e 's/^[^=]*=//'` +# echo "### processing $arg" 1>&2 + case "$arg" in + + # undocumented. + --debug) + set -x + ;; + + --noverify) + echo "### $ME: Error: --noverify must be the first argument." 1>&2 + exit 1 + ;; + + --so) + echo $SO + ;; + + --bindir) + echo $bindir + ;; + + --libdir) + echo $libdir + ;; + + --exists) + sanity + ;; + + --sbindir) + echo $sbindir + ;; + + --mkinstalldirs) + echo ${MKINSTALLDIRS} + ;; + + --install) + echo ${INSTALL} + ;; + + --invoke=*) + QUOT="\"" + CMD="${var}" + + # If it's not a locally executable command (1st choice) then + # search for it in the ICU directories. + if [ ! -x ${CMD} ]; then + if [ -x ${bindir}/${var} ]; then + CMD="${bindir}/${var}" + fi + if [ -x ${sbindir}/${var} ]; then + CMD="${sbindir}/${var}" + fi + fi + + echo "env ${QUOT}${LDLIBRARYPATH_ENVVAR}=${libdir}:"'${'"${LDLIBRARYPATH_ENVVAR}"'}'${QUOT} ${CMD} + ;; + + --invoke) + QUOT="\"" + echo "env ${QUOT}${LDLIBRARYPATH_ENVVAR}=${libdir}:"'${'"${LDLIBRARYPATH_ENVVAR}"'}'${QUOT} + ;; + + --cflags) + echo $ECHO_N "${CFLAGS} ${ECHO_C}" + ;; + + --cc) + echo $ECHO_N "${CC} ${ECHO_C}" + ;; + + --cxx) + echo $ECHO_N "${CXX} ${ECHO_C}" + ;; + + --cxxflags) + echo $ECHO_N "${CXXFLAGS} ${ECHO_C}" + ;; + + --cppflags) + # Don't echo the -I. - it's unneeded. + echo $ECHO_N "${CPPFLAGS} ${ECHO_C}" | sed -e 's/-I. //' + ;; + + --cppflags-searchpath) + echo $ECHO_N "-I${prefix}/include ${ECHO_C}" + ;; + + --cppflags-dynamic) + echo $ECHO_N "${SHAREDLIBCPPFLAGS} ${ECHO_C}" + ;; + + --cxxflags-dynamic) + echo $ECHO_N "${SHAREDLIBCXXFLAGS} ${ECHO_C}" + ;; + + --cflags-dynamic) + echo $ECHO_N "${SHAREDLIBCFLAGS} ${ECHO_C}" + ;; + + --ldflags-system) + echo $ECHO_N "${LIBS} ${ECHO_C}" + ;; + + --ldflags) + echo $ECHO_N "${LDFLAGS} ${ICULIBS} ${ECHO_C}" +# $RPATH_LDFLAGS + ;; + + --ldflags-libsonly) + echo $ECHO_N "${ICULIBS_I18N} ${ICULIBS_COMMON} ${ICULIBS_DATA} ${ECHO_C}" + ;; + + --ldflags-icuio) + echo $ECHO_N " ${ICULIBS_ICUIO} ${ECHO_C}" + ;; + + --ldflags-obsolete) + echo $ECHO_N "${ICULIBS_OBSOLETE} ${ECHO_C}" + ;; + + --ldflags-toolutil) + echo $ECHO_N " ${ICULIBS_TOOLUTIL} ${ECHO_C}" + ;; + + --ldflags-layout) + echo ${ME}: ERROR: the old layout engine has been removed. use HarfBuzz. + exit 1 + ;; + + --ldflags-searchpath) + echo $ECHO_N "-L${libdir} ${ECHO_C}" + ;; + + --detect-prefix) + HERE=`echo $0 | sed -e "s/$ME//g"` + if [ -f "${HERE}/../lib/${ICULIBS_COMMON_LIB_NAME}" -o -f "${HERE}/../lib/${ICULIBS_COMMON_LIB_NAME_A}" ]; then + prefix="${HERE}/.." + echo "## Using --prefix=${prefix}" 1>&2 + fi + loaddefs + loaddefs + ;; + + --exec-prefix) + echo $exec_prefix + ;; + + --prefix) + echo $prefix + ;; + + --prefix=*) + prefix=$var + loaddefs + loaddefs + ;; + + --sysconfdir) + echo $sysconfdir + ;; + + --mandir) + echo $mandir + ;; + + --shared-datadir) + echo $ECHO_N "${datadir} ${ECHO_C}" + ;; + + --incfile) + echo $ECHO_N "${pkglibdir}/Makefile.inc ${ECHO_C}" + ;; + + --incpkgdatafile) + echo $ECHO_N "${pkglibdir}/pkgdata.inc ${ECHO_C}" + ;; + + --icudata) + echo $ECHO_N "${ICUDATA_NAME} ${ECHO_C}" + ;; + + --icudata-mode) + echo $ECHO_N "${PKGDATA_MODE} ${ECHO_C}" + ;; + + --icudata-install-dir) + echo $ECHO_N "${ICUPKGDATA_DIR} ${ECHO_C}" + ;; + + --icudatadir) + echo $ECHO_N "${ICUDATA_DIR} ${ECHO_C}" + ;; + + --shlib-c) + echo $ECHO_N "${SHLIB_c} ${ECHO_C}" + ;; + + --shlib-cc) + echo $ECHO_N "${SHLIB_cc} ${ECHO_C}" + ;; + + --version) + echo $ECHO_N $VERSION + ;; + + --unicode-version) + echo $ECHO_N $UNICODE_VERSION + ;; + + --host) + echo $host + exit 0 + ;; + + --help) + usage + exit 0 + ;; + + --usage) + usage + exit 0 + ;; + +# --enable-rpath=*) +# ENABLE_RPATH=$var +# loaddefs +# ;; + + -?) + usage + exit 0 + ;; + + *) + echo ${ME}: ERROR Unknown Option $arg 1>&2 + echo 1>&2 + shortusage 1>&2 + echo "### $ME: Exitting." 1>&2 + exit 1; + ;; + esac + shift + + # Reset the ignore icuuc file check flag + if [ $IGNORE_ICUUC_FILE_CHECK = "yes" ]; then + IGNORE_ICUUC_FILE_CHECK="no" + sanity + fi +done +echo +# Check once before we quit (will check last used prefix) +sanity +## END of icu-config-bottom + +exit 0 \ No newline at end of file diff --git a/scripts/subtree.sh b/scripts/subtree.sh deleted file mode 100755 index 899caa1..0000000 --- a/scripts/subtree.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env bash - -set -e -x - -git subtree pull --prefix=src/ext/thirdParty/rxi-log https://github.com/rxi/log.c master --squash diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index 8289d49..95e7cca 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -1949,4 +1949,37 @@ }); } }); + + context('test toBoolean', function () { + $data = [ + [true, 'true'], + [true, '1'], + [true, 'on'], + [true, 'ON'], + [true, 'yes'], + [true, '999'], + [false, 'false'], + [false, '0'], + [false, 'off'], + [false, 'OFF'], + [false, 'no'], + [false, '-999'], + [false, ''], + [false, ' '], + [false, '  ', 'UTF-8'] // narrow no-break space (U+202F) + ]; + + foreach ($data as $key => $value) { + it(__formatMessage($key, $value), function () use ($value) { + @list($expected, $str, $encoding) = $value; + + $stringy = __('Stringy')::create($str, $encoding); + $result = $stringy->toBoolean(); + + \expect($stringy)->toBeAnInstanceOf(__('Stringy')); + \expect((string) $stringy)->toBe($str); + \expect((bool) $result)->toBe($expected); + }); + } + }); }); diff --git a/src/Minbaby/Php/Stringy/Stringy.php b/src/Minbaby/Php/Stringy/Stringy.php index bcabef9..b6dea8e 100644 --- a/src/Minbaby/Php/Stringy/Stringy.php +++ b/src/Minbaby/Php/Stringy/Stringy.php @@ -1002,4 +1002,27 @@ public function toLowerCase() return static::create($str, $this->encoding); } + + public function toBoolean() + { + $key = $this->toLowerCase()->str; + $map = [ + 'true' => true, + '1' => true, + 'on' => true, + 'yes' => true, + 'false' => false, + '0' => false, + 'off' => false, + 'no' => false + ]; + + if (array_key_exists($key, $map)) { + return $map[$key]; + } elseif (is_numeric($this->str)) { + return (intval($this->str) > 0); + } + + return (bool) $this->regexReplace('[[:space:]]', '')->str; + } } diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index 2df4af0..9281f7a 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -3588,6 +3588,68 @@ PHP_METHOD(Stringy, toLowerCase) RETURN_ZVAL(&obj, 0, 1); } +PHP_METHOD(Stringy, toBoolean) +{ + zval map, T, F; + ZVAL_TRUE(&T); + ZVAL_FALSE(&F); + + convert_to_array(&map); + char* trueList[] = { + "true", + "1", + "on", + "yes" + }; + for (size_t i = 0; i < 4; i++) + { + add_assoc_zval(&map, trueList[i], &T); + } + + char* falseList[] = { + "false", + "0", + "off", + "no" + }; + for (size_t i = 0; i < 4; i++) + { + add_assoc_zval(&map, falseList[i], &F); + } + + zval func, rv; + ZVAL_STRING(&func, "toLowerCase"); + call_user_function(NULL, getThis(), &func, return_value, 0, NULL); + + zval *str = zend_read_property(stringy_ce, return_value, ZEND_STRL("str"), 0, &rv); + + zend_string *key = Z_STR(*str); + HashTable *ht = Z_ARRVAL(map); + if (zend_symtable_exists_ind(ht, key)){ + RETURN_ZVAL(zend_symtable_find(ht, key), 0, 0) + } + + if (is_numeric_string(Z_STRVAL_P(str), Z_STRLEN_P(str), NULL, NULL, 0) == IS_LONG) { + convert_to_long(str); + RETURN_BOOL(Z_LVAL_P(str) > 0); + } + + zval regex, empty; + ZVAL_STRING(®ex, "[[:space:]]"); + ZVAL_STRING(&func, "regexReplace"); + ZVAL_EMPTY_STRING(&empty); + zval args_regex[] = { + regex, + empty, + }; + call_user_function(NULL, getThis(), &func, return_value, 2, args_regex); + + str = zend_read_property(stringy_ce, return_value, ZEND_STRL("str"), 0, &rv); + + convert_to_boolean(str); + RETURN_ZVAL(str, 0, 0); +} + static zend_function_entry methods[] = { PHP_ME(Stringy, __construct, arginfo___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) PHP_ME(Stringy, __toString, NULL, ZEND_ACC_PUBLIC) @@ -3672,6 +3734,7 @@ static zend_function_entry methods[] = { PHP_ME(Stringy, toTitleCase, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, toTabs, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, toLowerCase, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, toBoolean, NULL, ZEND_ACC_PUBLIC) PHP_FE_END }; From 0750281ddaf4a851d75192914e01edf3cdf9c7c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Sun, 5 Jul 2020 15:38:07 +0800 Subject: [PATCH 111/126] test --- README.MD | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.MD b/README.MD index 8457008..c591889 100644 --- a/README.MD +++ b/README.MD @@ -48,6 +48,8 @@ composer run test-php composer run test-ext ``` +4. 其他 + ## TODO - [ ] [stringy](https://github.com/danielstjules/Stringy) From a05688da3a3b992986096aa8bb48ccbb6ef9c230 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Sun, 5 Jul 2020 15:43:25 +0800 Subject: [PATCH 112/126] pre install dist --- composer.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/composer.json b/composer.json index 3b5e936..43ab53e 100644 --- a/composer.json +++ b/composer.json @@ -30,6 +30,11 @@ "require-dev": { "kahlan/kahlan": "^4.3" }, + "config": { + "preferred-install": "dist", + "sort-packages": true, + "optimize-autoloader": true + }, "scripts": { "init-dev": "./scripts/init-development.sh", "prepare": "./scripts/prepare.sh", From 288b093c421a4224868fd7d0d2938f67ce223905 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Sun, 5 Jul 2020 15:45:57 +0800 Subject: [PATCH 113/126] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BE=9D=E8=B5=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- composer.json | 6 ++++++ composer.lock | 12 ++++++------ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/composer.json b/composer.json index 43ab53e..652ad8f 100644 --- a/composer.json +++ b/composer.json @@ -35,6 +35,12 @@ "sort-packages": true, "optimize-autoloader": true }, + "repositories": { + "packagist": { + "type": "composer", + "url": "https://mirrors.aliyun.com/composer/" + } + }, "scripts": { "init-dev": "./scripts/init-development.sh", "prepare": "./scripts/prepare.sh", diff --git a/composer.lock b/composer.lock index 1dde26d..15be2dd 100644 --- a/composer.lock +++ b/composer.lock @@ -4,21 +4,21 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "e9af6fb6f2ce506d427232984d336f64", + "content-hash": "fb818576c980ca61900205c0af9fafc2", "packages": [], "packages-dev": [ { "name": "kahlan/kahlan", - "version": "4.7.2", + "version": "4.7.5", "source": { "type": "git", "url": "https://github.com/kahlan/kahlan.git", - "reference": "025114b7f13985abceff3ba0e28cca71cb0d40e8" + "reference": "c529ef24201053ba76d3c8c3531acd76b629ce87" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/kahlan/kahlan/zipball/025114b7f13985abceff3ba0e28cca71cb0d40e8", - "reference": "025114b7f13985abceff3ba0e28cca71cb0d40e8", + "url": "https://api.github.com/repos/kahlan/kahlan/zipball/c529ef24201053ba76d3c8c3531acd76b629ce87", + "reference": "c529ef24201053ba76d3c8c3531acd76b629ce87", "shasum": "", "mirrors": [ { @@ -65,7 +65,7 @@ "testing", "unit test" ], - "time": "2020-01-25T16:39:06+00:00" + "time": "2020-04-25T21:27:19+00:00" } ], "aliases": [], From c7572fc79417d5fd2dce4b2cdd9f5e5d56697c60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Sun, 5 Jul 2020 15:47:05 +0800 Subject: [PATCH 114/126] fix pre-source --- .drone.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.drone.yml b/.drone.yml index d820302..1f8fc31 100644 --- a/.drone.yml +++ b/.drone.yml @@ -8,7 +8,7 @@ steps: image: composer:1 commands: - php -v - - composer install -vvv --profile --no-interaction --prefer-source + - composer install -vvv --profile --no-interaction - name: build-ext(7.1) image: php:7.1-cli commands: From b7bb53b406c76a0d68dc3a3d5f87feff2253d6dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Mon, 19 Oct 2020 11:52:03 +0800 Subject: [PATCH 115/126] =?UTF-8?q?=E7=AE=80=E5=8C=96=E6=93=8D=E4=BD=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/clean.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/clean.sh b/scripts/clean.sh index f38f362..2d7c9ea 100755 --- a/scripts/clean.sh +++ b/scripts/clean.sh @@ -4,4 +4,4 @@ set -e set -x echo "clean..." -make clean && phpize --clean +[[ -f Makefile ]] && make clean && phpize --clean From fe83881221f55653f9d6a55764ec8c057257caaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Mon, 19 Oct 2020 14:58:03 +0800 Subject: [PATCH 116/126] update --- .gitignore | 3 ++- .vscode/c_cpp_properties.json | 4 ++-- composer.json | 6 +++++- scripts/init-development.sh | 6 +++--- src/ext/stringy/stringy.c | 15 +++++++++++++++ 5 files changed, 27 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index a2a1b76..740c89a 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ config.nice config.status config.sub configure +configure.ac configure.in include install-sh @@ -56,4 +57,4 @@ CMakeCache.txt /CMakeFiles/ /cmake-build-debug/ cmake_install.cmake -php_ext_startup.cbp \ No newline at end of file +php_ext_startup.cbp diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index 60ba042..143dcab 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -4,7 +4,7 @@ "name": "Linux", "includePath": [ "${workspaceFolder}/**", - "~/.phpbrew/build/php-7.1.33/**" + "~/.phpbrew/build/php-7.2.34/**" ], "defines": [], "compilerPath": "/usr/bin/gcc", @@ -16,7 +16,7 @@ "name": "Mac", "includePath": [ "${workspaceFolder}/**", - "~/.phpbrew/build/php-7.1.33/**" + "~/.phpbrew/build/php-7.2.34/**" ], "defines": [], "compilerPath": "/usr/bin/gcc", diff --git a/composer.json b/composer.json index 652ad8f..0b02e1e 100644 --- a/composer.json +++ b/composer.json @@ -42,9 +42,13 @@ } }, "scripts": { - "init-dev": "./scripts/init-development.sh", + "init-dev": [ + "Composer\\Config::disableProcessTimeout", + "./scripts/init-development.sh" + ], "prepare": "./scripts/prepare.sh", "build": "./scripts/build.sh", + "no": "phpbrew ext disable startup", "test": [ "@test-php", "@test-ext" diff --git a/scripts/init-development.sh b/scripts/init-development.sh index f0d84c1..6089a57 100755 --- a/scripts/init-development.sh +++ b/scripts/init-development.sh @@ -1,10 +1,10 @@ #!/usr/bin/env bash -set -e -x +set -e -x -u export PATH=/usr/bin:$PATH -export PHP_VERSION=php-7.1.33 +export PHP_VERSION=php-7.2.34 export SYSTEM_NAME=`uname` @@ -32,7 +32,7 @@ if [ "$SYSTEM_NAME" == "Linux" ]; then fi phpbrew --debug install \ - -j 4 \ + -j $(nproc) \ $PHP_VERSION \ +default \ +bz2$LIB_BZ2 \ diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index 9281f7a..79f21b8 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -3650,6 +3650,20 @@ PHP_METHOD(Stringy, toBoolean) RETURN_ZVAL(str, 0, 0); } +PHP_METHOD(Stringy, titleize) +{ + zval *ignore; + ZEND_PARSE_PARAMETERS_START(0, 1) + Z_PARAM_ZVAL(*ignore) + ZEND_PARSE_PARAMETERS_END(); + + zval *rv; + zval *encoding = zend_read_property(stringy_ce, getThis(), ZEND_STRL("encoding"), 0, &rv); +} +ZEND_BEGIN_ARG_INFO(arginfo_titleize, 1) + ZEND_ARG_ARRAY_INFO(0, ignore, 1) +ZEND_END_ARG_INFO(); + static zend_function_entry methods[] = { PHP_ME(Stringy, __construct, arginfo___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) PHP_ME(Stringy, __toString, NULL, ZEND_ACC_PUBLIC) @@ -3735,6 +3749,7 @@ static zend_function_entry methods[] = { PHP_ME(Stringy, toTabs, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, toLowerCase, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, toBoolean, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, titleize, NULL, ZEND_ACC_PUBLIC) PHP_FE_END }; From 83ead7da9c20b35ee3ec37adf6b200fa054bb20a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Tue, 20 Oct 2020 16:58:52 +0800 Subject: [PATCH 117/126] update --- scripts/init-development.sh | 11 ++++++++++- spec/Stringy/StringySpec.php | 28 ++++++++++++++++++++++++++++ src/Minbaby/Php/Stringy/Stringy.php | 22 ++++++++++++++++++++++ src/ext/stringy/stringy.c | 21 +-------------------- 4 files changed, 61 insertions(+), 21 deletions(-) diff --git a/scripts/init-development.sh b/scripts/init-development.sh index 6089a57..b278228 100755 --- a/scripts/init-development.sh +++ b/scripts/init-development.sh @@ -10,6 +10,15 @@ export SYSTEM_NAME=`uname` export SCRIPT_DIR=`dirname $0` +LIB_BZ2= +LIB_ZIP= +LIB_SSL= +if [ "$SYSTEM_NAME" == "Darwin" ] ;then + LIB_BZ2='=/usr/local/opt/bzip2/' + LIB_ZIP='=/usr/local/opt/zlib/' + LIB_SSL='=/usr/local/opt/openssl/' +fi + [ "$SYSTEM_NAME" == "Darwin" ] && LIB_BZ2='=/usr/local/opt/bzip2/' [ "$SYSTEM_NAME" == "Darwin" ] && LIB_ZIP='=/usr/local/opt/zlib/' [ "$SYSTEM_NAME" == "Darwin" ] && LIB_SSL='=/usr/local/opt/openssl/' @@ -19,7 +28,7 @@ if [ ! -x "$(command -v icu-config)" ]; then fi if [ "$SYSTEM_NAME" == "Linux" ]; then - sudo apt install \ + sudo apt install -y \ libxml2-dev \ libssh-dev \ libbz2-dev \ diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index 95e7cca..afa9429 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -1982,4 +1982,32 @@ }); } }); + + + + xcontext('test titleize', function () { + $ignore = ['at', 'by', 'for', 'in', 'of', 'on', 'out', 'to', 'the']; + + $data = [ + ['Title Case', 'TITLE CASE'], + ['Testing The Method', 'testing the method'], + ['Testing the Method', 'testing the method', $ignore], + ['I Like to Watch Dvds at Home', 'i like to watch DVDs at home', + $ignore], + ['Θα Ήθελα Να Φύγει', ' Θα ήθελα να φύγει ', null, 'UTF-8'] + ]; + + foreach ($data as $key => $value) { + it(__formatMessage($key, $value), function () use ($value) { + @list($expected, $str, $ignore, $encoding) = $value; + + $stringy = __('Stringy')::create($str, $encoding); + $result = $stringy->titleize($ignore); +var_dump($result); + \expect($stringy)->toBeAnInstanceOf(__('Stringy')); + \expect((string) $stringy)->toBe($str); + \expect((string) $result)->toBe($expected); + }); + } + }); }); diff --git a/src/Minbaby/Php/Stringy/Stringy.php b/src/Minbaby/Php/Stringy/Stringy.php index b6dea8e..5becb3a 100644 --- a/src/Minbaby/Php/Stringy/Stringy.php +++ b/src/Minbaby/Php/Stringy/Stringy.php @@ -1025,4 +1025,26 @@ public function toBoolean() return (bool) $this->regexReplace('[[:space:]]', '')->str; } + + public function titleize($ignore = null) + { + $stringy = static::create($this->trim(), $this->encoding); + $encoding = $this->encoding; + + $stringy->str = preg_replace_callback( + '/([\S]+)/u', + function ($match) use ($encoding, $ignore) { + if ($ignore && in_array($match[0], $ignore)) { + return $match[0]; + } + + $stringy = new Stringy($match[0], $encoding); + + return (string) $stringy->toLowerCase()->upperCaseFirst(); + }, + $stringy->str + ); + + return $stringy; + } } diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index 79f21b8..937db3f 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -960,7 +960,6 @@ static void preg_replace_callback_handler(INTERNAL_FUNCTION_PARAMETERS) call_user_function(NULL, NULL, &func, return_value, 2, args); } - static void preg_replace_callback_2_handler(INTERNAL_FUNCTION_PARAMETERS) { zval *arr = NULL; @@ -1323,7 +1322,6 @@ ZEND_BEGIN_ARG_INFO(arginfo_containsAll, 2) ZEND_ARG_INFO(0, caseSensitive) ZEND_END_ARG_INFO(); - PHP_METHOD(Stringy, containsAny) { zval *needles = NULL, *caseSensitive = NULL; @@ -1649,8 +1647,6 @@ ZEND_BEGIN_ARG_INFO(arginfo_startsWith, 0) ZEND_ARG_INFO(0, caseSensitive) ZEND_END_ARG_INFO(); - - PHP_METHOD(Stringy, ensureLeft) { zval *substring = NULL; @@ -3650,20 +3646,6 @@ PHP_METHOD(Stringy, toBoolean) RETURN_ZVAL(str, 0, 0); } -PHP_METHOD(Stringy, titleize) -{ - zval *ignore; - ZEND_PARSE_PARAMETERS_START(0, 1) - Z_PARAM_ZVAL(*ignore) - ZEND_PARSE_PARAMETERS_END(); - - zval *rv; - zval *encoding = zend_read_property(stringy_ce, getThis(), ZEND_STRL("encoding"), 0, &rv); -} -ZEND_BEGIN_ARG_INFO(arginfo_titleize, 1) - ZEND_ARG_ARRAY_INFO(0, ignore, 1) -ZEND_END_ARG_INFO(); - static zend_function_entry methods[] = { PHP_ME(Stringy, __construct, arginfo___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) PHP_ME(Stringy, __toString, NULL, ZEND_ACC_PUBLIC) @@ -3749,7 +3731,6 @@ static zend_function_entry methods[] = { PHP_ME(Stringy, toTabs, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, toLowerCase, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, toBoolean, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Stringy, titleize, NULL, ZEND_ACC_PUBLIC) PHP_FE_END }; @@ -3771,4 +3752,4 @@ void php_startup_register_stringy() spl_ce_Aggregate, spl_ce_ArrayAccess ); -} +} From 1cbbdf757a4c14ec7ba58fdffe818de57550b1b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Wed, 21 Oct 2020 10:25:21 +0800 Subject: [PATCH 118/126] remove phpdbg --- scripts/fetch.php | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/fetch.php b/scripts/fetch.php index ffddce2..1f72a32 100755 --- a/scripts/fetch.php +++ b/scripts/fetch.php @@ -19,7 +19,6 @@ 'async-ext' => 'https://github.com/swoole/async-ext.git', 'pthreads' => 'https://github.com/krakjoe/pthreads', 'SeasLog' => 'https://github.com/SeasX/SeasLog', - 'phpdbg' => 'https://github.com/krakjoe/phpdbg', 'php-rdkafka' => 'https://github.com/arnaud-lb/php-rdkafka', 'runkit' => 'https://github.com/zenovich/runkit', 'php-git' => 'https://github.com/libgit2/php-git', From de32592956fb6d8a52b82397f0bc5a8eb5558796 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Tue, 15 Dec 2020 10:41:27 +0800 Subject: [PATCH 119/126] =?UTF-8?q?=E8=BF=9B=E5=BA=A6=E5=86=85=E7=BD=AE&?= =?UTF-8?q?=E6=B3=A8=E9=87=8A=E4=B8=80=E4=BA=9B=E6=8B=93=E5=B1=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/jobs/stringy.md | 198 +++++++++++++++++++++++++++++++++++++++++++ scripts/fetch.php | 46 +++++----- 2 files changed, 221 insertions(+), 23 deletions(-) create mode 100644 docs/jobs/stringy.md diff --git a/docs/jobs/stringy.md b/docs/jobs/stringy.md new file mode 100644 index 0000000..33714af --- /dev/null +++ b/docs/jobs/stringy.md @@ -0,0 +1,198 @@ +# stringy + + +Stringy library + +https://github.com/danielstjules/Stringy + +- [x] __construct + +- [x] create + +- [x] __toString + +- [x] append + +- [x] at + +- [x] between + +- [x] camelize + +- [x] chars + +- [x] contains + +- [x] containsAll + +- [x] containsAny + +- [x] count + +- [x] countSubstr + +- [x] delimit +- [x] dasherize + + +- [x] endsWith + +- [x] endsWithAny + +- [x] ensureLeft + +- [x] ensureRight + +- [x] first + +- [x] getEncoding + +- [x] getIterator + +- [x] hasLowerCase + +- [x] hasUpperCase + +- [x] htmlDecode + +- [x] htmlEncode + +- [x] humanize + +- [x] indexOf + +- [x] indexOfLast + +- [x] insert + +- [x] isAlpha + +- [x] isAlphanumeric + +- [x] isBlank + +- [x] isHexadecimal + +- [x] isJson + +- [x] isLowerCase + +- [x] isSerialized + +- [x] isBase64 + +- [x] isUpperCase + +- [x] last + +- [x] length + +- [x] lines + +- [x] longestCommonPrefix + +- [x] longestCommonSuffix + +- [ ] longestCommonSubstring + +- [x] lowerCaseFirst + +- [x] offsetExists + +- [x] offsetGet + +- [x] offsetSet + +- [x] offsetUnset + +- [x] pad + +- [x] padBoth + +- [x] padLeft + +- [x] padRight + +- [x] applyPadding + +- [x] prepend + +- [x] regexReplace + +- [x] removeLeft + +- [x] removeRight + +- [x] repeat + +- [x] replace + +- [ ] reverse + +- [ ] safeTruncate + +- [ ] shuffle + +- [ ] slugify + +- [x] startsWith + +- [ ] startsWithAny + +- [ ] slice + +- [x] split + +- [ ] stripWhitespace + +- [x] substr + +- [ ] surround + +- [x] swapCase + +- [ ] tidy + +- [x] titleize + +- [x] toAscii + +- [x] toBoolean + +- [x] toLowerCase + +- [ ] toSpaces + +- [x] toTabs + +- [x] toTitleCase + +- [x] toUpperCase + +- [x] trim + +- [x] trimLeft + +- [x] trimRight + +- [x] truncate + +- [x] underscored + +- [x] upperCaseFirst + +- [x] charsArray + +- [x] langSpecificCharsArray + +- [x] matchesPattern + +- [x] eregReplace + +- [x] regexEncoding + +- [x] supportsEncoding + +- [x] collapseWhiteSpace + +- [ ] 测试 \ No newline at end of file diff --git a/scripts/fetch.php b/scripts/fetch.php index ffddce2..23c46b9 100755 --- a/scripts/fetch.php +++ b/scripts/fetch.php @@ -2,30 +2,30 @@ 'https://github.com/tpunt/pht', - 'php-ds' => 'https://github.com/php-ds/extension.git', - 'phactor' => 'https://github.com/tpunt/phactor', - 'phpredis' => 'https://github.com/phpredis/phpredis', - 'yaf' => 'https://github.com/laruence/yaf.git', - 'yar' => 'https://github.com/laruence/yar.git', - 'yac' => 'https://github.com/laruence/yac.git', - 'yaconf' => 'https://github.com/laruence/yaconf.git', - 'yaf' => 'https://github.com/laruence/yaf.git', - 'xhprof' => 'https://github.com/phacility/xhprof', + // 'pht' => 'https://github.com/tpunt/pht', + // 'php-ds' => 'https://github.com/php-ds/extension.git', + // 'phactor' => 'https://github.com/tpunt/phactor', + // 'phpredis' => 'https://github.com/phpredis/phpredis', + // 'yaf' => 'https://github.com/laruence/yaf.git', + // 'yar' => 'https://github.com/laruence/yar.git', + // 'yac' => 'https://github.com/laruence/yac.git', + // 'yaconf' => 'https://github.com/laruence/yaconf.git', + // 'yaf' => 'https://github.com/laruence/yaf.git', + // 'xhprof' => 'https://github.com/phacility/xhprof', 'msgpack-php' => 'https://github.com/msgpack/msgpack-php', - 'phptrace' => 'https://github.com/Qihoo360/phptrace', - 'php-memcached' => 'https://github.com/php-memcached-dev/php-memcached', - 'swoole' => 'https://github.com/swoole/swoole-src', - 'async-ext' => 'https://github.com/swoole/async-ext.git', - 'pthreads' => 'https://github.com/krakjoe/pthreads', - 'SeasLog' => 'https://github.com/SeasX/SeasLog', - 'phpdbg' => 'https://github.com/krakjoe/phpdbg', - 'php-rdkafka' => 'https://github.com/arnaud-lb/php-rdkafka', - 'runkit' => 'https://github.com/zenovich/runkit', - 'php-git' => 'https://github.com/libgit2/php-git', - 'AOP' => 'https://github.com/AOP-PHP/AOP', - 'xdeubg' => 'https://github.com/xdebug/xdebug.git', - 'apcu' => 'https://github.com/krakjoe/apcu.git', + // 'phptrace' => 'https://github.com/Qihoo360/phptrace', + // 'php-memcached' => 'https://github.com/php-memcached-dev/php-memcached', + // 'swoole' => 'https://github.com/swoole/swoole-src', + // 'async-ext' => 'https://github.com/swoole/async-ext.git', + // 'pthreads' => 'https://github.com/krakjoe/pthreads', + // 'SeasLog' => 'https://github.com/SeasX/SeasLog', + // 'phpdbg' => 'https://github.com/krakjoe/phpdbg', + // 'php-rdkafka' => 'https://github.com/arnaud-lb/php-rdkafka', + // 'runkit' => 'https://github.com/zenovich/runkit', + // 'php-git' => 'https://github.com/libgit2/php-git', + // 'AOP' => 'https://github.com/AOP-PHP/AOP', + // 'xdeubg' => 'https://github.com/xdebug/xdebug.git', + // 'apcu' => 'https://github.com/krakjoe/apcu.git', // 'swoole-pgsql' => 'git@github.com:swoole/ext-postgresql.git', ]; From e18f535786be254e2dac1dcc87a407d9fa658785 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Tue, 15 Dec 2020 13:02:42 +0800 Subject: [PATCH 120/126] stringy-reverse --- Makefile.frag | 2 +- README.MD | 23 +++++++++++-- docs/jobs/stringy.md | 3 +- scripts/gdb.sh | 5 +-- spec/Stringy/StringySpec.php | 26 ++++++++++++++- spec/functions.php | 2 +- src/Minbaby/Php/Stringy/Stringy.php | 13 ++++++++ src/ext/stringy/stringy.c | 51 +++++++++++++++++++++++++++++ startup.php | 2 +- 9 files changed, 118 insertions(+), 9 deletions(-) diff --git a/Makefile.frag b/Makefile.frag index 232a926..4da25ab 100644 --- a/Makefile.frag +++ b/Makefile.frag @@ -26,4 +26,4 @@ ext-test-ext: MINBABY_TEST_EXT=1 php ./vendor/bin/kahlan ext-first:ext-prepare ext-build ext-test ext-test-ext - @echo 1 + @echo Done diff --git a/README.MD b/README.MD index c591889..d29874f 100644 --- a/README.MD +++ b/README.MD @@ -34,21 +34,38 @@ ```bash composer run test +# or +make ext-first ``` 2. 测试 php 部分代码 ```bash composer run test-php +# or +make ext-test ``` 3. 测试 ext 部分代码 ```bash composer run test-ext +# or +make ext-test-ext +``` + +4. 其他命令 + +```bash +make ext-clean # clean code + +make ext-fetch # fetch configure ext code from github + +make ext-prepare # phpize & configure + +make ext-buidl ``` -4. 其他 ## TODO @@ -56,12 +73,14 @@ composer run test-ext ## 说明 +- 本项目只是学习实践使用 - 使用 `@` 抑制符不是一个好习惯,尽量不要使用。 - 依赖 `mb_string` 扩展 ## 已知问题 -- 0.0 +- 0.0 很多 +- memory leak (可能使用改方案来排查 https://github.com/arnaud-lb/php-memory-profiler) ### skip ci diff --git a/docs/jobs/stringy.md b/docs/jobs/stringy.md index 33714af..eb51703 100644 --- a/docs/jobs/stringy.md +++ b/docs/jobs/stringy.md @@ -1,5 +1,6 @@ # stringy +## 进度 Stringy library @@ -32,8 +33,8 @@ https://github.com/danielstjules/Stringy - [x] countSubstr - [x] delimit -- [x] dasherize +- [x] dasherize - [x] endsWith diff --git a/scripts/gdb.sh b/scripts/gdb.sh index f1c7c0e..0c11cea 100755 --- a/scripts/gdb.sh +++ b/scripts/gdb.sh @@ -20,6 +20,7 @@ # git clone https://github.com/snare/voltron sudo apt install gdb -f -git clone https://github.com/longld/peda.git ~/peda -echo "source ~/peda/peda.py" >> ~/.gdbinit +mkdir -p ~/code/repos/ +git clone https://github.com/longld/peda.git ~/code/repos/peda +echo "source ~/code/repos/peda/peda.py" >> ~/.gdbinit echo "DONE! debug your program with gdb and enjoy" \ No newline at end of file diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index afa9429..f619b80 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -2003,11 +2003,35 @@ $stringy = __('Stringy')::create($str, $encoding); $result = $stringy->titleize($ignore); -var_dump($result); + \expect($stringy)->toBeAnInstanceOf(__('Stringy')); \expect((string) $stringy)->toBe($str); \expect((string) $result)->toBe($expected); }); } }); + + context('x', function () { + $data = [ + ['', ''], + ['raboof', 'foobar'], + ['řàbôòf', 'fòôbàř', 'UTF-8'], + ['řàb ôòf', 'fòô bàř', 'UTF-8'], + ['∂∆ ˚åß', 'ßå˚ ∆∂', 'UTF-8'] + ]; + + foreach ($data as $key => $value) { + it(__formatMessage($key, $value), function () use ($value) { + + @list($str, $expected, $encoding) = $value; + + $stringy = __('Stringy')::create($str, $encoding); + $result = $stringy->reverse(); + + \expect($stringy)->toBeAnInstanceOf(__('Stringy')); + \expect((string) $stringy)->toBe($str); + \expect((string) $result)->toBe($expected); + }); + } + }); }); diff --git a/spec/functions.php b/spec/functions.php index 1d7e352..23302c4 100644 --- a/spec/functions.php +++ b/spec/functions.php @@ -42,7 +42,7 @@ function __(string $str): string function __formatMessage(string $message, array $data): string { - return sprintf('%s: ==> %s <==', $message, json_encode($data, JSON_UNESCAPED_UNICODE)); + return sprintf('%s: ==> %s <==', $message, json_encode($data, JSON_UNESCAPED_UNICODE|JSON_INVALID_UTF8_IGNORE)); } function __debug_array(array $arr): string diff --git a/src/Minbaby/Php/Stringy/Stringy.php b/src/Minbaby/Php/Stringy/Stringy.php index 5becb3a..7e12659 100644 --- a/src/Minbaby/Php/Stringy/Stringy.php +++ b/src/Minbaby/Php/Stringy/Stringy.php @@ -1047,4 +1047,17 @@ function ($match) use ($encoding, $ignore) { return $stringy; } + + public function reverse() + { + $strLength = $this->length(); + $reversed = ''; + + // Loop from last index of string to first + for ($i = $strLength - 1; $i >= 0; $i--) { + $reversed .= \mb_substr($this->str, $i, 1, $this->encoding); + } + + return static::create($reversed, $this->encoding); + } } diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index 937db3f..8c06e26 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -3646,6 +3646,56 @@ PHP_METHOD(Stringy, toBoolean) RETURN_ZVAL(str, 0, 0); } +PHP_METHOD(Stringy, reverse) { + zval func = {}; + ZVAL_STRING(&func, "length"); + call_user_function(NULL, getThis(), &func, return_value, 0, NULL); + + long len = Z_LVAL_P(return_value); + + + if (len == 0) { + RETURN_EMPTY_STRING(); + } + + zval reversed = {}; + + zval rv = {}; + zval *str = zend_read_property(stringy_ce, getThis(), ZEND_STRL("str"), 0, &rv); + zval *encoding = zend_read_property(stringy_ce, getThis(), ZEND_STRL("encoding"), 0, &rv); + + for (int i = len-1; i >=0; i--) + { + zval zval_i; + ZVAL_LONG(&zval_i, i); + + zval zval_1; + ZVAL_LONG(&zval_1, 1); + + ZVAL_STRING(&func, "mb_substr"); + zval args[] = { + *str, + zval_i, + zval_1 , + *encoding + }; + call_user_function(NULL, NULL, &func, return_value, 4, args); + + concat_function(&reversed, &reversed, return_value); + } + + zval obj; + object_init_ex(&obj, stringy_ce); + zval args_construct[] = { + reversed, + *encoding, + }; + ZVAL_STRING(&func, "__construct"); + call_user_function(NULL, &obj, &func, return_value, 2, args_construct); + + RETURN_ZVAL(&obj, 0, 1); +} + static zend_function_entry methods[] = { PHP_ME(Stringy, __construct, arginfo___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) PHP_ME(Stringy, __toString, NULL, ZEND_ACC_PUBLIC) @@ -3731,6 +3781,7 @@ static zend_function_entry methods[] = { PHP_ME(Stringy, toTabs, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, toLowerCase, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, toBoolean, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, reverse, NULL, ZEND_ACC_PUBLIC) PHP_FE_END }; diff --git a/startup.php b/startup.php index ac4408e..c589742 100644 --- a/startup.php +++ b/startup.php @@ -8,4 +8,4 @@ _ns(NS_STRINGY); -echo __('Stringy')::create("afds\tafsd")->toSpaces(); +echo __('Stringy')::create("∂∆ ˚åß")->reverse(); From 843c7baa56edd199bfcea70614f5d6cef66f0757 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Tue, 15 Dec 2020 13:25:05 +0800 Subject: [PATCH 121/126] 73 + 74 --- .circleci/config.yml | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index eb1b284..8bba5f3 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -31,14 +31,22 @@ jobs: - run: name: run test command: ./vendor/bin/kahlan - test-php71: + test-php74: <<: *common-test docker: - - image: circleci/php:7.1-browsers + - image: circleci/php:7.4-browsers + test-php73: + <<: *common-test + docker: + - image: circleci/php:7.3-browsers test-php72: <<: *common-test docker: - image: circleci/php:7.2-browsers + test-php71: + <<: *common-test + docker: + - image: circleci/php:7.1-browsers test-php70: <<: *common-test docker: @@ -50,4 +58,6 @@ workflows: - test-php70 - test-php71 - test-php72 + - test-php73 + - test-php74 From 9ee2fe287dd183cdc5964e80f75deedbb853fd02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Tue, 15 Dec 2020 18:35:51 +0800 Subject: [PATCH 122/126] =?UTF-8?q?=E6=B5=8B=E8=AF=95=E6=B2=A1=E6=9C=89?= =?UTF-8?q?=E5=AE=8C=E5=85=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/jobs/stringy.md | 4 +- spec/Stringy/StringySpec.php | 43 ++++++++++- src/Minbaby/Php/Stringy/Stringy.php | 28 +++++++ src/ext/stringy/stringy.c | 114 ++++++++++++++++++++++++++++ startup.php | 2 +- 5 files changed, 187 insertions(+), 4 deletions(-) diff --git a/docs/jobs/stringy.md b/docs/jobs/stringy.md index eb51703..b73d9aa 100644 --- a/docs/jobs/stringy.md +++ b/docs/jobs/stringy.md @@ -128,9 +128,9 @@ https://github.com/danielstjules/Stringy - [x] replace -- [ ] reverse +- [x] reverse -- [ ] safeTruncate +- [x] safeTruncate - [ ] shuffle diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index f619b80..42623c6 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -2011,7 +2011,7 @@ } }); - context('x', function () { + context('test reverse', function () { $data = [ ['', ''], ['raboof', 'foobar'], @@ -2034,4 +2034,45 @@ }); } }); + + context('test safeTruncate', function () { + $data = [ + ['Test foo bar', 'Test foo bar', 12], + ['Test foo', 'Test foo bar', 11], + ['Test foo', 'Test foo bar', 8], + ['Test', 'Test foo bar', 7], + ['Test', 'Test foo bar', 4], + ['Test foo bar', 'Test foo bar', 12, '...'], + ['Test foo...', 'Test foo bar', 11, '...'], + ['Test...', 'Test foo bar', 8, '...'], + ['Test...', 'Test foo bar', 7, '...'], + ['T...', 'Test foo bar', 4, '...'], + ['Test....', 'Test foo bar', 11, '....'], + ['Tëst fòô bàř', 'Tëst fòô bàř', 12, '', 'UTF-8'], + ['Tëst fòô', 'Tëst fòô bàř', 11, '', 'UTF-8'], + ['Tëst fòô', 'Tëst fòô bàř', 8, '', 'UTF-8'], + ['Tëst', 'Tëst fòô bàř', 7, '', 'UTF-8'], + ['Tëst', 'Tëst fòô bàř', 4, '', 'UTF-8'], + ['Tëst fòô bàř', 'Tëst fòô bàř', 12, 'ϰϰ', 'UTF-8'], + ['Tëst fòôϰϰ', 'Tëst fòô bàř', 11, 'ϰϰ', 'UTF-8'], + ['Tëstϰϰ', 'Tëst fòô bàř', 8, 'ϰϰ', 'UTF-8'], + ['Tëstϰϰ', 'Tëst fòô bàř', 7, 'ϰϰ', 'UTF-8'], + ['Tëϰϰ', 'Tëst fòô bàř', 4, 'ϰϰ', 'UTF-8'], + ['What are your plans...', 'What are your plans today?', 22, '...'] + ]; + + foreach ($data as $key => $value) { + it(__formatMessage($key, $value), function () use ($value) { + + @list($expected, $str, $length, $substring, $encoding) = $value; + + $stringy = __('Stringy')::create($str, $encoding); + $result = $stringy->safeTruncate($length, $substring); + + \expect($stringy)->toBeAnInstanceOf(__('Stringy')); + \expect((string) $stringy)->toBe($str); + \expect((string) $result)->toBe($expected); + }); + } + }); }); diff --git a/src/Minbaby/Php/Stringy/Stringy.php b/src/Minbaby/Php/Stringy/Stringy.php index 7e12659..ede1da5 100644 --- a/src/Minbaby/Php/Stringy/Stringy.php +++ b/src/Minbaby/Php/Stringy/Stringy.php @@ -1060,4 +1060,32 @@ public function reverse() return static::create($reversed, $this->encoding); } + + public function safeTruncate($length, $substring = '') + { + $stringy = static::create($this->str, $this->encoding); + if ($length >= $stringy->length()) { + return $stringy; + } + + // Need to further trim the string so we can append the substring + $encoding = $stringy->encoding; + $substringLength = \mb_strlen($substring, $encoding); + $length = $length - $substringLength; + + $truncated = \mb_substr($stringy->str, 0, $length, $encoding); + + // If the last word was truncated + if (mb_strpos($stringy->str, ' ', $length - 1, $encoding) != $length) { + // Find pos of the last occurrence of a space, get up to that + $lastPos = \mb_strrpos($truncated, ' ', 0, $encoding); + if ($lastPos !== false) { + $truncated = \mb_substr($truncated, 0, $lastPos, $encoding); + } + } + + $stringy->str = $truncated . $substring; + + return $stringy; + } } diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index 8c06e26..fb8359c 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -3696,6 +3696,119 @@ PHP_METHOD(Stringy, reverse) { RETURN_ZVAL(&obj, 0, 1); } +PHP_METHOD(Stringy, safeTruncate) { + zval *length; + zval *substring; + + substring = malloc(sizeof(zval)); + + ZVAL_STRING(substring, ""); + + ZEND_PARSE_PARAMETERS_START(1, 2) + Z_PARAM_ZVAL(length) + Z_PARAM_OPTIONAL + Z_PARAM_ZVAL(substring) + ZEND_PARSE_PARAMETERS_END(); + + zval rv; + zval *str = zend_read_property(NULL, getThis(), ZEND_STRL("str"), 0, &rv); + zval *encoding = zend_read_property(NULL, getThis(), ZEND_STRL("encoding"), 0, &rv); + + zval obj; + object_init_ex(&obj, stringy_ce); + zval args_construct[] = { + *str, + *encoding, + }; + zval func; + ZVAL_STRING(&func, "__construct"); + call_user_function(NULL, &obj, &func, return_value, 2, args_construct); + + ZVAL_STRING(&func, "length"); + call_user_function(NULL, &obj, &func, return_value, 0, NULL); + + int length_o = Z_LVAL_P(length); + int length_n = Z_LVAL_P(return_value); + if (length_o >= length_n) { + RETURN_ZVAL(&obj, 0, 0); + } + + ZVAL_STRING(&func, "mb_strlen"); + zval args_mb_strlen[] = { + *substring, + *encoding, + }; + call_user_function(NULL, NULL, &func, return_value, 2, args_mb_strlen); + length_o = length_n - Z_LVAL_P(return_value); + + ZVAL_STRING(&func, "mb_substr"); + zval zval_0; + ZVAL_BOOL(&zval_0, 0); + zval zval_length; + ZVAL_LONG(&zval_length, length_o); + zval args_mb_substr[] = { + *str, + zval_0, + zval_length, + *encoding, + }; + zval truncated; + call_user_function(NULL, NULL, &func, &truncated, 4, args_mb_substr); + + ZVAL_STRING(&func, "mb_strpos"); + zval estr; + ZVAL_STRING(&estr, " "); + zval length_1; + ZVAL_LONG(&length_1, length_o-1); + zval args_mb_strpos[] = { + *str, + estr, + length_1, + *encoding, + }; + call_user_function(NULL, NULL, &func, return_value, 4, args_mb_strpos); + + if (Z_LVAL_P(return_value) != length_o) { + ZVAL_STRING(&func, "mb_strrpos"); + ZVAL_STRING(&estr, " "); + zval length_1; + ZVAL_LONG(&length_1, length_o-1); + zval args_mb_strrpos[] = { + truncated, + estr, + zval_0, + *encoding, + }; + call_user_function(NULL, NULL, &func, return_value, 4, args_mb_strrpos); + if (Z_TYPE_P(return_value) != IS_FALSE) { + ZVAL_STRING(&func, "mb_substr"); + zval zval_0; + ZVAL_BOOL(&zval_0, 0); + zval args_mb_substr1[] = { + truncated, + zval_0, + *return_value, + *encoding, + }; + call_user_function(NULL, NULL, &func, &truncated, 4, args_mb_substr1); + } + } + + concat_function(return_value, &truncated, substring); + + zend_string *str_name = zend_string_init(ZEND_STRL("str"), 0); + zend_update_property_ex(NULL, &obj, str_name, return_value); + + + + RETURN_ZVAL(&obj, 1, 0); + +} +ZEND_BEGIN_ARG_INFO(arginfo_safeTruncate, 0) + ZEND_ARG_INFO(0, length) + ZEND_ARG_INFO(0, substring) +ZEND_END_ARG_INFO(); + static zend_function_entry methods[] = { PHP_ME(Stringy, __construct, arginfo___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) PHP_ME(Stringy, __toString, NULL, ZEND_ACC_PUBLIC) @@ -3782,6 +3895,7 @@ static zend_function_entry methods[] = { PHP_ME(Stringy, toLowerCase, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, toBoolean, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, reverse, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, safeTruncate, arginfo_safeTruncate, ZEND_ACC_PUBLIC) PHP_FE_END }; diff --git a/startup.php b/startup.php index c589742..9ce2840 100644 --- a/startup.php +++ b/startup.php @@ -8,4 +8,4 @@ _ns(NS_STRINGY); -echo __('Stringy')::create("∂∆ ˚åß")->reverse(); +echo __('Stringy')::create("Test foo bar")->safeTruncate(7); From 83640686cd004e2c979d95416c073d6b650b920b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Wed, 16 Dec 2020 11:23:20 +0800 Subject: [PATCH 123/126] =?UTF-8?q?=E4=BF=AE=E5=A4=8DboBoolen=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/gdb.sh | 2 +- spec/Stringy/StringySpec.php | 2 -- src/ext/stringy/stringy.c | 12 ++++-------- 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/scripts/gdb.sh b/scripts/gdb.sh index 0c11cea..657a6ef 100755 --- a/scripts/gdb.sh +++ b/scripts/gdb.sh @@ -14,7 +14,7 @@ # MINBABY_TEST_EXT=1 php -f startup.php -# ulimit -c 0 +# ulimit -c unlimited # gdb -c core php diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index 42623c6..d27122d 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -1,5 +1,4 @@ safeTruncate($length, $substring); diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index fb8359c..66b1452 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -3590,7 +3590,7 @@ PHP_METHOD(Stringy, toBoolean) ZVAL_TRUE(&T); ZVAL_FALSE(&F); - convert_to_array(&map); + array_init(&map); char* trueList[] = { "true", "1", @@ -3739,7 +3739,7 @@ PHP_METHOD(Stringy, safeTruncate) { *encoding, }; call_user_function(NULL, NULL, &func, return_value, 2, args_mb_strlen); - length_o = length_n - Z_LVAL_P(return_value); + length_o = length_o - Z_LVAL_P(return_value); ZVAL_STRING(&func, "mb_substr"); zval zval_0; @@ -3758,19 +3758,17 @@ PHP_METHOD(Stringy, safeTruncate) { ZVAL_STRING(&func, "mb_strpos"); zval estr; ZVAL_STRING(&estr, " "); - zval length_1; - ZVAL_LONG(&length_1, length_o-1); + ZVAL_LONG(&zval_length, length_o - 1); zval args_mb_strpos[] = { *str, estr, - length_1, + zval_length, *encoding, }; call_user_function(NULL, NULL, &func, return_value, 4, args_mb_strpos); if (Z_LVAL_P(return_value) != length_o) { ZVAL_STRING(&func, "mb_strrpos"); - ZVAL_STRING(&estr, " "); zval length_1; ZVAL_LONG(&length_1, length_o-1); zval args_mb_strrpos[] = { @@ -3799,8 +3797,6 @@ PHP_METHOD(Stringy, safeTruncate) { zend_string *str_name = zend_string_init(ZEND_STRL("str"), 0); zend_update_property_ex(NULL, &obj, str_name, return_value); - - RETURN_ZVAL(&obj, 1, 0); } From 8b489cac0ce85da471b9f4efa89aea01be0f8bad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Wed, 16 Dec 2020 15:41:02 +0800 Subject: [PATCH 124/126] titleize --- spec/Stringy/StringySpec.php | 4 +- src/ext/functions.c | 4 +- src/ext/stringy/stringy.c | 205 +++++++++++++++++++++++++++-------- startup.php | 2 +- 4 files changed, 166 insertions(+), 49 deletions(-) diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index d27122d..a885004 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -1982,9 +1982,7 @@ } }); - - - xcontext('test titleize', function () { + context('test titleize', function () { $ignore = ['at', 'by', 'for', 'in', 'of', 'on', 'out', 'to', 'the']; $data = [ diff --git a/src/ext/functions.c b/src/ext/functions.c index 5867994..9419a49 100644 --- a/src/ext/functions.c +++ b/src/ext/functions.c @@ -47,7 +47,7 @@ bool zval_str_equal(zval *first, zval *second) bool m_array_set(zval *array, const char *key, zval *value) { - + return true; } zval m_array_get(zval *array, const char *key) @@ -62,4 +62,4 @@ zval m_array_get(zval *array, const char *key) strsplit(key, x, "."); return ret; -} +} \ No newline at end of file diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index 66b1452..189a6d4 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -127,7 +127,7 @@ PHP_METHOD(Stringy, create) object_init_ex(&instance, stringy_ce); if (encoding == NULL) { - encoding = malloc(sizeof(zval)); + encoding = emalloc(sizeof(zval)); ZVAL_STRING(encoding, "UTF-8"); } @@ -465,7 +465,7 @@ PHP_METHOD(Stringy, regexReplace) ZEND_PARSE_PARAMETERS_END(); if (options == NULL) { - options = malloc(sizeof(zval)); + options = emalloc(sizeof(zval)); ZVAL_STRING(options, "msr"); } @@ -520,7 +520,7 @@ PHP_METHOD(Stringy, trim) { convert_to_string(chars); if (Z_STRLEN_P(chars) == 0) { - chars = malloc(sizeof(zval)); + chars = emalloc(sizeof(zval)); ZVAL_STRING(chars, "[:space:]"); } else { zval func, delimiter; @@ -534,7 +534,7 @@ PHP_METHOD(Stringy, trim) } else { - chars = malloc(sizeof(zval)); + chars = emalloc(sizeof(zval)); ZVAL_STRING(chars, "[:space:]"); } @@ -586,7 +586,7 @@ PHP_METHOD(Stringy, eregReplace) ZVAL_STRING(&func, "mb_ereg_replace"); if (option == NULL) { - option = malloc(sizeof(zval)); + option = emalloc(sizeof(zval)); ZVAL_EMPTY_STRING(option); } @@ -658,14 +658,14 @@ PHP_METHOD(Stringy, swapCase) zend_string *f = zend_string_init(ZEND_STRL("callback"), 0); - zendFunction.type = ZEND_INTERNAL_FUNCTION; - zendFunction.common.num_args = 1; - zendFunction.common.required_num_args = 1; - zendFunction.common.arg_info = zai; - zendFunction.common.prototype = NULL; - zendFunction.common.scope = NULL; - zendFunction.common.fn_flags = ZEND_ACC_CLOSURE; - zendFunction.common.function_name = f; + // zendFunction.type = ZEND_INTERNAL_FUNCTION; + // zendFunction.common.num_args = 1; + // zendFunction.common.required_num_args = 1; + // zendFunction.common.arg_info = zai; + // zendFunction.common.prototype = NULL; + // zendFunction.common.scope = NULL; + // zendFunction.common.fn_flags = ZEND_ACC_CLOSURE; + zendFunction.internal_function.function_name = f; zendFunction.internal_function.handler = swap_case_handler; zendFunction.internal_function.type = ZEND_INTERNAL_FUNCTION; zendFunction.internal_function.fn_flags = ZEND_ACC_CLOSURE; @@ -1019,14 +1019,14 @@ PHP_METHOD(Stringy, camelize) #pragma region first zend_string *f = zend_string_init(ZEND_STRL("callback"), 0); - zendFunction.type = ZEND_INTERNAL_FUNCTION; - zendFunction.common.num_args = 1; - zendFunction.common.required_num_args = 1; - zendFunction.common.arg_info = zai; - zendFunction.common.prototype = NULL; - zendFunction.common.scope = NULL; - zendFunction.common.fn_flags = ZEND_ACC_CLOSURE; - zendFunction.common.function_name = f; + // zendFunction.type = ZEND_INTERNAL_FUNCTION; + // zendFunction.common.num_args = 1; + // zendFunction.common.required_num_args = 1; + // zendFunction.common.arg_info = zai; + // zendFunction.common.prototype = NULL; + // zendFunction.common.scope = NULL; + // zendFunction.common.fn_flags = ZEND_ACC_CLOSURE; + zendFunction.internal_function.function_name = f; zendFunction.internal_function.handler = preg_replace_callback_handler; zendFunction.internal_function.type = ZEND_INTERNAL_FUNCTION; zendFunction.internal_function.fn_flags = ZEND_ACC_CLOSURE; @@ -1085,7 +1085,7 @@ PHP_METHOD(Stringy, trimLeft) { convert_to_string(chars); if (Z_STRLEN_P(chars) == 0) { - chars = malloc(sizeof(zval)); + chars = emalloc(sizeof(zval)); ZVAL_STRING(chars, "[:space:]"); } else { zval func, delimiter; @@ -1099,7 +1099,7 @@ PHP_METHOD(Stringy, trimLeft) } else { - chars = malloc(sizeof(zval)); + chars = emalloc(sizeof(zval)); ZVAL_STRING(chars, "[:space:]"); } @@ -1131,7 +1131,7 @@ PHP_METHOD(Stringy, trimRight) { convert_to_string(chars); if (Z_STRLEN_P(chars) == 0) { - chars = malloc(sizeof(zval)); + chars = emalloc(sizeof(zval)); ZVAL_STRING(chars, "[:space:]"); } else { zval func, delimiter; @@ -1145,7 +1145,7 @@ PHP_METHOD(Stringy, trimRight) } else { - chars = malloc(sizeof(zval)); + chars = emalloc(sizeof(zval)); ZVAL_STRING(chars, "[:space:]"); } @@ -1484,7 +1484,7 @@ PHP_METHOD(Stringy, endsWith) ZEND_PARSE_PARAMETERS_END(); if (caseSensitive == NULL) { - caseSensitive = malloc(sizeof(zval)); + caseSensitive = emalloc(sizeof(zval)); ZVAL_BOOL(caseSensitive, IS_TRUE); } @@ -1556,7 +1556,7 @@ PHP_METHOD(Stringy, endsWithAny) ZEND_PARSE_PARAMETERS_END(); if (caseSensitive == NULL) { - caseSensitive = malloc(sizeof(zval)); + caseSensitive = emalloc(sizeof(zval)); ZVAL_BOOL(caseSensitive, IS_TRUE); } @@ -1592,7 +1592,7 @@ PHP_METHOD(Stringy, startsWith) ZEND_PARSE_PARAMETERS_END(); if (caseSensitive == NULL) { - caseSensitive = malloc(sizeof(zval)); + caseSensitive = emalloc(sizeof(zval)); ZVAL_BOOL(caseSensitive, IS_TRUE); } @@ -1731,7 +1731,7 @@ PHP_METHOD(Stringy, first) ZEND_PARSE_PARAMETERS_END(); if (n == NULL) { - n = malloc(sizeof(zval)); + n = emalloc(sizeof(zval)); ZVAL_LONG(n, 0); } @@ -1776,7 +1776,7 @@ PHP_METHOD(Stringy, last) ZEND_PARSE_PARAMETERS_END(); if (n == NULL) { - n = malloc(sizeof(zval)); + n = emalloc(sizeof(zval)); ZVAL_LONG(n, 0); } @@ -2606,12 +2606,12 @@ PHP_METHOD(Stringy, pad) ZEND_PARSE_PARAMETERS_END(); if (padStr == NULL) { - padStr = malloc(sizeof(zval)); + padStr = emalloc(sizeof(zval)); ZVAL_STRING(padStr, " "); } if (padType == NULL) { - padType = malloc(sizeof(zval)); + padType = emalloc(sizeof(zval)); ZVAL_STRING(padType, "right"); } @@ -2667,7 +2667,7 @@ PHP_METHOD(Stringy, applyPadding) ZVAL_LONG(&zero, 0); if (left == NULL) { - left = malloc(sizeof(zval)); + left = emalloc(sizeof(zval)); ZVAL_LONG(left, 0); } @@ -2676,7 +2676,7 @@ PHP_METHOD(Stringy, applyPadding) } if (right == NULL) { - right = malloc(sizeof(zval)); + right = emalloc(sizeof(zval)); ZVAL_LONG(right, 0); } @@ -2685,7 +2685,7 @@ PHP_METHOD(Stringy, applyPadding) } if (padStr == NULL) { - padStr = malloc(sizeof(zval)); + padStr = emalloc(sizeof(zval)); ZVAL_STRING(padStr, " "); } @@ -2789,7 +2789,7 @@ PHP_METHOD(Stringy, padLeft) ZEND_PARSE_PARAMETERS_END(); if (padStr == NULL) { - padStr = malloc(sizeof(zval)); + padStr = emalloc(sizeof(zval)); ZVAL_STRING(padStr, " "); } @@ -2825,7 +2825,7 @@ PHP_METHOD(Stringy, padRight) ZEND_PARSE_PARAMETERS_END(); if (padStr == NULL) { - padStr = malloc(sizeof(zval)); + padStr = emalloc(sizeof(zval)); ZVAL_STRING(padStr, " "); } @@ -2861,7 +2861,7 @@ PHP_METHOD(Stringy, padBoth) ZEND_PARSE_PARAMETERS_END(); if (padStr == NULL) { - padStr = malloc(sizeof(zval)); + padStr = emalloc(sizeof(zval)); ZVAL_STRING(padStr, " "); } @@ -2959,12 +2959,12 @@ PHP_METHOD(Stringy, toAscii) ZEND_PARSE_PARAMETERS_END(); if (language == NULL) { - language = (zval *) malloc(sizeof(zval)); + language = (zval *) emalloc(sizeof(zval)); ZVAL_STRING(language, "en"); } if (removeUnsupported == NULL) { - removeUnsupported = (zval *) malloc(sizeof(zval)); + removeUnsupported = (zval *) emalloc(sizeof(zval)); ZVAL_BOOL(removeUnsupported, IS_TRUE); } @@ -3254,7 +3254,7 @@ PHP_METHOD(Stringy, langSpecificCharsArray) ZEND_PARSE_PARAMETERS_END(); if (language == NULL) { - language = malloc(sizeof(zval)); + language = emalloc(sizeof(zval)); ZVAL_STRING(language, "en"); } @@ -3518,7 +3518,7 @@ PHP_METHOD(Stringy, toTabs) ZEND_PARSE_PARAMETERS_END(); if (tabLength == NULL) { - tabLength = malloc(sizeof(zval)); + tabLength = emalloc(sizeof(zval)); ZVAL_LONG(tabLength, 4); } @@ -3646,6 +3646,124 @@ PHP_METHOD(Stringy, toBoolean) RETURN_ZVAL(str, 0, 0); } +static zval __ignore; +static zval __encoding; +static void titleize_handler(INTERNAL_FUNCTION_PARAMETERS) +{ + zval *arr; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ARRAY(arr) + ZEND_PARSE_PARAMETERS_END(); + + bool flag = false; + zval *first = zend_hash_index_find(Z_ARRVAL_P(arr), 0); + + zval func, args[] = { + *first, + __ignore, + }; + ZVAL_STRING(&func, "in_array"); + call_user_function(NULL, NULL, &func, return_value, 2, args); + convert_to_boolean(return_value); + + if (IS_NULL != Z_TYPE(__ignore) && Z_TYPE_P(return_value)==IS_TRUE) { + RETURN_ZVAL(first, 1, 1); + } + + zval obj; + convert_to_string(return_value); + object_init_ex(&obj, stringy_ce); + zval args_construct[] = { + *first, + __encoding, + }; + ZVAL_STRING(&func, "__construct"); + call_user_function(NULL, &obj, &func, return_value, 2, args_construct); + + ZVAL_STRING(&func, "toLowerCase"); + call_user_function(NULL, &obj, &func, return_value, 0, NULL); + + ZVAL_STRING(&func, "upperCaseFirst"); + call_user_function(NULL, return_value, &func, return_value, 0, NULL); + + convert_to_string(return_value); +} +PHP_METHOD(Stringy, titleize) { + zval *ignore; + ignore = emalloc(sizeof(zval)); + ZVAL_NULL(ignore); + + ZEND_PARSE_PARAMETERS_START(0, 1) + Z_PARAM_OPTIONAL + Z_PARAM_ZVAL(ignore) + ZEND_PARSE_PARAMETERS_END(); + + zval rv; + zval *str = zend_read_property(NULL, getThis(), ZEND_STRL("str"), 0, &rv); + zval *encoding = zend_read_property(NULL, getThis(), ZEND_STRL("encoding"), 0, &rv); + + zval func; + ZVAL_STRING(&func, "trim"); + call_user_function(NULL, getThis(), &func, return_value, 0, NULL); + + zval obj; + convert_to_string(return_value); + object_init_ex(&obj, stringy_ce); + zval args_construct[] = { + *return_value, + *encoding, + }; + ZVAL_STRING(&func, "__construct"); + call_user_function(NULL, &obj, &func, return_value, 2, args_construct); + + str = zend_read_property(NULL, &obj, ZEND_STRL("str"), 0, &rv); + + + zend_internal_arg_info zai[] = { + ZEND_ARG_ARRAY_INFO(0, "matches", 0) + }; + + zend_string *f = zend_string_init(ZEND_STRL("callback"), 0); + + zend_function zendFunction; + zendFunction.internal_function.function_name = f; + zendFunction.internal_function.handler = titleize_handler; + zendFunction.internal_function.type = ZEND_INTERNAL_FUNCTION; + zendFunction.internal_function.fn_flags = ZEND_ACC_CLOSURE; + zendFunction.internal_function.arg_info = zai; + zendFunction.internal_function.required_num_args =1; + zendFunction.internal_function.num_args = 1; + + + zval callback; + zend_create_closure(&callback, &zendFunction, NULL, NULL, NULL); + // 这个不知道怎么模拟use + if (Z_TYPE_P(ignore) == IS_NULL) { + array_init(ignore); + } + + __ignore = *ignore; + __encoding = *encoding; + + ZVAL_STRING(&func, "preg_replace_callback"); + zval reg; + ZVAL_STRING(®, "/([\\S]+)/u"); + zval args_preg_replace_callback[] = { + reg, + callback, + *str, + }; + call_user_function(NULL, NULL, &func, return_value, 3, args_preg_replace_callback); + + zend_update_property(NULL, &obj, ZEND_STRL("str"), return_value); + + RETURN_ZVAL(&obj, 1, 1); +} +ZEND_BEGIN_ARG_INFO(arginfo_titleize, 1) + ZEND_ARG_INFO(0, ignore) +ZEND_END_ARG_INFO(); + PHP_METHOD(Stringy, reverse) { zval func = {}; ZVAL_STRING(&func, "length"); @@ -3700,7 +3818,7 @@ PHP_METHOD(Stringy, safeTruncate) { zval *length; zval *substring; - substring = malloc(sizeof(zval)); + substring = emalloc(sizeof(zval)); ZVAL_STRING(substring, ""); @@ -3890,6 +4008,7 @@ static zend_function_entry methods[] = { PHP_ME(Stringy, toTabs, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, toLowerCase, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, toBoolean, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, titleize, arginfo_titleize, ZEND_ACC_PUBLIC) PHP_ME(Stringy, reverse, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, safeTruncate, arginfo_safeTruncate, ZEND_ACC_PUBLIC) PHP_FE_END diff --git a/startup.php b/startup.php index 9ce2840..53e003d 100644 --- a/startup.php +++ b/startup.php @@ -8,4 +8,4 @@ _ns(NS_STRINGY); -echo __('Stringy')::create("Test foo bar")->safeTruncate(7); +echo __('Stringy')::create("testing the method")->titleize(['at', 'by', 'for', 'in', 'of', 'on', 'out', 'to', 'the']); From f34cdab650a021c6c1445b64bb7658f0cbfa1e8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Wed, 16 Dec 2020 17:44:23 +0800 Subject: [PATCH 125/126] fix collapseWhitespace --- spec/Stringy/StringySpec.php | 4 ++-- src/ext/stringy/stringy.c | 34 ++++++++++++++++++---------------- startup.php | 2 +- 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index a885004..0c156f4 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -659,7 +659,7 @@ } }); - xit('test CollapseWhitespace', function () { + it('test CollapseWhitespace', function () { $data = [ ['foo bar', ' foo bar '], ['test string', 'test string'], @@ -1524,7 +1524,7 @@ it(__formatMessage($key, $value), function () use ($value) { @list($expected, $str, $otherStr, $encoding) = $value; - $stringy = __('Stringy')::create($str); + $stringy = __('Stringy')::create($str, $encoding); $result = $stringy->longestCommonSubstring($otherStr); \expect($stringy)->toBeAnInstanceOf(__('Stringy')); diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index 189a6d4..e102fa3 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -435,21 +435,22 @@ ZEND_END_ARG_INFO(); PHP_METHOD(Stringy, collapseWhiteSpace) { - zval retval, func, args[3], args_trim[1]; + zval retval, func; zval pattern, replacement, options, chars; ZVAL_STRING(&pattern, "[[:space:]]+"); ZVAL_STRING(&replacement, " "); - args[0] = pattern; - args[1] = replacement; - args[2] = options; + zval args[] = { + pattern, + replacement, + }; ZVAL_STRING(&func, "regexReplace"); - call_user_function(NULL, getThis(), &func, &retval, 3, args); + call_user_function(NULL, getThis(), &func, return_value, 2, args); ZVAL_STRING(&func, "trim"); - call_user_function(NULL, &retval, &func, return_value, 0, NULL); + call_user_function(NULL, return_value, &func, return_value, 0, NULL); } PHP_METHOD(Stringy, regexReplace) @@ -2529,18 +2530,19 @@ PHP_METHOD(Stringy, longestCommonSubstring) zval strChar, otherChar, i_tmp, j_tmp, const_substr_len; ZVAL_LONG(&const_substr_len, 1); for(int i = 1; i < Z_LVAL(strLen); i++) { - ZVAL_LONG(&i_tmp, i - 1); - zval args_mb_strlen[] = { - *str, - i_tmp, - const_substr_len, - *encoding, - }; - ZVAL_STRING(&func, "mb_substr"); - call_user_function(NULL, NULL, &func, &strChar, 4, args_mb_strlen); - + zend_array *ht = Z_ARRVAL(table); for(int j = 1; j < Z_LVAL(otherLength); j++) { + ZVAL_LONG(&i_tmp, i - 1); + zval args_mb_strlen[] = { + *str, + i_tmp, + const_substr_len, + *encoding, + }; + ZVAL_STRING(&func, "mb_substr"); + call_user_function(NULL, NULL, &func, &strChar, 4, args_mb_strlen); + ZVAL_LONG(&j_tmp, j - 1); zval args_mb_strlen2[] = { *otherStr, diff --git a/startup.php b/startup.php index 53e003d..8371839 100644 --- a/startup.php +++ b/startup.php @@ -8,4 +8,4 @@ _ns(NS_STRINGY); -echo __('Stringy')::create("testing the method")->titleize(['at', 'by', 'for', 'in', 'of', 'on', 'out', 'to', 'the']); +echo __('Stringy')::create("testing the method")->collapseWhitespace(); From 27124facc6d8bdcab2adf38484ab13af6d6f7881 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Wed, 16 Dec 2020 18:34:01 +0800 Subject: [PATCH 126/126] shuffle --- docs/jobs/stringy.md | 4 +- spec/Stringy/StringySpec.php | 29 ++++++++++++ src/Minbaby/Php/Stringy/Stringy.php | 13 ++++++ src/ext/stringy/stringy.c | 70 +++++++++++++++++++++++++++++ 4 files changed, 114 insertions(+), 2 deletions(-) diff --git a/docs/jobs/stringy.md b/docs/jobs/stringy.md index b73d9aa..156a4ea 100644 --- a/docs/jobs/stringy.md +++ b/docs/jobs/stringy.md @@ -132,7 +132,7 @@ https://github.com/danielstjules/Stringy - [x] safeTruncate -- [ ] shuffle +- [x] shuffle - [ ] slugify @@ -162,7 +162,7 @@ https://github.com/danielstjules/Stringy - [x] toLowerCase -- [ ] toSpaces +- [x] toSpaces - [x] toTabs diff --git a/spec/Stringy/StringySpec.php b/spec/Stringy/StringySpec.php index 0c156f4..8816321 100644 --- a/spec/Stringy/StringySpec.php +++ b/spec/Stringy/StringySpec.php @@ -2071,4 +2071,33 @@ }); } }); + + context('test shuffle', function () { + $data = [ + ['foo bar'], + ['∂∆ ˚åß', 'UTF-8'], + ['å´¥©¨ˆßå˚ ∆∂˙©å∑¥øœ¬', 'UTF-8'] + ]; + + foreach ($data as $key => $value) { + it(__formatMessage($key, $value), function () use ($value) { + + @list($str, $encoding) = $value; + $encoding = $encoding ?: mb_internal_encoding(); + $stringy = __('Stringy')::create($str, $encoding); + $result = $stringy->shuffle(); + + \expect($stringy)->toBeAnInstanceOf(__('Stringy')); + \expect((string) $stringy)->toBe($str); + \expect(mb_strlen($str, $encoding))->toBe(mb_strlen((string) $result, $encoding)); + + for ($i = 0; $i < mb_strlen($str, $encoding); $i++) { + $char = mb_substr($str, $i, 1, $encoding); + $countBefore = mb_substr_count($str, $char, $encoding); + $countAfter = mb_substr_count($result, $char, $encoding); + \expect($countBefore)->toBe($countAfter); + } + }); + } + }); }); diff --git a/src/Minbaby/Php/Stringy/Stringy.php b/src/Minbaby/Php/Stringy/Stringy.php index ede1da5..4c6cac0 100644 --- a/src/Minbaby/Php/Stringy/Stringy.php +++ b/src/Minbaby/Php/Stringy/Stringy.php @@ -1088,4 +1088,17 @@ public function safeTruncate($length, $substring = '') return $stringy; } + + public function shuffle() + { + $indexes = range(0, $this->length() - 1); + shuffle($indexes); + + $shuffledStr = ''; + foreach ($indexes as $i) { + $shuffledStr .= \mb_substr($this->str, $i, 1, $this->encoding); + } + + return static::create($shuffledStr, $this->encoding); + } } diff --git a/src/ext/stringy/stringy.c b/src/ext/stringy/stringy.c index e102fa3..0469068 100644 --- a/src/ext/stringy/stringy.c +++ b/src/ext/stringy/stringy.c @@ -3925,6 +3925,75 @@ ZEND_BEGIN_ARG_INFO(arginfo_safeTruncate, 0) ZEND_ARG_INFO(0, substring) ZEND_END_ARG_INFO(); +PHP_METHOD(Stringy, shuffle) +{ + zval zval_0; + ZVAL_LONG(&zval_0, 0); + + zval func; + ZVAL_STRING(&func, "length"); + call_user_function(NULL, getThis(), &func, return_value, 0, NULL); + + long l = Z_LVAL_P(return_value); + + zval indexes; + zval zval_len; + ZVAL_LONG(&zval_len, l - 1); + zval args[] = { + zval_0, + zval_len + }; + ZVAL_STRING(&func, "range"); + call_user_function(NULL, NULL, &func, &indexes, 2, args); + + zval ref; + ZVAL_NEW_REF(&ref, &indexes); + + ZVAL_STRING(&func, "shuffle"); + zval args_shuffle[] = { + ref, + }; + call_user_function(NULL, NULL, &func, return_value, 1, args_shuffle); + + zval shuffledStr; + + zval rv; + zval *str = zend_read_property(NULL, getThis(), ZEND_STRL("str"), 0, &rv); + zval *encoding = zend_read_property(NULL, getThis(), ZEND_STRL("encoding"), 0, &rv); + + zval *value; + zend_string *key; + zval x; + ulong idx; + ZEND_HASH_REVERSE_FOREACH_KEY_VAL_IND(Z_ARRVAL(indexes), idx, key, value) + zval zval_1; + ZVAL_LONG(&zval_1, 1); + + zval args_mb_substr[] = { + *str, + *value, + zval_1, + *encoding, + }; + ZVAL_STRING(&func, "mb_substr"); + call_user_function(NULL, NULL, &func, return_value, 4, args_mb_substr); + + concat_function(&shuffledStr, &shuffledStr, return_value); + ZEND_HASH_FOREACH_END(); + + zval obj; + object_init_ex(&obj, stringy_ce); + zval args_construct[] = { + shuffledStr, + *encoding, + }; + ZVAL_STRING(&func, "__construct"); + call_user_function(NULL, &obj, &func, return_value, 2, args_construct); + + + RETURN_ZVAL(&obj, 0, 0); +} + static zend_function_entry methods[] = { PHP_ME(Stringy, __construct, arginfo___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) PHP_ME(Stringy, __toString, NULL, ZEND_ACC_PUBLIC) @@ -4013,6 +4082,7 @@ static zend_function_entry methods[] = { PHP_ME(Stringy, titleize, arginfo_titleize, ZEND_ACC_PUBLIC) PHP_ME(Stringy, reverse, NULL, ZEND_ACC_PUBLIC) PHP_ME(Stringy, safeTruncate, arginfo_safeTruncate, ZEND_ACC_PUBLIC) + PHP_ME(Stringy, shuffle, NULL, ZEND_ACC_PUBLIC) PHP_FE_END };