I had some free time this evening so I coded up the following quick patch
(on our OIIO 1.5).  It needs some massage to put it in the OIIO coding
format (indentation is off, etc...) and I duplicated some functions which I
bet with some refactoring could be much improved.  It also doesn't handle
checking for user-specified attributes (I have no idea what those are).
For my purposes, this is good enough, but I suspect you'll want to clean it
up if you end up committing it into OIIO.

In argparse.cpp, there is a memory leak if a user called parse(string), and
then parse(xargc, xargv).   I don't know what your rules are on c++11 for
OIIO 1.5, but this code would be way simpler if you could use
std::unique_ptr.  If you can use an alternative such as from boost, that
would work too.

Here's how it looks in action:

8:13% maketx ~/Desktop/IMG_1067.JPG --checknan --tile 32 128 -o "out of\
file.tx" -u
maketx: no update required for "out of\ file.tx"
8:13% maketx ~/Desktop/IMG_1067.JPG --checknan --tile 32 32 -o "out of\
file.tx" -u
8:13% maketx ~/Desktop/IMG_1067.JPG --checknan  -o "out of\ file.tx" -u
8:13% maketx ~/Desktop/IMG_1067.JPG --checknan -o "out file.tx" -u
8:13% maketx ~/Desktop/IMG_1067.JPG --checknan -o "out file.tx" -u
maketx: no update required for "out file.tx"
8:14% maketx ~/Desktop/IMG_1067.JPG -o "out file.tx" -u
8:14% maketx ~/Desktop/IMG_1067.JPG -o "out file.tx" -u
maketx: no update required for "out file.tx"
8:14% maketx ~/Desktop/IMG_1067.JPG  -u
8:14% maketx ~/Desktop/IMG_1067.JPG -u
maketx: no update required for "/Users/thiago/Desktop/IMG_1067.tx"
8:14% maketx -u ~/Desktop/IMG_1067.JPG
maketx: no update required for "/Users/thiago/Desktop/IMG_1067.tx"
8:14% maketx -u ~/Desktop/IMG_1067.JPG -v
maketx: no update required for "/Users/thiago/Desktop/IMG_1067.tx"

Thiago

On Tue, Dec 1, 2015 at 9:09 PM, Thiago Ize <[email protected]> wrote:

