LINUX.ORG.RU

Кошерная обработка параметров командной строки

 


0

3

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

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

Но вот понадобилось мне реализовать возможность задания определенных параметров несколько раз. И пришлось ваять это (почти весь день сегодня убил, благо, полдня ЛОР лежал и ничто не отвлекало). (на ЖЖшке).

Вот что получается при запуске:

./myopt_example -a 1e-5 -f type=as:xsz=5s something -a 3e-9 -f type=med:ysz=15 some_more -s again -f xsz=5 -s more -M diam=8:foc=10 -vvvv
Globals:
S_dev = 8 (default)
randAmp[0]: 1e-05
randAmp[1]: 3e-09
meet str args:
str[0] = again
str[1] = more
S_interp = 100
S_image = 1000
N_phot = 10000
randMask = 0
Mirror =
	D = 8
	F = 10
	Zincl = 0
	Aincl = 0
rewrite_ifexists = 0
verbose = 4
There's also 2 free parameters:
	   0: something
	   1: some_more
filter parameters:
0:
Wrong argument "5s" of parameter "xsz"
	bad params
1:
	filtertype = med, sizes: 3x15
2:
	filtertype = (null), sizes: 5x3
Т.е. есть переменные с инкрементом (-v — чем больше раз встречается, тем больше число), массивы (randAmp, str), обработка по порядку свободных параметров (something, some_more), предварительная (до передачи управления обратно в вызвавшую parce_args функцию) обработка вложенных аргументов и постобработка вложенных аргументов (filter parameters) — уже вне велосипеда.

Однако, скажем, ffmpeg умеет делать такие сложные вещи, как определение групп параметров между одноименными ключами. Как бы и мне сделать так, чтобы, скажем,

./myopt_example -f filt1:xzs=10 -h 10 -v 20 -f filt2:ysz=20 -s par -f filt3
Автоматом бы связывал каким-то образом параметры, чтобы при обработке первого -f к нему же были привязаны -h, -v; при обработке второго — -s?

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

☆☆☆☆☆

Последнее исправление: Eddy_Em (всего исправлений: 1)

Это уже ближе к написанию собственного языка. Посмотри, какие у VLC бывают развесистые параметры командной строки и не уподобляйся :)

Имхо, если для Си-программы нужны сложные параметры, проще сделать конфиг на lua. Для остального есть getopts

Deleted
()
Последнее исправление: Deleted (всего исправлений: 1)

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

staseg ★★★★★
()
Ответ на: комментарий от Deleted

Я потихоньку пишу простенький процессор фитс-файлов, чтобы делать кое-какие вещи, отсутствующие, скажем, в MIDAS'е или IRAF'е, и сильно тормозящие в октаве.

И вот для конвейера, чтобы на баше не писать длинную простыню с промежуточными файлами, захотелось мне параметрами командной строки весь порядок обработки записывать. Чтобы указал входной файл, параметры, выходной файл; подождал маленько, получил файл. Это всяко шустрей будет, чем толпы промежуточных файлов на диск писать.

Eddy_Em ☆☆☆☆☆
() автор топика

В чём смысл спрашивать, если ты всё равно обложишь все ответы и продолжишь писать велосипеды?

i-rinat ★★★★★
()
Ответ на: комментарий от i-rinat

А вдруг существует такая мегакошернейшая библиотека, что я скажу: «какой же я идиот-велосипедописатель», выкину все велосипеды и стану пользоваться ею?

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от Eddy_Em

Мне лень читать всю ту простыню, чтобы понять, как ты до этого докатился.

staseg ★★★★★
()
Ответ на: комментарий от Eddy_Em

А вдруг существует такая мегакошернейшая библиотека

Нет, таких нет.

Я прочитал достаточно твоих комментариев, чтобы понять: тебе не понравится ничего.

i-rinat ★★★★★
()
Последнее исправление: i-rinat (всего исправлений: 2)
Ответ на: комментарий от Eddy_Em

Делай сценарии на LUA :)

