// // Модуль: процедуры обработки командной строки для различных утилит // Компилятор: Microsoft Visual C++ v6.0 // Разработчик: 1801BM1@gmail.com // // 14 августа 2002 // Написан первый код // #define __CMDLINE_INTERNAL__ #include "vnet32.h" //#ifdef KEY_INFILE_BIT // // Функция копирования имени файла в указанный буфер // При этом производятся возможные проверки и если // не указано расширение имени файла, то добавляется // расширение по умолчанию. // В случае ошибки выводит сообщение и возвращает TRUE // BOOL CL_SetFileName(char* Buf, char* Name) { int Len; Len = strlen(Name); if (Len > MAX_FILE_NAME) { ERR_ShowError(ERR_FATAL"Too long filename\n\r"); return TRUE; } strcpy(Buf, Name); #ifdef DEF_FILE_EXT // // Проверим, может быть расширение уже указано // if (strrchr(Buf, '.')) return FALSE; // // Расширение не указано, добавляем по умолчанию // предварительно проверив наличие места в буфере // if (Len >= (MAX_FILE_NAME - sizeof(DEF_FILE_EXT))) { ERR_ShowError(ERR_FATAL"Too long filename\n\r"); return TRUE; } strcpy(Buf + Len, DEF_FILE_EXT); #endif return FALSE; } #ifdef KEY_INFILE_BIT // // Функция обработки имени файла, в зависимости от параметров // и предыстории (имя входного файла/имя выходного файла) копирует имя // в один из статических буферов, если требуется, добавляет расширение // В случае ошибки выводит сообщение и возвращает TRUE // BOOL CL_EnumerateFile(char* Key) { if(CL_KeyPresent(KEY_INFILE_BIT)) { // // Одно имя файла (входного) уже обнаружено // Смотрим, допускается ли второе имя // #ifdef KEY_OUTFILE_BIT if(CL_KeyPresent(KEY_OUTFILE_BIT)) { // // Все имена файлов уже указаны - ошибка // ERR_ShowError(ERR_FATAL"Too many filenames specified\n\r"); return TRUE; } else { CLD_KeyMask |= KEY_OUTFILE_BIT; return CL_SetFileName(OutFileName, Key); } #else // // Второе имя файла недопустимо - выводим ошибку // ERR_ShowError(ERR_FATAL"Too many filenames specified\n\r"); return TRUE; #endif } else { CLD_KeyMask |= KEY_INFILE_BIT; return CL_SetFileName(InFileName, Key); } } #endif // KEY_INFILE_BIT // // Функция преобразования строчки десятичных цифр в беззнаковое целое // В случае успеха возвращает полученное значение, в случае ошибки // возвращает 0 и устанавливает признак ошибки CLD_ConvError // // DWORD CL_GetDecValue(char* Line) { DWORD Value = 0; int i; // // Изначально предполагаем ошибку // CLD_ConvError = TRUE; // // Пропускаем незначащие нули // while(*Line == '0') Line++; // // Принимаем не более 9 значащих цифр, таким образом мы // избегаем неопределенности при возникновении переполнения // for(i = 0; i < (sizeof(DWORD) * 2 + 1); i++) { // // Проверяем конец строки // if (*Line == 0) break; if (!isdigit(*Line)) break; Value = Value * 10 + *Line - '0'; Line++; } // // Цикл закончился, проверяем, достигнут ли конец строки // if (*Line == 0) { CLD_ConvError = FALSE; return Value; } // // Слишком длинная строчка // return 0; } // // Функция преобразования строчки шестнадцатиричных цифр в беззнаковое целое // В случае успеха возвращает полученное значение, в случае ошибки // возвращает 0 и устанавливает признак ошибки CLD_ConvError // DWORD CL_GetHexValue(char* Line) { DWORD Value = 0; DWORD Add; // // Изначально предполагаем ошибку // CLD_ConvError = TRUE; // // Принимаем не более 8 значащих цифр, таким образом мы // избегаем неопределенности при возникновении переполнения // while (*Line) { // // Проверяем символ на допустимость // if (!isxdigit(*Line)) break; if (Value & (0xF0L << ((sizeof(DWORD) - 1)*8))) break; if (isdigit(*Line)) { Add = *Line - '0'; } else { Add = toupper(*Line) - 'A' + 10; } Value = (Value << 4) + Add; Line++; } // // Цикл закончился, проверяем, достигнут ли конец строки // if (*Line == 0) { CLD_ConvError = FALSE; return Value; } // // Слишком длинная строчка // return 0; } // // Функция обработки ключа, получает указатель на конкретный ключ, // ищет его в таблице ключей, получает и проверяет значения стандартных типов. // В случае ошибки выводит сообщение и возвращает TRUE // BOOL CL_ProcessKey(char* Key) { char Chr; char *VPtr; PSWITCH_DESC Desc; Chr = *Key; Chr = toupper(Chr); for(Desc = &Switch[0]; Desc < &Switch[KEY_TAB_SIZE]; Desc++) { if (Desc->Letter == Chr) { // // Обнаружена запись в массиве описателей ключей // if (CL_KeyPresent(Desc->KeyBit)) { // // Ключ указан два и более раз - ошибка // ERR_ShowError(ERR_FATAL"Multiple switch specification\n\r"); return TRUE; } // // Ключ обнаружен, устанавливаем признаки наличия ключа // CLD_KeyMask |= Desc->KeyBit; Desc->Flags |= SWFLG_PRESENT; VPtr = Key + 1; // указатель на возможное значение ключа switch(Desc->Type) { // // ключ не может иметь никаких значений // #ifdef SWTYP_NOVALUE case SWTYP_NOVALUE: { if (*VPtr != 0) { ERR_ShowError(ERR_FATAL"Switch -%c has unexpected value\n\r", *Key); return TRUE; } break; } #endif SWTYP_NOVALUE // // ключ может иметь беззнаковое десятичное значение // #ifdef SWTYP_DECVALUE case SWTYP_DECVALUE: { // // Проверим, у ключа должно ли обязательно быть значение // if(Desc->Format & SWFMT_MUSTVALUE) { if (*VPtr == 0) { ERR_ShowError(ERR_FATAL"Switch -%c must have value\n\r", *Key); return TRUE; } } if(*VPtr != 0) { // // Получаем требуемое значение // Desc->Value = CL_GetDecValue(VPtr); if (CLD_ConvError) { ERR_ShowError(ERR_FATAL"Switch -%c has invalid value\n\r", *Key); return TRUE; } Desc->Flags |= SWFLG_HASVALUE; } break; } #endif SWTYP_DECVALUE // // ключ может иметь беззнаковое шестнадцатиричное значение // #ifdef SWTYP_HEXVALUE case SWTYP_HEXVALUE: { // // Проверим, у ключа должно ли обязательно быть значение // if(Desc->Format & SWFMT_MUSTVALUE) { if (*VPtr == 0) { ERR_ShowError(ERR_FATAL"Switch -%c must have value\n\r", *Key); return TRUE; } } if(*VPtr != 0) { // // Получаем требуемое значение // Desc->Value = CL_GetHexValue(VPtr); if (CLD_ConvError) { ERR_ShowError(ERR_FATAL"Switch -%c has invalid value\n\r", *Key); return TRUE; } Desc->Flags |= SWFLG_HASVALUE; } break; } #endif SWTYP_HEXVALUE // // ключ может иметь строковое значение // #ifdef SWTYP_STRING case SWTYP_STRING: { // // Проверим, у ключа должно ли обязательно быть значение // if(Desc->Format & SWFMT_MUSTVALUE) { if (*VPtr == 0) { ERR_ShowError(ERR_FATAL"Switch -%c must have value\n\r", *Key); return TRUE; } } if(*VPtr != 0) { // // Получаем требуемое значение // Desc->Value = (DWORD)VPtr; Desc->Flags |= SWFLG_HASVALUE; } break; } #endif SWTYP_STRING // // При добавлении новых типов ключей следует добавить новые метки // default: { ERR_ShowError(ERR_DEBUG"Unknown switch type encountered\n\r"); return TRUE; } } return FALSE; } } ERR_ShowError(ERR_FATAL"Unknown switch specified: -%s\n\r", Key); return TRUE; } // // Функция обработки очередного ключа, производит синтаксические проверки // В случае ошибки выводит сообщение и возвращает TRUE // BOOL CL_EnumerateKey(char* Key) { char C; C = *Key; if (!C) { ERR_ShowError(ERR_FATAL"Command line syntax error\n\r"); return TRUE; } if ( (C != '-') && (C != '/')) { #ifdef KEY_INFILE_BIT // // Возможно обнаружено имя файла, тогда попытаемся обработать // return CL_EnumerateFile(Key); #else // // Если имя файла в командной строке недопустимо, то обнаружена ошибка // ERR_ShowError(ERR_FATAL"Command line syntax error\n\r"); return TRUE; #endif } Key++; C = *Key; if (!C) { ERR_ShowError(ERR_FATAL"Command line syntax error\n\r"); return TRUE; } return CL_ProcessKey(Key); } // // Функция проверки полученных значений ключей // BOOL CL_CheckValues(void) { PSWITCH_DESC Desc; for(Desc = &Switch[0]; Desc < &Switch[KEY_TAB_SIZE]; Desc++) { if ( ! Desc->Flags & SWFLG_PRESENT ) continue; // // Если ключ не имеет значения, то не проверяем его // if ( ! Desc->Flags & SWFLG_HASVALUE) continue; switch(Desc->Type) { // // ключ не может иметь никаких значений, ничего не проверяем // #ifdef SWTYP_NOVALUE case SWTYP_NOVALUE: { break; } #endif SWTYP_NOVALUE // // ключ может иметь беззнаковое десятичное значение // #ifdef SWTYP_DECVALUE case SWTYP_DECVALUE: { if(Desc->Format & SWFMT_LOWLIMIT) { if(Desc->Value < Desc->LowLimit) { ERR_ShowError(ERR_FATAL"Switch -%c has value less than lower limit\n\r", Desc->Letter); return TRUE; } } if(Desc->Format & SWFMT_HIGHLIMIT) { if(Desc->Value > Desc->HighLimit) { ERR_ShowError(ERR_FATAL"Switch -%c has value more than upper limit\n\r", Desc->Letter); return TRUE; } } // // Вызываем опциональную процедуру проверки // if (Desc->ValueProc != NULL) if(Desc->ValueProc(Desc)) return TRUE; break; } #endif SWTYP_DECVALUE // // ключ может иметь беззнаковое шестнадцатиричное значение // #ifdef SWTYP_HEXVALUE case SWTYP_HEXVALUE: { if(Desc->Format & SWFMT_LOWLIMIT) { if(Desc->Value < Desc->LowLimit) { ERR_ShowError(ERR_FATAL"Switch -%c has value less than lower limit\n\r", Desc->Letter); return TRUE; } } if(Desc->Format & SWFMT_HIGHLIMIT) { if(Desc->Value > Desc->HighLimit) { ERR_ShowError(ERR_FATAL"Switch -%c has value more than upper limit\n\r", Desc->Letter); return TRUE; } } // // Вызываем опциональную процедуру проверки // if (Desc->ValueProc != NULL) if(Desc->ValueProc(Desc)) return TRUE; break; } #endif SWTYP_HEXVALUE // // ключ можеь являтся произвольной строкой, но модет быть реализована // собственная функция проверки // #ifdef SWTYP_STRING case SWTYP_STRING: { // // Вызываем опциональную процедуру проверки // if (Desc->ValueProc != NULL) if(Desc->ValueProc(Desc)) return TRUE; break; } #endif SWTYP_STRING // // При добавлении новых типов ключей SWTYP_xxxx следует добавить новые метки // default: { ERR_ShowError(ERR_DEBUG"Unknown switch type encountered\n\r"); return TRUE; } } // switch } // for return FALSE; } // // Функция проверки взаимной совместимости ключей между собой // Проверяются следующие критерии: // - если какой-то ключ требует указания какого-то другого ключа // или комбинации ключей, то это условие проверяется; // - проверяются несовместимые комбинации ключей // - могут вызываться дополнительные процедуры проверки; // BOOL CL_CheckCompatibility(void) { PSWITCH_DESC Desc; for(Desc = &Switch[0]; Desc < &Switch[KEY_TAB_SIZE]; Desc++) { if ( ! Desc->Flags & SWFLG_PRESENT ) continue; if ( CLD_KeyMask & Desc->IncompKey ) { ERR_ShowError(ERR_FATAL"Incompatible switch combination specified\n\r"); return TRUE; } if ((CLD_KeyMask & Desc->RequireKey) != Desc->RequireKey) { ERR_ShowError(ERR_FATAL"Incomplete switch combination specified\n\r"); return TRUE; } if (Desc->VerifyProc != NULL) if(Desc->VerifyProc(Desc)) return TRUE; } return FALSE; } // // Функция первичной обработки командной строки // Получает аргументы, переданные основной функции main() // В случае ошибки выводит сообщения с использованием // функции ERR_ShowText() и возвращает ненулевое значение // BOOL CL_ParseCmdLine(int arg, char* argv[]) { int i; if (arg < 2) { // // если не указано дополнительных // аргументов, то выводим справочное сообщение // ERR_ShowHelp(); return TRUE; } for (i = 1; i < arg; i++) { // // Поочередно обрабатываем ключи и проверяем синтаксис отдельных ключей // if (CL_EnumerateKey(argv[i])) { return TRUE; } } // // Производим проверку допустимости значений и совместимости ключей // Вызываем их только тогда, когда все ключи получены и предварительно // обработаны // if (CL_CheckValues()|| CL_CheckCompatibility()) { return TRUE; } return FALSE; } // // Функции получения имен входного и выходного файлов, если имена // не были указаны, то возвращают NULL // #ifdef KEY_INFILE_BIT char* CL_GetInFile(void) { // // Проверим, было ли указано имя входного в файла в командной строке // if (CL_KeyPresent(KEY_INFILE_BIT) && strlen(InFileName)) { return &InFileName[0]; } return NULL; } #ifdef KEY_OUTFILE_BIT char* CL_GetOutFile(void) { // // Проверим, было ли указано имя выходного в файла в командной строке // if (CL_KeyPresent(KEY_OUTFILE_BIT) && strlen(OutFileName)) { return &OutFileName[0]; } return NULL; } #endif #endif // // Функция получения указателя на значение ключа (если было указано // в командной строке, иначе возвращается указатель на значение // по умолчанию), дальнейшая обработка зависит от типа значения // ключа. Если ключ не был указан, то возвращает NULL // // PVOID CL_GetValuePtr(DWORD KeyBit) { PSWITCH_DESC Desc; PVOID Result = NULL; for(Desc = &Switch[0]; Desc < &Switch[KEY_TAB_SIZE]; Desc++) { if(Desc->KeyBit == KeyBit) { if (!CL_KeyPresent(KeyBit)) { // // Если ключ не присутствует в командной строке вернем NULL // break; } if ((Desc->Flags & SWFLG_HASVALUE) == 0) { // // У ключа не указано значение - нет указателя // break; } switch(Desc->Type) { // // ключ не может иметь никаких значений // #ifdef SWTYP_NOVALUE case SWTYP_NOVALUE: { break; } #endif SWTYP_NOVALUE // // ключ может иметь беззнаковое десятичное значение // #ifdef SWTYP_DECVALUE case SWTYP_DECVALUE: { Result = &Desc->Value; break; } #endif SWTYP_DECVALUE // // ключ может иметь беззнаковое шестнадцатиричное значение // #ifdef SWTYP_HEXVALUE case SWTYP_HEXVALUE: { Result = &Desc->Value; break; } #endif SWTYP_HEXVALUE // // ключ является строчным значением // #ifdef SWTYP_STRING case SWTYP_STRING: { Result = (PVOID)(Desc->Value); break; } #endif SWTYP_STRING // // При добавлении новых типов ключей следует добавить новые метки // default: { ERR_ShowError(ERR_DEBUG"Unknown switch type encountered\n\r"); break; } } break; } } return Result; }