> deal :)
>
> On Tue, Dec 1, 2015 at 6:06 PM, Larry Gritz <[email protected]> wrote:
>
>> I'm busy but it also sounds pretty simple. Mainly I didn't want us both
>> to do it.
>>
>> How about this: whichever one of us gets around to starting it first,
>> send the other an email so they know not to redundantly do it.
>>
>>
>>
>> On Dec 1, 2015, at 4:28 PM, Thiago Ize <[email protected]> wrote:
>>
>> I haven't gotten around yet to fixing this.  Of course I won't complain
>> if you (or someone else) wants to tackle this.  If you're busy, just let me
>> know and I'll give it a shot.
>>
>> On Tue, Dec 1, 2015 at 5:17 PM, Larry Gritz <[email protected]> wrote:
>>
>>> I think this totally makes sense. The dumb -u behavior is probably just
>>> an artifact of having predated our current use of the metadata and the
>>> growing richness of command-line options.
>>>
>>> So are you proposing to do it, or are you requesting that I do it?
>>>
>>>
>>>
>>> On Dec 1, 2015, at 4:11 PM, Thiago Ize <[email protected]> wrote:
>>>
>>> That's exactly the solution I was imagining.
>>>
>>> I think it's less surprising to rebuild the .tx file if the arguments
>>> are different.  Right now users might be confused why their changes aren't
>>> taking effect.  After this, if users are trying to create the same file it
>>> will likely early exit and if they are trying something new, it will
>>> rebuild.  The wrong case (what surprises users) shifts from the image
>>> incorrectly still being outdated to the correct image being used through
>>> extra redundant work.  So trade incorrect image for correct but slower
>>> images.
>>>
>>> On Tue, Dec 1, 2015 at 5:01 PM, Larry Gritz <[email protected]> wrote:
>>>
>>>> The original meaning of -u is "skip the work if the source image is
>>>> older than the existing texture output." Dumb and simple! Also, easy to
>>>> understand and not prone to people wondering why it did or didn't succeed.
>>>> But yes, I totally see your point.
>>>>
>>>> You are proposing to try to make it much smarter: "skip the work if you
>>>> are reasonably certain that you'll get the same image as last time."
>>>>
>>>> I think this should be possible. The command line arguments are stored
>>>> in the metadata of the texture file! So I suppose it could parse that and
>>>> compare to the present command line arguments.
>>>>
>>>> The question is, will this produce a more subtle behavior that
>>>> inadvertently causes people to be frequently surprised or not understand
>>>> what it's doing?
>>>>
>>>>
>>>> On Dec 1, 2015, at 3:07 PM, Thiago Ize <[email protected]> wrote:
>>>>
>>>> I think my question is best explained through an example:
>>>>
>>>> $ maketx --colorconvert linear sRGB foo.png -o foo.tx
>>>> ... creates a foo.tx
>>>> $ maketx  -colorconvert linear linear  foo.png -o foo.tx -u
>>>> ... does nothing since timestamps are the same
>>>> $ maketx  -colorconvert linear linear  foo.png -o foo.tx -u
>>>> ... does nothing since timestamps are the same
>>>> $ maketx foo.png -o foo.tx -u
>>>> ... does nothing since timestamps are the same
>>>>
>>>> Wouldn't it be better if instead of just checking timestamps, it also
>>>> checked if the arguments used to create the .tx file are different?  Then
>>>> you'd get something like:
>>>>
>>>> $ maketx --colorconvert linear sRGB foo.png -o foo.tx
>>>> ... creates a foo.tx
>>>> $ maketx  -colorconvert linear linear  foo.png -o foo.tx -u
>>>> ... updates foo.tx
>>>> $ maketx  -colorconvert linear linear  foo.png -o foo.tx -u
>>>> ... does nothing since the resulting file would be the same
>>>> $ maketx foo.png -o foo.tx -u
>>>> ... updates file since arguments are different (let's not try to think
>>>> too hard about whether linear to linear would have done the same thing or
>>>> not).
>>>> $ maketx foo.png -o foo.tx -u
>>>> ... does nothing since the resulting file would be the same
>>>> $ maketx foo.png -u
>>>> ... ideally would do nothing, but I wouldn't be too upset if it updated.
>>>> $ maketx -u foo.png
>>>> ... do nothing.  We should ignore ordering differences when applicable
>>>>
>>>> I can imagine trying to handle all cases is rather complicated (such as
>>>> different arguments that produce the same image), but if we can at least
>>>> get the easy cases, and if in doubt, always do an update, I imagine that
>>>> would handle 99% of the use cases and would only have the drawback that
>>>> very rarely maketx would end up doing redundant work, which is annoying but
>>>> at least results in a correct file.
>>>>
>>>> Thiago
>>>> _______________________________________________
>>>> Oiio-dev mailing list
>>>> [email protected]
>>>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org
>>>>
>>>>
>>>> --
>>>> Larry Gritz
>>>> [email protected]
>>>>
>>>>
>>>>
>>>> _______________________________________________
>>>> Oiio-dev mailing list
>>>> [email protected]
>>>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org
>>>>
>>>>
>>> _______________________________________________
>>> Oiio-dev mailing list
>>> [email protected]
>>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org
>>>
>>>
>>> --
>>> Larry Gritz
>>> [email protected]
>>>
>>>
>>>
>>> _______________________________________________
>>> Oiio-dev mailing list
>>> [email protected]
>>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org
>>>
>>>
>> _______________________________________________
>> Oiio-dev mailing list
>> [email protected]
>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org
>>
>>
>> --
>> Larry Gritz
>> [email protected]
>>
>>
>>
>> _______________________________________________
>> Oiio-dev mailing list
>> [email protected]
>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org
>>
>>
>
diff --git a/src/include/OpenImageIO/argparse.h 
b/src/include/OpenImageIO/argparse.h
index 3bfc1dd..03230f8 100644
--- a/src/include/OpenImageIO/argparse.h
+++ b/src/include/OpenImageIO/argparse.h
@@ -160,6 +160,7 @@ public:
     /// With the options already set up, parse the command line.
     /// Return 0 if ok, -1 if it's a malformed command line.
     int parse (int argc, const char **argv);
