С++ и опции(ключи) запуска программы

Вопросы написания собственного программного кода (на любых языках)

Модератор: Olej

Dima2387
Интересующийся
Сообщения: 9
Зарегистрирован: 21 ноя 2014, 17:35
Контактная информация:

С++ и опции(ключи) запуска программы

Непрочитанное сообщение Dima2387 » 03 дек 2014, 09:41

Добрый день. Пытаюсь написать программу которая бы при заданных ключах - создавала конфиг файл для другой программы.

Код: Выделить всё


#include <stdio.h>
#include <fstream>
#include <iostream>
#include <unistd.h>
#include <getopt.h>
#include <stdlib.h>
using namespace std;

int main (int argc, char *argv[]){



                ofstream out("/tmp/config_nginx.ini"); //ofstream - это тип данных. Внутри скобок параметр, принимаемый конструктором объявленного объекта

                out<<"user "<<argv[1]<<";\n"; // тут подставляю первую опцию (ключ)
                out<<" \n";
                out<<"# As a thumb rule: One per CPU. If you are serving a large amount\n";
                out<<"# of static files, which requires blocking disk reads, you may want\n";
                out<<"# to increase this from the number of cpu_cores available on your\n";
                out<<"# system.\n";
                out<<"#\n";
                out<<"# The maximum number of connections for Nginx is calculated by:\n";
                out<<"# max_clients = worker_processes * worker_connections\n";
                out<<"worker_processes 1;\n";
                out<<" \n";
                out<<"# Maximum file descriptors that can be opened per process\n";
                out<<"# This should be > worker_connections\n";
                out<<"worker_rlimit_nofile 8192;\n";
                out<<" \n";
                out<<"events {\n";
                out<<"# When you need > 8000 * cpu_cores connections, you start optimizing\n";
                out<<"# your OS, and this is probably the point at where you hire people\n";
                out<<"# who are smarter than you, this is *a lot* of requests.\n";
                out<<"worker_connections 8000;\n";
                out<<"}\n";
                out<<" \n";
                out<<"error_log /var/log/nginx/error.log;\n";
                out<<" \n";
                out<<"pid /var/run/nginx.pid;\n";
                out<<" \n";
                out<<"http {\n";
                out<<"charset "<<argv[2]<<";\n"; // а здесь вторая опция(ключ)
                out<<"\n";
                out<<"\n";
                out<<"\n";
                out<<"ssl_session_cache   shared:SSL:10m;\n";
                out<<"ssl_session_timeout 5m;\n";
                out<<"ssl_prefer_server_ciphers on;\n";
                out<<"ssl_stapling on;\n";
                out<<"resolver 8.8.8.8;\n";
                out<<"\n";
                out<<"\n";
                out<<"\n";
                out<<"\n";
                out<<"\n";
                out<<" \n";
                out<<"# Set the mime-types via the mime.types external file\n";
                out<<"include mime.types;\n";
                out<<" \n";
                out<<"# And the fallback mime-type\n";
                out<<"default_type application/octet-stream;\n";
                out<<" \n";
                out<<"# Click tracking!\n";
                out<<"access_log /var/log/nginx/access.log;\n";
                out<<" \n";
                out<<"# Hide nginx version\n";
                out<<"server_tokens off;\n";
                out<<" \n";
                out<<"# ~2 seconds is often enough for HTML/CSS, but connections in\n";
                out<<"# Nginx are cheap, so generally it's safe to increase it\n";
                out<<"keepalive_timeout 20;\n";
                out<<" \n";
                out<<"# You usually want to serve static files with Nginx\n";
                out<<"sendfile on;\n";
                out<<" \n";
                out<<"tcp_nopush on; # off may be better for Comet/long-poll stuff\n";
                out<<"tcp_nodelay off; # on may be better for Comet/long-poll stuff\n";
                out<<" \n";
                out<<"server_name_in_redirect off;\n";
                out<<"types_hash_max_size 2048;\n";
                out<<" \n";
                out<<"gzip on;\n";
                out<<"gzip_http_version 1.0;\n";
                out<<"gzip_comp_level 5;\n";
                out<<"gzip_min_length 512;\n";
                out<<"gzip_buffers 4 8k;\n";
                out<<"gzip_proxied any;\n";
                out<<"gzip_types\n";
                out<<"# text/html is always compressed by HttpGzipModule\n";
                out<<"text/css\n";
                out<<"text/plain\n";
                out<<"text/x-component\n";
                out<<"application/javascript\n";
                out<<"application/json\n";
                out<<"application/xml\n";
                out<<"application/xhtml+xml\n";
                out<<"application/x-font-ttf\n";
                out<<"application/x-font-opentype\n";
                out<<"application/vnd.ms-fontobject\n";
                out<<"image/svg+xml\n";
                out<<"image/x-icon;\n";
                out<<" \n";
                out<<"# This should be turned on if you are going to have pre-compressed copies (.gz) of\n";
                out<<"# static files available. If not it should be left off as it will cause extra I/O\n";
                out<<"# for the check. It would be better to enable this in a location {} block for\n";
                out<<"# a specific directory:\n";
                out<<"# gzip_static on;\n";
                out<<" \n";
                out<<"gzip_disable msie6;\n";
                out<<"gzip_vary on;\n";
                out<<"# Upstream to abstract backend connection(s) for PHP\n";
                out<<"upstream php {\n";
                out<<"server unix:/tmp/php5-fpm.sock;\n";
                out<<"}\n";
                out<<" \n";
                out<<"include /etc/nginx/conf.d/*.conf;\n";
                out<<"include /etc/nginx/sites-enabled/*;\n";
                out<<"}\n";
                out<<"\n";

                    out.close(); //Закрываем файл









    return 0;
    }


