comparison src/strings.c @ 25567:0082503ff2ff v8.2.3320

patch 8.2.3320: some local functions are not static Commit: https://github.com/vim/vim/commit/8ee52affe7fd4daa03e002bc06611f0a8c3bcd5b Author: Yegappan Lakshmanan <yegappan@yahoo.com> Date: Mon Aug 9 19:59:06 2021 +0200 patch 8.2.3320: some local functions are not static Problem: Some local functions are not static. Solution: Add "static". Move snprintf() related code to strings.c. (Yegappan Lakshmanan, closes #8734)
author Bram Moolenaar <Bram@vim.org>
date Mon, 09 Aug 2021 20:00:06 +0200
parents e8e2c4d33b9b
children 000b37efd5fa
comparison
equal deleted inserted replaced
25566:e1c7aa26ddf5 25567:0082503ff2ff
9 9
10 /* 10 /*
11 * strings.c: string manipulation functions 11 * strings.c: string manipulation functions
12 */ 12 */
13 13
14 #define USING_FLOAT_STUFF
14 #include "vim.h" 15 #include "vim.h"
15 16
16 /* 17 /*
17 * Copy "string" into newly allocated memory. 18 * Copy "string" into newly allocated memory.
18 */ 19 */
75 char_u *p2; 76 char_u *p2;
76 char_u *escaped_string; 77 char_u *escaped_string;
77 unsigned length; 78 unsigned length;
78 int l; 79 int l;
79 80
80 /* 81 // First count the number of backslashes required.
81 * First count the number of backslashes required. 82 // Then allocate the memory and insert them.
82 * Then allocate the memory and insert them.
83 */
84 length = 1; // count the trailing NUL 83 length = 1; // count the trailing NUL
85 for (p = string; *p; p++) 84 for (p = string; *p; p++)
86 { 85 {
87 if (has_mbyte && (l = (*mb_ptr2len)(p)) > 1) 86 if (has_mbyte && (l = (*mb_ptr2len)(p)) > 1)
88 { 87 {
1263 } 1262 }
1264 else 1263 else
1265 len = slen - nbyte; // default: all bytes that are available. 1264 len = slen - nbyte; // default: all bytes that are available.
1266 } 1265 }
1267 1266
1268 /* 1267 // Only return the overlap between the specified part and the actual
1269 * Only return the overlap between the specified part and the actual 1268 // string.
1270 * string.
1271 */
1272 if (nbyte < 0) 1269 if (nbyte < 0)
1273 { 1270 {
1274 len += nbyte; 1271 len += nbyte;
1275 nbyte = 0; 1272 nbyte = 0;
1276 } 1273 }
1666 } 1663 }
1667 rettv->vval.v_string = vim_strnsave(head, tail - head); 1664 rettv->vval.v_string = vim_strnsave(head, tail - head);
1668 } 1665 }
1669 1666
1670 #endif 1667 #endif
1668
1669 #if defined(FEAT_EVAL)
1670 static char *e_printf = N_("E766: Insufficient arguments for printf()");
1671
1672 /*
1673 * Get number argument from "idxp" entry in "tvs". First entry is 1.
1674 */
1675 static varnumber_T
1676 tv_nr(typval_T *tvs, int *idxp)
1677 {
1678 int idx = *idxp - 1;
1679 varnumber_T n = 0;
1680 int err = FALSE;
1681
1682 if (tvs[idx].v_type == VAR_UNKNOWN)
1683 emsg(_(e_printf));
1684 else
1685 {
1686 ++*idxp;
1687 n = tv_get_number_chk(&tvs[idx], &err);
1688 if (err)
1689 n = 0;
1690 }
1691 return n;
1692 }
1693
1694 /*
1695 * Get string argument from "idxp" entry in "tvs". First entry is 1.
1696 * If "tofree" is NULL tv_get_string_chk() is used. Some types (e.g. List)
1697 * are not converted to a string.
1698 * If "tofree" is not NULL echo_string() is used. All types are converted to
1699 * a string with the same format as ":echo". The caller must free "*tofree".
1700 * Returns NULL for an error.
1701 */
1702 static char *
1703 tv_str(typval_T *tvs, int *idxp, char_u **tofree)
1704 {
1705 int idx = *idxp - 1;
1706 char *s = NULL;
1707 static char_u numbuf[NUMBUFLEN];
1708
1709 if (tvs[idx].v_type == VAR_UNKNOWN)
1710 emsg(_(e_printf));
1711 else
1712 {
1713 ++*idxp;
1714 if (tofree != NULL)
1715 s = (char *)echo_string(&tvs[idx], tofree, numbuf, get_copyID());
1716 else
1717 s = (char *)tv_get_string_chk(&tvs[idx]);
1718 }
1719 return s;
1720 }
1721
1722 # ifdef FEAT_FLOAT
1723 /*
1724 * Get float argument from "idxp" entry in "tvs". First entry is 1.
1725 */
1726 static double
1727 tv_float(typval_T *tvs, int *idxp)
1728 {
1729 int idx = *idxp - 1;
1730 double f = 0;
1731
1732 if (tvs[idx].v_type == VAR_UNKNOWN)
1733 emsg(_(e_printf));
1734 else
1735 {
1736 ++*idxp;
1737 if (tvs[idx].v_type == VAR_FLOAT)
1738 f = tvs[idx].vval.v_float;
1739 else if (tvs[idx].v_type == VAR_NUMBER)
1740 f = (double)tvs[idx].vval.v_number;
1741 else
1742 emsg(_("E807: Expected Float argument for printf()"));
1743 }
1744 return f;
1745 }
1746 # endif
1747 #endif
1748
1749 #ifdef FEAT_FLOAT
1750 /*
1751 * Return the representation of infinity for printf() function:
1752 * "-inf", "inf", "+inf", " inf", "-INF", "INF", "+INF" or " INF".
1753 */
1754 static const char *
1755 infinity_str(int positive,
1756 char fmt_spec,
1757 int force_sign,
1758 int space_for_positive)
1759 {
1760 static const char *table[] =
1761 {
1762 "-inf", "inf", "+inf", " inf",
1763 "-INF", "INF", "+INF", " INF"
1764 };
1765 int idx = positive * (1 + force_sign + force_sign * space_for_positive);
1766
1767 if (ASCII_ISUPPER(fmt_spec))
1768 idx += 4;
1769 return table[idx];
1770 }
1771 #endif
1772
1773 /*
1774 * This code was included to provide a portable vsnprintf() and snprintf().
1775 * Some systems may provide their own, but we always use this one for
1776 * consistency.
1777 *
1778 * This code is based on snprintf.c - a portable implementation of snprintf
1779 * by Mark Martinec <mark.martinec@ijs.si>, Version 2.2, 2000-10-06.
1780 * Included with permission. It was heavily modified to fit in Vim.
1781 * The original code, including useful comments, can be found here:
1782 * http://www.ijs.si/software/snprintf/
1783 *
1784 * This snprintf() only supports the following conversion specifiers:
1785 * s, c, d, u, o, x, X, p (and synonyms: i, D, U, O - see below)
1786 * with flags: '-', '+', ' ', '0' and '#'.
1787 * An asterisk is supported for field width as well as precision.
1788 *
1789 * Limited support for floating point was added: 'f', 'F', 'e', 'E', 'g', 'G'.
1790 *
1791 * Length modifiers 'h' (short int) and 'l' (long int) and 'll' (long long int)
1792 * are supported. NOTE: for 'll' the argument is varnumber_T or uvarnumber_T.
1793 *
1794 * The locale is not used, the string is used as a byte string. This is only
1795 * relevant for double-byte encodings where the second byte may be '%'.
1796 *
1797 * It is permitted for "str_m" to be zero, and it is permitted to specify NULL
1798 * pointer for resulting string argument if "str_m" is zero (as per ISO C99).
1799 *
1800 * The return value is the number of characters which would be generated
1801 * for the given input, excluding the trailing NUL. If this value
1802 * is greater or equal to "str_m", not all characters from the result
1803 * have been stored in str, output bytes beyond the ("str_m"-1) -th character
1804 * are discarded. If "str_m" is greater than zero it is guaranteed
1805 * the resulting string will be NUL-terminated.
1806 */
1807
1808 /*
1809 * When va_list is not supported we only define vim_snprintf().
1810 *
1811 * vim_vsnprintf_typval() can be invoked with either "va_list" or a list of
1812 * "typval_T". When the latter is not used it must be NULL.
1813 */
1814
1815 // When generating prototypes all of this is skipped, cproto doesn't
1816 // understand this.
1817 #ifndef PROTO
1818
1819 // Like vim_vsnprintf() but append to the string.
1820 int
1821 vim_snprintf_add(char *str, size_t str_m, const char *fmt, ...)
1822 {
1823 va_list ap;
1824 int str_l;
1825 size_t len = STRLEN(str);
1826 size_t space;
1827
1828 if (str_m <= len)
1829 space = 0;
1830 else
1831 space = str_m - len;
1832 va_start(ap, fmt);
1833 str_l = vim_vsnprintf(str + len, space, fmt, ap);
1834 va_end(ap);
1835 return str_l;
1836 }
1837
1838 int
1839 vim_snprintf(char *str, size_t str_m, const char *fmt, ...)
1840 {
1841 va_list ap;
1842 int str_l;
1843
1844 va_start(ap, fmt);
1845 str_l = vim_vsnprintf(str, str_m, fmt, ap);
1846 va_end(ap);
1847 return str_l;
1848 }
1849
1850 int
1851 vim_vsnprintf(
1852 char *str,
1853 size_t str_m,
1854 const char *fmt,
1855 va_list ap)
1856 {
1857 return vim_vsnprintf_typval(str, str_m, fmt, ap, NULL);
1858 }
1859
1860 int
1861 vim_vsnprintf_typval(
1862 char *str,
1863 size_t str_m,
1864 const char *fmt,
1865 va_list ap,
1866 typval_T *tvs)
1867 {
1868 size_t str_l = 0;
1869 const char *p = fmt;
1870 int arg_idx = 1;
1871
1872 if (p == NULL)
1873 p = "";
1874 while (*p != NUL)
1875 {
1876 if (*p != '%')
1877 {
1878 char *q = strchr(p + 1, '%');
1879 size_t n = (q == NULL) ? STRLEN(p) : (size_t)(q - p);
1880
1881 // Copy up to the next '%' or NUL without any changes.
1882 if (str_l < str_m)
1883 {
1884 size_t avail = str_m - str_l;
1885
1886 mch_memmove(str + str_l, p, n > avail ? avail : n);
1887 }
1888 p += n;
1889 str_l += n;
1890 }
1891 else
1892 {
1893 size_t min_field_width = 0, precision = 0;
1894 int zero_padding = 0, precision_specified = 0, justify_left = 0;
1895 int alternate_form = 0, force_sign = 0;
1896
1897 // If both the ' ' and '+' flags appear, the ' ' flag should be
1898 // ignored.
1899 int space_for_positive = 1;
1900
1901 // allowed values: \0, h, l, L
1902 char length_modifier = '\0';
1903
1904 // temporary buffer for simple numeric->string conversion
1905 # if defined(FEAT_FLOAT)
1906 # define TMP_LEN 350 // On my system 1e308 is the biggest number possible.
1907 // That sounds reasonable to use as the maximum
1908 // printable.
1909 # else
1910 # define TMP_LEN 66
1911 # endif
1912 char tmp[TMP_LEN];
1913
1914 // string address in case of string argument
1915 const char *str_arg = NULL;
1916
1917 // natural field width of arg without padding and sign
1918 size_t str_arg_l;
1919
1920 // unsigned char argument value - only defined for c conversion.
1921 // N.B. standard explicitly states the char argument for the c
1922 // conversion is unsigned
1923 unsigned char uchar_arg;
1924
1925 // number of zeros to be inserted for numeric conversions as
1926 // required by the precision or minimal field width
1927 size_t number_of_zeros_to_pad = 0;
1928
1929 // index into tmp where zero padding is to be inserted
1930 size_t zero_padding_insertion_ind = 0;
1931
1932 // current conversion specifier character
1933 char fmt_spec = '\0';
1934
1935 // buffer for 's' and 'S' specs
1936 char_u *tofree = NULL;
1937
1938
1939 p++; // skip '%'
1940
1941 // parse flags
1942 while (*p == '0' || *p == '-' || *p == '+' || *p == ' '
1943 || *p == '#' || *p == '\'')
1944 {
1945 switch (*p)
1946 {
1947 case '0': zero_padding = 1; break;
1948 case '-': justify_left = 1; break;
1949 case '+': force_sign = 1; space_for_positive = 0; break;
1950 case ' ': force_sign = 1;
1951 // If both the ' ' and '+' flags appear, the ' '
1952 // flag should be ignored
1953 break;
1954 case '#': alternate_form = 1; break;
1955 case '\'': break;
1956 }
1957 p++;
1958 }
1959 // If the '0' and '-' flags both appear, the '0' flag should be
1960 // ignored.
1961
1962 // parse field width
1963 if (*p == '*')
1964 {
1965 int j;
1966
1967 p++;
1968 j =
1969 # if defined(FEAT_EVAL)
1970 tvs != NULL ? tv_nr(tvs, &arg_idx) :
1971 # endif
1972 va_arg(ap, int);
1973 if (j >= 0)
1974 min_field_width = j;
1975 else
1976 {
1977 min_field_width = -j;
1978 justify_left = 1;
1979 }
1980 }
1981 else if (VIM_ISDIGIT((int)(*p)))
1982 {
1983 // size_t could be wider than unsigned int; make sure we treat
1984 // argument like common implementations do
1985 unsigned int uj = *p++ - '0';
1986
1987 while (VIM_ISDIGIT((int)(*p)))
1988 uj = 10 * uj + (unsigned int)(*p++ - '0');
1989 min_field_width = uj;
1990 }
1991
1992 // parse precision
1993 if (*p == '.')
1994 {
1995 p++;
1996 precision_specified = 1;
1997 if (*p == '*')
1998 {
1999 int j;
2000
2001 j =
2002 # if defined(FEAT_EVAL)
2003 tvs != NULL ? tv_nr(tvs, &arg_idx) :
2004 # endif
2005 va_arg(ap, int);
2006 p++;
2007 if (j >= 0)
2008 precision = j;
2009 else
2010 {
2011 precision_specified = 0;
2012 precision = 0;
2013 }
2014 }
2015 else if (VIM_ISDIGIT((int)(*p)))
2016 {
2017 // size_t could be wider than unsigned int; make sure we
2018 // treat argument like common implementations do
2019 unsigned int uj = *p++ - '0';
2020
2021 while (VIM_ISDIGIT((int)(*p)))
2022 uj = 10 * uj + (unsigned int)(*p++ - '0');
2023 precision = uj;
2024 }
2025 }
2026
2027 // parse 'h', 'l' and 'll' length modifiers
2028 if (*p == 'h' || *p == 'l')
2029 {
2030 length_modifier = *p;
2031 p++;
2032 if (length_modifier == 'l' && *p == 'l')
2033 {
2034 // double l = __int64 / varnumber_T
2035 length_modifier = 'L';
2036 p++;
2037 }
2038 }
2039 fmt_spec = *p;
2040
2041 // common synonyms:
2042 switch (fmt_spec)
2043 {
2044 case 'i': fmt_spec = 'd'; break;
2045 case 'D': fmt_spec = 'd'; length_modifier = 'l'; break;
2046 case 'U': fmt_spec = 'u'; length_modifier = 'l'; break;
2047 case 'O': fmt_spec = 'o'; length_modifier = 'l'; break;
2048 default: break;
2049 }
2050
2051 # if defined(FEAT_EVAL)
2052 switch (fmt_spec)
2053 {
2054 case 'd': case 'u': case 'o': case 'x': case 'X':
2055 if (tvs != NULL && length_modifier == '\0')
2056 length_modifier = 'L';
2057 }
2058 # endif
2059
2060 // get parameter value, do initial processing
2061 switch (fmt_spec)
2062 {
2063 // '%' and 'c' behave similar to 's' regarding flags and field
2064 // widths
2065 case '%':
2066 case 'c':
2067 case 's':
2068 case 'S':
2069 str_arg_l = 1;
2070 switch (fmt_spec)
2071 {
2072 case '%':
2073 str_arg = p;
2074 break;
2075
2076 case 'c':
2077 {
2078 int j;
2079
2080 j =
2081 # if defined(FEAT_EVAL)
2082 tvs != NULL ? tv_nr(tvs, &arg_idx) :
2083 # endif
2084 va_arg(ap, int);
2085 // standard demands unsigned char
2086 uchar_arg = (unsigned char)j;
2087 str_arg = (char *)&uchar_arg;
2088 break;
2089 }
2090
2091 case 's':
2092 case 'S':
2093 str_arg =
2094 # if defined(FEAT_EVAL)
2095 tvs != NULL ? tv_str(tvs, &arg_idx, &tofree) :
2096 # endif
2097 va_arg(ap, char *);
2098 if (str_arg == NULL)
2099 {
2100 str_arg = "[NULL]";
2101 str_arg_l = 6;
2102 }
2103 // make sure not to address string beyond the specified
2104 // precision !!!
2105 else if (!precision_specified)
2106 str_arg_l = strlen(str_arg);
2107 // truncate string if necessary as requested by precision
2108 else if (precision == 0)
2109 str_arg_l = 0;
2110 else
2111 {
2112 // Don't put the #if inside memchr(), it can be a
2113 // macro.
2114 // memchr on HP does not like n > 2^31 !!!
2115 char *q = memchr(str_arg, '\0',
2116 precision <= (size_t)0x7fffffffL ? precision
2117 : (size_t)0x7fffffffL);
2118 str_arg_l = (q == NULL) ? precision
2119 : (size_t)(q - str_arg);
2120 }
2121 if (fmt_spec == 'S')
2122 {
2123 if (min_field_width != 0)
2124 min_field_width += STRLEN(str_arg)
2125 - mb_string2cells((char_u *)str_arg, -1);
2126 if (precision)
2127 {
2128 char_u *p1;
2129 size_t i = 0;
2130
2131 for (p1 = (char_u *)str_arg; *p1;
2132 p1 += mb_ptr2len(p1))
2133 {
2134 i += (size_t)mb_ptr2cells(p1);
2135 if (i > precision)
2136 break;
2137 }
2138 str_arg_l = precision = p1 - (char_u *)str_arg;
2139 }
2140 }
2141 break;
2142
2143 default:
2144 break;
2145 }
2146 break;
2147
2148 case 'd': case 'u':
2149 case 'b': case 'B':
2150 case 'o':
2151 case 'x': case 'X':
2152 case 'p':
2153 {
2154 // NOTE: the u, b, o, x, X and p conversion specifiers
2155 // imply the value is unsigned; d implies a signed
2156 // value
2157
2158 // 0 if numeric argument is zero (or if pointer is
2159 // NULL for 'p'), +1 if greater than zero (or nonzero
2160 // for unsigned arguments), -1 if negative (unsigned
2161 // argument is never negative)
2162 int arg_sign = 0;
2163
2164 // only set for length modifier h, or for no length
2165 // modifiers
2166 int int_arg = 0;
2167 unsigned int uint_arg = 0;
2168
2169 // only set for length modifier l
2170 long int long_arg = 0;
2171 unsigned long int ulong_arg = 0;
2172
2173 // only set for length modifier ll
2174 varnumber_T llong_arg = 0;
2175 uvarnumber_T ullong_arg = 0;
2176
2177 // only set for b conversion
2178 uvarnumber_T bin_arg = 0;
2179
2180 // pointer argument value -only defined for p
2181 // conversion
2182 void *ptr_arg = NULL;
2183
2184 if (fmt_spec == 'p')
2185 {
2186 length_modifier = '\0';
2187 ptr_arg =
2188 # if defined(FEAT_EVAL)
2189 tvs != NULL ? (void *)tv_str(tvs, &arg_idx,
2190 NULL) :
2191 # endif
2192 va_arg(ap, void *);
2193 if (ptr_arg != NULL)
2194 arg_sign = 1;
2195 }
2196 else if (fmt_spec == 'b' || fmt_spec == 'B')
2197 {
2198 bin_arg =
2199 # if defined(FEAT_EVAL)
2200 tvs != NULL ?
2201 (uvarnumber_T)tv_nr(tvs, &arg_idx) :
2202 # endif
2203 va_arg(ap, uvarnumber_T);
2204 if (bin_arg != 0)
2205 arg_sign = 1;
2206 }
2207 else if (fmt_spec == 'd')
2208 {
2209 // signed
2210 switch (length_modifier)
2211 {
2212 case '\0':
2213 case 'h':
2214 // char and short arguments are passed as int.
2215 int_arg =
2216 # if defined(FEAT_EVAL)
2217 tvs != NULL ? tv_nr(tvs, &arg_idx) :
2218 # endif
2219 va_arg(ap, int);
2220 if (int_arg > 0)
2221 arg_sign = 1;
2222 else if (int_arg < 0)
2223 arg_sign = -1;
2224 break;
2225 case 'l':
2226 long_arg =
2227 # if defined(FEAT_EVAL)
2228 tvs != NULL ? tv_nr(tvs, &arg_idx) :
2229 # endif
2230 va_arg(ap, long int);
2231 if (long_arg > 0)
2232 arg_sign = 1;
2233 else if (long_arg < 0)
2234 arg_sign = -1;
2235 break;
2236 case 'L':
2237 llong_arg =
2238 # if defined(FEAT_EVAL)
2239 tvs != NULL ? tv_nr(tvs, &arg_idx) :
2240 # endif
2241 va_arg(ap, varnumber_T);
2242 if (llong_arg > 0)
2243 arg_sign = 1;
2244 else if (llong_arg < 0)
2245 arg_sign = -1;
2246 break;
2247 }
2248 }
2249 else
2250 {
2251 // unsigned
2252 switch (length_modifier)
2253 {
2254 case '\0':
2255 case 'h':
2256 uint_arg =
2257 # if defined(FEAT_EVAL)
2258 tvs != NULL ? (unsigned)
2259 tv_nr(tvs, &arg_idx) :
2260 # endif
2261 va_arg(ap, unsigned int);
2262 if (uint_arg != 0)
2263 arg_sign = 1;
2264 break;
2265 case 'l':
2266 ulong_arg =
2267 # if defined(FEAT_EVAL)
2268 tvs != NULL ? (unsigned long)
2269 tv_nr(tvs, &arg_idx) :
2270 # endif
2271 va_arg(ap, unsigned long int);
2272 if (ulong_arg != 0)
2273 arg_sign = 1;
2274 break;
2275 case 'L':
2276 ullong_arg =
2277 # if defined(FEAT_EVAL)
2278 tvs != NULL ? (uvarnumber_T)
2279 tv_nr(tvs, &arg_idx) :
2280 # endif
2281 va_arg(ap, uvarnumber_T);
2282 if (ullong_arg != 0)
2283 arg_sign = 1;
2284 break;
2285 }
2286 }
2287
2288 str_arg = tmp;
2289 str_arg_l = 0;
2290
2291 // NOTE:
2292 // For d, i, u, o, x, and X conversions, if precision is
2293 // specified, the '0' flag should be ignored. This is so
2294 // with Solaris 2.6, Digital UNIX 4.0, HPUX 10, Linux,
2295 // FreeBSD, NetBSD; but not with Perl.
2296 if (precision_specified)
2297 zero_padding = 0;
2298 if (fmt_spec == 'd')
2299 {
2300 if (force_sign && arg_sign >= 0)
2301 tmp[str_arg_l++] = space_for_positive ? ' ' : '+';
2302 // leave negative numbers for sprintf to handle, to
2303 // avoid handling tricky cases like (short int)-32768
2304 }
2305 else if (alternate_form)
2306 {
2307 if (arg_sign != 0
2308 && (fmt_spec == 'b' || fmt_spec == 'B'
2309 || fmt_spec == 'x' || fmt_spec == 'X') )
2310 {
2311 tmp[str_arg_l++] = '0';
2312 tmp[str_arg_l++] = fmt_spec;
2313 }
2314 // alternate form should have no effect for p
2315 // conversion, but ...
2316 }
2317
2318 zero_padding_insertion_ind = str_arg_l;
2319 if (!precision_specified)
2320 precision = 1; // default precision is 1
2321 if (precision == 0 && arg_sign == 0)
2322 {
2323 // When zero value is formatted with an explicit
2324 // precision 0, the resulting formatted string is
2325 // empty (d, i, u, b, B, o, x, X, p).
2326 }
2327 else
2328 {
2329 char f[6];
2330 int f_l = 0;
2331
2332 // construct a simple format string for sprintf
2333 f[f_l++] = '%';
2334 if (!length_modifier)
2335 ;
2336 else if (length_modifier == 'L')
2337 {
2338 # ifdef MSWIN
2339 f[f_l++] = 'I';
2340 f[f_l++] = '6';
2341 f[f_l++] = '4';
2342 # else
2343 f[f_l++] = 'l';
2344 f[f_l++] = 'l';
2345 # endif
2346 }
2347 else
2348 f[f_l++] = length_modifier;
2349 f[f_l++] = fmt_spec;
2350 f[f_l++] = '\0';
2351
2352 if (fmt_spec == 'p')
2353 str_arg_l += sprintf(tmp + str_arg_l, f, ptr_arg);
2354 else if (fmt_spec == 'b' || fmt_spec == 'B')
2355 {
2356 char b[8 * sizeof(uvarnumber_T)];
2357 size_t b_l = 0;
2358 uvarnumber_T bn = bin_arg;
2359
2360 do
2361 {
2362 b[sizeof(b) - ++b_l] = '0' + (bn & 0x1);
2363 bn >>= 1;
2364 }
2365 while (bn != 0);
2366
2367 memcpy(tmp + str_arg_l, b + sizeof(b) - b_l, b_l);
2368 str_arg_l += b_l;
2369 }
2370 else if (fmt_spec == 'd')
2371 {
2372 // signed
2373 switch (length_modifier)
2374 {
2375 case '\0': str_arg_l += sprintf(
2376 tmp + str_arg_l, f,
2377 int_arg);
2378 break;
2379 case 'h': str_arg_l += sprintf(
2380 tmp + str_arg_l, f,
2381 (short)int_arg);
2382 break;
2383 case 'l': str_arg_l += sprintf(
2384 tmp + str_arg_l, f, long_arg);
2385 break;
2386 case 'L': str_arg_l += sprintf(
2387 tmp + str_arg_l, f, llong_arg);
2388 break;
2389 }
2390 }
2391 else
2392 {
2393 // unsigned
2394 switch (length_modifier)
2395 {
2396 case '\0': str_arg_l += sprintf(
2397 tmp + str_arg_l, f,
2398 uint_arg);
2399 break;
2400 case 'h': str_arg_l += sprintf(
2401 tmp + str_arg_l, f,
2402 (unsigned short)uint_arg);
2403 break;
2404 case 'l': str_arg_l += sprintf(
2405 tmp + str_arg_l, f, ulong_arg);
2406 break;
2407 case 'L': str_arg_l += sprintf(
2408 tmp + str_arg_l, f, ullong_arg);
2409 break;
2410 }
2411 }
2412
2413 // include the optional minus sign and possible
2414 // "0x" in the region before the zero padding
2415 // insertion point
2416 if (zero_padding_insertion_ind < str_arg_l
2417 && tmp[zero_padding_insertion_ind] == '-')
2418 zero_padding_insertion_ind++;
2419 if (zero_padding_insertion_ind + 1 < str_arg_l
2420 && tmp[zero_padding_insertion_ind] == '0'
2421 && (tmp[zero_padding_insertion_ind + 1] == 'x'
2422 || tmp[zero_padding_insertion_ind + 1] == 'X'))
2423 zero_padding_insertion_ind += 2;
2424 }
2425
2426 {
2427 size_t num_of_digits = str_arg_l
2428 - zero_padding_insertion_ind;
2429
2430 if (alternate_form && fmt_spec == 'o'
2431 // unless zero is already the first
2432 // character
2433 && !(zero_padding_insertion_ind < str_arg_l
2434 && tmp[zero_padding_insertion_ind] == '0'))
2435 {
2436 // assure leading zero for alternate-form
2437 // octal numbers
2438 if (!precision_specified
2439 || precision < num_of_digits + 1)
2440 {
2441 // precision is increased to force the
2442 // first character to be zero, except if a
2443 // zero value is formatted with an
2444 // explicit precision of zero
2445 precision = num_of_digits + 1;
2446 }
2447 }
2448 // zero padding to specified precision?
2449 if (num_of_digits < precision)
2450 number_of_zeros_to_pad = precision - num_of_digits;
2451 }
2452 // zero padding to specified minimal field width?
2453 if (!justify_left && zero_padding)
2454 {
2455 int n = (int)(min_field_width - (str_arg_l
2456 + number_of_zeros_to_pad));
2457 if (n > 0)
2458 number_of_zeros_to_pad += n;
2459 }
2460 break;
2461 }
2462
2463 # ifdef FEAT_FLOAT
2464 case 'f':
2465 case 'F':
2466 case 'e':
2467 case 'E':
2468 case 'g':
2469 case 'G':
2470 {
2471 // Floating point.
2472 double f;
2473 double abs_f;
2474 char format[40];
2475 int l;
2476 int remove_trailing_zeroes = FALSE;
2477
2478 f =
2479 # if defined(FEAT_EVAL)
2480 tvs != NULL ? tv_float(tvs, &arg_idx) :
2481 # endif
2482 va_arg(ap, double);
2483 abs_f = f < 0 ? -f : f;
2484
2485 if (fmt_spec == 'g' || fmt_spec == 'G')
2486 {
2487 // Would be nice to use %g directly, but it prints
2488 // "1.0" as "1", we don't want that.
2489 if ((abs_f >= 0.001 && abs_f < 10000000.0)
2490 || abs_f == 0.0)
2491 fmt_spec = ASCII_ISUPPER(fmt_spec) ? 'F' : 'f';
2492 else
2493 fmt_spec = fmt_spec == 'g' ? 'e' : 'E';
2494 remove_trailing_zeroes = TRUE;
2495 }
2496
2497 if ((fmt_spec == 'f' || fmt_spec == 'F') &&
2498 # ifdef VAX
2499 abs_f > 1.0e38
2500 # else
2501 abs_f > 1.0e307
2502 # endif
2503 )
2504 {
2505 // Avoid a buffer overflow
2506 STRCPY(tmp, infinity_str(f > 0.0, fmt_spec,
2507 force_sign, space_for_positive));
2508 str_arg_l = STRLEN(tmp);
2509 zero_padding = 0;
2510 }
2511 else
2512 {
2513 if (isnan(f))
2514 {
2515 // Not a number: nan or NAN
2516 STRCPY(tmp, ASCII_ISUPPER(fmt_spec) ? "NAN"
2517 : "nan");
2518 str_arg_l = 3;
2519 zero_padding = 0;
2520 }
2521 else if (isinf(f))
2522 {
2523 STRCPY(tmp, infinity_str(f > 0.0, fmt_spec,
2524 force_sign, space_for_positive));
2525 str_arg_l = STRLEN(tmp);
2526 zero_padding = 0;
2527 }
2528 else
2529 {
2530 // Regular float number
2531 format[0] = '%';
2532 l = 1;
2533 if (force_sign)
2534 format[l++] = space_for_positive ? ' ' : '+';
2535 if (precision_specified)
2536 {
2537 size_t max_prec = TMP_LEN - 10;
2538
2539 // Make sure we don't get more digits than we
2540 // have room for.
2541 if ((fmt_spec == 'f' || fmt_spec == 'F')
2542 && abs_f > 1.0)
2543 max_prec -= (size_t)log10(abs_f);
2544 if (precision > max_prec)
2545 precision = max_prec;
2546 l += sprintf(format + l, ".%d", (int)precision);
2547 }
2548 format[l] = fmt_spec == 'F' ? 'f' : fmt_spec;
2549 format[l + 1] = NUL;
2550
2551 str_arg_l = sprintf(tmp, format, f);
2552 }
2553
2554 if (remove_trailing_zeroes)
2555 {
2556 int i;
2557 char *tp;
2558
2559 // Using %g or %G: remove superfluous zeroes.
2560 if (fmt_spec == 'f' || fmt_spec == 'F')
2561 tp = tmp + str_arg_l - 1;
2562 else
2563 {
2564 tp = (char *)vim_strchr((char_u *)tmp,
2565 fmt_spec == 'e' ? 'e' : 'E');
2566 if (tp != NULL)
2567 {
2568 // Remove superfluous '+' and leading
2569 // zeroes from the exponent.
2570 if (tp[1] == '+')
2571 {
2572 // Change "1.0e+07" to "1.0e07"
2573 STRMOVE(tp + 1, tp + 2);
2574 --str_arg_l;
2575 }
2576 i = (tp[1] == '-') ? 2 : 1;
2577 while (tp[i] == '0')
2578 {
2579 // Change "1.0e07" to "1.0e7"
2580 STRMOVE(tp + i, tp + i + 1);
2581 --str_arg_l;
2582 }
2583 --tp;
2584 }
2585 }
2586
2587 if (tp != NULL && !precision_specified)
2588 // Remove trailing zeroes, but keep the one
2589 // just after a dot.
2590 while (tp > tmp + 2 && *tp == '0'
2591 && tp[-1] != '.')
2592 {
2593 STRMOVE(tp, tp + 1);
2594 --tp;
2595 --str_arg_l;
2596 }
2597 }
2598 else
2599 {
2600 char *tp;
2601
2602 // Be consistent: some printf("%e") use 1.0e+12
2603 // and some 1.0e+012. Remove one zero in the last
2604 // case.
2605 tp = (char *)vim_strchr((char_u *)tmp,
2606 fmt_spec == 'e' ? 'e' : 'E');
2607 if (tp != NULL && (tp[1] == '+' || tp[1] == '-')
2608 && tp[2] == '0'
2609 && vim_isdigit(tp[3])
2610 && vim_isdigit(tp[4]))
2611 {
2612 STRMOVE(tp + 2, tp + 3);
2613 --str_arg_l;
2614 }
2615 }
2616 }
2617 if (zero_padding && min_field_width > str_arg_l
2618 && (tmp[0] == '-' || force_sign))
2619 {
2620 // padding 0's should be inserted after the sign
2621 number_of_zeros_to_pad = min_field_width - str_arg_l;
2622 zero_padding_insertion_ind = 1;
2623 }
2624 str_arg = tmp;
2625 break;
2626 }
2627 # endif
2628
2629 default:
2630 // unrecognized conversion specifier, keep format string
2631 // as-is
2632 zero_padding = 0; // turn zero padding off for non-numeric
2633 // conversion
2634 justify_left = 1;
2635 min_field_width = 0; // reset flags
2636
2637 // discard the unrecognized conversion, just keep *
2638 // the unrecognized conversion character
2639 str_arg = p;
2640 str_arg_l = 0;
2641 if (*p != NUL)
2642 str_arg_l++; // include invalid conversion specifier
2643 // unchanged if not at end-of-string
2644 break;
2645 }
2646
2647 if (*p != NUL)
2648 p++; // step over the just processed conversion specifier
2649
2650 // insert padding to the left as requested by min_field_width;
2651 // this does not include the zero padding in case of numerical
2652 // conversions
2653 if (!justify_left)
2654 {
2655 // left padding with blank or zero
2656 int pn = (int)(min_field_width - (str_arg_l + number_of_zeros_to_pad));
2657
2658 if (pn > 0)
2659 {
2660 if (str_l < str_m)
2661 {
2662 size_t avail = str_m - str_l;
2663
2664 vim_memset(str + str_l, zero_padding ? '0' : ' ',
2665 (size_t)pn > avail ? avail
2666 : (size_t)pn);
2667 }
2668 str_l += pn;
2669 }
2670 }
2671
2672 // zero padding as requested by the precision or by the minimal
2673 // field width for numeric conversions required?
2674 if (number_of_zeros_to_pad == 0)
2675 {
2676 // will not copy first part of numeric right now, *
2677 // force it to be copied later in its entirety
2678 zero_padding_insertion_ind = 0;
2679 }
2680 else
2681 {
2682 // insert first part of numerics (sign or '0x') before zero
2683 // padding
2684 int zn = (int)zero_padding_insertion_ind;
2685
2686 if (zn > 0)
2687 {
2688 if (str_l < str_m)
2689 {
2690 size_t avail = str_m - str_l;
2691
2692 mch_memmove(str + str_l, str_arg,
2693 (size_t)zn > avail ? avail
2694 : (size_t)zn);
2695 }
2696 str_l += zn;
2697 }
2698
2699 // insert zero padding as requested by the precision or min
2700 // field width
2701 zn = (int)number_of_zeros_to_pad;
2702 if (zn > 0)
2703 {
2704 if (str_l < str_m)
2705 {
2706 size_t avail = str_m - str_l;
2707
2708 vim_memset(str + str_l, '0',
2709 (size_t)zn > avail ? avail
2710 : (size_t)zn);
2711 }
2712 str_l += zn;
2713 }
2714 }
2715
2716 // insert formatted string
2717 // (or as-is conversion specifier for unknown conversions)
2718 {
2719 int sn = (int)(str_arg_l - zero_padding_insertion_ind);
2720
2721 if (sn > 0)
2722 {
2723 if (str_l < str_m)
2724 {
2725 size_t avail = str_m - str_l;
2726
2727 mch_memmove(str + str_l,
2728 str_arg + zero_padding_insertion_ind,
2729 (size_t)sn > avail ? avail : (size_t)sn);
2730 }
2731 str_l += sn;
2732 }
2733 }
2734
2735 // insert right padding
2736 if (justify_left)
2737 {
2738 // right blank padding to the field width
2739 int pn = (int)(min_field_width
2740 - (str_arg_l + number_of_zeros_to_pad));
2741
2742 if (pn > 0)
2743 {
2744 if (str_l < str_m)
2745 {
2746 size_t avail = str_m - str_l;
2747
2748 vim_memset(str + str_l, ' ',
2749 (size_t)pn > avail ? avail
2750 : (size_t)pn);
2751 }
2752 str_l += pn;
2753 }
2754 }
2755 vim_free(tofree);
2756 }
2757 }
2758
2759 if (str_m > 0)
2760 {
2761 // make sure the string is nul-terminated even at the expense of
2762 // overwriting the last character (shouldn't happen, but just in case)
2763 //
2764 str[str_l <= str_m - 1 ? str_l : str_m - 1] = '\0';
2765 }
2766
2767 if (tvs != NULL && tvs[arg_idx - 1].v_type != VAR_UNKNOWN)
2768 emsg(_("E767: Too many arguments to printf()"));
2769
2770 // Return the number of characters formatted (excluding trailing nul
2771 // character), that is, the number of characters that would have been
2772 // written to the buffer if it were large enough.
2773 return (int)str_l;
2774 }
2775
2776 #endif // PROTO