+    int parse (std::string command_line);
 
     /// Return any error messages generated during the course of parse()
     /// (and clear any error flags).  If no error has occurred since the
@@ -174,6 +175,7 @@ public:
     /// Return the entire command-line as one string.
     ///
     std::string command_line () const;
+    const char** command_line (const std::string& s, int& argc) const;
 
 private:
     int m_argc;                           // a copy of the command line argc
@@ -182,6 +184,7 @@ private:
     ArgOption *m_global;                  // option for extra cmd line 
arguments
     std::string m_intro;
     std::vector<ArgOption *> m_option;
+    bool need_to_delete;
 
     ArgOption *find_option(const char *name);
     // void error (const char *format, ...)
diff --git a/src/libOpenImageIO/maketexture.cpp 
b/src/libOpenImageIO/maketexture.cpp
index d36fe3e..6003b5d 100644
--- a/src/libOpenImageIO/maketexture.cpp
+++ b/src/libOpenImageIO/maketexture.cpp
@@ -788,9 +788,327 @@ write_mipmap (ImageBufAlgo::MakeTextureMode mode,
     return true;
 }
 
+static std::vector<std::string> filenames;
+static int
+parse_files (int argc, const char *argv[])
+{
+    for (int i = 0;  i < argc;  i++)
+        filenames.push_back (argv[i]);
+    return 0;
+}
 
 
 static bool
