numpy 2.0.0
src/multiarray/numpyos.c File Reference
#include <Python.h>
#include <locale.h>
#include <stdio.h>
#include "numpy/arrayobject.h"
#include "numpy/npy_math.h"
#include "npy_config.h"
#include "numpy/npy_3kcompat.h"

Defines

#define PY_SSIZE_T_CLEAN
#define _MULTIARRAYMODULE
#define NPY_NO_PREFIX
#define MIN_EXPONENT_DIGITS   2
#define FLOAT_FORMATBUFLEN   120
#define _ASCII_FORMAT(type, suffix, print_type)
#define END_MATCH()   goto buffer_filled
#define NEXT_CHAR()
#define MATCH_ALPHA_STRING_NOCASE(string)
#define MATCH_ONE_OR_NONE(condition)   do { if (condition) NEXT_CHAR(); } while (0)
#define MATCH_ONE_OR_MORE(condition)
#define MATCH_ZERO_OR_MORE(condition)   while (condition) { NEXT_CHAR(); }

Functions

static void _ensure_minimum_exponent_length (char *buffer, size_t buf_size)
static void _ensure_decimal_point (char *buffer, size_t buf_size)
static void _change_decimal_from_locale_to_dot (char *buffer)
static int _check_ascii_format (const char *format)
static char * _fix_ascii_format (char *buf, size_t buflen, int decimal)
NPY_NO_EXPORT int NumPyOS_ascii_isspace (char c)
static int NumPyOS_ascii_isalpha (char c)
static int NumPyOS_ascii_isdigit (char c)
static int NumPyOS_ascii_isalnum (char c)
static char NumPyOS_ascii_tolower (char c)
static int NumPyOS_ascii_strncasecmp (const char *s1, const char *s2, size_t len)
static double NumPyOS_ascii_strtod_plain (const char *s, char **endptr)
NPY_NO_EXPORT double NumPyOS_ascii_strtod (const char *s, char **endptr)
NPY_NO_EXPORT int NumPyOS_ascii_ftolf (FILE *fp, double *value)

Define Documentation

#define _ASCII_FORMAT (   type,
  suffix,
  print_type 
)
NumPyOS_ascii_format*:
  • buffer: A buffer to place the resulting string in
  • buf_size: The length of the buffer.
  • format: The printf()-style format to use for the code to use for
System Message: WARNING/2 (<string>, line 5) Bullet list ends without a blank line; unexpected unindent.

converting.

  • value: The value to convert
  • decimal: if != 0, always has a decimal, and at leasat one digit after the decimal. This has the same effect as passing 'Z' in the origianl PyOS_ascii_formatd
This is similar to PyOS_ascii_formatd in python > 2.6, except that it does not handle 'n', and handles nan / inf.
Converts a #gdouble to a string, using the '.' as decimal point. To format the number you pass in a printf()-style format string. Allowed conversion specifiers are 'e', 'E', 'f', 'F', 'g', 'G'.
Return value: The pointer to the buffer with the converted string.
#define _MULTIARRAYMODULE
#define END_MATCH ( )    goto buffer_filled
#define FLOAT_FORMATBUFLEN   120
see FORMATBUFLEN in unicodeobject.c

Referenced by NumPyOS_ascii_strncasecmp().

#define MATCH_ALPHA_STRING_NOCASE (   string)
Value:
do {                                                                \
            for (p=(string); *p!='\0' && (c==*p || c+('a'-'A')==*p); ++p)   \
                NEXT_CHAR();                                                \
            if (*p != '\0') END_MATCH();                                    \
        } while (0)
#define MATCH_ONE_OR_MORE (   condition)
Value:
do {                                                                \
            ok = 0;                                                         \
            while (condition) { NEXT_CHAR(); ok = 1; }                      \
            if (!ok) END_MATCH();                                           \
        } while (0)
#define MATCH_ONE_OR_NONE (   condition)    do { if (condition) NEXT_CHAR(); } while (0)
#define MATCH_ZERO_OR_MORE (   condition)    while (condition) { NEXT_CHAR(); }
#define MIN_EXPONENT_DIGITS   2
From the C99 standard, section 7.19.6: The exponent always contains at least two digits, and only as many more digits as necessary to represent the exponent.
We force 3 digits on windows for python < 2.6 for compatibility reason
#define NEXT_CHAR ( )
Value:
do {                                                                \
            if (c == EOF || endp >= buffer + FLOAT_FORMATBUFLEN)            \
                END_MATCH();                                                \
            *endp++ = (char)c;                                              \
            c = getc(fp);                                                   \
        } while (0)
#define NPY_NO_PREFIX
#define PY_SSIZE_T_CLEAN

Function Documentation

static void _change_decimal_from_locale_to_dot ( char *  buffer) [static]
Given a string that may have a decimal point in the current locale, change it back to a dot. Since the string cannot get longer, no need for a maximum buffer size parameter.

buffer needs to get smaller

static int _check_ascii_format ( const char *  format) [static]
Check that the format string is a valid one for NumPyOS_ascii_format*

The last character in the format string must be the format char
I'm not sure why this test is here. It's ensuring that the format string after the first character doesn't have a single quote, a lowercase l, or a percent. This is the reverse of the commented-out test about 10 lines ago.
Also curious about this function is that it accepts format strings like "xg", which are invalid for floats. In general, the interface to this function is not very good, but changing it is difficult because it's a public API.

