Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Чтение данных из файла в DOS, Проблема с ф-й DOS 3Fh:"Доступ запрещен" 
V
    Опции темы
SantaXP
  Дата 7.5.2008, 23:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 95
Регистрация: 5.6.2003

Репутация: нет
Всего: нет



В этом симестре начали в универе изучать asm (Синтаксис Intel, компилятор TASM). Тут вот дали задание:
"Полугодовая информация о подписных изданиях по каждому подписчику имеет структуру: ФИО, участок доставки, адрес, количество выписанных изданий, список изданий (название, газета или журнал, месяцы, на которые оформлена подписка). Создайте файл, в который запишите ФИО подписчиков, оформивших подписку на наибольшее число изданий, независимо от количества месяцев."
А вот то, что я понаписал:
Код

;-----------------------task3.asm----------------------------
; Полугодовая информация о подписных изданиях по каждому
; подписчику имеет структуру: ФИО, участок доставки, адрес,
; количество выписанных изданий, список изданий (название,
; газета или журнал, месяцы, на которые оформлена подписка).
; Создайте файл, в который запишите ФИО подписчиков,
; оформивших подписку на наибольшее число изданий, независимо
; от количества месяцев.
;-----------------------------------------------------------
; Количество изданий на данный момент ограничено 9-ю.
;-----------------------------------------------------------
        .model  tiny
        .code
        org     100h            ; Начало .COM файла.
;-----------------------------------------------------------
;                      Начало программы.
;-----------------------------------------------------------
_main:
        mov     ah,3Dh          ; Открытие входного файла
        mov     al,11b          ; для чтения и записи.
        lea     dx,ifName
        int     21h
        jc      open_error      ; Перейти, если ошибка.
        mov     ifId,ax         ; Идентификатор файла в ifId.
        
        mov     ah,5Bh          ; Создание и открытие 
                                ; выходного файла.
        mov     al,11b          ; Для чтения и записи.?????
        xor     cx,cx           ; Без атрибутов.
        lea     dx,ofName
        int     21h
        jc      create_error    ; Перейти, если ошибка.
        mov     ofId,ax         ; Идентификатор файла в ofId.
        
; Считывание и сравнение данных о подписчиках:
do_read:
        call    readData
        cmp     dx,1            ; Сравнение DX с 1.
        jl      exit            ; Если DX = 0 - выход.
        jg      if_eof          ; Если DX = 2 - конец файла.
        
        call    cmpMax          ; Если DX = 1 - сравниваем.
        test    dx,dx           ; Сравниваем DX c 0.
        jz      do_read         ; Если DX = 0 - искомый
                                ; подписчик не найден.
        
        call    cpMax           ; Если DX = 1 - искомый
        jmp     do_read         ; подписчик найден.
        
if_eof:                         ; Обнаружен конец файла.
        call    cmpMax          ; Выполняем действия с 
        test    dx,dx           ; последней записью в файле.
        jz      do_write
        call    cpMax

do_write:
        call    writeMax        ; Записываем данные в файл.
        test    dx,dx
        jz      exit 
        
open_error:                     ; Печать ошибки на экран.
        mov     ah,09h
        lea     dx,openError
        int     21h
        jmp     exit
        
create_error:                   ; Печать ошибки на экран.
        mov     ah,09h
        lea     dx,createError
        int     21h
        
exit:                           ; Выход из программы.
        call    doExit
        
;-----------------------------------------------------------
;                         Процедуры.
;-----------------------------------------------------------
; Назначение:
; Считывание данных из входного файла и запись их в anInfo.
; Выход:
; DX = 0, если произошла ошибка чтения.
; DX = 1, если обнаружен конец файла.
; DX = 2, если все нормально.
readData    proc    near
        mov     ax,ifId
        lea     bx,anInfo.fio
        push    ax
        push    bx
        push    0020            ; Считываем ФИО.
        call    getData
        pop     ax              ; Убираем адрес буфера
        pop     ax              ; и размер из стека.
        cmp     dx,2            ; Если ошибка или конец файла,
        jl      proc_exit       ; то выходим из процедуры.
        
        lea     ax,anInfo.dest
        push    ax
        push    0015            ; Считываем участок доставки.
        call    getData
        pop     ax              
        pop     ax
        cmp     dx,2
        jl      proc_exit
        
        lea     ax,anInfo.address
        push    ax
        push    0015            ; Считываем адрес.
        call    getData
        pop     ax              
        pop     ax
        cmp     dx,2
        jl      proc_exit
        
        lea     ax,anInfo.amount
        push    ax
        push    0001            ; Считываем количество
        call    getData         ; выписанных изданий.
        pop     ax              
        pop     ax
        cmp     dx,2
        jl      proc_exit
        
        lea     ax,anInfo.list
        push    ax
        push    0256            ; Считываем список изданий.
        call    getData
        pop     ax              
        pop     ax