+getmaketxargs (const std::string &commandline, ImageSpec &configspec)
+{
+    bool help = false;
+    // Basic runtime options
+    std::string dataformatname = "";
+    std::string fileformatname = "";
+    std::vector<std::string> mipimages;
+    int tile[3] = { 64, 64, 1 };  // FIXME if we ever support volume MIPmaps
+    std::string compression = "zip";
+    bool updatemode = false;
+    bool checknan = false;
+    std::string fixnan; // none, black, box3
+    bool set_full_to_pixels = false;
+    bool do_highlight_compensation = false;
+    std::string filtername;
+    // Options controlling file metadata or mipmap creation
+    float fovcot = 0.0f;
+    std::string wrap = "black";
+    std::string swrap;
+    std::string twrap;
+    bool doresize = false;
+    Imath::M44f Mcam(0.0f), Mscr(0.0f);  // Initialize to 0
+    bool separate = false;
+    bool nomipmap = false;
+    bool prman_metadata = false;
+    bool constant_color_detect = false;
+    bool monochrome_detect = false;
+    bool opaque_detect = false;
+    bool compute_average = true;
+    int nchannels = -1;
+    bool prman = false;
+    bool oiio = false;
+    bool ignore_unassoc = false;  // ignore unassociated alpha tags
+    bool unpremult = false;
+    bool sansattrib = false;
+    float sharpen = 0.0f;
+    std::string incolorspace;
+    std::string outcolorspace;
+    std::string channelnames;
+    std::vector<std::string> string_attrib_names, string_attrib_values;
+    std::vector<std::string> any_attrib_names, any_attrib_values;
+    filenames.clear();
+
+    bool verbose;
+    std::string outputfilename;
+    bool stats = false;
+    int nthreads = 0;    // default: use #cores threads if available
+    bool mipmapmode = false;
+    bool shadowmode = false;
+    bool envlatlmode = false;
+    bool envcubemode = false;
+    bool lightprobemode = false;
+
+
+    ArgParse ap;
+    ap.options ("maketx -- convert images to tiled, MIP-mapped textures\n"
+                OIIO_INTRO_STRING "\n"
+                "Usage:  maketx [options] file...",
+                  "%*", parse_files, "",
+                  "--help", &help, "Print help message",
+                  "-v", &verbose, "Verbose status messages",
+                  "-o %s", &outputfilename, "Output filename",
+                  "--new", NULL, "",
+                  "--old", NULL, "Old mode",
+                  "--threads %d", &nthreads, "Number of threads (default: 
#cores)",
+                  "-u", &updatemode, "Update mode",
+                  "--format %s", &fileformatname, "Specify output file format 
(default: guess from extension)",
+                  "--nchannels %d", &nchannels, "Specify the number of output 
image channels.",
+                  "--chnames %s", &channelnames, "Rename channels 
(comma-separated)",
+                  "-d %s", &dataformatname, "Set the output data format to one 
of: "
+                          "uint8, sint8, uint16, sint16, half, float",
+                  "--tile %d %d", &tile[0], &tile[1], "Specify tile size",
+                  "--separate", &separate, "Use planarconfig separate 
(default: contiguous)",
+                  "--compression %s", &compression, "Set the compression 
method (default = zip, if possible)",
+                  "--fovcot %f", &fovcot, "Override the frame aspect ratio. 
Default is width/height.",
+                  "--wrap %s", &wrap, "Specify wrap mode (black, clamp, 
periodic, mirror)",
+                  "--swrap %s", &swrap, "Specific s wrap mode separately",
+                  "--twrap %s", &twrap, "Specific t wrap mode separately",
+                  "--resize", &doresize, "Resize textures to power of 2 
(default: no)",
+                  "--noresize %!", &doresize, "Do not resize textures to power 
of 2 (deprecated)",
+                  "--filter %s", &filtername, "",
+                  "--hicomp", &do_highlight_compensation,
+                          "Compress HDR range before resize, expand after.",
+                  "--sharpen %f", &sharpen, "Sharpen MIP levels (default = 0.0 
= no)",
+                  "--nomipmap", &nomipmap, "Do not make multiple MIP-map 
levels",
+                  "--checknan", &checknan, "Check for NaN/Inf values (abort if 
found)",
+                  "--fixnan %s", &fixnan, "Attempt to fix NaN/Inf values in 
the image (options: none, black, box3)",
+                  "--fullpixels", &set_full_to_pixels, "Set the 'full' image 
range to be the pixel data window",
+                  "--Mcamera %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f",
+                          &Mcam[0][0], &Mcam[0][1], &Mcam[0][2], &Mcam[0][3], 
+                          &Mcam[1][0], &Mcam[1][1], &Mcam[1][2], &Mcam[1][3], 
+                          &Mcam[2][0], &Mcam[2][1], &Mcam[2][2], &Mcam[2][3], 
+                          &Mcam[3][0], &Mcam[3][1], &Mcam[3][2], &Mcam[3][3], 
+                          "Set the camera matrix",
+                  "--Mscreen %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f",
+                          &Mscr[0][0], &Mscr[0][1], &Mscr[0][2], &Mscr[0][3], 
+                          &Mscr[1][0], &Mscr[1][1], &Mscr[1][2], &Mscr[1][3], 
+                          &Mscr[2][0], &Mscr[2][1], &Mscr[2][2], &Mscr[2][3], 
+                          &Mscr[3][0], &Mscr[3][1], &Mscr[3][2], &Mscr[3][3], 
+                          "Set the screen matrix",
+                  "--hash", NULL, "",
+                  "--prman-metadata", &prman_metadata, "Add prman specific 
metadata",
+                  "--attrib %L %L", &any_attrib_names, &any_attrib_values, 
"Sets metadata attribute (name, value)",
+                  "--sattrib %L %L", &string_attrib_names, 
&string_attrib_values, "Sets string metadata attribute (name, value)",
+                  "--sansattrib", &sansattrib, "Write command line into 
Software & ImageHistory but remove --sattrib and --attrib options",
+                  "--constant-color-detect", &constant_color_detect, "Create 
1-tile textures from constant color inputs",
+                  "--monochrome-detect", &monochrome_detect, "Create 1-channel 
textures from monochrome inputs",
+                  "--opaque-detect", &opaque_detect, "Drop alpha channel that 
is always 1.0",
+                  "--no-compute-average %!", &compute_average, "Don't compute 
and store average color",
+                  "--ignore-unassoc", &ignore_unassoc, "Ignore unassociated 
alpha tags in input (don't autoconvert)",
+                  "--stats", &stats, "Print runtime statistics",
+                  "--mipimage %L", &mipimages, "Specify an individual MIP 
level",
+                  "<SEPARATOR>", "Basic modes (default is plain texture):",
+                  "--shadow", &shadowmode, "Create shadow map",
+                  "--envlatl", &envlatlmode, "Create lat/long environment map",
+                  "--lightprobe", &lightprobemode, "Create lat/long 
environment map from a light probe",
+//                  "--envcube", &envcubemode, "Create cubic env map (file 
order: px, nx, py, ny, pz, nz) (UNIMP)",
+                  "<SEPARATOR>", "",
+                  "--colorconvert %s %s", &incolorspace, &outcolorspace,
+                          "",
+                  "--unpremult", &unpremult, "Unpremultiply before color 
conversion, then premultiply "
+                          "after the color conversion.  You'll probably want 
to use this flag "
+                          "if your image contains an alpha channel.",
+                  "<SEPARATOR>", "Configuration Presets",
+                  "--prman", &prman, "Use PRMan-safe settings for tile size, 
planarconfig, and metadata.",
+                  "--oiio", &oiio, "Use OIIO-optimized settings for tile size, 
planarconfig, metadata.",
+                  NULL);
+    if (ap.parse (commandline) < 0) {
+        std::cerr << ap.geterror() << std::endl;
+        ap.usage ();
+        return false;
+    }
+
+    int optionsum = ((int)shadowmode + (int)envlatlmode + (int)envcubemode +
+                     (int)lightprobemode);
+    if (optionsum > 1) {
+        std::cerr << "maketx ERROR: At most one of the following options may 
be set:\n"
+                  << "\t--shadow --envlatl --envcube --lightprobe\n";
+        ap.usage ();
+        return false;
+    }
+    if (optionsum == 0)
+        mipmapmode = true;
+    
+    if (prman && oiio) {
+        std::cerr << "maketx ERROR: '--prman' compatibility, and '--oiio' 
optimizations are mutually exclusive.\n";
+        std::cerr << "\tIf you'd like both prman and oiio compatibility, you 
should choose --prman\n";
+        std::cerr << "\t(at the expense of oiio-specific optimizations)\n";
+        ap.usage ();
+        return false;
+    }
+
+    // Figure out which data format we want for output
+    if (! dataformatname.empty()) {
+        if (dataformatname == "uint8")
+            configspec.format = TypeDesc::UINT8;
+        else if (dataformatname == "int8" || dataformatname == "sint8")
+            configspec.format = TypeDesc::INT8;
+        else if (dataformatname == "uint16")
+            configspec.format = TypeDesc::UINT16;
+        else if (dataformatname == "int16" || dataformatname == "sint16")
+            configspec.format = TypeDesc::INT16;
+        else if (dataformatname == "half")
+            configspec.format = TypeDesc::HALF;
+        else if (dataformatname == "float")
+            configspec.format = TypeDesc::FLOAT;
+        else if (dataformatname == "double")
+            configspec.format = TypeDesc::DOUBLE;
+        else {
+            std::cerr << "maketx ERROR: unknown data format \"" << 
dataformatname << "\"\n";
+            return false;
+        }
+    }
+
+    configspec.tile_width  = tile[0];
+    configspec.tile_height = tile[1];
+    configspec.tile_depth  = tile[2];
+    configspec.attribute ("compression", compression);
+    if (fovcot != 0.0f)
+        configspec.attribute ("fovcot", fovcot);
+    configspec.attribute ("planarconfig", separate ? "separate" : "contig");
+    if (Mcam != Imath::M44f(0.0f))
+        configspec.attribute ("worldtocamera", TypeDesc::TypeMatrix, &Mcam);
+    if (Mscr != Imath::M44f(0.0f))
+        configspec.attribute ("worldtoscreen", TypeDesc::TypeMatrix, &Mscr);
+    std::string wrapmodes = (swrap.size() ? swrap : wrap) + ',' + 
+                            (twrap.size() ? twrap : wrap);
+    configspec.attribute ("wrapmodes", wrapmodes);
+
+    configspec.attribute ("maketx:verbose", verbose);
+    configspec.attribute ("maketx:stats", stats);
+    configspec.attribute ("maketx:resize", doresize);
+    configspec.attribute ("maketx:nomipmap", nomipmap);
+    configspec.attribute ("maketx:updatemode", updatemode);
+    configspec.attribute ("maketx:constant_color_detect", 
constant_color_detect);
+    configspec.attribute ("maketx:monochrome_detect", monochrome_detect);
+    configspec.attribute ("maketx:opaque_detect", opaque_detect);
+    configspec.attribute ("maketx:compute_average", compute_average);
+    configspec.attribute ("maketx:unpremult", unpremult);
+    configspec.attribute ("maketx:incolorspace", incolorspace);
+    configspec.attribute ("maketx:outcolorspace", outcolorspace);
+    configspec.attribute ("maketx:checknan", checknan);
+    configspec.attribute ("maketx:fixnan", fixnan);
+    configspec.attribute ("maketx:set_full_to_pixels", set_full_to_pixels);
+    configspec.attribute ("maketx:highlightcomp", 
(int)do_highlight_compensation);
+    configspec.attribute ("maketx:sharpen", sharpen);
+    if (filtername.size())
+        configspec.attribute ("maketx:filtername", filtername);
+    configspec.attribute ("maketx:nchannels", nchannels);
+    configspec.attribute ("maketx:channelnames", channelnames);
+    if (fileformatname.size())
+        configspec.attribute ("maketx:fileformatname", fileformatname);
+    configspec.attribute ("maketx:prman_metadata", prman_metadata);
+    configspec.attribute ("maketx:oiio_options", oiio);
+    configspec.attribute ("maketx:prman_options", prman);
+    if (mipimages.size())
+        configspec.attribute ("maketx:mipimages", 
Strutil::join(mipimages,";"));
+
+    // Add user-specified string attributes
+    for (size_t i = 0; i < string_attrib_names.size(); ++i) {
+        configspec.attribute (string_attrib_names[i], string_attrib_values[i]);
+    }
+
+    // Add user-specified "any" attributes -- try to deduce the type
+    for (size_t i = 0; i < any_attrib_names.size(); ++i) {
+        string_view s = any_attrib_values[i];
+        // Does it parse as an int (and nothing more?)
+        int ival;
+        if (Strutil::parse_int(s,ival)) {
+            Strutil::skip_whitespace(s);
+            if (! s.size()) {
+                configspec.attribute (any_attrib_names[i], ival);
+                continue;
+            }
+        }
+        s = any_attrib_values[i];
+        // Does it parse as a float (and nothing more?)
+        float fval;
+        if (Strutil::parse_float(s,fval)) {
+            Strutil::skip_whitespace(s);
+            if (! s.size()) {
+                configspec.attribute (any_attrib_names[i], fval);
+                continue;
+            }
+        }
+        // OK, treat it like a string
+        configspec.attribute (any_attrib_names[i], any_attrib_values[i]);
+    }
+
+    if (ignore_unassoc) {
+        configspec.attribute ("maketx:ignore_unassoc", (int)ignore_unassoc);
+        ImageCache *ic = ImageCache::create ();  // get the shared one
+        ic->attribute ("unassociatedalpha", (int)ignore_unassoc);
+    }
+    return true;
+}
+
+static bool attrib_int_equal(const char* name, const ImageSpec& src, const 
ImageSpec& dst)
+{
+   return src.get_int_attribute(name) == dst.get_int_attribute(name);
+}
+static bool attrib_flt_equal(const char* name, const ImageSpec& src, const 
ImageSpec& dst)
+{
+   return src.get_float_attribute(name) == dst.get_float_attribute(name);
+}
+static bool attrib_str_equal(const char* name, const ImageSpec& src, const 
ImageSpec& dst)
+{
+   return src.get_string_attribute(name) == dst.get_string_attribute(name);
+}
+static bool compare_maketx_flags(const ImageSpec& src, const ImageSpec& dst)
+{
+   return
+      src.tile_width == dst.tile_width &&
+      src.tile_height == dst.tile_height &&
+      src.tile_depth == dst.tile_depth &&
+      src.format == dst.format &&
+      attrib_str_equal("compression", src, dst) &&
+      attrib_int_equal("fovcot", src, dst) &&
+      attrib_str_equal("planarconfig", src, dst) &&
+      attrib_int_equal("worldtocamera", src, dst) &&
+      attrib_int_equal("worldtoscreen", src, dst) &&
+      attrib_str_equal("wrapmodes", src, dst) &&
+      attrib_int_equal("maketx:resize", src, dst) &&
+      attrib_int_equal("maketx:nomipmap", src, dst) &&
+      attrib_int_equal("maketx:constant_color_detect", src, dst) &&
+      attrib_int_equal("maketx:monochrome_detect", src, dst) &&
+      attrib_int_equal("maketx:opaque_detect", src, dst) &&
+      attrib_int_equal("maketx:compute_average", src, dst) &&
+      attrib_int_equal("maketx:unpremult", src, dst) &&
+      attrib_str_equal("maketx:incolorspace", src, dst) &&
+      attrib_str_equal("maketx:outcolorspace", src, dst) &&
+      attrib_int_equal("maketx:checknan", src, dst) &&
+      attrib_int_equal("maketx:fixnan", src, dst) &&
+      attrib_int_equal("maketx:set_full_to_pixels", src, dst) &&
+      attrib_int_equal("maketx:highlightcomp", src, dst) &&
+      attrib_flt_equal("maketx:sharpen", src, dst) &&
+      attrib_str_equal("maketx:filtername", src, dst) &&
+      attrib_int_equal("maketx:nchannels", src, dst) &&
+      attrib_str_equal("maketx:channelnames", src, dst) &&
+      attrib_str_equal("maketx:fileformatname", src, dst) &&
+      attrib_int_equal("maketx:prman_metadata", src, dst) &&
+      attrib_int_equal("maketx:oiio_options", src, dst) &&
+      attrib_int_equal("maketx:prman_options", src, dst) &&
+      attrib_str_equal("maketx:mipimages", src, dst) &&
+      attrib_int_equal("maketx:ignore_unassoc", src, dst);
+
+   // TODO: need to handle user-specified attributes
+}
+
+static bool
 make_texture_impl (ImageBufAlgo::MakeTextureMode mode,
                    const ImageBuf *input,
                    std::string filename,
@@ -877,9 +1195,30 @@ make_texture_impl (ImageBufAlgo::MakeTextureMode mode,
         in_time = Filesystem::last_write_time (src->name());
         if (updatemode && Filesystem::exists (outputfilename) &&
             (in_time == Filesystem::last_write_time (outputfilename))) {
-            outstream << "maketx: no update required for \"" 
-                      << outputfilename << "\"\n";
-            return true;
+
+           // We have same timestamps, but what if we want to make the texture
+           // with different settings from last time?
+           ImageSpec out_spec;
+           ImageInput *input = ImageInput::open(outputfilename);
+           std::string history = input->spec().get_string_attribute 
("Software");
+           input->close();
+
+           size_t maketx_start = history.find("maketx ");
+           if (maketx_start != std::string::npos) {
+              history = history.substr(maketx_start);
+
+              ImageSpec out_configspec;
+              bool success = getmaketxargs(history, out_configspec);
+
+              if (success) {
+                 success = compare_maketx_flags(configspec, out_configspec);
+                 if (success) { 
+                    outstream << "maketx: no update required for \"" 
+                              << outputfilename << "\"\n";
+                    return true;
+                 }
+              }
+           }
         }
     }
 
diff --git a/src/libutil/argparse.cpp b/src/libutil/argparse.cpp
index dcf35bc..a3c5d3b 100644
--- a/src/libutil/argparse.cpp
+++ b/src/libutil/argparse.cpp
@@ -320,7 +320,7 @@ ArgOption::add_argument (const char *argv)
 
 
 ArgParse::ArgParse (int argc, const char **argv)
-    : m_argc(argc), m_argv(argv), m_global(NULL)
+    : m_argc(argc), m_argv(argv), m_global(NULL), need_to_delete(false)
 {
 }
 
@@ -332,8 +332,27 @@ ArgParse::~ArgParse()
         ArgOption *opt = m_option[i];
         delete opt;
     }
