

				STAMP 2.0


   - Печать, друг мой Бао, печать! - истово выдохнул даос.
   И судья, плохо соображая, что делает, шагнул вперёд и с силой вдавил
висевшую у него на поясе печать в самую середину необъятного живота якши.
   После чего, опомнившись, проворно отскочил назад.
   И почти сразу же прямо из потолка с оглушительным громовым раскатом
ударила синяя молния о восьми зубцах, угодившая как раз туда, куда судья
Бао только что приложил государственную печать.
   Вот уж и впрямь: не успела просохнуть тушь...
   Всё произошло быстро: только что зубастый тайвей стоял с занесённой над
головой палицей - и вот уже обгорелая палица с грохотом катится по паркету,
а на месте припечатанного якши догорает кучка дымящегося пепла.
   На какое-то время воцарилась полная тишина - и в этой тишине прозвучал
полный ужаса вопль лазоревого дракона, прятавшегося под своим столом:
   - Солнечный чиновник!
   - Солнечный чиновник... - бледнея, повторил старший дракон, пятясь к
дверям.

						    "Мессия очищает диск"
								Г.Л.Олди

Содержание
----------

	1. Что это такое
	2. Особенности STAMP
	3. Возможные дополнения
	4. Синтаксис
	5. Исполнение и ограничения
	6. Предыстория
	7. Условия распространения и связь с автором


1. Что это такое
----------------

STAMP - это программа для установки атрибутов файлов (Readonly, Hidden,
System, Archive) и даты/времени их последней модификации. STAMP также
позволяет сравнить для одного или множества файлов их атрибуты, дату и
время с заданными или с текущими датой или временем.

STAMP является компактной, но и более функциональной заменой стандартной
утилиты ATTRIB и утилит типа TOUCH и предназначена для обслуживания файлов
и расширения стандартного пакетного языка MS-DOS проверками существования
файлов и каталогов и проверками их даты/времени и атрибутов. Например, в
следующем фрагменте показано, как можно по разному реагировать на случаи,
когда цель является файлом, каталогом, либо отсутствует:

	stamp/a-d /e path>nul
	if errorlevel 2 goto not-exist
	if errorlevel 1 goto directory
	:file
	...
	:directory
	...
	:not-exist
	...

За счёт сравнения даты/времени с помощью STAMP можно организовать разовые
запуски программ в заданном (секунда/минута/час/день/месяц/год) интервале.
Ниже показан пример, как заставить пакет с антивирусами запускаться один
раз в день:

	stamp/d /e c:\temp\antivir.chk>nul
	if not errorlevel 1 goto skip
	call antivirs
	>c:\temp\antivir.chk
	:skip

Поскольку STAMP умеет сравнивать заданные дату и время не только с датой и
временем последней модификации файла, но и с текущими датой и временем, за
счёт этого можно организовать контроль внутренних часов на тех машинах, на
которых CMOS имеет тенденцию сбрасываться. Для этого нужно выбрать одну из
уже прошедших дат:

	stamp/d97@@ /c /l
	if errorlevel 1 goto restore-timer


2. Особенности STAMP
--------------------

- установка даты/времени последней модификации файлов;
- установка атрибутов файлов и каталогов;
- сравнение даты/времени и атрибутов файлов и каталогов с указанными
  датой/временем и атрибутами;
- произвольное сравнение указанных даты/времени с текущими и
  датой/временем файлов, как в целом, так и по отдельным полям;

- поля аргументов опций указания даты/времени могут брать значения полей
  текущих и даты/времени файла помимо задания явных числовых значений;
- аргументы опций дата/время могут указываться в форматах, соответствующих
  настройкам страны (COUNTRY);

- допускаются символы национального, заданного COUNTRY, алфавита в путях;
- допускается указание путей в форматах UNC и NetWare;
- в одной командной строке можно указать несколько целей;
- расширенный поиск: метаимена могут включать любое количество не только
  символов '?', но и '*'; "имя" означает "имя.", но "*" означает "*.*";

- знак начала опций ('/' или '-') выбирается автоматически по первой опции;
- опция для включения имён каталогов в поиск по метаименам;
- опция для рекурсивного поиска файлов и каталогов по всем подкаталогам;
- опция для чтения списка целей из файла; пустой аргумент этой опции
  означает стандартный вход.


3. Возможные дополнения
-----------------------

STAMP является утилитой, удовлетворяющей множество запросов, но и для неё
можно предложить ещё что-то, что расширит функциональность без нарушения
стройности и лёгкости использования. Ниже приведён список подобных
дополнений:

