URI: 
       tAllow Imlib2 cache size to be controlled with command line argument - croptool - Image cropping tool
  HTML git clone git://lumidify.org/croptool.git (fast, but not encrypted)
  HTML git clone https://lumidify.org/git/croptool.git (encrypted, but very slow)
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
   DIR commit 6ac1850fa404420f18bcea62c5cefcfd7d575a1a
   DIR parent ab4ae60ad89cba4cca0d2f9b802628358fefaf0a
  HTML Author: lumidify <nobody@lumidify.org>
       Date:   Tue, 21 Sep 2021 15:45:59 +0200
       
       Allow Imlib2 cache size to be controlled with command line argument
       
       Diffstat:
         M croptool.1                          |       5 +++++
         M croptool.c                          |      35 +++++++++++++++++++++++--------
       
       2 files changed, 31 insertions(+), 9 deletions(-)
       ---
   DIR diff --git a/croptool.1 b/croptool.1
       t@@ -51,6 +51,11 @@ Default: #000000.
        .It Fl s Ar color
        Set the secondary color for the cropping rectangle.
        Default: #FFFFFF.
       +.It Fl z Ar size
       +Set the Imlib2 in-memory cache to
       +.Ar size
       +MiB (valid values: 0-1024).
       +Default: 4.
        .El
        .Sh OUTPUT FORMAT
        The cropping commands for each image are output using the format given by
   DIR diff --git a/croptool.c b/croptool.c
       t@@ -57,6 +57,8 @@ static short SELECTION_REDRAW = 1;
          %f: Filename of image.
        */
        static const char *CMD_FORMAT = "croptool_crop %wx%h+%l+%t '%f'";
       +/* Size of Imlib2 in-memory cache in MiB */
       +static int CACHE_SIZE = 4;
        
        extern char *optarg;
        extern int optind;
       t@@ -159,7 +161,7 @@ static void button_release(void);
        static void button_press(XEvent event);
        static void key_press(XEvent event);
        static void queue_update(int x, int y, int w, int h);
       -static int parse_small_positive_int(const char *str, int *value);
       +static int parse_int(const char *str, int min, int max, int *value);
        
        static void
        usage(void) {
       t@@ -172,7 +174,7 @@ int
        main(int argc, char *argv[]) {
                char c;
        
       -        while ((c = getopt(argc, argv, "f:w:c:mrp:s:")) != -1) {
       +        while ((c = getopt(argc, argv, "f:w:c:mrp:s:z:")) != -1) {
                        switch (c) {
                        case 'f':
                                CMD_FORMAT = optarg;
       t@@ -190,17 +192,23 @@ main(int argc, char *argv[]) {
                                SELECTION_COLOR2 = optarg;
                                break;
                        case 'c':
       -                        if (parse_small_positive_int(optarg, &COLLISION_PADDING)) {
       +                        if (parse_int(optarg, 1, 99, &COLLISION_PADDING)) {
                                        fprintf(stderr, "Invalid collision padding.\n");
                                        exit(1);
                                }
                                break;
                        case 'w':
       -                        if (parse_small_positive_int(optarg, &LINE_WIDTH)) {
       +                        if (parse_int(optarg, 1, 99, &LINE_WIDTH)) {
                                        fprintf(stderr, "Invalid line width.\n");
                                        exit(1);
                                }
                                break;
       +                case 'z':
       +                        if (parse_int(optarg, 0, 1024, &CACHE_SIZE)) {
       +                                fprintf(stderr, "Invalid cache size.\n");
       +                                exit(1);
       +                        }
       +                        break;
                        default:
                                usage();
                                exit(1);
       t@@ -410,7 +418,13 @@ setup(int argc, char *argv[]) {
                cursors.bottomright = XCreateFontCursor(state.dpy, XC_bottom_right_corner);
                cursors.grab = XCreateFontCursor(state.dpy, XC_fleur);
        
       -        imlib_set_cache_size(2048 * 2048);
       +        /* note: since CACHE_SIZE is <= 1024, this definitely fits in long */
       +        long cs = (unsigned long long)CACHE_SIZE * 1024 * 1024;
       +        if (cs > INT_MAX) {
       +                fprintf(stderr, "Cache size would cause integer overflow.\n");
       +                exit(1);
       +        }
       +        imlib_set_cache_size((int)cs);
                imlib_set_color_usage(128);
                imlib_context_set_dither(1);
                imlib_context_set_display(state.dpy);
       t@@ -511,16 +525,19 @@ print_cmd(const char *filename, int x, int y, int w, int h, int dry_run) {
                }
        }
        
       -/* Parses integer between 0 and 100 (non-inclusive).
       +/* Parse integer between min and max (inclusive).
           Returns 1 on error, 0 otherwise.
       -   The result is stored in *value. */
       +   The result is stored in *value.
       +   Based on OpenBSD's strtonum. */
        static int
       -parse_small_positive_int(const char *str, int *value) {
       +parse_int(const char *str, int min, int max, int *value) {
                char *end;
                long l = strtol(str, &end, 10);
       +        if (min > max)
       +                return 1;
                if (str == end || *end != '\0') {
                        return 1; 
       -        } else if (l <= 0 || l >= 100 || ((l == LONG_MIN ||
       +        } else if (l < min || l > max || ((l == LONG_MIN ||
                    l == LONG_MAX) && errno == ERANGE)) {
                        return 1;
                }