4.11. Командные параметры и переменные среды

В случае если команда не передавалась бы интерпретатору DOS, а выполня­лась нами самостоятельно, то оказалось бы: чтобы запустить любую программу из-под shell.com, нужно предварительно перейти в директорию с этой програм­мой или ввести ее, указав полный путь. Дело в том, что COMMAND.COM при запуске файла ищет его по очереди в каждой из директорий, указанных в пере­менной среды PATH. DOS создает копию всех переменных среды (так называе­мое окружение DOS) для каждого запускаемого процесса. Сегментный адрес ко­пии окружения для текущего процесса располагается в PSP по смещению 2Ch. В этом сегменте записаны все переменные подряд форме вида "COMSPEC=C:\WINDOWS\COMMAND.COM",0. По окончании последней строки стоит дополнительный нулевой байт, затем слово (обычно 1) - количество дополнительных строк окружения, а потом - дополнительные строки. Первая до­полнительная строка - всегда полный путь и имя текущей программы - также в форме ASCIZ-строки. При запуске новой программы с помощью функции 4Bh можно создать полностью новое окружение и передать его сегментный адрес за­пускаемой программе в блоке ЕРВ или просто указать 0, позволив DOS скопиро­вать окружение текущей программы.

Кроме того, в предыдущем примере мы передавали запускаемой программе (command.com) параметры (/с команда), но пока не объяснили, как программа может определить, что за параметры были переданы ей при старте. Во время за­пуска программы DOS помещает всю командную строку (включая последний символ ODh) в блок PSP запущенной программы по смещению 8Ш и ее длину в байт 80h (таким образом, длина командной строки не может быть больше 7Eh (126) символов). Под Windows 95 и DOS 4.0, если командная строка превышает эти раз­меры, байт PSP:0080h (длина) устанавливается в 7Fh, в последний байт PSP (PSP:OOFFh) записывается ODh, первые 126 байт командной строки размещают­ся в PSP, а вся строка целиком - в переменной среды CMDLINE.

; cat.asm

; Копирует объединенное содержимое всех файлов, указанных в командной строке,

; в стандартный вывод. Можно как указывать список файлов,  так и использовать

; маски (символы "*" и "?") в одном или нескольких параметрах,

например:

cat header *.txt footer > all-texts помещает содержимое файла header, всех файлов с расширением- .txt в текущей директории и файла footer - в файл all-texts.

Длинные имена файлов не используются,  ошибки игнорируются.

tiny

. code

org cmd_length

cmd_line

org

start:

eld mov mov cmp jle

mov mov int

80h db ? db ? 100h

bp, sp

cl,cmd_length

cl,l

show_usage ah,1Ah

DTA

21h

По смещению 80Ь от начала РЗР находятся:

длина командной строки

и сама командная строка.

