5 ms·
In general I agree with your sentiment, but getopt is one where I'm willing to make an exception. getopt_long is barely any actual code, and honestly its design
by DSMan195276 12y ago
In general I agree with your sentiment, but getopt is one where I'm willing to make an exception. getopt_long is barely any actual code, and honestly its design stinks for an argument parser. It's also just standard C (IE. No platform issues to worry about assuming you're going to get argv and argc). I've written my own argument parser in just around 100 lines that's pretty similar to getopt and so far it's been well worth it.
- JoshTriplett 12y agoDoes your hand-written parser handle all the corner cases getopt does? Ending option processing with "--"? Interleaving options in any order (ls foo -l)? Stacking short options (ls -la) or writing them separately (ls -l -a)?
- DSMan195276 12y agoI had to go check if it does '--', but yes it does all of those things you listed. My parser is similar to getopt, but it's less clunky and avoids the duplication that getopt_long results in.
- JoshTriplett 12y agoThank you for your diligence, then; most hand-written parsers fail one or more of those. > less clunky and avoids the duplication that getopt_long results in. Duplication because of the ugly flag/val logic, which in practice is typically passed as either NULL, 's' (long option for short option 's') or NULL, OPTION_FOO (long option with no short option, OPTION_FOO > 255)? Yeah, that does seem silly. I think they did that to simplify the setting of boolean parameters, by passing &some_flag, 1, but that seems woefully insufficient when you need to handle arguments. I'd love to have a C library as capable as Python's argparse, instead.
- DSMan195276 12y agoOf course, I wasn't going to half-do it if I was gonna replace getopt. I'm with you in that I get annoyed when I run into programs which do just half-done job at a getopt replacement and you can't do the normal stuff like "-df" instead of "-d -f". And yes, that's pretty much what I'm getting at. The issue really stems down to the fact that getopt_long is just bolted on to getopt, so there's still the string short-opt syntax like "sf:t", and then you duplicate the options in the array of long opts with the chars or some random number > 255 otherwise. The string is really the most annoying part because there's no good way to generate it via the C preprocessor that I could come-up with, leading to some duplication between the long-opts and short-opts. It also can't easily generate help text for you from your arguments, which bugged me. My argument parser basically works off of a single xmacro header that holds all the argument information for getopt (Which gets organized via a few macros into an enum and an array). It's dead simple to add new arguments and there's no duplication or separate strings or etc. that you have to update at the same time besides adding code to handle that argument. Personally, I wrote my argument parser specifically because I couldn't find any that I was happy with after looking around. They were either clunky to use (getopt_long), or were full libraries and seemed like it would be a hassle to get it integrated into my code. I'd love to see a 'standard' argument parser that works with long options well and doesn't just feel like an afterthought like it does with getopt_long, but I think the chance to make such a thing has been missed. Personally, if I would ever use such a thing then it needs to be a single or just a few .c and .h files that I can stick directly into my program. I wouldn't want to have to bet on the distribution having it or not, and I'm not going to add a separate dependency just for argument parsing.
- lsaferite 12y agoIs this parser open source? If so, why not post a link?
- DSMan195276 12y agoWell you can find it in here: https://github.com/DSMan195276/cmips https://github.com/DSMan195276/cmips I don't have it as a separate project specifically for the argument parser which is why I didn't link to it. But the meat of the parser is in ./common/arg_parse.c, with the header for it in ./include/common/arg_parse.h. If you want to throw it into your own project you'll want to take a quick look through the ./arg_parse.c and modify it to suit your project (The help text specifically is for my program, so you'll want to rewrite the text in that part). You can see an 'example' usage in the same repo. The files listed below parse the arguments into a single struct with few flags inside, and also look for filenames in the arguments to load into the emulator: ./cmips/args.c ./cmips/args.h ./cmips/args.x ./cmips/args.x is a xmacro header. It mostly just contains the contents of the struct arg array for this program, but it's also used to create enum entries which index the struct arg array. The 'parse_args' function is fairly similar to what you'd do with getopt, just with the 'arg_parser' function instead. The argument parser code could probably be improved. Just looking back at it, it's got a bit to much logic going on in that single function, it could probably be split up a bit. I'm gonna be working on this project again pretty soon I think, so I might fix up this parser along with it.