84433ce74c44e50071d9a193935342e270986c7f
[alexxy/gromacs.git] / src / gromacs / gmxlib / string2.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 #ifdef HAVE_CONFIG_H
39 #include <config.h>
40 #endif
41
42 #include <ctype.h>
43 #include <errno.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <sys/types.h>
48 #include <time.h>
49
50 #ifdef HAVE_SYS_TIME_H
51 #include <sys/time.h>
52 #endif
53
54 #ifdef HAVE_UNISTD_H
55 #include <unistd.h>
56 #endif
57
58 #ifdef HAVE_PWD_H
59 #include <pwd.h>
60 #endif
61 #include <time.h>
62 #include <assert.h>
63
64 #include "typedefs.h"
65 #include "smalloc.h"
66 #include "gmx_fatal.h"
67 #include "macros.h"
68 #include "main.h"
69 #include "string2.h"
70 #include "gromacs/fileio/futil.h"
71
72 int continuing(char *s)
73 {
74     int sl;
75     assert(s);
76
77     rtrim(s);
78     sl = strlen(s);
79     if ((sl > 0) && (s[sl-1] == CONTINUE))
80     {
81         s[sl-1] = 0;
82         return TRUE;
83     }
84     else
85     {
86         return FALSE;
87     }
88 }
89
90
91
92 char *fgets2(char *line, int n, FILE *stream)
93 {
94     char *c;
95     if (fgets(line, n, stream) == NULL)
96     {
97         return NULL;
98     }
99     if ((c = strchr(line, '\n')) != NULL)
100     {
101         *c = '\0';
102     }
103     else
104     {
105         /* A line not ending in a newline can only occur at the end of a file,
106          * or because of n being too small.
107          * Since both cases occur very infrequently, we can check for EOF.
108          */
109         if (!gmx_eof(stream))
110         {
111             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);
112         }
113     }
114     if ((c = strchr(line, '\r')) != NULL)
115     {
116         *c = '\0';
117     }
118
119     return line;
120 }
121
122 void strip_comment (char *line)
123 {
124     char *c;
125
126     if (!line)
127     {
128         return;
129     }
130
131     /* search for a comment mark and replace it by a zero */
132     if ((c = strchr(line, COMMENTSIGN)) != NULL)
133     {
134         (*c) = 0;
135     }
136 }
137
138 void upstring (char *str)
139 {
140     int i;
141
142     for (i = 0; (i < (int)strlen(str)); i++)
143     {
144         str[i] = toupper(str[i]);
145     }
146 }
147
148 void ltrim (char *str)
149 {
150     char *tr;
151     int   i, c;
152
153     if (NULL == str)
154     {
155         return;
156     }
157
158     c = 0;
159     while (('\0' != str[c]) && isspace(str[c]))
160     {
161         c++;
162     }
163     if (c > 0)
164     {
165         for (i = c; ('\0' != str[i]); i++)
166         {
167             str[i-c] = str[i];
168         }
169         str[i-c] = '\0';
170     }
171 }
172
173 void rtrim (char *str)
174 {
175     int nul;
176
177     if (NULL == str)
178     {
179         return;
180     }
181
182     nul = strlen(str)-1;
183     while ((nul > 0) && ((str[nul] == ' ') || (str[nul] == '\t')) )
184     {
185         str[nul] = '\0';
186         nul--;
187     }
188 }
189
190 void trim (char *str)
191 {
192     ltrim (str);
193     rtrim (str);
194 }
195
196 char *
197 gmx_ctime_r(const time_t *clock, char *buf, int n)
198 {
199     char tmpbuf[STRLEN];
200
201 #ifdef GMX_NATIVE_WINDOWS
202     /* Windows */
203     ctime_s( tmpbuf, STRLEN, clock );
204 #elif (defined(__sun))
205     /*Solaris*/
206     ctime_r(clock, tmpbuf, n);
207 #else
208     ctime_r(clock, tmpbuf);
209 #endif
210     strncpy(buf, tmpbuf, n-1);
211     buf[n-1] = '\0';
212
213     return buf;
214 }
215
216 void nice_header (FILE *out, const char *fn)
217 {
218     const char    *unk = "onbekend";
219     time_t         clock;
220     const char    *user = unk;
221     int            gh;
222 #ifdef HAVE_PWD_H
223     uid_t          uid;
224 #else
225     int            uid;
226 #endif
227     char           buf[256] = "";
228     char           timebuf[STRLEN];
229 #ifdef HAVE_PWD_H
230     struct passwd *pw;
231 #endif
232
233     /* Print a nice header above the file */
234     time(&clock);
235     fprintf (out, "%c\n", COMMENTSIGN);
236     fprintf (out, "%c\tFile '%s' was generated\n", COMMENTSIGN, fn ? fn : unk);
237
238 #ifdef HAVE_PWD_H
239     uid  = getuid();
240     pw   = getpwuid(uid);
241     gh   = gmx_gethostname(buf, 255);
242     /* pw returns null on error (e.g. compute nodes lack /etc/passwd) */
243     user = pw ? pw->pw_name : unk;
244 #else
245     uid = 0;
246     gh  = -1;
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 }