+    if (need_to_delete) {
+       for (int i=0; i < m_argc; ++i)
+          delete[] m_argv[i];
+       delete[] m_argv;
+    }
 }
 
+int
+ArgParse::parse (std::string s)
+{
+   if (need_to_delete) {
+      for (int i=0; i < m_argc; ++i)
+         delete[] m_argv[i];
+      delete[] m_argv;
+      m_argc = 0;
+      m_argv = NULL;
+   }
+   need_to_delete = true;
+   m_argv = command_line(s, m_argc);
+   return parse(m_argc, m_argv);
+}
 
 
 // Top level command line parsing function called after all options
@@ -555,7 +574,46 @@ ArgParse::command_line () const
     return s;
 }
 
-
+// The caller must delete the returned char**.  Would be much better to instead
+// use std::unique_ptr
+const char** ArgParse::command_line (const std::string& s, int& argc) const
+{
+   // the command_line that returns a std::string will wrap all multiple word
+   // arguments in quotation marks, so we can assume that is all we need to
+   // handle here. We will also assume simple args, so no escaped quotation
+   // marks, tabs, or other weirdness.
+   std::vector<std::string> args;
+   std::string arg;
+   for (size_t i=0; i < s.size(); ++i) {
+      for (; s[i] == ' '; ++i); // consume spaces
+
+      // was the end all white space?
+      if (i >= s.size())
+         break;
+
+      size_t end;
+
+      if (s[i] == '\"') // quoted arg?
+         end = s.find_first_of('\"', i+1);
+      else
+         end = s.find_first_of(' ', i);
+
+      if (end == std::string::npos)
+         end = s.size();
+      arg = s.substr(i, end-i);
+      args.push_back(arg);
+      i = end;
+   }
+
+   argc = static_cast<int>(args.size());
+   char** argv = new char*[argc];
+   for (int i=0; i < argc; ++i)
+   {
+      argv[i] = new char[args[i].size()+1];
+      memcpy(argv[i], args[i].c_str(), args[i].size()+1);
+   }
+   return const_cast<const char**>(argv);
+}
 
 }
 OIIO_NAMESPACE_EXIT
_______________________________________________
Oiio-dev mailing list
[email protected]
http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org

Reply via email to