- выдача списков обработанных файлов;
- расширенный алгоритм сканирования командной строки, допускающий слияние
  опций и знающий о длинной командной строке "CMDLINE";
- поддержка длинных имён и кавычек в именах;
- копирование даты/времени/атрибутов с заданного файла;
- сравнение даты/времени/атрибутов целей с заданным файлом;
- выражения для увеличения/уменьшения значения полей даты/времени;
- сравнение на больше/меньше для атрибутов.

Если найдутся желающие, которые покажут полезность одного из приведённых
выше, либо своего дополнения, а также покажут, как это дополнение должно
выглядеть, то, вполне возможно, что оно будет внесено в программу.


4. Синтаксис
------------

Командная строка STAMP является комбинацией опций и целей, независимой от
порядка следования. Опции корректируют поведение программы и опознаются по
первому знаку (началу опции) за которым следует символ опции и, возможно,
аргумент опции. Началом опции может быть знак '/', либо '-', и выбор между
ними производится по первому же аргументу командной строки, начинающемуся
с одного из этих знаков. Все опции опознаются по выбранному знаку начала.

Цель - это путь с именем файла, каталога или метаименем, который подлежит
обработке. Метаимя отличается от имени наличием метасимволов '?' (означает
любой знак в данной позиции) и '*' (означает любое количество любых знаков
в данной позиции), позволяя в одном имени задать множество имён. В отличие
от правил MS-DOS, требующих не более одного метасимвола '*' в конце имени
и типа, в STAMP допустимы любые сочетания с этим метасимволом - например,
"a*b*c.*d*". Если имя указано без типа и точки в конце, то подразумевается
файл без типа для простого имени и файлы с любым типом для метаимени (т.е.
"имя" означает "имя.", а "*" означает "*.*").

В именах допустимы символы национального, заданного настройками страны
(COUNTRY), алфавита. Пути могут соответствовать не только стандартному
формату MS-DOS [<D>:][\]{<dirname>\}<name>, но и сетевым форматам UNC и
NetWare:

	\\server\{<dirname>\}<name>
	<server>[/<volume>]:[\]{<dirname>\}<name>

В одной командной строке можно указать несколько целей. Более того, списки
целей могут быть также переданы через файлы с помощью опции /@.

Аргументы (и цели, и опции) должны быть разделены пробелами, аргументы же
опций должны идти за ними вплотную, без пробелов. Пропуск пробелов между
опцией, даже начинающейся со знака '/', и предыдущим аргументом (целью или
другой опцией) не допускается. Также не допускается объединение нескольких
опций без аргументов в одну опцию, практикуемое в некоторых утилитах.

Если один из аргументов является парой из знаков начала опции ("--", либо
"//", с учётом того, какой знак уже был использован в предыдущих опциях),
то аргументы, следующие за этой парой, воспринимаются как цели независимо
от их первых знаков - это позволяет указывать пути, начинающиеся с любого
знака.

Дублирование опций в командной строке, за исключением /@, не допускается.
Опции не чувствительны к регистру (т.е. /d и /D означают одну опцию). При
запуске STAMP без аргументов или с опцией /? будет дана следующая
подсказка:

______________O\_/_________________________________\_/O______________
STAMP - Files attributes manipulation, Version 2.0, (c)1998 Arkady Belousov

Syntax: STAMP [/a<a>] [/d[<d>]] [/t[<t>]] {path | /@[list]}...
	STAMP [/a<a>] [/d[<d>]] [/t[<t>]] <compare> {path | /@[list]}...
Options:
    /r	- Include directories when search by wildcards
    /s	- Process files in all subdirectories of specified targets
Arguments:
    <a>	- Union of attributes (ARHSD) with '+' or '-' prefix; prefixes can
	  be ommited (i.e. /aha-sr works as /a+h+a-s-r), ommited argument
	  clears RHS attributes (i.e. /a works as /a-rhs)
    <d>	- Date in [[[c]y]m]d (century, year, month, day) format*
    <t>	- Time in h[m[s]] (hour, minute, second) format*
Compare options:
    /e	- Check if given date, time and/or attributes equal to file
    /g	- Check if given date and/or time greater than file
    /l	- Check if given date and/or time lesser than file
    /c	- Compare given date/time with current, not file date/time (i.e.
	  "/d!!!! file /g /c" works same as "/d /l file")

