Mercurial > vim
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 |