So I want to write a C++ program to automate Avisynth script making given some filenames. Before you start pointing me to scripts, lemme just say I wanna practice my C++.

usage: ./program name episodestart episodeend files

1. The program assumes that the shell will provide a sorted list of files when a wildcard is used, for instance *.mkv. Is this a reasonable assumption?

2. The output should look like name-episodecount.avs. I had the bright idea to use C++, so luckily I get the convenience of C++ string classes. However, I can't figure out how to format the string - it isn't any of the following:

1. Assuming that the shell will give you a sorted list of names is reasonable if this will only be executed on *NIX platforms. On Windows it is the app's responsibility to expand wildcards.

2. My personal preference for stuff like this would actually be Python. C/C++ has always been a bit clunky for string manipulation. Madman's approach will get the job done, but the C++ stream I/O model is rather brain-dead. I actually drop back to C idiom and use sprintf/snprintf/vsprintf/vsnprintf whenever I need to do stuff like that in C++, just because I find the C++ stream libraries so utterly detestable.

The years just pass like trains. I wave, but they don't slow down.-- Steven Wilson

just brew it! wrote:2. My personal preference for stuff like this would actually be Python. C/C++ has always been a bit clunky for string manipulation. Madman's approach will get the job done, but the C++ stream I/O model is rather brain-dead. I actually drop back to C idiom and use sprintf/snprintf/vsprintf/vsnprintf whenever I need to do stuff like that in C++, just because I find the C++ stream libraries so utterly detestable.

They are actually not that bad. The problem now with the printf-family is that you have to pretty much know the buffer size ahead of time and if you don't, you are looking at potential buffer-overflow situations. The idea of the stream library is pretty good is that I think they do smarter buffer reallocation if the text you are appending is going to exceed the buffer. Also assuming proper C++ exception handling in place, you don't have to use the older style check error code business and you get the nicer std::exception getting thrown if something happens. Moreover, type conversion IMO is better handled with overloaded operator<<() than remembering esoteric %d, %l, %f, etc.

That said, if you are dumb enough to do this I will smack you in the head:

just brew it! wrote:2. My personal preference for stuff like this would actually be Python. C/C++ has always been a bit clunky for string manipulation. Madman's approach will get the job done, but the C++ stream I/O model is rather brain-dead. I actually drop back to C idiom and use sprintf/snprintf/vsprintf/vsnprintf whenever I need to do stuff like that in C++, just because I find the C++ stream libraries so utterly detestable.

They are actually not that bad.

We will have to agree to disagree then. The problem with the C++ stream library is that the format of the output is determined by hidden persistent state. You have to either A) set all of the formatting options every time you want to write something; or B) assume that all other code writing to the stream plays nice and saves/restores the formatting state. This is a glaring design flaw IMO.

The problem now with the printf-family is that you have to pretty much know the buffer size ahead of time and if you don't, you are looking at potential buffer-overflow situations.

Yes, you do need to know the buffer size ahead of time; but you need not be inviting buffer overflows. All modern runtime libraries support the 'n' variants (snprintf, etc.), which allow the buffer size to be explicitly passed in. Is this a perfect solution? No. But it is less painful than using the stream libraries.

The idea of the stream library is pretty good is that I think they do smarter buffer reallocation if the text you are appending is going to exceed the buffer. Also assuming proper C++ exception handling in place, you don't have to use the older style check error code business and you get the nicer std::exception getting thrown if something happens.

Heh... don't get me started. IMO the entire concept of using an overloaded << operator for formatted output falls into the category of gratuitous and overly clever use of operator overloading. This brain-dead design decision is also what forces us down the path of needing to maintain hidden format control state -- you can't pass additional optional arguments to an operator overload like you can to a member function.

It is almost as if the designers of the standard C++ I/O library said "Hey, hold my beer and watch this!"

The years just pass like trains. I wave, but they don't slow down.-- Steven Wilson

Question: c_str() converts from a C++ string object to a C string (an array of chars, I heard)? Why is that needed? Why should I even take the time to convert it to back to a character array (const char *aaa as Madman said)?It seems the arguments are provided as arrays of strings. Why do you call them arrays of chars, because if they are arrays of chars (which are C strings right) then each increment of the index should point to a different letter of the arguments?How do I convert from argv[1] to a string?