Данный код позволяет мне запускать приложение с ключами(не указывая имя ключа) через пробел и ключи подставляются на место argv[1] и argv[2]
Пример запуска:

./untitled15 dima cp1251

сгенереный конфиг выглядит следующим образом:

user dima;

# As a thumb rule: One per CPU. If you are serving a large amount
# of static files, which requires blocking disk reads, you may want
# to increase this from the number of cpu_cores available on your
# system.
#
# The maximum number of connections for Nginx is calculated by:
# max_clients = worker_processes * worker_connections
worker_processes 1;

# Maximum file descriptors that can be opened per process
# This should be > worker_connections
worker_rlimit_nofile 8192;

events {
# When you need > 8000 * cpu_cores connections, you start optimizing
# your OS, and this is probably the point at where you hire people
# who are smarter than you, this is *a lot* of requests.
worker_connections 8000;
}

error_log /var/log/nginx/error.log;

pid /var/run/nginx.pid;

http {
charset cp1251;

.......


Вопрос

Как сделать длинные опции(ключи) для работы с моим приложением по типу чтобы с приложением можно было работать

./untitled15 --user=dima --charset=cp1251
Программирование в Linux с нуля http://linuxdevelop.net/

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: С++ и опции(ключи) запуска программы

Непрочитанное сообщение Olej » 03 дек 2014, 15:10

Dima2387 писал(а): Вопрос

Как сделать длинные опции(ключи) для работы с моим приложением по типу чтобы с приложением можно было работать

./untitled15 --user=dima --charset=cp1251
Для обработки опций и параметров командной строки запуска используйте исключительно вызовы getopt() (для коротких опций, вида -...) и getopt_long() и getopt_long_only() (для длинных опций, вида --...).

Так нужно делать (а не ручную разборку argv[...]) для того, чтобы синтаксис вашей командной строки был совместим с синтаксисом UNIX. Кроме того, для того, чтобы разделить опции от параметров запуска команды, если они записаны в произвольном порядке.
Такая разборка командной строки практикуется в UNIX аж с 1980 года. ;-)

См. :

Код: Выделить всё

$ man 3 getopt
...
SYNOPSIS
       #include <unistd.h>

       int getopt(int argc, char * const argv[],
                  const char *optstring);

       extern char *optarg;
       extern int optind, opterr, optopt;

       #include <getopt.h>

       int getopt_long(int argc, char * const argv[],
                  const char *optstring,
                  const struct option *longopts, int *longindex);

       int getopt_long_only(int argc, char * const argv[],
                  const char *optstring,
                  const struct option *longopts, int *longindex);
Обращаем внимание сразу на 2 обстоятельства:

1. getopt() - это POSIX API, это будет (обязано!) работать в любых UNIX-like OS, getopt_long() - это Linux-расширение, поэтому это может работать, а может и не работать в других OS.

2. они даже описаны в разных включаемых файлах заголовков.

Пример использования я допишу позже.

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: С++ и опции(ключи) запуска программы

