root/branches/maintenance/2.2.2/Modelica/C-Sources/ModelicaStrings.c

Revision 324, 12.1 kB (checked in by Christian, 3 years ago)

Updated copyright to 2006

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/* External utility functions for Modelica package
2   Modelica.Functions.Strings.
3
4   Release Notes:
5      Sep. 24, 2004: by Martin Otter.
6                     Final cleaning up of the code
7
8      Sep.  9, 2004: by Dag Bruck, Dynasim AB.
9                     Implementation of scan functions
10
11      Aug. 19, 2004: by Martin Otter, DLR.
12                     Changed according to the decisions of the 37th
13                     design meeting in Lund (see minutes)
14                     
15      Jan.  7, 2002: by Martin Otter, DLR.
16                     Implemented a first version
17
18   Copyright (C) 2002-2006, Modelica Association and DLR.
19
20   The content of this file is free software; it can be redistributed
21   and/or modified under the terms of the Modelica license, see the
22   license conditions and the accompanying disclaimer in file
23   ModelicaLicense.txt or in Modelica.UsersGuide.ModelicaLicense.
24*/
25
26#include <ctype.h>
27#if !defined(NO_FILE_SYSTEM)
28#include <stdio.h>
29#endif
30#include <string.h>
31#include "ModelicaUtilities.h"
32
33
34static const char* ModelicaStrings_substring(const char* string, int startIndex, int endIndex) {
35       
36  /* Return string1(startIndex:endIndex) if endIndex >= startIndex,
37     or return string1(startIndex:startIndex), if endIndex = 0.
38     An assert is triggered, if startIndex/endIndex are not valid.
39  */
40     char* substring;
41     int len1 = strlen(string);
42     int len2;
43
44  /* Check arguments */
45     if ( startIndex < 1 ) {
46        ModelicaFormatError("Wrong call of Utilities.Strings.substring:\n"
47                            "  startIndex = %d (has to be > 0).\n"
48                            "  string     = \"%s\"\n", startIndex, string);
49     } else if ( endIndex == -999 ) {
50        endIndex = startIndex;
51     } else if ( endIndex < startIndex ) {
52        ModelicaFormatError("Wrong call of  Utilities.Strings.substring:\n"
53                            "  startIndex = %d\n"
54                            "  endIndex   = %d (>= startIndex required)\n"
55                            "  string     = \"%s\"\n", startIndex, endIndex, string);
56     } else if ( endIndex > len1 ) {
57        ModelicaFormatError("Wrong call of Utilities.Strings.substring:\n"
58                            "  endIndex = %d (<= %d required (=length(string)).\n"
59                            "  string   = \"%s\"\n", endIndex, len1, string);
60     };
61     
62  /* Allocate memory and copy string */
63     len2 = endIndex - startIndex + 1;
64     substring = ModelicaAllocateString(len2);
65     strncpy(substring, &string[startIndex-1], len2);
66     substring[len2] = '\0';
67     return substring;
68};
69
70
71static int ModelicaStrings_length(const char* string)
72/* Returns the number of characters "string" */
73{
74     return strlen(string);
75}
76
77
78static int ModelicaStrings_compare(const char* string1, const char* string2, int caseSensitive)
79/* compares two strings, optionally ignoring case */
80{ 
81    int result;
82    if (string1 == 0 || string2 == 0) return 2;
83   
84    if (caseSensitive) {
85        result = strcmp(string1, string2);
86    } else {
87        while (tolower(*string1) == tolower(*string2) && *string1 != '\0') {
88            string1++;
89            string2++;
90        }
91        result = (int)(tolower(*string1)) - (int)(tolower(*string2));
92    }
93   
94    if ( result < 0 ) {
95        result = 1;
96    } else if ( result == 0 ) {
97        result = 2;
98    } else {
99        result = 3;
100    };
101    return result;
102}
103
104
105#define MAX_TOKEN_SIZE 100
106
107static int ModelicaStrings_skipWhiteSpace(const char* string, int i)
108/* Return index in string after skipping ws, or position of terminating nul. */
109{
110    while (string[i-1] != '\0' && isspace(string[i-1]))
111        ++i;
112    return i;
113}
114
115
116/* ----------------- utility functions used in scanXXX functions ----------- */
117
118static int InSet(const char* string, int i, const char* separators)
119/* Returns true if string[i] is one of the characters in separators. */
120{
121    return strchr(separators, string[i-1]) != NULL;
122}
123
124static int SkipNonWhiteSpaceSeparator(const char* string, int i, const char* separators)
125/* Return index in string of first character which is ws or character in separators,
126   or position of terminating nul. */
127{
128    while (string[i-1] != '\0' && (isspace(string[i-1]) || InSet(string, i, separators)))
129        ++i;
130    return i;
131}
132
133static int get_token(const char* string, int startIndex, const char* separators,
134                     int* output_index, int* token_start, int* token_length)
135{
136    int past_token;
137    int sep_pos;
138
139    *token_start = ModelicaStrings_skipWhiteSpace(string, startIndex);
140    /* Index of first char of token, after ws. */
141
142    past_token = SkipNonWhiteSpaceSeparator(string, *token_start, separators);
143    /* Index of first char after token, ws or separator. */
144
145    sep_pos = ModelicaStrings_skipWhiteSpace(string, past_token);
146    /* Index of first char after ws after token, maybe a separator. */
147   
148    *output_index = InSet(string, sep_pos, separators) ? sep_pos + 1 : sep_pos;
149    /* Skip any separator. */
150
151    *token_length = past_token-*token_start;
152   
153    if (*token_length == 0 || *token_length > MAX_TOKEN_SIZE) {
154        /* Token missing or too long. */
155        *output_index = startIndex;
156        return 0; /* error */
157    }
158
159    return 1; /* ok */
160}
161
162static int MatchUnsignedInteger(const char* string, int start)
163/* Starts matching character which make an unsigned integer. The matching
164   begins at the start index (first char has index 1). Returns the number
165   of characters that could be matched, or zero if the first character
166   was not a digit. */
167{
168    const char* begin = &string[start-1];
169    const char* p = begin;
170    while (*p != '\0' && isdigit(*p))
171        ++p;
172    return p - begin;
173}
174
175/* --------------- end of utility functions used in scanXXX functions ----------- */
176
177
178static void ModelicaStrings_scanIdentifier(const char* string, int startIndex, int* nextIndex, const char** identifier)
179{
180    int token_length=0;
181   
182    int token_start = ModelicaStrings_skipWhiteSpace(string, startIndex);
183    /* Index of first char of token, after ws. */
184
185    if (isalpha(string[token_start-1])) {
186        /* Identifier has begun. */
187        token_length = 1;
188        while (string[token_start+token_length-1] != '\0' &&
189            (isalpha(string[token_start+token_length-1]) ||
190            isdigit(string[token_start+token_length-1]) ||
191            string[token_start+token_length-1] == '_'))
192        {
193            ++token_length;
194        }
195       
196       {
197        char* s = ModelicaAllocateString(token_length);
198        strncpy(s, string+token_start-1, token_length);
199        s[token_length] = '\0';
200        *nextIndex = token_start + token_length;
201        *identifier = s;
202        return;
203       }
204    }
205
206    /* Token missing or not identifier. */
207    *nextIndex  = startIndex;
208    *identifier = ModelicaAllocateString(0);
209    return;
210}
211
212static void ModelicaStrings_scanInteger(const char* string, int startIndex, int unsignedNumber, 
213                                        int* nextIndex, int* integerNumber)
214{
215    int number_length=0;
216    int sign = 0;
217    /* Number of characters used for sign. */
218   
219    int token_start = ModelicaStrings_skipWhiteSpace(string, startIndex);
220    /* Index of first char of token, after ws. */
221   
222    if (string[token_start-1] == '+' || string[token_start-1] == '-')
223        sign = 1;
224   
225    if (unsignedNumber==0 || unsignedNumber==1 && sign==0) {
226        number_length = MatchUnsignedInteger(string, token_start + sign);
227        /* Number of characters in unsigned number. */
228       
229        if (number_length > 0 && sign + number_length < MAX_TOKEN_SIZE) {
230          /* check if the scanned string is no Real number */
231          int next = token_start + sign + number_length - 1;
232          if (  string[next] == '\0' ||
233               (string[next] != '\0' && string[next] != '.'
234                                     && string[next] != 'e'
235                                     && string[next] != 'E') ) {
236             /* get Integer value */
237             char buf[MAX_TOKEN_SIZE+1];
238             int x;
239             
240             strncpy(buf, string+token_start-1, sign + number_length);
241             buf[sign + number_length] = '\0';
242#if !defined(NO_FILE_SYSTEM)
243             if (sscanf(buf, "%d", &x) == 1) {             
244                *integerNumber = x;
245                *nextIndex = token_start + sign + number_length;
246                return;
247             }
248#endif
249          } else {
250            ++number_length;
251          }
252        }
253    }
254   
255    /* Token missing or cannot be converted to result type. */
256    *nextIndex     = startIndex;
257    *integerNumber = 0;
258     return;
259}
260
261static void ModelicaStrings_scanReal(const char* string, int startIndex, int unsignedNumber,
262                                     int* nextIndex, double* number)
263{
264    /*
265    Grammar of real number:
266
267    real ::= [sign] unsigned [fraction] [exponent]
268    sign ::= '+' | '-'
269    unsigned ::= digit [unsigned]
270    fraction ::= '.' [unsigned]
271    exponent ::= ('e' | 'E') [sign] unsigned
272    digit ::= '0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9'
273    */
274   
275    int len = 0;
276    /* Temporary variable for the length of a matched unsigned number. */
277   
278    int total_length = 0;
279    /* Total number of characters recognized as part of a decimal number. */
280   
281    int token_start = ModelicaStrings_skipWhiteSpace(string, startIndex);
282    /* Index of first char of token, after ws. */
283   
284    /* Scan sign of decimal number */
285   
286    if (string[token_start-1] == '+' || string[token_start-1] == '-') {
287        total_length = 1;
288        if (unsignedNumber==1) goto error;
289    }
290   
291    /* Scan integer part of mantissa. */
292   
293    len = MatchUnsignedInteger(string, token_start + total_length);
294    total_length += len;
295   
296    /* Scan decimal part of mantissa. */
297   
298    if (string[token_start + total_length-1] == '.') {
299        total_length += 1;
300        len = MatchUnsignedInteger(string, token_start + total_length);
301        if (len > 0) {
302            total_length += len;
303        }
304    }
305   
306    /* Scan exponent part of mantissa. */
307   
308    if (string[token_start + total_length-1] == 'e' || string[token_start + total_length-1] == 'E') {
309        // total_length += 1;
310        int exp_len = 1;
311   
312        if (string[token_start + total_length] == '+' || string[token_start + total_length] == '-') {
313            exp_len += 1;
314        }
315        len = MatchUnsignedInteger(string, token_start + total_length + exp_len);
316        if (len == 0) goto error;
317        total_length += exp_len + len;
318    }
319
320    /* Convert accumulated characters into a number. */
321   
322    if (total_length > 0 && total_length < MAX_TOKEN_SIZE) {
323        char buf[MAX_TOKEN_SIZE+1];
324        double x;
325       
326        strncpy(buf, string+token_start-1, total_length);
327        buf[total_length] = '\0';
328#if !defined(NO_FILE_SYSTEM)
329        if (sscanf(buf, "%lg", &x) == 1) {
330            *number = x;
331            *nextIndex = token_start + total_length;
332            return;
333        }
334#endif
335    }
336   
337    /* Token missing or cannot be converted to result type. */
338 
339error:
340    *nextIndex = startIndex;
341    *number = 0;
342    return;
343}
344
345
346static void ModelicaStrings_scanString(const char* string, int startIndex,
347                                       int* nextIndex, const char** result)
348{
349    int i, token_start, past_token, token_length;
350   
351    token_length = 0;
352    token_start = ModelicaStrings_skipWhiteSpace(string, startIndex);
353    i = token_start;
354    if (string[token_start-1] != '"') goto error;
355    /* Index of first char of token, after ws. */
356   
357    ++i;
358    while (1) {
359        if (string[i-1] == '\0') goto error;
360        if (string[i-2] == '\\' && string[i-1] == '"')
361            ; /* escaped quote, consume */
362        else if (string[i-1] == '"')
363            break;      /* end quote */
364        ++i;
365    }
366    past_token = i + 1;
367    /* Index of first char after token, ws or separator. */
368   
369    token_length = past_token-token_start-2;
370   
371    if (token_length > 0) {
372        char* s = ModelicaAllocateString(token_length);
373        strncpy(s, string+token_start, token_length);
374        s[token_length] = '\0';
375        *result = s;
376        *nextIndex = past_token;
377        return;
378    }
379   
380error:
381    *result = ModelicaAllocateString(0);
382    *nextIndex = startIndex;
383    return;
384}
Note: See TracBrowser for help on using the browser.