added string max length option for unit functions bUnit_AsString and bUnit_ReplaceString
authorCampbell Barton <ideasman42@gmail.com>
Thu, 13 Aug 2009 17:05:27 +0000 (17:05 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Thu, 13 Aug 2009 17:05:27 +0000 (17:05 +0000)
source/blender/blenkernel/BKE_unit.h
source/blender/blenkernel/intern/unit.c
source/blender/editors/interface/interface.c
source/blender/editors/transform/transform.c

index df29971867387e4d1f7afc4d6a1c44c90aa9d754..54d5bba057af80ffe5d720192c405d1bc1386c7c 100644 (file)
@@ -31,10 +31,10 @@ extern "C" {
 /* in all cases the value is assumed to be scaled by the user preference */
 
 /* humanly readable representation of a value in units (used for button drawing) */
-void   bUnit_AsString(char *str, double value, int prec, int system, int type, int split, int pad);
+void   bUnit_AsString(char *str, int len_max, double value, int prec, int system, int type, int split, int pad);
 
 /* replace units with values, used before python button evaluation */
-int            bUnit_ReplaceString(char *str, char *str_orig, char *str_prev, double scale_pref, int system, int type);
+int            bUnit_ReplaceString(char *str, int len_max, char *str_prev, double scale_pref, int system, int type);
 
 /* the size of the unit used for this value (used for calculating the ckickstep) */
 double bUnit_ClosestScalar(double value, int system, int type);
index dfec54eb5ea0871accd9f5e5cfdf6b9120247e2b..fde0ac5391dda75915ae2221e7191687766de2fa 100644 (file)
@@ -27,6 +27,8 @@
 #include <string.h>
 #include <math.h>
 
+#define TEMP_STR_SIZE 256
+
 /* define a single unit */
 typedef struct bUnitDef {
        char *name;
@@ -89,7 +91,7 @@ static struct bUnitDef buImperialLenDef[] = {
        {"thou", "Thous",                               "mil", NULL,0.0000254, 0.0,     B_UNIT_DEF_NONE},
        {NULL, NULL, NULL, NULL, 0.0, 0.0}
 };
-static struct bUnitCollection buImperialLenCollecton = {buImperialLenDef, 3, 0, sizeof(buImperialLenDef)/sizeof(bUnitDef)};
+static struct bUnitCollection buImperialLenCollecton = {buImperialLenDef, 4, 0, sizeof(buImperialLenDef)/sizeof(bUnitDef)};
 
 
 /* Time */
@@ -156,7 +158,7 @@ static void unit_dual_convert(double value, bUnitCollection *usys,
        *unit_b=        unit_best_fit(*value_b, usys, *unit_a, 1);
 }
 
-static int unit_as_string(char *str, double value, int prec, bUnitCollection *usys,
+static int unit_as_string(char *str, int len_max, double value, int prec, bUnitCollection *usys,
                /* non exposed options */
                bUnitDef *unit, char pad)
 {
@@ -178,32 +180,33 @@ static int unit_as_string(char *str, double value, int prec, bUnitCollection *us
 
        /* Convert to a string */
        {
-               char conv_str[5] = {'%', '.', '0'+prec, 'f', '\0'}; /* "%.2f" when prec is 2, must be under 10 */
-               len= sprintf(str, conv_str, (float)value_conv);
+               char conv_str[6] = {'%', '.', '0'+prec, 'l', 'f', '\0'}; /* "%.2lf" when prec is 2, must be under 10 */
+               len= snprintf(str, len_max, conv_str, (float)value_conv);
+
+               if(len >= len_max)
+                       len= len_max;
        }
        
-       
        /* Add unit prefix and strip zeros */
-       {
-               /* replace trailing zero's with spaces 
-                * so the number is less complicated but allignment in a button wont
-                * jump about while dragging */
-               int j;
-               i= len-1;
 
+       /* replace trailing zero's with spaces
+        * so the number is less complicated but allignment in a button wont
+        * jump about while dragging */
+       i= len-1;
+
+       while(i>0 && str[i]=='0') { /* 4.300 -> 4.3 */
+               str[i--]= pad;
+       }
+
+       if(i>0 && str[i]=='.') { /* 10. -> 10 */
+               str[i--]= pad;
+       }
        
-               while(i>0 && str[i]=='0') { /* 4.300 -> 4.3 */
-                       str[i--]= pad;
-               }
-               
-               if(i>0 && str[i]=='.') { /* 10. -> 10 */
-                       str[i--]= pad;
-               }
-               
-               /* Now add the suffix */
+       /* Now add the suffix */
+       if(i<len_max) {
+               int j=0;
                i++;
-               j=0;
-               while(unit->name_short[j]) {
+               while(unit->name_short[j] && (i < len_max)) {
                        str[i++]= unit->name_short[j++];
                }
 
@@ -212,21 +215,23 @@ static int unit_as_string(char *str, double value, int prec, bUnitCollection *us
                         * the unit name only used padded chars,
                         * In that case add padding for the name. */
 
-                       while(i<=len+j) {
+                       while(i<=len+j && (i < len_max)) {
                                str[i++]= pad;
                        }
                }
-               
-               /* terminate no matter whats done with padding above */
-               str[i] = '\0';
        }
 
+       /* terminate no matter whats done with padding above */
+       if(i >= len_max)
+               i= len_max-1;
+
+       str[i] = '\0';
        return i;
 }
 
 
 /* Used for drawing number buttons, try keep fast */
-void bUnit_AsString(char *str, double value, int prec, int system, int type, int split, int pad)
+void bUnit_AsString(char *str, int len_max, double value, int prec, int system, int type, int split, int pad)
 {
        bUnitCollection *usys = unit_get_system(system, type);
 
@@ -242,56 +247,111 @@ void bUnit_AsString(char *str, double value, int prec, int system, int type, int
 
                /* check the 2 is a smaller unit */
                if(unit_b > unit_a) {
-                       i= unit_as_string(str, value_a, prec, usys,  unit_a, '\0');
-                       str[i++]= ',';
-                       str[i++]= ' ';
+                       i= unit_as_string(str, len_max, value_a, prec, usys,  unit_a, '\0');
 
-                       /* use low precision since this is a smaller unit */
-                       unit_as_string(str+i, value_b, prec?1:0, usys,  unit_b, '\0');
+                       /* is there enough space for at least 1 char of the next unit? */
+                       if(i+3 < len_max) {
+                               str[i++]= ',';
+                               str[i++]= ' ';
+
+                               /* use low precision since this is a smaller unit */
+                               unit_as_string(str+i, len_max-i, value_b, prec?1:0, usys,  unit_b, '\0');
+                       }
                        return;
                }
        }
 
-       unit_as_string(str, value, prec, usys,    NULL, pad?' ':'\0');
+       unit_as_string(str, len_max, value, prec, usys,    NULL, pad?' ':'\0');
 }
 
 
-static int unit_scale_str(char *str, char *str_tmp, double scale_pref, bUnitDef *unit, char *replace_str)
+static char *unit_find_str(char *str, char *substr)
 {
        char *str_found;
-       int change= 0;
 
-       if(replace_str==NULL || replace_str[0] == '\0')
-               return 0;
+       if(substr && substr[0] != '\0') {
+               str_found= strstr(str, substr);
+               if(str_found) {
+                       /* previous char cannot be a letter */
+                       if (str_found == str || isalpha(*(str_found-1))==0) {
+                               /* next char cannot be alphanum */
+                               int len_name = strlen(substr);
 
-       if((str_found= strstr(str, replace_str))) {
-               /* previous char cannot be a letter */
-               if (str_found == str || isalpha(*(str_found-1))==0) {
-                       int len_name = strlen(replace_str);
-
-                       /* next char cannot be alphanum */
-                       if (!isalpha(*(str_found+len_name))) {
-                               int len= strlen(str);
-                               int len_num= sprintf(str_tmp, "*%g", unit->scalar/scale_pref);
-                               memmove(str_found+len_num, str_found+len_name, (len+1)-(int)((str_found+len_name)-str)); /* may grow or shrink the string, 1+ to copy the string terminator */
-                               memcpy(str_found, str_tmp, len_num); /* without the string terminator */
-                               change= 1;
+                               if (!isalpha(*(str_found+len_name))) {
+                                       return str_found;
+                               }
                        }
                }
+
        }
-       return change;
+       return NULL;
+
+}
+
+static int unit_scale_str(char *str, int len_max, char *str_tmp, double scale_pref, bUnitDef *unit, char *replace_str)
+{
+       char *str_found= unit_find_str(str, replace_str);
+
+       if(str_found) { /* XXX - investigate, does not respect len_max properly  */
+               int len, len_num, len_name, len_move, found_ofs;
+
+               found_ofs = (int)(str_found-str);
+
+               len= strlen(str);
+
+               len_name = strlen(replace_str);
+               len_move= (len - (found_ofs+len_name)) + 1; /* 1+ to copy the string terminator */
+               len_num= snprintf(str_tmp, TEMP_STR_SIZE, "*%lg", unit->scalar/scale_pref);
+
+               if(len_num > len_max)
+                       len_num= len_max;
+
+               if(found_ofs+len_num+len_move > len_max) {
+                       /* can't move the whole string, move just as much as will fit */
+                       len_move -= (found_ofs+len_num+len_move) - len_max;
+               }
+
+               if(len_move>0) {
+                       /* resize the last part of the string */
+                       memmove(str_found+len_num, str_found+len_name, len_move); /* may grow or shrink the string */
+               }
+
+               if(found_ofs+len_num > len_max) {
+                       /* not even the number will fit into the string, only copy part of it */
+                       len_num -= (found_ofs+len_num) - len_max;
+               }
+
+               if(len_num > 0) {
+                       /* its possible none of the number could be copied in */
+                       memcpy(str_found, str_tmp, len_num); /* without the string terminator */
+               }
+
+               str[len_max-1]= '\0'; /* since the null terminator wont be moved */
+               return 1;
+       }
+       return 0;
 }
 
-static int unit_replace(char *str, char *str_tmp, double scale_pref, bUnitDef *unit)
+static int unit_replace(char *str, int len_max, char *str_tmp, double scale_pref, bUnitDef *unit)
 {      
        int change= 0;
-       change |= unit_scale_str(str, str_tmp, scale_pref, unit, unit->name_short);
-       change |= unit_scale_str(str, str_tmp, scale_pref, unit, unit->name_plural);
-       change |= unit_scale_str(str, str_tmp, scale_pref, unit, unit->name_alt);
-       change |= unit_scale_str(str, str_tmp, scale_pref, unit, unit->name);
+       change |= unit_scale_str(str, len_max, str_tmp, scale_pref, unit, unit->name_short);
+       change |= unit_scale_str(str, len_max, str_tmp, scale_pref, unit, unit->name_plural);
+       change |= unit_scale_str(str, len_max, str_tmp, scale_pref, unit, unit->name_alt);
+       change |= unit_scale_str(str, len_max, str_tmp, scale_pref, unit, unit->name);
        return change;
 }
 
+static int unit_find(char *str, bUnitDef *unit)
+{
+       if (unit_find_str(str, unit->name_short))       return 1;
+       if (unit_find_str(str, unit->name_plural))      return 1;
+       if (unit_find_str(str, unit->name_alt))         return 1;
+       if (unit_find_str(str, unit->name))                     return 1;
+
+       return 0;
+}
+
 /* make a copy of the string that replaces the units with numbers
  * this is used before parsing
  * This is only used when evaluating user input and can afford to be a bit slower
@@ -304,15 +364,13 @@ static int unit_replace(char *str, char *str_tmp, double scale_pref, bUnitDef *u
  *
  * return true of a change was made.
  */
-int bUnit_ReplaceString(char *str, char *str_orig, char *str_prev, double scale_pref, int system, int type)
+int bUnit_ReplaceString(char *str, int len_max, char *str_prev, double scale_pref, int system, int type)
 {
        bUnitCollection *usys = unit_get_system(system, type);
 
        bUnitDef *unit;
-       char str_tmp[256];
+       char str_tmp[TEMP_STR_SIZE];
        int change= 0;
-       
-       strcpy(str, str_orig);
 
        if(usys==NULL || usys->units[0].name==NULL) {
                return 0;
@@ -324,7 +382,7 @@ int bUnit_ReplaceString(char *str, char *str_orig, char *str_prev, double scale_
                        continue;
 
                /* incase there are multiple instances */
-               while(unit_replace(str, str_tmp, scale_pref, unit))
+               while(unit_replace(str, len_max, str_tmp, scale_pref, unit))
                        change= 1;
        }
        unit= NULL;
@@ -343,7 +401,7 @@ int bUnit_ReplaceString(char *str, char *str_orig, char *str_prev, double scale_
                                                continue;
 
                                        /* incase there are multiple instances */
-                                       while(unit_replace(str, str_tmp, scale_pref, unit))
+                                       while(unit_replace(str, len_max, str_tmp, scale_pref, unit))
                                                change= 1;
                                }
                        }
@@ -355,25 +413,24 @@ int bUnit_ReplaceString(char *str, char *str_orig, char *str_prev, double scale_
                /* no units given so infer a unit from the previous string or default */
                if(str_prev) {
                        /* see which units the original value had */
-                       strcpy(str, str_prev); /* temp overwrite */
                        for(unit= usys->units; unit->name; unit++) {
 
                                if(unit->flag & B_UNIT_DEF_SUPPRESS)
                                        continue;
 
-                               if (unit_replace(str, str_tmp, scale_pref, unit))
+                               if (unit_find(str_prev, unit))
                                        break;
                        }
-                       strcpy(str, str_orig); /* temp overwrite */
                }
 
                if(unit==NULL)
                        unit= unit_default(usys);
 
                /* add the unit prefic and re-run */
-               sprintf(str_tmp, "%s %s", str, unit->name);
+               snprintf(str_tmp, sizeof(str_tmp), "%s %s", str, unit->name);
+               strncpy(str, str_tmp, len_max);
 
-               return bUnit_ReplaceString(str, str_tmp, NULL, scale_pref, system, type);
+               return bUnit_ReplaceString(str, len_max, NULL, scale_pref, system, type);
        }
 
        // printf("replace %s\n", str);
index bbdaad5fd5d9f6e0fbcdc6ec76193b84524d7596..ac26fe863642f4ca699723b047dc238772d44a3c 100644 (file)
@@ -1339,7 +1339,7 @@ static double ui_get_but_scale_unit(uiBut *but, double value)
        }
 }
 
-static void ui_get_but_string_unit(uiBut *but, char *str, double value, int pad)
+static void ui_get_but_string_unit(uiBut *but, char *str, int len_max, double value, int pad)
 {
        Scene *scene= CTX_data_scene((bContext *)but->block->evil_C);
        int do_split= scene->unit.flag & USER_UNIT_OPT_SPLIT;
@@ -1352,7 +1352,7 @@ static void ui_get_but_string_unit(uiBut *but, char *str, double value, int pad)
        if(precission>4)                precission= 4;
        else if(precission==0)  precission= 2;
 
-       bUnit_AsString(str, ui_get_but_scale_unit(but, value), precission, scene->unit.system, unit_type, do_split, pad);
+       bUnit_AsString(str, len_max, ui_get_but_scale_unit(but, value), precission, scene->unit.system, unit_type, do_split, pad);
 }
 
 static float ui_get_but_step_unit(uiBut *but, double value, float step_default)
@@ -1428,7 +1428,7 @@ void ui_get_but_string(uiBut *but, char *str, int maxlen)
 
                if(ui_is_but_float(but)) {
                        if(ui_is_but_unit(but)) {
-                               ui_get_but_string_unit(but, str, value, 0);
+                               ui_get_but_string_unit(but, str, maxlen, value, 0);
                        }
                        else if(but->a2) { /* amount of digits defined */
                                if(but->a2==1) BLI_snprintf(str, maxlen, "%.1f", value);
@@ -1505,21 +1505,20 @@ int ui_set_but_string(bContext *C, uiBut *but, const char *str)
 
 #ifndef DISABLE_PYTHON
                {
-                       Scene *scene= CTX_data_scene((bContext *)but->block->evil_C);
                        char str_unit_convert[256];
                        int unit_type;
-                               
-                       if (but->rnaprop)
-                               RNA_SUBTYPE_UNIT_VALUE(RNA_property_subtype(but->rnaprop));
+                       Scene *scene= CTX_data_scene((bContext *)but->block->evil_C);
+
+                       if(but->rnaprop)
+                               unit_type= RNA_SUBTYPE_UNIT_VALUE(RNA_property_subtype(but->rnaprop));
                        else
                                unit_type= 0;
-                       
+
+                       BLI_strncpy(str_unit_convert, str, sizeof(str_unit_convert));
+
                        if(scene->unit.system != USER_UNIT_NONE && unit_type) {
                                /* ugly, use the draw string to get the value, this could cause problems if it includes some text which resolves to a unit */
-                               bUnit_ReplaceString(str_unit_convert, (char *)str, but->drawstr, ui_get_but_scale_unit(but, 1.0), scene->unit.system, unit_type);
-                       }
-                       else {
-                               strcpy(str_unit_convert, str);
+                               bUnit_ReplaceString(str_unit_convert, sizeof(str_unit_convert), but->drawstr, ui_get_but_scale_unit(but, 1.0), scene->unit.system, unit_type);
                        }
 
                        if(BPY_button_eval(C, str_unit_convert, &value)) {
@@ -1875,9 +1874,9 @@ void ui_check_but(uiBut *but)
                        else if(value == -FLT_MAX) sprintf(but->drawstr, "%s-inf", but->str);
                        /* support length type buttons */
                        else if(ui_is_but_unit(but)) {
-                               char new_str[256];
-                               ui_get_but_string_unit(but, new_str, value, TRUE);
-                               sprintf(but->drawstr, "%s%s", but->str, new_str);
+                               char new_str[sizeof(but->drawstr)];
+                               ui_get_but_string_unit(but, new_str, sizeof(new_str), value, TRUE);
+                               snprintf(but->drawstr, sizeof(but->drawstr), "%s%s", but->str, new_str);
                        }
                        else if(but->a2) { /* amount of digits defined */
                                if(but->a2==1) sprintf(but->drawstr, "%s%.1f", but->str, value);
index 042e4a1941a46b31a15e2d295262a821bd8321e7..dd7cebdfe3f40ad379dbc0cf360ab601e87b1483 100644 (file)
@@ -3044,7 +3044,7 @@ static void headerTranslation(TransInfo *t, float vec[3], char *str) {
                        int i, do_split= t->scene->unit.flag & USER_UNIT_OPT_SPLIT ? 1:0;
 
                        for(i=0; i<3; i++)
-                               bUnit_AsString(&tvec[i*20], dvec[i]*t->scene->unit.scale_length, 4, t->scene->unit.system, B_UNIT_LENGTH, do_split, 1);
+                               bUnit_AsString(&tvec[i*20], 20, dvec[i]*t->scene->unit.scale_length, 4, t->scene->unit.system, B_UNIT_LENGTH, do_split, 1);
                }
                else {
                        sprintf(&tvec[0], "%.4f", dvec[0]);
@@ -3054,7 +3054,7 @@ static void headerTranslation(TransInfo *t, float vec[3], char *str) {
        }
 
        if(t->scene->unit.system)
-               bUnit_AsString(distvec, dist*t->scene->unit.scale_length, 4, t->scene->unit.system, B_UNIT_LENGTH, t->scene->unit.flag & USER_UNIT_OPT_SPLIT, 0);
+               bUnit_AsString(distvec, sizeof(distvec), dist*t->scene->unit.scale_length, 4, t->scene->unit.system, B_UNIT_LENGTH, t->scene->unit.flag & USER_UNIT_OPT_SPLIT, 0);
        else if( dist > 1e10 || dist < -1e10 )  /* prevent string buffer overflow */
                sprintf(distvec, "%.4e", dist);
        else