static void _ensure_decimal_point ( char *  buffer,
size_t  buf_size 
) [static]
Ensure that buffer has a decimal point in it. The decimal point will not be in the current locale, it will always be '.'

search for the first non-digit character
Skip leading sign, if present. I think this could only ever be '-', but it can't hurt to check for both.
Nothing to do, we already have a decimal point and a digit after it.
We have a decimal point, but no following digit. Insert a zero after the decimal.
If there is not enough room in the buffer for the additional text, just skip it. It's not worth generating an error over.

static void _ensure_minimum_exponent_length ( char *  buffer,
size_t  buf_size 
) [static]
Ensure that any exponent, if present, is at least MIN_EXPONENT_DIGITS in length.

Skip over the exponent and the sign.
Find the end of the exponent, keeping track of leading zeros.
If there are 2 exactly digits, we're done, regardless of what they contain
There are more than 2 digits in the exponent. See if we can delete some of the leading zeros
Delete extra_zeros_cnt worth of characters from the front of the exponent
Add one to significant_digit_cnt to copy the trailing 0 byte, thus setting the length
If there are fewer than 2 digits, add zeros until there are 2, if there's enough room

static char* _fix_ascii_format ( char *  buf,
size_t  buflen,
int  decimal 
) [static]
Fix the generated string: make sure the decimal is ., that exponent has a minimal number of digits, and that it has a decimal + one digit after that decimal if decimal argument != 0 (Same effect that 'Z' format in PyOS_ascii_formatd

Get the current locale, and find the decimal point string. Convert that string back to a dot.
If an exponent exists, ensure that the exponent is at least MIN_EXPONENT_DIGITS digits, providing the buffer is large enough for the extra zeros. Also, if there are more than MIN_EXPONENT_DIGITS, remove as many zeros as possible until we get back to MIN_EXPONENT_DIGITS

NPY_NO_EXPORT int NumPyOS_ascii_ftolf ( FILE *  fp,
double *  value 
)
NumPyOS_ascii_ftolf:
  • fp: FILE pointer
  • value: Place to store the value read
Similar to PyOS_ascii_strtod, except that it reads input from a file.
Similarly to fscanf, this function always consumes leading whitespace, and any text that could be the leading part in valid input.

Return value: similar to fscanf.
  • 0 if no number read,
  • 1 if a number read,
  • EOF if end-of-file met before reading anything.

Pass on to PyOS_ascii_strtod the leftmost matching part in regexp <blockquote>

s*[+-]? ( [0-9]*.[0-9]+([eE][+-]?[0-9]+)
nan ( ([:alphanum:_]*) )?
inf(inity)?
System Message: WARNING/2 (<string>, line 6) Line block ends without a blank line.

)

</blockquote>

case-insensitively.
The "do { ... } while (0)" wrapping in macros ensures that they behave properly eg. in "if ... else" structures.
  1. emulate fscanf EOF handling
  1. consume leading whitespace unconditionally
  1. start reading matching input to buffer
4.1 sign (optional)
4.2 nan, inf, infinity; [case-insensitive]
accept nan([:alphanum:_]*), similarly to strtod
4.3 mantissa
4.4 exponent
  1. try to convert buffer.
return 1 if something read, else 0

static int NumPyOS_ascii_isalnum ( char  c) [static]
NumPyOS_ascii_isalnum:
Same as isalnum under C locale

References NPY_ALLOW_C_API_DEF.

static int NumPyOS_ascii_isalpha ( char  c) [static]
NumPyOS_ascii_isalpha:
Same as isalpha under C locale

References NumPyOS_ascii_tolower().

static int NumPyOS_ascii_isdigit ( char  c) [static]
NumPyOS_ascii_isdigit:
Same as isdigit under C locale
NPY_NO_EXPORT int NumPyOS_ascii_isspace ( char  c)
NumPyOS_ascii_isspace:
Same as isspace under C locale

References c.

Referenced by NumPyOS_ascii_strncasecmp().

static int NumPyOS_ascii_strncasecmp ( const char *  s1,
const char *  s2,
size_t  len 
) [static]
NumPyOS_ascii_strncasecmp:
Same as strncasecmp under C locale

References FLOAT_FORMATBUFLEN, and NumPyOS_ascii_isspace().

Referenced by NumPyOS_ascii_strtod().

NPY_NO_EXPORT double NumPyOS_ascii_strtod ( const char *  s,
char **  endptr 
)
NumPyOS_ascii_strtod:
Work around bugs in PyOS_ascii_strtod

##1
Recognize POSIX inf/nan representations on all platforms.
End of ##1
## 2
At least Python versions <= 2.5.2 and <= 2.6.1
Fails to do best-efforts parsing of strings of the form "1<DP>234" where <DP> is the decimal point under the foreign locale.
End of ##2

References NPY_INFINITY, and NumPyOS_ascii_strncasecmp().

static double NumPyOS_ascii_strtod_plain ( const char *  s,
char **  endptr 
) [static]
_NumPyOS_ascii_strtod_plain:
PyOS_ascii_strtod work-alike, with no enhanced features, for forward compatibility with Python >= 2.7
static char NumPyOS_ascii_tolower ( char  c) [static]
NumPyOS_ascii_tolower:
Same as tolower under C locale

Referenced by NumPyOS_ascii_isalpha().