perlhacktut
СОДЕРЖАНИЕ
НАЗВАНИЕ
perlhacktut - Пошаговое руководство по созданию простого переключения кода C
ОПИСАНИЕ
Этот документ предоставляет пример простого переключения.
Если вы еще не читали perlhack, сделайте это сначала! Вам также может быть интересно прочитать perlsource.
После завершения работы с этим документом перейдите к perlhacktips.
ПРИМЕР ПРОСТОГО ПЕРЕКЛЮЧЕНИЯ
Давайте рассмотрим простой пример переключения от начала до конца.
Вот что предложил Ларри: если U является первым активным форматом во время pack, (например, pack "U3C8", @stuff) то результирующая строка должна обрабатываться как закодированная в UTF-8.
Если вы работаете с копией репозитория Perl с помощью git, вам следует создать ветвь для своих изменений. Это значительно упростит создание правильного переключения. Смотрите perlgit для получения подробной информации о том, как это сделать.
Создание переключения
Как подготовиться к исправлению? Сначала найдите интересующий нас код – pack происходит во время выполнения, поэтому он будет в одном из файлов pp. Действительно, pp_pack находится в pp.c. Так как мы собираемся изменить этот файл, скопируем его в pp.c~.
[Ну, это было в pp.c, когда этот учебник был написан. Теперь он был разделен с pp_unpack в отдельный файл pp_pack.c]
Теперь давайте рассмотрим pp_pack: мы принимаем шаблон в pat, затем перебираем шаблон, принимая каждый символ формата в datum_type. Затем для каждого возможного символа формата мы поглощаем другие аргументы в шаблоне (ширина поля, звездочка и т. д.) и преобразуем следующий фрагмент входных данных в указанный формат, добавляя его к выходному SV cat.
Как мы можем узнать, является ли U первым форматом в pat? Если у нас есть указатель на начало pat, то если мы видим U, мы можем проверить, находимся ли мы все еще в начале строки. Итак, вот где устанавливается pat:
STRLEN fromlen;
char *pat = SvPVx(*++MARK, fromlen);
char *patend = pat + fromlen;
I32 len;
I32 datumtype;
SV *fromstr; У нас будет еще один указатель на строку:
STRLEN fromlen;
char *pat = SvPVx(*++MARK, fromlen);
char *patend = pat + fromlen;
+ char *patcopy;
I32 len;
I32 datumtype;
SV *fromstr; И непосредственно перед началом цикла мы установим patcopy в начало pat:
items = SP - MARK;
MARK++;
SvPVCLEAR(cat);
+ patcopy = pat;
while (pat < patend) { Теперь, если мы увидим U, который находился в начале строки, мы включим флаг UTF8 для выходного SV, cat:
+ if (datumtype == 'U' && pat==patcopy+1)
+ SvUTF8_on(cat);
if (datumtype == '#') {
while (pat < patend && *pat != '\n')
pat++; Запомните, что это должно быть patcopy+1, потому что первый символ строки – это U, который был поглощен в datumtype!
Ого, мы забыли одну вещь: а что, если в начале шаблона есть пробелы? pack(" U*", @stuff) будет иметь U как первый активный символ, даже если это не первое в шаблоне. В этом случае нам нужно продвинуть patcopy вместе с pat, когда мы видим пробелы:
if (isSPACE(datumtype))
continue; должно стать
if (isSPACE(datumtype)) {
patcopy++;
continue;
} Хорошо. Это сделано с частью C. Теперь нам нужно сделать еще две вещи, прежде чем это переключение будет готово: мы изменили поведение Perl, поэтому мы должны это задокументировать. Также нам нужно предоставить дополнительные регрессионные тесты, чтобы убедиться, что наше переключение работает и не создает ошибки в другом месте.
Тестирование переключения
Регрессионные тесты для каждого оператора находятся в t/op/, поэтому мы копируем t/op/pack.t в t/op/pack.t~. Теперь мы можем добавить наши тесты в конец. Сначала мы проверим, что U действительно создает строки Unicode.
t/op/pack.t имеет функцию ok(), но если бы ее не было, мы могли бы использовать ту, что из t/test.pl.
require './test.pl';
plan( tests => 159 ); итак, вместо этого:
print 'not ' unless "1.20.300.4000" eq sprintf "%vd",
pack("U*",1,20,300,4000);
print "ok $test\n"; $test++; мы можем написать более понятный (смотрите Test::More для полного объяснения функций is() и других функций тестирования).
is( "1.20.300.4000", sprintf "%vd", pack("U*",1,20,300,4000),
"U* produces Unicode" ); Теперь проверим, что мы правильно обработали пробелы в начале:
is( "1.20.300.4000", sprintf "%vd", pack(" U*",1,20,300,4000),
" with spaces at the beginning" ); И, наконец, проверим, что мы не создаем строки Unicode, если U не является первым активным форматом:
isnt( v1.20.300.4000, sprintf "%vd", pack("C0U*",1,20,300,4000),
"U* not first isn't Unicode" ); Нельзя забыть изменить количество тестов вверху, иначе автоматический тестировщик запутается. Это будет выглядеть так:
print "1..156\n"; или так:
plan( tests => 156 ); Теперь мы компилируем Perl и запускаем его через набор тестов. Наши новые тесты проходят, ура!
Документирование переключения
Наконец, документация. Работа никогда не завершается, пока не будут завершены все бумажные дела, поэтому давайте опишем внесенное нами изменение. Соответствующее место – pod/perlfunc.pod; снова мы создаем копию, а затем вставим этот текст в описание pack:
=item *
If the pattern begins with a C<U>, the resulting string will be treated
as UTF-8-encoded Unicode. You can force UTF-8 encoding on in a string
with an initial C<U0>, and the bytes that follow will be interpreted as
Unicode characters. If you don't want this to happen, you can begin
your pattern with C<C0> (or anything else) to force Perl not to UTF-8
encode your string, and then follow this with a C<U*> somewhere in your
pattern. Отправить
Подробная информация об отправке переключения приведена в perlhack.
АВТОР
Этот документ был первоначально написан Натаном Торкинтоном и поддерживается почтовой рассылкой perl5-porters.
© 1993–2023 Larry Wall and others
Licensed under the GNU General Public License version 1 or later, or the Artistic License.
The Perl logo is a trademark of the Perl Foundation.
https://perldoc.perl.org/5.38.0/perlhacktut