Manually sort some includes in src/gromacs
[alexxy/gromacs.git] / src / gromacs / utility / cstringutil.c
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5  * Copyright (c) 2001-2004, The GROMACS development team.
6  * Copyright (c) 2013,2014, by the GROMACS development team, led by
7  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
8  * and including many others, as listed in the AUTHORS file in the
9  * top-level source directory and at http://www.gromacs.org.
10  *
11  * GROMACS is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public License
13  * as published by the Free Software Foundation; either version 2.1
14  * of the License, or (at your option) any later version.
15  *
16  * GROMACS is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with GROMACS; if not, see
23  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
24  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
25  *
26  * If you want to redistribute modifications to GROMACS, please
27  * consider that scientific software is very special. Version
28  * control is crucial - bugs must be traceable. We will be happy to
29  * consider code for inclusion in the official distribution, but
30  * derived work must not be called official GROMACS. Details are found
31  * in the README & COPYING files - if they are missing, get the
32  * official version at http://www.gromacs.org.
33  *
34  * To help us fund GROMACS development, we humbly ask that you cite
35  * the research papers on the package. Check out http://www.gromacs.org.
36  */
37 /* This file is completely threadsafe - keep it that way! */
38 #include "gmxpre.h"
39
40 #include "cstringutil.h"
41
42 #include <assert.h>
43 #include <ctype.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <time.h>
48
49 #include <sys/types.h>
50
51 #include "config.h"
52
53 #ifdef HAVE_SYS_TIME_H
54 #include <sys/time.h>
55 #endif
56 #ifdef HAVE_PWD_H
57 #include <pwd.h>
58 #endif
59 #ifdef HAVE_UNISTD_H
60 #include <unistd.h>
61 #endif
62
63 #include "gromacs/utility/basedefinitions.h"
64 #include "gromacs/utility/basenetwork.h"
65 #include "gromacs/utility/fatalerror.h"
66 #include "gromacs/utility/futil.h"
67 #include "gromacs/utility/smalloc.h"
68
69 int continuing(char *s)
70 {
71     int sl;
72     assert(s);
73
74     rtrim(s);
75     sl = strlen(s);
76     if ((sl > 0) && (s[sl-1] == CONTINUE))
77     {
78         s[sl-1] = 0;
79         return TRUE;
80     }
81     else
82     {
83         return FALSE;
84     }
85 }
86
87
88
89 char *fgets2(char *line, int n, FILE *stream)
90 {
91     char *c;
92     if (fgets(line, n, stream) == NULL)
93     {
94         return NULL;
95     }
96     if ((c = strchr(line, '\n')) != NULL)
97     {
98         *c = '\0';
99     }
100     else
101     {
102         /* A line not ending in a newline can only occur at the end of a file,
103          * or because of n being too small.
104          * Since both cases occur very infrequently, we can check for EOF.
105          */
106         if (!feof(stream))
107         {
108             gmx_fatal(FARGS, "An input file contains a line longer than %d characters, while the buffer passed to fgets2 has size %d. The line starts with: '%20.20s'", n, n, line);
109         }
110     }
111     if ((c = strchr(line, '\r')) != NULL)
112     {
113         *c = '\0';
114     }
115
116     return line;
117 }
118
119 void strip_comment (char *line)
120 {
121     char *c;
122
123     if (!line)
124     {
125         return;
126     }
127
128     /* search for a comment mark and replace it by a zero */
129     if ((c = strchr(line, COMMENTSIGN)) != NULL)
130     {
131         (*c) = 0;
132     }
133 }
134
135 void upstring (char *str)
136 {
137     int i;
138
139     for (i = 0; (i < (int)strlen(str)); i++)
140     {
141         str[i] = toupper(str[i]);
142     }
143 }
144
145 void ltrim (char *str)
146 {
147     char *tr;
148     int   i, c;
149
150     if (NULL == str)
151     {
152         return;
153     }
154
155     c = 0;
156     while (('\0' != str[c]) && isspace(str[c]))
157     {
158         c++;
159     }
160     if (c > 0)
161     {
162         for (i = c; ('\0' != str[i]); i++)
163         {
164             str[i-c] = str[i];
165         }
166         str[i-c] = '\0';
167     }
168 }
169
170 void rtrim (char *str)
171 {
172     int nul;
173
174     if (NULL == str)
175     {
176         return;
177     }
178
179     nul = strlen(str)-1;
180     while ((nul > 0) && ((str[nul] == ' ') || (str[nul] == '\t')) )
181     {
182         str[nul] = '\0';
183         nul--;
184     }
185 }
186
187 void trim (char *str)
188 {
189     ltrim (str);
190     rtrim (str);
191 }
192
193 char *
194 gmx_ctime_r(const time_t *clock, char *buf, int n)
195 {
196 #ifdef _MSC_VER
197     /* Windows */
198     ctime_s( buf, n, clock );
199 #elif defined(GMX_NATIVE_WINDOWS)
200     char *tmpbuf = ctime( clock );
201     strncpy(buf, tmpbuf, n-1);
202     buf[n-1] = '\0';
203 #elif (defined(__sun))
204     /*Solaris*/
205     ctime_r(clock, buf, n);
206 #else
207     char tmpbuf[STRLEN];
208     ctime_r(clock, tmpbuf);
209     strncpy(buf, tmpbuf, n-1);
210     buf[n-1] = '\0';
211 #endif
212     return buf;
213 }
214
215 void nice_header (FILE *out, const char *fn)
216 {
217     const char    *unk = "onbekend";
218     time_t         clock;
219     const char    *user;
220     int            gh;
221 #ifdef HAVE_PWD_H
222     uid_t          uid;
223 #else
224     int            uid;
225 #endif
226     char           buf[256] = "";
227     char           timebuf[STRLEN];
228 #ifdef HAVE_PWD_H
229     struct passwd *pw;
230 #endif
231
232     /* Print a nice header above the file */
233     time(&clock);
234     fprintf (out, "%c\n", COMMENTSIGN);
235     fprintf (out, "%c\tFile '%s' was generated\n", COMMENTSIGN, fn ? fn : unk);
236
237 #ifdef HAVE_PWD_H
238     uid  = getuid();
239     pw   = getpwuid(uid);
240     gh   = gmx_gethostname(buf, 255);
241     /* pw returns null on error (e.g. compute nodes lack /etc/passwd) */
242     user = pw ? pw->pw_name : unk;
243 #else
244     uid  = 0;
245     gh   = -1;
246     user = unk;
247 #endif
248
249     gmx_ctime_r(&clock, timebuf, STRLEN);
250     fprintf (out, "%c\tBy user: %s (%d)\n", COMMENTSIGN,
251              user ? user : unk, (int) uid);
252     fprintf(out, "%c\tOn host: %s\n", COMMENTSIGN, (gh == 0) ? buf : unk);
253
254     fprintf (out, "%c\tAt date: %s", COMMENTSIGN, timebuf);
255     fprintf (out, "%c\n", COMMENTSIGN);
256 }
257
258
259 int gmx_strcasecmp_min(const char *str1, const char *str2)
260 {
261     char ch1, ch2;
262
263     do
264     {
265         do
266         {
267             ch1 = toupper(*(str1++));
268         }
269         while ((ch1 == '-') || (ch1 == '_'));
270         do
271         {
272             ch2 = toupper(*(str2++));
273         }
274         while ((ch2 == '-') || (ch2 == '_'));
275
276         if (ch1 != ch2)
277         {
278             return (ch1-ch2);
279         }
280     }
281     while (ch1);
282     return 0;
283 }
284
285 int gmx_strncasecmp_min(const char *str1, const char *str2, int n)
286 {
287     char  ch1, ch2;
288     char *stri1, *stri2;
289
290     stri1 = (char *)str1;
291     stri2 = (char *)str2;
292     do
293     {
294         do
295         {
296             ch1 = toupper(*(str1++));
297         }
298         while ((ch1 == '-') || (ch1 == '_'));
299         do
300         {
301             ch2 = toupper(*(str2++));
302         }
303         while ((ch2 == '-') || (ch2 == '_'));
304
305         if (ch1 != ch2)
306         {
307             return (ch1-ch2);
308         }
309     }
310     while (ch1 && (str1-stri1 < n) && (str2-stri2 < n));
311     return 0;
312 }
313
314 int gmx_strcasecmp(const char *str1, const char *str2)
315 {
316     char ch1, ch2;
317
318     do
319     {
320         ch1 = toupper(*(str1++));
321         ch2 = toupper(*(str2++));
322         if (ch1 != ch2)
323         {
324             return (ch1-ch2);
325         }
326     }
327     while (ch1);
328     return 0;
329 }
330
331 int gmx_strncasecmp(const char *str1, const char *str2, int n)
332 {
333     char ch1, ch2;
334
335     if (n == 0)
336     {
337         return 0;
338     }
339
340     do
341     {
342         ch1 = toupper(*(str1++));
343         ch2 = toupper(*(str2++));
344         if (ch1 != ch2)
345         {
346             return (ch1-ch2);
347         }
348         n--;
349     }
350     while (ch1 && n);
351     return 0;
352 }
353
354 char *gmx_strdup(const char *src)
355 {
356     char *dest;
357
358     snew(dest, strlen(src)+1);
359     strcpy(dest, src);
360
361     return dest;
362 }
363
364 char *
365 gmx_strndup(const char *src, int n)
366 {
367     int   len;
368     char *dest;
369
370     len = strlen(src);
371     if (len > n)
372     {
373         len = n;
374     }
375     snew(dest, len+1);
376     strncpy(dest, src, len);
377     dest[len] = 0;
378     return dest;
379 }
380
381 /* Magic hash init number for Dan J. Bernsteins algorithm.
382  * Do NOT use any other value unless you really know what you are doing.
383  */
384 const unsigned int
385     gmx_string_hash_init = 5381;
386
387
388 unsigned int
389 gmx_string_fullhash_func(const char *s, unsigned int hash_init)
390 {
391     int c;
392
393     while ((c = (*s++)) != '\0')
394     {
395         hash_init = ((hash_init << 5) + hash_init) ^ c; /* (hash * 33) xor c */
396     }
397     return hash_init;
398 }
399
400 unsigned int
401 gmx_string_hash_func(const char *s, unsigned int hash_init)
402 {
403     int c;
404
405     while ((c = toupper(*s++)) != '\0')
406     {
407         if (isalnum(c))
408         {
409             hash_init = ((hash_init << 5) + hash_init) ^ c;            /* (hash * 33) xor c */
410         }
411     }
412     return hash_init;
413 }
414
415 int
416 gmx_wcmatch(const char *pattern, const char *str)
417 {
418     while (*pattern)
419     {
420         if (*pattern == '*')
421         {
422             /* Skip multiple wildcards in a sequence */
423             while (*pattern == '*' || *pattern == '?')
424             {
425                 ++pattern;
426                 /* For ?, we need to check that there are characters left
427                  * in str. */
428                 if (*pattern == '?')
429                 {
430                     if (*str == 0)
431                     {
432                         return GMX_NO_WCMATCH;
433                     }
434                     else
435                     {
436                         ++str;
437                     }
438                 }
439             }
440             /* If the pattern ends after the star, we have a match */
441             if (*pattern == 0)
442             {
443                 return 0;
444             }
445             /* Match the rest against each possible suffix of str */
446             while (*str)
447             {
448                 /* Only do the recursive call if the first character
449                  * matches. We don't have to worry about wildcards here,
450                  * since we have processed them above. */
451                 if (*pattern == *str)
452                 {
453                     int rc;
454                     /* Match the suffix, and return if a match or an error */
455                     rc = gmx_wcmatch(pattern, str);
456                     if (rc != GMX_NO_WCMATCH)
457                     {
458                         return rc;
459                     }
460                 }
461                 ++str;
462             }
463             /* If no suffix of str matches, we don't have a match */
464             return GMX_NO_WCMATCH;
465         }
466         else if ((*pattern == '?' && *str != 0) || *pattern == *str)
467         {
468             ++str;
469         }
470         else
471         {
472             return GMX_NO_WCMATCH;
473         }
474         ++pattern;
475     }
476     /* When the pattern runs out, we have a match if the string has ended. */
477     return (*str == 0) ? 0 : GMX_NO_WCMATCH;
478 }
479
480 char *wrap_lines(const char *buf, int line_width, int indent, gmx_bool bIndentFirst)
481 {
482     char    *b2;
483     int      i, i0, i2, j, b2len, lspace = 0, l2space = 0;
484     gmx_bool bFirst, bFitsOnLine;
485
486     /* characters are copied from buf to b2 with possible spaces changed
487      * into newlines and extra space added for indentation.
488      * i indexes buf (source buffer) and i2 indexes b2 (destination buffer)
489      * i0 points to the beginning of the current line (in buf, source)
490      * lspace and l2space point to the last space on the current line
491      * bFirst is set to prevent indentation of first line
492      * bFitsOnLine says if the first space occurred before line_width, if
493      * that is not the case, we have a word longer than line_width which
494      * will also not fit on the next line, so we might as well keep it on
495      * the current line (where it also won't fit, but looks better)
496      */
497
498     b2    = NULL;
499     b2len = strlen(buf)+1+indent;
500     snew(b2, b2len);
501     i0 = i2 = 0;
502     if (bIndentFirst)
503     {
504         for (i2 = 0; (i2 < indent); i2++)
505         {
506             b2[i2] = ' ';
507         }
508     }
509     bFirst = TRUE;
510     do
511     {
512         l2space = -1;
513         /* find the last space before end of line */
514         for (i = i0; ((i-i0 < line_width) || (l2space == -1)) && (buf[i]); i++)
515         {
516             b2[i2++] = buf[i];
517             /* remember the position of a space */
518             if (buf[i] == ' ')
519             {
520                 lspace  = i;
521                 l2space = i2-1;
522             }
523             /* if we have a newline before the line is full, reset counters */
524             if (buf[i] == '\n' && buf[i+1])
525             {
526                 i0     = i+1;
527                 b2len += indent;
528                 srenew(b2, b2len);
529                 /* add indentation after the newline */
530                 for (j = 0; (j < indent); j++)
531                 {
532                     b2[i2++] = ' ';
533                 }
534             }
535         }
536         /* If we are at the last newline, copy it */
537         if (buf[i] == '\n' && !buf[i+1])
538         {
539             b2[i2++] = buf[i++];
540         }
541         /* if we're not at the end of the string */
542         if (buf[i])
543         {
544             /* check if one word does not fit on the line */
545             bFitsOnLine = (i-i0 <= line_width);
546             /* reset line counters to just after the space */
547             i0 = lspace+1;
548             i2 = l2space+1;
549             /* if the words fit on the line, and we're beyond the indentation part */
550             if ( (bFitsOnLine) && (l2space >= indent) )
551             {
552                 /* start a new line */
553                 b2[l2space] = '\n';
554                 /* and add indentation */
555                 if (indent)
556                 {
557                     if (bFirst)
558                     {
559                         line_width -= indent;
560                         bFirst      = FALSE;
561                     }
562                     b2len += indent;
563                     srenew(b2, b2len);
564                     for (j = 0; (j < indent); j++)
565                     {
566                         b2[i2++] = ' ';
567                     }
568                     /* no extra spaces after indent; */
569                     while (buf[i0] == ' ')
570                     {
571                         i0++;
572                     }
573                 }
574             }
575         }
576     }
577     while (buf[i]);
578     b2[i2] = '\0';
579
580     return b2;
581 }
582
583 gmx_int64_t
584 str_to_int64_t(const char *str, char **endptr)
585 {
586 #ifndef _MSC_VER
587     return strtoll(str, endptr, 10);
588 #else
589     return _strtoi64(str, endptr, 10);
590 #endif
591 }
592
593 char *gmx_step_str(gmx_int64_t i, char *buf)
594 {
595     sprintf(buf, "%"GMX_PRId64, i);
596     return buf;
597 }
598
599 void parse_digits_from_plain_string(const char *digitstring, int *ndigits, int **digitlist)
600 {
601     int i;
602
603     if (NULL == digitstring)
604     {
605         *ndigits   = 0;
606         *digitlist = NULL;
607         return;
608     }
609
610     *ndigits = strlen(digitstring);
611
612     snew(*digitlist, *ndigits);
613
614     for (i = 0; i < *ndigits; i++)
615     {
616         if (digitstring[i] < '0' || digitstring[i] > '9')
617         {
618             gmx_fatal(FARGS, "Invalid character in digit-only string: '%c'\n",
619                       digitstring[i]);
620         }
621         (*digitlist)[i] = digitstring[i] - '0';
622     }
623 }
624
625 static void parse_digits_from_csv_string(const char gmx_unused *digitstring, int gmx_unused *ndigits, int gmx_unused *digitlist)
626 {
627     /* TODO Implement csv format to support (e.g.) more than 10
628        different GPUs in a node. */
629     gmx_incons("Not implemented yet");
630 }