<< Пред.           стр. 35 (из 121)           След. >>

Список литературы по разделу

  break;
 
  case 'v':
  // обработка опции version
  break;
 
  case 'h':
  // обработка опции help
  break;
 
  case 'o':
  // приготовимся обработать выходной файл
  break;
 
  case 'l':
  // приготовимся обработать макс.размер
  break;
 
  default:
  // неопознанная опция:
  // сообщить об ошибке и завершить выполнение
  }
 }
 Опция -d задает необходимость отладки. Ее обработка заключается в присваивании переменной с объявлением
 bool debug_on = false;
 значения true:
 case 'd':
  debug_on = true;
 break;
 В нашу программу может входить код следующего вида:
 if ( debug_on )
  display_state_elements( obj );
 Опция -v выводит номер версии программы и завершает исполнение:
 case 'v':
  cout << program_name << "::"
  << program_version << endl;
  return 0;
 Опция -h запрашивает информацию о синтаксисе запуска и завершает исполнение. Вывод сообщения и выход из программы выполняется функцией usage():
 case 'h':
  // break не нужен: usage() вызывает exit()
  usage();
 Опция -o сигнализирует о том, что следующая строка содержит имя выходного файла. Аналогично опция -l говорит, что за ней указан максимальный размер. Как нам обработать эти ситуации?
 Если в строке параметра нет дефиса, возможны три варианта: параметр содержит имя выходного файла, максимальный размер или имя входного файла. Чтобы различать эти случаи, присвоим true переменным, отражающим внутреннее состояние:
 // если ofi1e_on==true,
 // следующий параметр - имя выходного файла
 bool ofi1e_on = false;
 
 // если ofi1e_on==true,
 // следующий параметр - максимальный размер
 bool limit_on = false;
 Вот обработка опций -l и -o в нашей инструкции switch:
 case 'l':
  limit_on = true;
  break;
 
 case 'o':
  ofile_on = true;
  break;
 Встретив строку, не начинающуюся с дефиса, мы с помощью переменных состояния можем узнать ее содержание:
 // обработаем максимальный размер для опции -1
 // имя выходного файла для -o
 // имена входных файлов ...
 default: {
  // ofile_on включена, если -o встречалась
  if ( ofile_on ) {
  // обработаем имя выходного файла
  // выключим ofile_on
  }
  else if ( limit_on ) { // если -l встречалась
  // обработаем максимальный размер
  // выключим limit_on
  } else {
  // обработаем имя входного файла
  }
 }
 Если аргумент является именем выходного файла, сохраним это имя и выключим ofile_on:
 if ( ofile_on ) {
  ofile_on = false;
  ofile = pchar;
 }
 Если аргумент задает максимальный размер, мы должны преобразовать строку встроенного типа в представляемое ею число. Сделаем это с помощью стандартной функции atoi(), которая принимает строку в качестве аргумента и возвращает int (также существует функция atof(), возвращающая double). Для использования atoi() включим заголовочный файл ctype.h. Нужно проверить, что значение максимального размера неотрицательно и выключить limit_on:
 // int limit;
 else
 if ( limit_on ) {
  limit_on = false;
  limit = atoi( pchar );
  if ( limit < 0 ) {
  cerr << program_name << "::"
  << program_version << " : error: "
  << "negative value for limit.\n\n";
  usage( -2 );
  }
 }
 Если обе переменных состояния равны false, у нас есть имя входного файла. Сохраним его в векторе строк:
 else
  file_names.push_back( string( pchar ));
 При обработке параметров командной строки важен способ реакции на неверные опции. Мы решили, что задание отрицательной величины в качестве максимального размера будет фатальной ошибкой. Это приемлемо или нет в зависимости от ситуации. Также можно распознать эту ситуацию как ошибочную, выдать предупреждение и использовать ноль или какое-либо другое значение по умолчанию.
 Слабость нашей реализации становится понятной, если пользователь небрежно относится к пробелам, разделяющим параметры. Скажем, ни одна из следующих двух строк не будет обработана:
 prog - d dataOl
 prog -oout_file dataOl
 (Оба случая мы оставим для упражнений в конце раздела.)
 Вот полный текст нашей программы. (Мы добавили инструкции печати для трассировки выполнения.)
 #include
 
 #include
 #include
 
 #include
 
 const char *const program_name = "comline";
 const char *const program_version = "version 0.01 (08/07/97)";
 
 inline void usage( int exit_value = 0 )
 {
  // печатает отформатированное сообщение о порядке вызова
  // и завершает программу с кодом exit_value ...
 
  cerr << "порядок вызова:\n"
  << program_name << " "
  << "[-d] [-h] [-v] \n\t"
  << "[-o output_file] [-l limit] \n\t"
  << "file_name\n\t[file_name [file_name [ ... ]]]\n\n"
  << "где [] указывает на необязательность опции:\n\n\t"
  << "-h: справка.\n\t\t"
  << "печать этого сообщения и выход\n\n\t"
  << "-v: версия.\n\t\t"
  << "печать информации о версии программы и выход\n\n\t"
  << "-d: отладка.\n\t\t включает отладочную печать\n\n\t"
  << "-l limit\n\t\t"
  << "limit должен быть неотрицательным целым числом\n\n\t"
  << "-o ofile\n\t\t"
  << "файл, в который выводится результат\n\t\t"
  << "по умолчанию результат записывается на стандартный вывод\n\n"
  << "file_name\n\t\t"
  << "имя подлежащего обработке файла\n\t\t"
  << "должно быть задано хотя бы одно имя --\n\t\t"
  << "но максимальное число не ограничено\n\n"
  << "примеры:\n\t\t"
  << "$command chapter7.doc\n\t\t"
  << "$command -d -l 1024 -o test_7_8 "
  << "chapter7.doc chapter8.doc\n\n";
 
  exit( exit_value );
 }
 
 int main( int argc, char* argv[] )
 {
  bool debug_on = false;
  bool ofile_on = false;
  bool limit_on = false;
  int limit = -1;
  string ofile;
  vector file_names;
 
  cout << "демонстрация обработки параметров в командной строке:\n"
  << "argc: " << argc << endl;
 
  for ( int ix = 1; ix < argc; ++ix )
  {
  cout << "argv[ " << ix << " ]: "
  << argv[ ix ] << endl;
 
  char *pchar = argv[ ix ];
  switch ( pchar[ 0 ] )
  {
  case '-':
  {
  cout << "встретился \'-\'\n";
  switch( pchar[ 1 ] )
  {
  case 'd':
  cout << "встретилась -d: "
  << "отладочная печать включена\n";
 
  debug_on = true;
  break;
 
  case 'v':
  cout << "встретилась -v: "
  << "выводится информация о версии\n";
 
  cout << program_name
  << " :: "
  << program_version
  << endl;
 
  return 0;
 
  case 'h':
  cout << "встретилась -h: "
  << "справка\n";
 
  // break не нужен: usage() завершает программу
  usage();
 
  case 'o':
  cout << "встретилась -o: выходной файл\n";
  ofile_on = true;
  break;
  case 'l':
  cout << "встретилась -l: "
  << "ограничение ресурса\n";
 
  limit_on = true;
  break;
 
  default:
  cerr << program_name
  << " : ошибка : "
  << "неопознанная опция: - "
  << pchar << "\n\n";
 
  // break не нужен: usage() завершает программу
  usage( -1 );
  }
  break;
  }
 
  default: // либо имя файла
  cout << "default: параметр без дефиса: "
  << pchar << endl;
 
  if ( ofile_on ) {
  ofile_on = false;
  ofile = pchar;
  }
  else
  if ( limit_on ) {
  limit_on = false;
  limit = atoi( pchar );
  if ( limit < 0 ) {
  cerr << program_name
  << " : ошибка : "
  << "отрицательное значение limit.\n\n";
 
  usage( -2 );
  }
  }
  else file_names.push_back( string( pchar ));
  break;
  }
  }
 
  if ( file_names.empty() ) {
  cerr << program_name
  << " : ошибка : "
  << "не задан ни один входной файл.\n\n";
  usage( -3 );
  }
 
  if ( limit != -1 )
  cout << "Заданное пользователем значение limit: "
  << limit << endl;
 
  if ( ! ofile.empty() )
  cout << "Заданный пользователем выходной файл: "
  << ofile << endl;
 
  cout << (file_names.size() == 1 ? "Файл, " : "Файлы, ")
  << "подлежащий(е) обработке:\n";
 
  for ( int inx = 0; inx < file_names.size(); ++inx )
  cout << "\t" << file_names[ inx ] << endl;
 }
 a.out -d -l 1024 -o test_7_8 chapter7.doc chapters.doc
 Вот трассировка обработки параметров командной строки:
 
 демонстрация обработки параметров в командной строке:
 argc: 8
 argv[ 1 ]: -d
 встретился '-'
 встретилась -d: отладочная печать включена
 argv[ 2 ]: -l
 встретился '-'
 встретилась -l: ограничение ресурса
 argv[ 3 ]: 1024
 default: параметр без дефиса: 1024
 argv[ 4 ]: -o
 встретился '-'
 встретилась -o: выходной файл
 argv[ 5 ]: test_7_8
 default: параметр без дефиса: test_7_8
 argv[ 6 ]: chapter7.doc
 default: параметр без дефиса: chapter7.doc
 argv[ 7 ]: chapter8.doc
 default: параметр без дефиса: chapter8.doc
 Заданное пользователем значение limit: 1024
 Заданный пользователем выходной файл: test_7_8
 Файлы, подлежащий(е) обработке:
  chapter7.doc
  chapter8.doc
 
 7.8.1. Класс для обработки параметров командной строки
 Чтобы не перегружать функцию main() деталями, касающимися обработки параметров командной строки, лучше отделить этот фрагмент. Можно написать для этого функцию. Например:
 extern int parse_options( int arg_count, char *arg_vector );
 
 int main( int argc, char *argv[] ) {
  // ...
  int option_status;
  option_status = parse_options( argc, argv );

<< Пред.           стр. 35 (из 121)           След. >>

Список литературы по разделу