proc_exit:   
        call    doExit
        
readData    endp

; Назначение: Считывание данных в буфер до появления
; символа перехода на новую строку.
; Вход:
; Первый параметр в стеке - Адрес буфера.
; Второй параметр в стеке - Дескриптор файла.
; Выход:
; DX = 0, если произошла ошибка чтения.
; DX = 1, если обнаружен конец файла.
; DX = 2, если все нормально.
getData     proc    near
; Параметры:
parFId      equ     [bp+8]      ; Дескриптора файла.
parBuffer   equ     [bp+6]      ; Адрес буфера.
parBSize    equ     [bp+4]      ; Размер буфера.
; Локальные переменные:
myCounter   equ     [bp-2]      ; Счетчик байтов.
        push    bp              ; Сохранить BP.
        mov     bp,sp           ; Установить BP для этой процедуры.
        sub     sp,6            ; 6 байт для лок-х переменных.
; Тело процедуры:
        mov     word ptr myCounter,0
        mov     ah,3Fh          ; Считывание данных из файла.
        mov     bx,parFId       ; Идентификатор файла в BX.
        mov     cx,1
        mov     dx,parBuffer    ; Адрес буфера в DX.
        dec     dx              ; Уменьшаем на 1, чтобы начать с
                                ; 0-го байта после INC DX.
continue:
        inc     dx          
        inc     word ptr myCounter
; >>>>>>> Вот тут проблема: >>>>>>>>>
        int     21h                            
        jc      read_error
; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
        cmp     ax,1            ; Если ax < cx(1), то это конец файла.
        jl      eof
        mov     ax,parBSize
        cmp     ax,myCounter    ; Если размер буфера меньше кол-ва
        jl      read_error      ; считанных байтов - ошибка.
        mov     ax,[dx]
        cmp     ax,0Ah          ; Если не был считан символ перехода,
        jne     continue        ; продолжаем работу.
        
        mov     dx,2            ; Завершение работы процедуры.
        mov     sp,bp           ; LEAVE и ENTER не работают. =(
        pop     bp
        ret
        
        
read_error:                     ; Печать ошибки на экран.
        mov     ah,09h
        lea     dx,readError
        int     21h
        mov     bx,0
        mov     sp,bp           ; Выбросить из стека локальные
        pop     bp              ; переменные. Восстановить BP.
        call    doExit

eof:                            ; Обнаружен конец файла.
        mov     bx,1
        mov     sp,bp           ; Выбросить из стека локальные
        pop     bp              ; переменные. Восстановить BP.
        ret                     ; Выход без удаления параметров
                                ; из стека.
getData     endp

; Назначение: Сравнение данных с искомым подписчиком.
; Выход:
; DX = 0, новый искомый подписчик не найден.
; DX = 1, новый искомый подписчик найден.
cmpMax      proc    near
        mov     al,anInfo.amount
        mov     ah,maxInfo.amount
        cmp     al,ah
        jg      new_max
        mov     dx,0
        ret

new_max:
        mov     dx,1
        ret
        
cmpMax      endp

;Назначение: Копирование данных в структуру искомого подписчика.
cpMax       proc    near
        lea     si,anInfo.fio 
        lea     di,maxInfo.fio
        rep     movsb
        lea     si,anInfo.dest
        lea     di,maxInfo.dest
        rep     movsb
        lea     si,anInfo.address 
        lea     di,maxInfo.address
        rep     movsb
        mov     al,anInfo.amount
        mov     maxInfo.amount,al
        lea     si,anInfo.list 
        lea     di,maxInfo.list
        rep     movsb
        ret
        
cpMax       endp

; Назначение: Запись искомого подписчика в выходной файл.
; Выход:
; DX = 0, если произошла ошибка записи.
; DX = 1, если все прошло успешно.
writeMax    proc    near
        xor     cx,cx
        mov     ah,40h          ; Запись в выходной файл.
        mov     bx,ofId
        mov     cl,20           ; Запись ФИО.
        lea     dx,maxInfo.fio
        int     21h
        jc      write_error
        mov     cx,15           ; Запись участка доставки.
        jc      write_error
        lea     dx,maxInfo.dest
        int     21h
        jc      write_error
        mov     cx,15           ; Запись адреса. 
        lea     dx,maxInfo.address
        int     21h
        jc      write_error
        mov     cx,1            ; Запись количества
        lea     dx,maxInfo.amount; выписанных изданий.
        int     21h
        jc      write_error
        mov     cx,256          ; Запись списка изданий.
        lea     dx,maxInfo.list
        int     21h
        jc      write_error
        mov     dx,1
        ret
        
write_error:                    ; Печать ошибки на экран.
        mov     ah,09h
        lea     dx,writeError
        int     21h
        mov     dx,0
        ret
        
writeMax    endp

; Назначение: Осуществляет корректный выход из программы.
doExit      proc    near
        mov     ax,004Ch
        int     21h
        ret
doExit      endp
;-----------------------------------------------------------
;                          Данные.
;-----------------------------------------------------------

        .data
ifId        dw  ?               ; Идентификатор входного файла.
ofId        dw  ?               ; Идентификатор выходного файла.
ifName      db  'C:\in.txt',0   ; Имя входного файла
ofName      db  'C:\out.txt',0  ; Имя выходного файла.
maxPos      db  ?               ; Позиция искомого подписчика в файле.
lastPos     dw  ?               ; Последняя позиция при считывании. 
openError   db  'ERROR: Can not open the file!',0Ah,0Dh,'$'
createError db  'ERROR: Can not create the file!',0Ah,0Dh,'$'
readError   db  'ERROR: Can not read data!',0Ah,0Dh,'$'
writeError  db  'ERROR: Can not write data!',0Ah,0Dh,'$'

INFO    struc                   ; Структура: Информация о подписчике.
fio         db  20 DUP(?)
dest        db  15 DUP(?)
address     db  15 DUP(?)
amount      db  ?
list        db  256 DUP(?)
INFO    ends

anInfo  INFO    <0,0,0,0,0>     ; Инициализация структуры.
maxInfo INFO    <0,0,0,0,0>     ; Данные искомого подписчика.

;-----------------------------------------------------------
;                       Конец программы.
;-----------------------------------------------------------
        end     _main

Многое пробовал на asm чисто для ознакомления, да и на звание гуру asm тоже не претендую. =) Поэтому строго не судите, плиз. 
---
В коде я отметил, что возникает проблема при вызове функции DOS 3Fh, которая должна осуществлять чтение из устройства или файла. Файл открыт, дескриптор есть (в дебагере отлаживал - вроде все ОК с этим), но при вызове 3Fh в AX возвращается 05h, что означает:
"Доступ запрещен".
Подскажите, пожалуйста, в чем проблема и какой там доступ должен быть. Ибо входной файл 'C:\in.txt' присутсвует, он открывается, все права (на чтение, на запись) есть. Не пойму, в чем проблема.
---
P.S.: Для запуска использую эмулятор DOS-BOX и DOS Emulator. Все это под линуксом, под виндой DOS-BOX криво работает почему-то. Отладчик стандартный - Turbo Debuger. 
Заранее спасибо.
PM MAIL   Вверх
dumb
Дата 8.5.2008, 10:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


sceloglauxalbifacies
****


Профиль
Группа: Экс. модератор
Сообщений: 2929
Регистрация: 16.6.2006

Репутация: 7
Всего: 158



getData не рабочая: индексация по dx, что вообще не должно компилиться
при повторной попытке чтения(цикл continue) регистр ax уже не содержит номера функции чтения, а содержит два байта из буфера чтения, хотя читаем по одному.
сравниваем эти два байта с LF(0ah), что выполнится только при условии, если в строке перед LF будет 0.

вобщем, один сплошной глюк.
PM MAIL   Вверх
SantaXP
Дата 8.5.2008, 12:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 95
Регистрация: 5.6.2003

Репутация: нет
Всего: нет