(не обязательно к этому проекту, но хотя бы посмотри, как луа интегрируется в C. От этого можно просто... получить удовольствие. Это не какой-то там бессмысленный и беспощадный жырнопитон, это - очень утилитарная и легкая фича.

Если не подходит - я пас, мне getopts хватает.

Deleted
()
Ответ на: комментарий от Deleted

Делай сценарии на Lua

Примерчик какой-нибудь можно посмотреть? А то, честно говоря, вообще не имею ни малейшего понятия, что за Lua такой, и как его можно интегрировать с С.

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от ossa

Интересно. Надо пошукать книжки о Lua. Жаль, в библиотеке нет — придется или покупать, или распечатывать.

Eddy_Em ☆☆☆☆☆
() автор топика

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

st4l1k ★★
()
Ответ на: комментарий от st4l1k

И шо, таки, дядя Изя говорил по поводу того как справится кошерный getopt с примерами Едди_Ем?

anonymous
()
Ответ на: комментарий от Eddy_Em

Ну, вроде того. Упрощенный псевдокод. Передача данных между C и Lua осуществляется через стек параметров (потому что луа внтури сам такой)

Запуск сценария инициализации(сложный конфиг)


LuaState * L = load("file.lua");
run(L); // обрабатываем сценарий, выполняется луа скрипт, заполняются глобальные переменные луа.

get_global(L, "option1"); // допустим, option1 сложная структура lua (таблица в терминах lua)

struct S {int a; char b[MAX]} option1;  // сюда читаем данные option1

pop_num(L, &option1.a);
pop_string(L, &option1.b, MAX);

Можно вызывать функции луа:

int handler_wrapper(int a, b)
{
get_global(L, "Handler"); // Handler(int a, b);

push_num(L, a);
push_num(L, b);
pcall(L);

int res;
pop_num(L, &res);
return res;
}

http://www.troubleshooters.com/codecorn/lua/lua_c_calls_lua.htm

http://www.lua.org/manual/5.3/manual.html

Короче, преимущество для конфигов в том, что у тебя клевый config.lua, в котором ты можешь вычислять параметры и формировать сложные структуры и результат принимать в С. При этом конфиг может быть простой (типа «opt1=13») или навороченный - парсит и вычисляет(!) это все lua, а ты через стековый интероп забирараешь. Луа же сам по себе настолько прозрачен и тонок (если почитаешь как устроен его интерпретатор), что это по сути C, реализация очень простая и понятная (стековая машина).

Deleted
()
Ответ на: комментарий от Deleted

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

anonymous
()

getopt уже предлагали не?

и его сорцы в особо запущенных случаях.

mos ★★☆☆☆
()

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

чем getopt_long не устраивает?

waker ★★★★★
()
Ответ на: комментарий от itn

И что, каждый раз конфиг писать что ли? Да и парсинг конфигов — штука еще хуже, нежели парсинг аргументов CLI.

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от waker

Я его и использую в своем велосипеде. Но думал, вдруг есть готовое. А то уже суммарно суток трое убил тупо на эту сраную фигню.

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от Eddy_Em

Я его и использую в своем велосипеде. Но думал, вдруг есть готовое. А то уже суммарно суток трое убил тупо на эту сраную фигню.

а, ну ок.. у меня getopt_long работает прекрасно в ~10 разных программах на работе, на нескольких языках, и никаких проблем пока не возникало.

waker ★★★★★
()

напиши грамматику для парсера какого нибудь.

anonymous
()

optparse-applicative. Мой идеал. Но, правда, только для Haskell

yoghurt ★★★★★
()

ыыы! залезть в тройные указатели — это надо суметь

теперь решение по шагам:

1. заюзать какую-то либу, позволяющую длинные опции типа --filter1-x

2А. пропатчить ком-строку перлом

2В. если не хочется тащить перл, то пропатчить ком-строку примерно так:

for( i=0; i<bla; i++)
{
    if( strcmp(argv[i],"-f")==0 && strncmp(argv[i],"filt1",bla)==0 ) filter="filt1";
    if( strcmp(argv[i],"-f")==0 && strncmp(argv[i],"filt2",bla)==0 ) filter="filt2";

    if( strcmp(argv[i],"-x")==0 && filter=="filt1") argv[i]="--filter1-x";
    if( strcmp(argv[i],"-x")==0 && filter=="filt2") argv[i]="--filter2-x";
}

bla стоит там, где мне лень писать

если argv константный, то неглубоко его скопировать (memcpy подойдет я думаю), затем так же пропатчить, затем скормить библиотеке опций

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от www_linux_org_ru

Твой вариант с чем-нибудь вроде -vxf filter=... не будет работать! А это даже гетопт обработает!

Вот я и сделал обертку на основе гетопта, чтобы в дальнейшем не гробиться! Только все равно жирновато получается.

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от Eddy_Em

И что, каждый раз конфиг писать что ли?

А что, писать каждый раз длиннющую простыню опций тебя не ломает? Ну ок, тогда

myopt --yaml 'твои опции в yaml'

no-such-file ★★★★★
()

если задача усложняется, есть смысл пересмотреть подход к ее решению.

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

conalex ★★★
()
Ответ на: комментарий от conalex

Не, я хотел вообще что-то вроде калькулятора сделать навроде «взять этот FITS-файл, вычесть определенным методом из него фон, найти объекты таким-то методом, по каталогу выдрать их координаты и забульбенить в FITS-шапку правильные wcs, а еще приплюсовать к данному файлу табличку с координатами выделенных объектов.

Правда, это уже совсем борзо, эдакая смесь sextractor'а и, скажем, MIDAS'а.

Жаль, негусто среди софта: MIDAS, IRAF да через пень-колоду Octave. Огороженный анально IDL не хочу использовать принципиально, хотя куча народа его юзает и не морщится.

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от Eddy_Em

я хотел вообще что-то вроде калькулятора сделать навроде «взять этот FITS-файл, вычесть определенным методом из него фон, найти объекты таким-то методом, по каталогу выдрать их координаты и забульбенить в FITS-шапку правильные wcs, а еще приплюсовать к данному файлу табличку с координатами выделенных объектов.

Тогда встраивание Lua тебе подойдёт самым лучшим образом. Будут не конфиги, а программы.

i-rinat ★★★★★
()
Ответ на: комментарий от i-rinat

Таперча остается лишь книжку годную по Lua найти. Но не слишком дорогую или не слишком толстую (чтобы не нужно было полдня у принтера стоять, печатать).

Eddy_Em ☆☆☆☆☆
() автор топика

если у тебя такая прорва параметров - не лучше ли использовать конфиг файлы?

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

reprimand ★★★★★
()

Клинический случай. А почему компилятору не передавать всю программу через командную строку? А то файлы еще какие выдумали...

eddycc -istdio.h --function=main::int --call=printf -p"Hello World" --endfunction
Pavval ★★★★★
()
Ответ на: комментарий от SkyMaverick

http://www.lua.org/ftp/refman-5.0.pdf
http://www.lua.org/manual/5.3/

Не годится. По рефманам язык изучить никак не получится. Нужно что-то вроде K&R, но для Lua.

Книжки у них на сайте продаются

Угу, по дофигища евриков?

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от SkyMaverick

У тебя неправильные ссылки, т.к. торренты у меня не работают. Я лучше нашел. Уже качаю. Кошерно, что автор в латехе набрал. Молодец. Вся книжка 366 страниц, так что выйдет 11.5 тетрадей по 32 страницы — не так уж и много, можно за вечер распечатать, а за следующий вечер сшить и вклеить в твердый переплет.

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от ossa

Там и в epub, только нафиг мне этот формат? pdf распечатать удобней.

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от Eddy_Em

Твой вариант с чем-нибудь вроде -vxf filter=... не будет работать! А это даже гетопт обработает!

а подумать хотя бы 2 минуты перед ответом тебе твоя религия не позволяет?

если тебе надо объединять опции, сделай desugaring (т.е. конвертилку "-vxf filter1=..." в "-v -x -f filter1=...") и затем уже патчи

хороший getopt должен уметь делать desugaring сам, но и написать его можно в несколько строк

а вообще я, когда мне надо что-то типа твоего, просто пишу код на с++ в командной строке, который затем скриптом скармливаю компилятору

на самом деле это даже не с++, а покруче, типа

do_something f=x²+y² φ=xyz w=u⨯v

которое регуляркой конвертится в с++ — в результате все работает быстро даже внутри цикла, и луа мне нахрен не сдался

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от Eddy_Em

да, добавлю:

1. вариант на перле лепится за полчаса (а не за 3 дня)

2. ты там месишь char-ы, поэтому тебе *ничего* не нужно конвертировать в void*, так что удивительно, почему никто не назвал твое изделие говнокодом

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от www_linux_org_ru

ты там месишь char-ы, поэтому тебе *ничего* не нужно конвертировать в void*

Я конвертирую в void* именно из-за того, что могу любые типы данных разгребать. А не только строки!

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от Eddy_Em

не нужно. Lua изучается за полчаса. по мере необходимости (крайне редко) можно заглядывать в справочник. он настолько прост, что с ним справляются даже обычные юзеры. единственное, надо немного потренироваться интегрировать его в С. но это тоже фигня.

Iron_Bug ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.