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