dumb
Спасибо за помощь. 
1) Про индексацию в  DX - Все верно, уже исправил. =)
2) Про AX не усмотрел, спасибо еще раз.
3) Про 0Ah - а как же мне тогда считывать, если не по 1-му байту? По 2-а получается? Я правда не въезжаю.  smile 
---
Собственно, возвращаясь с сабжу - а что же это за таинственная ошибка 05h - "Доступ запрещен" и как с ней бороться? smile Время поджимает уже... =(  

Это сообщение отредактировал(а) SantaXP - 8.5.2008, 13:02
PM MAIL   Вверх
dumb
Дата 8.5.2008, 13:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


sceloglauxalbifacies
****


Профиль
Группа: Экс. модератор
Сообщений: 2929
Регистрация: 16.6.2006

Репутация: 7
Всего: 158



Цитата(SantaXP @  8.5.2008,  13:38 Найти цитируемый пост)
Про индексацию в  DX - все работает.
.com-файл покажи(прикрепи к посту). из 16-битных регистров индексными могут быть только bx,bp,si,di.

Цитата(SantaXP @  8.5.2008,  13:38 Найти цитируемый пост)
Про 0Ah - а как же мне тогда считывать, если не по 1-му байту?
читаешь из файла то ты по 1-му, а вот из массива берешь два символа сразу: mov ax,[буфер]. и сравниваешь эти два символа со значением 000Ah.

Цитата(SantaXP @  8.5.2008,  13:38 Найти цитируемый пост)
Собственно, возвращаясь с сабжу - а что же это за таинственная ошибка 05h - "Доступ запрещен" и как с ней бороться?
не надо ни с кем бороться. ошибки сначала исправь. после занесения в ax своих данных, ты по сути вызываешь неопределенную функцию ДОС.

погоди-ка, а ты вообще в курсе, что регистр ah является старшей половинкой регистра ax?!

примерно так:
Код

        mov     bx,parFId       ; Идентификатор файла в BX.
        mov     cx,1
        mov     dx,parBuffer    ; Адрес буфера в DX.
        dec     dx              ; Уменьшаем на 1, чтобы начать с
                                ; 0-го байта после INC DX.
continue:
        inc     dx          
        inc     word ptr myCounter
mov ah,3fh
        int     21h ; вот только не помню насчет cx и dx - они то хоть остаются целыми после вызова?..
...
mov si,dx
        mov     al,[si]
        cmp     al,0Ah          ; Если не был считан символ перехода,
        jne     continue        ; продолжаем работу.


ps. относительно общей логики работы кода говорить ничего не буду. по-хорошему, все надо переписать.

PM MAIL   Вверх
SantaXP
Дата 8.5.2008, 13:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 95
Регистрация: 5.6.2003

Репутация: нет
Всего: нет



dumb
1) Про DX: Пардон, я просто неправильно Вас понял. Я изменил прошлый пост, но вы меня опередили. Уже убрал индексацию. =)
2) Про 0Ah врубился.
3) Про AH и AL вкурсе. =) Просто программа выходит с ошибкой уже на первом проходе цикла, когда значение AX ещё не испорчено. =(
---
Пойду исправлять. 
PM MAIL   Вверх
SantaXP
Дата 8.5.2008, 13:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 95
Регистрация: 5.6.2003

Репутация: нет
Всего: нет



Все исправил - результат тот же. CF = 1, AX = 05h - "Доступ заперещен". =( 
PM MAIL   Вверх
SantaXP
  Дата 10.5.2008, 17:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 95
Регистрация: 5.6.2003

Репутация: нет
Всего: нет



Извиняюсь, что пишу 3-й пост подряд. Проблема решилась. Ошибка выскакивала из-за кода в самом начале программы:
Код

;-----------------------------------------------------------
;                      Начало программы.
;-----------------------------------------------------------
_main:
        mov     ah,3Dh          ; Открытие входного файла
        mov     al,11b          ; для чтения и записи.

Нужно убрать mov al,11b и тогда все работает. =) 
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Asm для начинающих"
MAKCim
  • Проставьте несколько ключевых слов темы, чтобы её можно было легче найти.
  • Не забывайте пользоваться кнопкой КОД.
  • Телепатов на форуме нет! Задавайте чёткий, конкретный и полный вопрос. Указывайте полностью ошибки компилятора и компоновщика.
  • Новое сообщение должно иметь прямое отношение к разделу форума. Флуд, флейм, оффтопик запрещены.
  • Категорически запрещается обсуждение вареза, "кряков", взлома программ и т.д.

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, MAKCim.

 
 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Asm для начинающих | Следующая тема »


 




[ Время генерации скрипта: 0.0834 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.