* Ommited option don't touch corresponding attribute
* Fields must be '@' (gets value from current date/time), '!' (from file
  date/time) or 2-digit numbers; ommited argument mean current date/time
  (i.e. /d and /t works as /d@@@@ and /t@@@), ommited field mean '@' for
  date (unless century, which mean '!' if year represented by '!') and 0
  for time (i.e. /d!@@ and /t! works as /d!!@@ and /t!0000)
* Date and time can be presented in formats, that conforms COUNTRY
  settings (i.e. for USA /d3-19-! works as /d!!1903)
_____________________________________________________________________
              O/~\                                 /~\O

Ниже дано развёрнутое описание всех опций и особенностей их сочетания
(предполагается, что знаком начала опции выбран знак '/').

/r    - цель с простым именем обрабатывается независимо от того, является
	ли она файлом или каталогом, а для метаимени соответствие ищется
	только среди файлов; с опцией /r поиск будет вестись также среди
	имён каталогов

/s    - при этой опции файлы и каталоги, соответствующие цели, ищутся не
	только в пути, заданном целью, но также и (рекурсивно) во всех
	подкаталогах заданного пути

/a<a> - опция /a задаёт атрибуты, которые следует установить или сравнить.
	Аргумент <a> должен являться комбинацией атрибутов ARHSD (Archive,
	Readonly, Hidden, System и Directory) с префиксами состояния '+' и
	'-' (установлен/сброшен). Состояние атрибута без префикса берётся
	у предыдущего атрибута; если первый атрибут не имеет префикса, то
	он устанавливается (т.е. /ar-hs и /a-h+r-s означают одно и то же).

	Отсутствие аргумента подразумевает сброс атрибутов RHS (т.е. /a
	означает /a-rhs), в противном случае только указанные атрибуты
	меняются или участвуют в сравнениях. При отсутствии же опции /a
	атрибуты файла не меняются и в сравнениях не участвуют совсем.

/d<d> - опция /d задаёт дату, с которой следует сравнивать или которая
	будет установлена датой последней модификации файла. Аргумент <d>
	должен соответствовать формату [[[c]y]m]d (век, год, месяц, день),
	где значение не пропущенных полей задаётся либо двузначным числом
	(самое первое поле может быть однозначным), либо, неявно, знаками
	'@' (значение поля берётся из соответствующего поля текущей даты)
	и '!' (значение поля даты модификации файла). Значение пропущенных
	полей берётся из текущей даты (т.е. /d означает /d@@@@), исключая
	век, значение которого берётся из даты модификации файла, если год
	задан как '!', и равно 20, если значение года задано явно и меньше
	80 (т.е. /d!!! означает /d!!!!, а /d3!! означает /d2003!!).

	Аргумент <d> может также иметь формат, соответствующий настройкам
	страны (COUNTRY) - например, при country=1 (формат даты MM/DD/YY),
	допустим аргумент 11/22/99; при других country= первым может идти
	день (DD/MM/YY) или год (YY/MM/DD). Разделителем, помимо заданного
	настройками, может быть любой из знаков "/-.", не допустимо только
	сочетание разных знаков в одном аргументе. Значение пропущенного
	века формируется по описанным выше правилам, поля аргумента можно
	также задавать знаками '@' и '!' (т.е. /d3-19-! и /d!!1903 значат
	одно и тоже).

	Явно заданные поля аргумента проверяются на допустимость (значение
	века только 19, 20 и 21; месяца от 1 до 12; дня от 1 до 29, 30 или
	31 в зависимости от месяца). При отсутствии опции /d дата файла не
	меняется и в сравнениях не участвует.

/t<t> - опция /t задаёт время, с которым следует сравнивать или которое
	будет установлено временем последней модификации файла. Аргумент
	<t> должен соответствовать формату h[m[s]] (часы/минуты/секунды),
	где значение полей указывается либо явно, двузначным числом (поле
	часов может быть однозначным), либо неявно, знаками '@' (значение
	берётся из соответствующего поля текущего времени) и '!' (значение
	из времени модификации файла).

	Аргумент <t> может также иметь формат, соответствующий настройкам
	страны (COUNTRY), т.е. перед не пропущенными полями минут и секунд
	может идти (помимо заданного настройками) любой из знаков ":."; не
	допустимо только наличие знака не перед всеми полями или сочетание
	разных знаков в одном аргументе. Но, независимо от настроек, время
	всегда должно быть 24-часовым (так называемое военное время). Поля
	аргумента можно также задавать знаками '@' и '!'.

	Поля аргумента на превышение допустимых диапазонов не проверяются.
	Отсутствие аргумента значит текущее время, но значение пропущенных
	полей равно 0 (т.е. /t значит /t@@@, а /t!:4 значит /t!0400). При
	отсутствии же опции /t вообще время модификации файла не меняется
	и в сравнениях не участвует.

