1 /*
2 *+
3 *  Name:
4 *     palIntin
5 
6 *  Purpose:
7 *     Convert free-format input into an integer
8 
9 *  Language:
10 *     Starlink ANSI C
11 
12 *  Type of Module:
13 *     Library routine
14 
15 *  Invocation:
16 *     void palIntin( const char * string, int *nstrt,
17 *                     long *ireslt, int *jflag );
18 
19 *  Arguments:
20 *     string = const char * (Given)
21 *        String containing number to be decoded.
22 *     nstrt = int * (Given and Returned)
23 *        Character number indicating where decoding should start.
24 *        On output its value is updated to be the location of the
25 *        possible next value. For compatibility with SLA the first
26 *        character is index 1.
27 *     ireslt = long * (Returned)
28 *        Result. Not updated when jflag=1.
29 *     jflag = int * (Returned)
30 *        status: -1 = -OK, 0 = +OK, 1 = null, 2 = error
31 
32 *  Description:
33 *     Extracts a number from an input string starting at the specified
34 *     index.
35 
36 *  Authors:
37 *     TIMJ: Tim Jenness (JAC, Hawaii)
38 *     {enter_new_authors_here}
39 
40 *  Notes:
41 *     - Uses the strtol() system call to do the parsing. This may lead to
42 *       subtle differences when compared to the SLA/F parsing.
43 *     - Commas are recognized as a special case and are skipped if one happens
44 *       to be the next character when updating nstrt. Additionally the output
45 *       nstrt position will skip past any trailing space.
46 *     - If no number can be found flag will be set to 1.
47 *     - If the number overflows or underflows jflag will be set to 2. For overflow
48 *       the returned result will have the value LONG_MAX, for underflow it
49 *       will have the value LONG_MIN.
50 
51 *  History:
52 *     2012-03-15 (TIMJ):
53 *        Initial version
54 *        Matches the SLALIB interface but brand new implementation using
55 *        C library calls and not a direct port of the Fortran.
56 *     2014-08-07 (TIMJ):
57 *        Check for isblank availability.
58 *     {enter_further_changes_here}
59 
60 *  Copyright:
61 *     Copyright (C) 2012,2014 Science and Technology Facilities Council.
62 *     All Rights Reserved.
63 
64 *  Licence:
65 *     This program is free software; you can redistribute it and/or
66 *     modify it under the terms of the GNU General Public License as
67 *     published by the Free Software Foundation; either version 3 of
68 *     the License, or (at your option) any later version.
69 *
70 *     This program is distributed in the hope that it will be
71 *     useful, but WITHOUT ANY WARRANTY; without even the implied
72 *     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
73 *     PURPOSE. See the GNU General Public License for more details.
74 *
75 *     You should have received a copy of the GNU General Public License
76 *     along with this program; if not, write to the Free Software
77 *     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
78 *     MA 02110-1301, USA.
79 
80 *  Bugs:
81 *     {note_any_bugs_here}
82 *-
83 */
84 
85 #if HAVE_CONFIG_H
86 #  include <config.h>
87 #endif
88 
89 #include <stdlib.h>
90 #include <errno.h>
91 
92 /* isblank() is a C99 feature so we just reimplement it if it is missing */
93 #if HAVE_ISBLANK
94 #ifndef _ISOC99_SOURCE
95 #define _ISOC99_SOURCE
96 #endif
97 #include <ctype.h>
98 # define ISBLANK isblank
99 #else
100 
ISBLANK(int c)101 static int ISBLANK( int c ) {
102   return ( c == ' ' || c == '\t' );
103 }
104 
105 #endif
106 
107 /* Still need ctype for isalpha and isdigit */
108 #include <ctype.h>
109 
110 #include "pal.h"
111 
palIntin(const char * string,int * nstrt,long * ireslt,int * jflag)112 void palIntin( const char * string, int *nstrt,
113                long *ireslt, int *jflag ) {
114 
115   const char *strstart = NULL; /* Pointer to start of search */
116   const char * ctemp = NULL; /* Pointer into string */
117   char * endptr = NULL;/* Pointer to string after number */
118   int retval;       /* Return value from strtol */
119   int hasminus;     /* is this a -0 */
120 
121   /* strtol man page indicates that we should reset errno before
122      calling strtod */
123   errno = 0;
124 
125   /* Locate the start postion */
126   strstart = &(string[*nstrt-1]);
127 
128   /* We have to be able to deal with -0 so we have to search the
129      string first and look for the negative */
130   hasminus = 0;
131   ctemp = strstart;
132   while ( *ctemp != '\0' ) {
133     if (isdigit(*ctemp)) break;
134     /* Reset so that - 12345 is not a negative number */
135     hasminus = 0;
136     /* Flag that we have found a minus */
137     if (*ctemp == '-') hasminus = 1;
138     ctemp++;
139   }
140 
141   /* Look for the number using the system call, offsetting using
142      1-based counter. */
143   retval = strtol( strstart, &endptr, 10 );
144   if (retval == 0.0 && endptr == strstart) {
145     /* conversion did not find anything */
146     *jflag = 1;
147 
148     /* but SLA compatibility requires that we step
149        through to remove leading spaces. We also step
150        through alphabetic characters since they can never
151        be numbers. Skip past a "+" since it doesn't gain
152        us anything and matches slalib. */
153     while (ISBLANK(*endptr) || isalpha(*endptr) || *endptr == '+' ) {
154       endptr++;
155     }
156 
157   } else if ( errno == ERANGE ) {
158     *jflag = 2;
159   } else {
160     if ( retval < 0 || hasminus ) {
161       *jflag = -1;
162     } else {
163       *jflag = 0;
164     }
165   }
166 
167   /* Sort out the position for the next index */
168   *nstrt = endptr - string + 1;
169 
170   /* Skip a comma */
171   if (*endptr == ',') {
172     (*nstrt)++;
173   } else {
174     /* jump past any leading spaces for the next part of the string */
175     ctemp = endptr;
176     while ( ISBLANK(*ctemp) ) {
177       (*nstrt)++;
178       ctemp++;
179     }
180   }
181 
182   /* And the result unless we found nothing */
183   if (*jflag != 1) *ireslt = retval;
184 
185 }
186