2 заметки с тегом

cmd

Uptime в Windows (на CMD)

Я заморочился и написал uptime на чистом CMD, раз уж на PowerShell уже до меня сделали. CMD — ужасный язык программирования!

Это я после Турции до программирования дорвался. 

@ECHO OFF
REM Евгений Степанищев //bolknote.ru 2011/04/09

REM Здесь CALL нельзя использовать, иначе хилый CMD не выдержит и лопнет —
REM подстановки переменных через %var% и !var! хватать перестанет
FOR /F "usebackq tokens=3" %%i ^
IN (`net stats srv ^| findstr /R "[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]*"`) DO SET DATE0=%%i

SET YEAR0=%DATE0:~6%
SET MONTH0=%DATE0:~3,2%
SET DAY0=%DATE0:~0,2%

SET YEAR1=%DATE:~6%
SET MONTH1=%DATE:~3,2%
SET DAY1=%DATE:~0,2%

REM Избавляемся от ведущих нулей, иначе CMD будет считать
REM числа восьмеричными
IF %DAY0:~0,1% == 0 SET DAY0=%DAY0:~1%
IF %MONTH0:~0,1% == 0 SET MONTH0=%MONTH0:~1%
IF %DAY1:~0,1% == 0 SET DAY1=%DAY1:~1%
IF %MONTH1:~0,1% == 0 SET MONTH1=%MONTH1:~1%

SET /A SUM=%DAY1%-%DAY0%
SETLOCAL ENABLEDELAYEDEXPANSION

IF %YEAR1% == %YEAR0% (
    SET /A END=%MONTH1%-1

    FOR /L %%M IN (%MONTH0%,1,!END!) DO (
        CALL :getMonthDays %%M %YEAR0%
        SET /A SUM+=!DAYS!
    )
) ELSE (
    REM 02.2010 -> +10 months
    FOR /L %%M IN (%MONTH0%,1,12) DO (
        CALL :getMonthDays %%M %YEAR0%
        SET /A SUM+=!DAYS!
    )

    REM 02.2011 -> +2 months
    FOR /L %%M IN (1,1,%MONTH1%) DO (
        CALL :getMonthDays %%M %YEAR0%
        SET /A SUM+=!DAYS!
    )

    REM Full years
    SET /A START=%YEAR0%+1
    SET /A STOP=%YEAR1%-1

    FOR /L %%Y IN (!START!,1,!STOP!) DO (
        CALL :isLeapYear %%Y
        IF !FEB! == 29 (
            SET /A SUM+=366
        ) ELSE (
            SET /A SUM+=365
        )
    )
)

ECHO %SUM%

GOTO :EOF

REM ====== Функции ==========

REM Високосный ли год?
REM isLeapYear <год>
:isLeapYear
SET /A FEB=(%1/400)*400

IF %FEB% == %1 (
    SET FEB=29
    GOTO :EOF
)

SET /A FEB=(%1/100)*100

IF %FEB% == %1 (
    SET FEB=28
    GOTO :EOF
)

SET /A FEB=(%1/4)*4

IF %FEB% == %1 (
    SET FEB=29
    GOTO :EOF
)

SET FEB=28
GOTO :EOF

REM Количество дней в месяце
REM getMonthDays <месяц> <год>

:getMonthDays
CALL :isLeapYear %2

IF %1 == 2 (
    SET DAYS=%FEB%
    GOTO :EOF
)

IF /I %1 LSS 8 (
    SET DAYS=30
    SET /A DAYS+="%1&1"
) ELSE (
    SET DAYS=31
    SET /A DAYS-="%1&1"
)

GOTO :EOF

Бесполезное: переводим строку в десятичные коды

Недавно решил попристальнее посмотреть что нового появилось в CMD (язык пакетных файлов Windows) со времён Windows NT. Написал небольшую программу, которая переводит строку в десятичные коды. Мне показалось, что CMD стал ещё более нелогичным чем был. Например, я так и не догадался как решить все проблемы с кавычками. Какое бы решение я не придумывал для того, чтобы проверить входной параметр, я тут же придумывал решение для того, чтобы разрушить код.

В итоге, исключить в программе влияние кавычек я не смог. Если у кого-то получится, расскажите как это делается в CMD. Вот программа:

@ECHO OFF
REM BOLK

REM Вспомогательная процедура для прохождения по массиву
IF NOT "%2"=="" GOTO :LINE

SETLOCAL
REM Входной параметр
SET LINE="%~1"
ECHO In: %LINE%

REM Сюда попадёт результат из ONE
SET OUT=""
REM Переменная останова вспомогательной процедуры
SET LINEBREAK=0
REM Сюда мы поместим результат и выведем его
SET RESULT=
CALL :ONE

REM ECHO Out: %OUT%
REM GOTO :EOF

REM Цикл прохода для DEBUG, который даст нам кучу переменных с шестнадцатеричными
REM значениями в каждой
(ECHO E100 %OUT% 0 && ECHO D100 && ECHO Q) | ^
FOR /F "usebackq tokens=2-15 skip=2 delims=- " %%a IN (`DEBUG`) DO ^
@CALL %0 %%a %%b %%c %%d %%e %%f %%g %%h %%i %%j %%k %%l %%m %%n

GOTO :EOF

: Процедура осторожного разбора входной строки, разбираем так,
: чтобы спецсимволы не попали в код
:ONE
SET L="%LINE:~-2,1%"

REM Это для DEBUG — нужно чтобы заэкранировалась кавычка
IF ^%L:~1,-1%==^" (
  SET OUT="""%OUT:~1,-1%
) ELSE (
  SET OUT="%L:~1,-1%%OUT:~1,-1%"
)

SET LINE="%LINE:~1,-2%"

IF NOT %LINE%=="" GOTO ONE
GOTO :EOF

: Процедура для прохода по массиву. Так как вызывается через pipe,
: тормозить придётся самостоятельно — родительский процесс ничего отсюда
: не получает
:LINE
IF %LINEBREAK%==1 GOTO :EOF
IF "%1"=="00" (SET LINEBREAK=1 && ECHO %RESULT% && GOTO :EOF)
CALL :CHAR %1
SHIFT
GOTO LINE

: Победа разума над CMD — преобразование hex->dec
:CHAR
SET /A RES=0x%1
IF DEFINED RESULT (SET RESULT=%RESULT% %RES%) ELSE SET RESULT=%RES%
2008   cmd   useless