Непрочитанное сообщение Olej » 03 дек 2014, 16:29

Olej писал(а):Пример использования я допишу позже.
Ну вот возможный пример:

Код: Выделить всё

#include <stdlib.h>
#include <getopt.h>
#include <string.h>
#include <string>
#include <iostream>
using namespace std;

int main( int argc, char **argv ) {
   int helplevel = 1; 
   //---------------------- обработка коротких опций:
   char user[ 40 ] = "unknown";
   string charset( "utf8" );
   while( true ) {
      char c, short_opt[] = "u:c:";                  // короткие опции
      struct option long_opt[] = {                   // длинные опции:
         { "help", optional_argument, NULL, 'h' },   // не обязательный аргумент
         { "user", required_argument, NULL, 3 },     // обязательные аргументы ...
         { "charset", required_argument, NULL, 'C' },
         { 0, 0, 0, 0 }                              // завершитель описания опций
      };
      int opt_index = 0;
      c = getopt_long( argc, argv, short_opt, long_opt, &opt_index );
      if( -1 == c ) break;                           // перебрали все опции
      switch( c ) {
         case 'u':
            strcpy( user, optarg );
            break;
         case 3:
            strcpy( user, optarg );
            break;
         case 'c':
         case 'C':
            charset = string( optarg );
            break;
         case 'h':
            helplevel = NULL == optarg ? 0 : atoi( optarg );
            break;
         case '?': // недопустимая опция
            exit( 1 );
         default:
            cout << "! getopt возвратил неизвестно что: " 
                 << c << '(' << (int)c << ')' << endl;
      }
   }
   cout << "уровень подсказок = " << helplevel << endl
        << "пользователь: " << user << endl
        << "кодировка: " << charset.c_str() << endl;
   if( optind != argc ) {
      cout << "параметры команды: ";
      for( int c = optind; c < argc; c++ ) 
         cout << argv[ c ] << ( c != argc - 1 ? " , " : "\n" );
   }
   return 0;
}
Обратите внимание на такие вещи:
1. getopt_long() не заменяет (или дополняет) getopt(), она просто обрабатывает в едином потоке как короткие, так и длинные опции - это расширение getopt(), если вам нужно обрабатывать только длинные опции - можете использовать getopt_long_only() ... или задать пустой строку коротких опций с вызове getopt_long() (3-й параметр) - это я так думаю ;-) , я не проверял.
3. значение опции, если оно было указано, вы получите в строке optarg, это строка ASCIZ (char*) ... в зависимости от того, куда вам нужен результат, это сильно зависит от char* или string (я специально показал оба варианта), или преобразовывать строчное изображение в численную величину, если надо.

Вот вам некоторые результаты теста:

Код: Выделить всё

[Olej@modules getopt]$ ./tstopt 
уровень подсказок = 1
пользователь: unknown
кодировка: utf8

[Olej@modules getopt]$ ./tstopt -u root --charset=cp1251 file.in file.out
уровень подсказок = 1
пользователь: root
кодировка: cp1251
параметры команды: file.in , file.out

[Olej@modules getopt]$ ./tstopt file.in -u root --charset=cp1251 file.out
уровень подсказок = 1
пользователь: root
кодировка: cp1251
параметры команды: file.in , file.out

[Olej@modules getopt]$ ./tstopt --help
уровень подсказок = 0
пользователь: unknown
кодировка: utf8

[Olej@modules getopt]$ ./tstopt --help=5
уровень подсказок = 5
пользователь: unknown
кодировка: utf8

[Olej@modules getopt]$ ./tstopt -z
./tstopt: invalid option -- 'z'

[Olej@modules getopt]$ ./tstopt --class=123
./tstopt: unrecognized option '--class=123'


Здесь есть и а). обработка недозволенных опций и б). необязательный параметр у длинной опции и в). произвольный порядок (впересыпку) опция и параметров командной строки (в конце).
Вложения
tstopt.cc
(2.03 КБ) 267 скачиваний

Dima2387
Интересующийся
Сообщения: 9
Зарегистрирован: 21 ноя 2014, 17:35
Контактная информация:

Re: С++ и опции(ключи) запуска программы

Непрочитанное сообщение Dima2387 » 03 дек 2014, 17:13

Огромное спасибо за работающий пример длинных ключей!
Программирование в Linux с нуля http://linuxdevelop.net/

Ответить

Вернуться в «Программирование»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 4 гостя