/e    - при наличии одной из этих опций производится не изменение даты и
/g	времени последней модификации файлов или их атрибутов на заданные
/l	значения, а сравнение значений аргументов соответствующих опций с
	датой, временем и/или атрибутами файлов. Отсюда следует, что хотя
	бы одна из опций, задающих эти значения, должна быть представлена.

	Сравнение для даты и времени производится на равенство (equality),
	больше (greater) или меньше (lesser). Атрибуты же в любом случае
	сравниваются только на равенство. Если сравнение успешно для всех
	целей, то возвращается нулевой код возврата, иначе единичный.

/c    - при этой опции сравнение заданных даты и/или времени производится
	не с датой и временем файла, а с текущими датой или временем (т.е.
	"/d!!!! file /g /c" идентично "/d /l file"). Если аргументы опций
	даты и времени не ссылаются на дату и время файла с помощью знака
	'!', то цели в командной строке при наличии опции /c не нужны. Для
	атрибутов не определено понятие "текущего значения", поэтому опция
	/a с опцией /c сочетаться не должна.


5. Исполнение и ограничения
---------------------------

Как было сказано выше, командная строка STAMP является комбинацией опций и
целей, независимой от порядка следования. То есть сначала командная строка
просматривается на предмет наличия опций, и уже затем, на втором проходе,
обрабатываются все указанные цели. При этом дублирование опций, не считая
/@, указывающей файл со списком целей, не допускается.

Длина каждого пути, заданного целями в командной строке и переданных через
файлы со списками целей, не должна превышать 256 знаков.

Все указанные цели обрабатываются последовательно и независимо, поэтому,
если какие-то цели расположены в одном каталоге или имеют общий корневой
путь при наличии опции /s (рекурсивный поиск в подкаталогах), совмещения
нескольких проходов для таких пересекающихся целей в один не происходит.
Однако, если целевой путь содержит столько файлов или сканируемое дерево
велико настолько, что заметно увеличивается время работы, то общее время
можно сократить либо описав пересекающиеся цели в одном метаимени (если
это возможно), либо обрабатывая цели через заранее подготовленный список
соответствующих целям файлов и каталогов с помощью опции /@.

Для сокращения количества сканирований каталогов при наличии опции /s в
два раза (отдельно для поиска целей и прохода по подкаталогам), а также
для уменьшения пробега головок диска в случае совмещения поиска целей с
проходом по подкаталогам, в STAMP при поиске имён, соответствующих целям,
имена подкаталогов сначала добавляются в буфер размером 44K, и уже после
обработки целей имена подкаталогов выталкиваются из буфера и выполняется
проход по ним. Отсюда следует ограничение, что, если средняя длина имени
каталогов содержит 8 знаков, то в любой ветви сканируемого поддерева не
может быть более 5632 имён подкаталогов.

При наличии одной из опций сравнения (/e, /g или /l) вместо модификации
даты, времени или атрибутов файла производится их сравнение с заданными.
При успешном сравнении возвращается нулевой код ошибки, при неуспешном -
единичный. Код ошибки затем может быть проверен с помощью if errorlevel,
что и было показано во введении в примерах. Если в командной строке явно
и через опцию /@ задано несколько целей, то в коде ошибки все результаты
будут логически просуммированы, т.е. нулевым код будет только в случае
успеха всех сравнений.

Для атрибутов отношения "больше" и "меньше" не определены, поэтому при
наличии опций /g или /l сравнение всё равно будет производиться на
равенство.

В опциях даты и времени с помощью знака '!' в аргументах можно ссылаться
на поля даты и времени последней модификации файла и, таким образом, при
установке даты или времени сохранять значения этих полей, а при сравнении
исключать их из сравнения. Если в командной строке явно и через опцию /@
задано несколько целей, то значение ссылающихся на дату и время файла
аргументов будет пересчитываться для каждого файла и каталога заново.

В MS-DOS отсутствует поддержка модификации даты и времени каталогов, это
можно проделать только через прямое обращение к диску, что, разумеется, не
будет работать в защищённых операционных системах типа Windows NT, OS/2 и
эмуляторах DOS под Unix. Поэтому при попытке модифицировать дату или время
каталога в STAMP будет выдано сообщение об ошибке "Access denied".