Начало СОМ-программы - 10(Ш от начала РЭР.

Для команд строковой обработки. Сохранить текущую вершину стека в ВР.

; Если командная строка пуста -;   вывести информацию о программе

;  функция DOS 1Ah:

и выйти.

переместить DTA (по умолчанию она совпадает ;  с командной строкой PSP)

Преобразовать список параметров в РЗР:8111 следующим образом: Каждый параметр заканчивается нулем (АЭСИ-строка), адреса всех параметров помещаются в стек в порядке обнаружения. В переменную агде записывается число параметров.

mov

cx,-1

;  Для команд работы со строками.

mov

di,offset cmd_line

; Начало командной строки в Е8:01,

find_param:

 

 

mov

 

Искать первый символ,

repz

scasb

не являющийся пробелом.

dec

di ■

РІ - адрес начала очередного параметра.

push

di

Поместить его в стек

inc

word ptr argc

и увеличить агде на один.

mov

si, di

Э1 = Ш для следующей команды ІойзЬ.

scan pa rams:

 

 

lodsb

 

Прочитать следующий символ из параметра.

cmp

al.ODh

Если это ОРїї - это был последний параметр

je

params_ended

и он кончился.

cmp

al,20h

Если это 20п - этот параметр кончился, ;

jne

scan_params

•но могут быть еще.

dec

si

- первый байт после конца параметра.'

mov

byte ptr [si],0

Записать в него 0.

mov

di, si

РІ =      для команды зсаБЬ.

inc

di

РІ - следующий после нуля символ.

' jmp

short find_param

Продолжить разбор командной строки.

params_ended:

dec

mov

si

byte ptr [si],0

81 - первый байт после конца последнего параметра - записать в него 0.

Каждый параметр воспринимается как файл или маска для поиска файлов, все найденные файлы выводятся на э1:аоит..   Если параметр - не имя файла, то ошибка игнорируется.

mov argc next_file_from_param:

dec bp

dec bp

dec si

js no_more_params

mov dx.word ptr [bp]

mov     • ah,4Eh

mov cx,0100111b

int    ■   21 h

jc next_file_from_param

call output_found find next:

SI

BP

число оставшихся параметров.

адрес адреса параметра.

Уменьшить число оставшихся параметров, если оно стало отрицательным - все.

DS:DX

адрес очередного параметра.

Функция DOS 4Eh.

Искать все файлы, кроме директорий

и меток

Найти первый файл.

Если произошла ошибка - файла нет.

найденный файл на stdout.

mov

ab,4Fh

; Функция DOS 4Fh.

mov

dx,offset DTA

Адрес нашей области DTA.

int

21h

Найти следующий файл.

jc

next_file_f rom_param

Если ошибка - файлы кончились.

call

output_found

Вывести найденный файл на stdout.

jmp

short find_next

Продолжить поиск файлов.

pa rams:

 

 

mov

ptr argc

 

shl .

ax, 1

 

add

sp, ax

Удалить из стека 2 х argc байтов (то

 

 

список адресов параметров командной

ret

 

Конец программы.

Процедура

Выводит информацию о программе.

show_usage:

mov mov int

ret

ah, 9

usage

21h

Функция DOS 09h.

Вывести строку на экран. Выход из процедуры.

Процедура о^ри^оипО.

Выводит в БЬаоиР файл,  имя которого находится в области РТА.

output_found: mov mov

int

jc

mov . mov do_output:

mov

mov

mov

int

jc

mov

jcxz

mov xchg

int

xchg jc ■ jmp

file_done: mov int

skip_file:

ret

usage

argc DTA:

end

dx, offset DTA+1Eh ax,3000h

21h

skip_file bx.ax

di,1

cx.1024

dx,offset DTA+45 ah,3Fh

21h

file_done

ax

file_done

ah,40h bx, di 21h

di,bx

file_done

short do_output

ah,3Eh

21h

Адрес ASCIZ-строки с именем файла. . Функция DOS 30h:

открыть файл   (al = 0 - только на чтение).

Если ошибка - не трогать этот файл.

Идентификатор файла - в ВХ.

DI будет хранить идентификатор STDOUT. Размер блока для чтения файла.

Буфер для чтения/записи располагается за концом DTA.

Функция DOS 3Fh.

Прочитать  1024 байта из файла.

Если ошибка - закрыть файл.

Число реально прочитанных байтов в СХ. Если это не ноль - закрыть файл.

db db db db

dw

Функция DOS 40h.

ВХ = 1 - устройство STDOUT.

Вывод прочитанного числа байтов в STDOUT.

Вернуть идентификатор файла в ВХ.

Если ошибка - закрыть файл,

продолжить вывод файла. ; Функция DOS 3Eh:

закрыть файл.

Конец процедуры "cat.com v1. О", ODh.OAh

"объединяет и выводит файлы на stdout",ODh,OAh "исполвзование:  cat имя_файла,   . ..",0Dh,0Ah

"(имя файла может содержать маски * и

Число параметров ;   (должен бытв 0 при старте программы!).

Область DTA начинается сразу за концом файла, а за областью DTA -

;  1024-байтный буфер для чтения файла.

start

Размер блока для чтения файла можно значительно увеличить, но в таком слу­чае почти наверняка потребуется проследить за объемом памяти, доступным для программы.