Проверка файлов в текстовых и HEX редакторах потдверждает корректность файлов и всех переводов строк.
Итак, тестовый код (добавлены стековые комментарии для SREAD-LINE):
Код:
: CRLF-Count \ ( a u -- )
0 >R
BEGIN \ a u
DUP \ a u u
IF
2DUP \ a u a u
CRLF \ a u a u a1 u1
SEARCH \ a u a u a2 u2 ?
0= \ a u a u a2 u2 -?
IF \ a u a u a2 u2
2DROP \ a u a u
2DUP \ a u a u a u
+ \ a u a u a+u
0 \ a u a u a+u 0
2SWAP \ a u a+u 0 a u
ELSE \ a u a u a2 u2
2DUP \ a u a u a2 u2 a2 u2
2>R \ a u a u a2 u2 R: a2 u2
NIP \ a u a u u2 R: a2 u2
- \ a u a u-u2 R: a2 u2
2R> \ a u a u-u2 a2 u2
2 \ a u a u-u2 a2 u2 2
/STRING \ a u a u-u2 a2+2 u2-2
2SWAP \ a u a2+2 u2-2 a u-u2
THEN
TRUE
ELSE
2DUP FALSE \ a u a u ?
THEN
OK
WHILE
2DROP
\ R@ . . . CR
R> 1+ >R
REPEAT
2DROP 2DROP
R> . CR
;
: crlfCounterTest
0 -ROT
OVER + SWAP DO
I C@ 0x0D =
I 1+ C@ 0x0A = AND IF 1+ THEN
LOOP
. CR
;
И результат у меня такой получается:
Код:
S" TestFile.txt" FILE crlfCounterTest
180000
И вот такой:
Код:
S" TestFile.txt" FILE CRLF-Count
...
Ok ( 83732948 1310720 83732940 6 4294967295(-1) )
Ok ( 85043668 0 83732948 1310720 4294967295(-1) )
Ok ( 85043668 0 85043668 0 0 )
13817
SREAD-LINE Возвращает флаг, найденную строку и следующую строку.
83732948 1310720 - следующая строка
83732940 6 - найденная строка
Очевидно, что именно на этой найденной строке и происходит остановка поиска. Посмотрим что там внутри:
Код:
99789268 32 DUMP
5F2A9D4 32 34 33 31 35 34 0D 0A 34 34 35 36 37 35 0D 0A 243154..445675..
5F2A9E4 35 35 30 39 30 39 0D 0A 33 33 38 34 34 31 0D 0A 550909..338441.. Ok
Как видно - в строке все хорошо.
Проверим результат поиска:
Код:
99789268 1310720 CRLF SEARCH . . .
0 1310720 99789268 Ok
Опаньки! Как это так? Попробуем еще раз:
Код:
99789268 1310720 S" 445675" SEARCH . . .
0 1310720 99789268 Ok
99789268 1310720 S" 243154" SEARCH . . .
0 1310720 99789268 Ok
Хмм... Все становистя еще интереснее. А если вот так:
Код:
99789268 1310719 CRLF SEARCH . . .
-1 1310713 99789274 Ok
99789268 1310721 CRLF SEARCH . . .
-1 1310715 99789274 Ok
99789267 1310720 CRLF SEARCH . . .
0 1310720 99789267 Ok
99789269 1310720 CRLF SEARCH . . .
0 1310720 99789269 Ok
Очевидно, проблема в длине строки - именно эту длину строки поиск не принимает. Интересно, почему же? Посмотрим-ка что это за число более внимательно:
Код:
1310720 .H
00140000 Ok
1310720 .B
0000 0000 0001 0100 0000 0000 0000 0000 Ok
Интересное число, не правда ли? Проверим-ка одну теорию:
Код:
99789267 65535 CRLF SEARCH . . .
-1 65528 99789274 Ok
Работает. И еще разок:
Код:
99789267 65536 CRLF SEARCH . . .
0 65536 99789267 Ok
Не работает. Теперь причина такого поведения поиска вполне очевидна:
Код:
65535 = 0xFFFF = 0b 0000 0000 0000 0001 0000 0000 0000 0000
65536 = 0x10000 = 0b 0000 0000 0000 0001 0000 0000 0000 0000
Поиск шестандцатибитный. Т.е., максимальная длина строки, в которой производится поиск составляет 65535.
Тот же самый код в SPF4 ведет себя как ожидается - поиск там 32-х битный:
Код:
S" E:\TEMP\Count\TestFile.txt" FILE CRLF-Count
180000
Ok
Проблема в команде
JCXZ @@1 - её надо заменить на
JECXZ @@1 и поиск будет работать на 32 битных строках.
Исправленный поиск:
Код:
CODE SEARCH ( c-addr1 u1 c-addr2 u2 -- c-addr3 u3 flag ) \ 94 STRING Произвести поиск в строке, заданной c-addr1 u1, строки, заданной c-addr2 u2. Если флаг "истина", совпадение найдено по адресу c-addr3 с оставшимися u3 символами. Если флаг "ложь", совпадения не найдено, и c-addr3 есть c-addr1, и u3 есть u1.
PUSH EDI
CLD
MOV EBX, [EBP]
OR EBX, EBX
JZ @@5
MOV EDX, 8 [EBP]
MOV EDI, 0x0C [EBP]
ADD EDX, EDI
@@4: MOV ESI, 4 [EBP]
LODS BYTE
MOV ECX, EDX
SUB ECX, EDI
JECXZ @@1
REPNZ SCAS BYTE
JNZ @@1 \ во всей строке нет первого символа искомой строки
CMP EBX, # 1
JZ @@2 \ искомая строка имела длину 1 и найдена
MOV ECX, EBX
DEC ECX
MOV EAX, EDX
SUB EAX, EDI
CMP EAX, ECX
JC @@1 \ остаток строки короче искомой строки
PUSH EDI
REPZ CMPS BYTE
POP EDI
JNZ @@4
@@2: DEC EDI \ нашли полное совпадение
SUB EDX, EDI
MOV 0x0C [EBP], EDI
MOV 8 [EBP], EDX
@@5: MOV EAX, # -1
JMP @@3
@@1: XOR EAX, EAX
@@3: ADD EBP, # 4
MOV [EBP], EAX
POP EDI
RET
END-CODE
Для применения исправления необходимо подключить ассемблер из дистрибутива SPF4.
Либо воспользоваться простым хаком (достаточно один раз вызвать в nncron.ini или в подключенном плагине):
Код:
0x90 ' SEARCH 29 + C!
Если я правильно понял ман по асму, то по этому адресу находится префикс для команды (0x66/0x67) JECXZ, который переключает разрядность данных, с которыми работает данная команда. Данный хак просто заменяет префикс на команду
NOP.
Но если честно, я сам не все понял тут и возможно данное решение неправильно и я где-то ошибся ) (Не совсем понятна логика ассемблера СПФ для команд JECXZ и JCXZ и добавление префикса).