Crayon Shin Chan wrote:Question: c_str() converts from a C++ string object to a C string (an array of chars, I heard)? Why is that needed?

As I said, char* or char[] in C is just a pointer to a contiguous block of memory, not a real C++ object. std::string is an object. A lot of people who grew up on Java/C#/etc often miss this. Grab a good C book and really understand pointers please (definitely not going to recommend K&R, but "C Primer Plus" is good). So using .c_str() returns a const pointer (don't mess with it!) where you can pass in to functions that take const char*.

Crayon Shin Chan wrote:Why should I even take the time to convert it to back to a character array (const char *aaa as Madman said)?

I think he was just illustrating. When doing mixed C/C++, try to stay with C++ strings/stringstream until the last possible moment to do c_str(). If you don't need to pass into some C function then no need.

Crayon Shin Chan wrote:It seems the arguments are provided as arrays of strings. Why do you call them arrays of chars, because if they are arrays of chars (which are C strings right) then each increment of the index should point to a different letter of the arguments?

Again, char*/char[] != string objects. argv is actually an array of char pointers, which in theory each member can be pointing to different blocks of memory containing the arrays of characters all over your process space.

Crayon Shin Chan wrote:How do I convert from argv[1] to a string?

Either you use good old fashion s[n]printf (or s[n]printf_s on Windows with VC++) then you can stay with char*, or if you are going to use C++/Boost's real string functions, that is easy to do:

This constructs a new string object (separate storage in memory). In the general case of course you have to be careful of the implications of that memory allocation.

Re: printf vs iostream - These days I don't do much of that because of localization. It is almost either FormatMessage or boost::format. Of course for some quick internal concat and stuff I'm actually all for stringstream (strcat/strncat is now falling out of favour due to those now infamous overflows).

The Model M is not for the faint of heart. You either like them or hate them.

Crayon Shin Chan wrote:Question: c_str() converts from a C++ string object to a C string (an array of chars, I heard)? Why is that needed? Why should I even take the time to convert it to back to a character array (const char *aaa as Madman said)?It seems the arguments are provided as arrays of strings. Why do you call them arrays of chars, because if they are arrays of chars (which are C strings right) then each increment of the index should point to a different letter of the arguments?How do I convert from argv[1] to a string?

Technically they're arrays of pointers. Frankly, without a solid understanding of pointers, C++ is a waste of time and energy. I'd suggest getting a good book - C++ Primer by Stan Lippman is a great place to start.

Criticism? Any object oriented way of doing this? I'm aware that my code always looks very procedural, i.e. C-like. Not that there's a problem with that, but maybe it would be nice to jump on this OO bandwagon.

Also, I tried making the actual part that puts in the values into the text file a separate function, but I had real trouble passing my string/ostringstream objects into this function. Is it really necessary to convert an ostringstream into a string just so I can use string's c_str() function to pass it into a function?

just brew it! wrote:I actually drop back to C idiom and use sprintf/snprintf/vsprintf/vsnprintf whenever I need to do stuff like that in C++, just because I find the C++ stream libraries so utterly detestable.

You'd probably appreciate the Google C++ string-printf utility functions (this post is a bit late because I didn't realize that implementations were publicly available in Chrome until now). See stringprintf.h/cc and stringprintf_unittest.cc in Chromium's base library:http://src.chromium.org/svn/trunk/src/base/

There's StringPrintf (returns a new string), SStringPrintf (takes a pointer to the destination string as first argument), and StringAppendF. Since they just wrap sprintf, the behavior is the same, so they're super convenient. The only wart IMO is that passing actual C++ strings requires adding .c_str() to each one since printf style functions use C variadic functions (va_list and so forth) and C++ objects don't play nice with that (the C++ standard says that things passed in as va_arg must be POD -- plain old data -- which any non-trivial class is not). Still, on balance, I find it to be very convenient, especially since it's identical to sprintf and doesn't require you to add an entire new formatting library dependency to your project.