Хранение даты и времени файлов и каталогов в MS-DOS избыточно, то есть их
поля могут принимать больший диапазон значений, чем имело бы смысл. Ниже
приведён список возможных значений (секунды всегда усекаются до чётного
значения):

			Секунды	Минуты  Часы	День	Месяц	Год
Корректный диапазон	1-59	1-59	1-23	1-31	1-12	1980-2099
Диапазон хранения	0-60	0-61	0-31	0-31	0-15	1980-2107

В STAMP производится проверка корректности для явно заданных (числовых)
полей даты и некорректные отвергаются, что не позволяет в явном порядке
задать некорректные даты. Однако значения полей, получаемых из текущей
даты или даты модификации файла, а также поля времени, не проверяются.
Если значение поля аргумента опции времени превысит также и диапазон
хранения, то значение времени будет не определено (произвольно).

В случае некорректной командной строки, неудач в сравнениях или проблем
при обращении к диску вернётся ненулевой код ошибки. Ниже перечислены
возможные значения кода ошибки:

0   - установка даты/времени и атрибутов или их сравнение успешны;
1   - сравнение (одно из) неуспешно;
2   - ошибка доступа к файлу или установки даты/времени или атрибутов;
128 - недопустимая или повторяющаяся опция;
129 - несовместимые опции, не указаны цели или недопустимые аргументы;
130 - внутренняя ошибка (нехватка памяти или слишком глубоко вложенный
	каталог).


6. Предыстория
--------------

	1.0 [16.02.98]
+ первая редакция

	1.1 [19.02.98]
+ разрешено указание аргументов опций даты/времени в форматах,
  соответствующих настройкам страны (COUNTRY)

	1.2 [21.02.98]
* улучшена интерпретация пропущенных полей и аргументов опций даты/времени
* уменьшен размер исполняемого модуля
+ добавлена опция -a для установки атрибутов файлов и каталогов

	1.3 [21.02.98]
+ разрешено указание нескольких целей в одной командной строке
+ разрешено использование опции -a при сравнении

	1.4 [26.02.98]
# теперь исполнение не прерывается при ошибке, а продолжается для
  следующей цели
# при перенаправлении в файл вывод теперь на консоль не дублируется
* опция -@ переименована на -c
+ разрешено сравнение для даты/времени каталогов
+ разрешены метаимена в качестве целей
+ добавлена опция -r для включения имён каталогов в поиск по метаименам

	1.41 [28.02.98]
+ символ опций теперь выбирается по первому вхождению символа '/' или '-'
+ одиночная пара символов опций ("--" или "//") прекращает дальнейший
  поиск опций
+ одиночный символ опций теперь означает стандартный вход
- добавление символа опций перед именами, начинающимися с такого же знака,
  для передачи этих имён как аргументов, теперь вызовет сообщение об
  ошибке; для передачи имён, начинающихся с символа опций, можно ранее в
  командной строке указать одиночную пару символов опций

	1.5 [14.03.98]
# исправлено: при некоторых условиях явно указанные допустимые значения
  дня 30 и 31 отвергались
# теперь имя цели преобразуется к верхнему регистру в соответствии с
  настройками страны (COUNTRY)
+ добавлена опция /s для рекурсивного поиска файлов и каталогов по всем
  подкаталогам

	2.0 [14.04.98]
# исправлено: при чтении времени файла терялся старший бит поля секунд
+ добавлена опция /@ для чтения списка целей из файла
* одиночный символ опций теперь указывает стандартный вход только как
  аргумент опции /@
* уменьшен размер исполняемого модуля
+ для сжатия исполняемого модуля использована программа DIET


7. Условия распространения и связь с автором
--------------------------------------------

Данная программа распространяется на условиях GPL (GNU Public License) -
свободное распространение исполняемого модуля и исходных кодов с условием
сохранения копирайта при их модификации. Последнии версии исходных кодов
могут быть получены у автора.

Автор будет благодарен как любой моральной и материальной поддержке,
свидетельствующей об интересе к продолжению этой работы, так и любым
замечаниям и пожеланиям к программе, позволяющим улучшить её свойства
или, тем более, исправить ошибки (а кто от них застрахован?). ;) Тем не
менее автор не несёт ответственности за возможный ущерб, который может
быть причинён использованием данной программы. B-|


					Белоусов Аркадий Владимирович
					E-mail: ark@mos.ru
