Merge remote-tracking branch 'origin/release-4-6'
[alexxy/gromacs.git] / src / gromacs / gmxlib / string2.c
1 /*
2  * 
3  *                This source code is part of
4  * 
5  *                 G   R   O   M   A   C   S
6  * 
7  *          GROningen MAchine for Chemical Simulations
8  * 
9  *                        VERSION 3.2.0
10  * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
11  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
12  * Copyright (c) 2001-2004, The GROMACS development team,
13  * check out http://www.gromacs.org for more information.
14
15  * This program is free software; you can redistribute it and/or
16  * modify it under the terms of the GNU General Public License
17  * as published by the Free Software Foundation; either version 2
18  * of the License, or (at your option) any later version.
19  * 
20  * If you want to redistribute modifications, please consider that
21  * scientific software is very special. Version control is crucial -
22  * bugs must be traceable. We will be happy to consider code for
23  * inclusion in the official distribution, but derived work must not
24  * be called official GROMACS. Details are found in the README & COPYING
25  * files - if they are missing, get the official version at www.gromacs.org.
26  * 
27  * To help us fund GROMACS development, we humbly ask that you cite
28  * the papers on the package - you can find them in the top README file.
29  * 
30  * For more info, check our website at http://www.gromacs.org
31  * 
32  * And Hey:
33  * GROningen Mixture of Alchemy and Childrens' Stories
34  */
35 /* This file is completely threadsafe - keep it that way! */
36 #ifdef HAVE_CONFIG_H
37 #include <config.h>
38 #endif
39 #include "gromacs/utility/gmx_header_config.h"
40
41 #ifdef GMX_CRAY_XT3
42 #undef HAVE_PWD_H
43 #endif
44
45 #include <stdio.h>
46 #include <ctype.h>
47 #include <stdlib.h>
48 #include <errno.h>
49 #include <sys/types.h>
50 #include <time.h>
51
52 #ifdef HAVE_SYS_TIME_H
53 #include <sys/time.h>
54 #endif
55
56 #ifdef HAVE_UNISTD_H
57 #include <unistd.h>
58 #endif
59
60 #ifdef HAVE_PWD_H
61 #include <pwd.h>
62 #endif
63 #include <time.h>
64 #include <assert.h>
65
66 #include "typedefs.h"
67 #include "smalloc.h"
68 #include "gmx_fatal.h"
69 #include "macros.h"
70 #include "string2.h"
71 #include "futil.h"
72
73 int continuing(char *s)
74 /* strip trailing spaces and if s ends with a CONTINUE remove that too.
75  * returns TRUE if s ends with a CONTINUE, FALSE otherwise.
76  */
77 {
78   int sl;
79   assert(s);
80
81   rtrim(s);
82   sl = strlen(s);
83   if ((sl > 0) && (s[sl-1] == CONTINUE)) {
84     s[sl-1] = 0;
85     return TRUE;
86   }
87   else
88     return FALSE;
89 }
90
91
92
93 char *fgets2(char *line, int n, FILE *stream)
94 /* This routine reads a string from stream of max length n
95  * and zero terminated, without newlines
96  * line should be long enough (>= n)
97  */
98 {
99   char *c;
100   if (fgets(line,n,stream) == NULL) {
101     return NULL;
102   }
103   if ((c=strchr(line,'\n')) != NULL) {
104     *c = '\0';
105   } else {
106     /* A line not ending in a newline can only occur at the end of a file,
107      * or because of n being too small.
108      * Since both cases occur very infrequently, we can check for EOF.
109      */
110     if (!gmx_eof(stream)) {
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     *c = '\0';
116   }
117
118   return line;
119 }
120
121 void strip_comment (char *line)
122 {
123   char *c;
124
125   if (!line)
126     return;
127
128   /* search for a comment mark and replace it by a zero */
129   if ((c = strchr(line,COMMENTSIGN)) != NULL) 
130     (*c) = 0;
131 }
132
133 void upstring (char *str)
134 {
135   int i;
136
137   for (i=0; (i < (int)strlen(str)); i++) 
138     str[i] = toupper(str[i]);
139 }
140
141 void ltrim (char *str)
142 {
143   char *tr;
144   int i,c;
145
146   if (NULL == str)
147     return;
148
149   c = 0;
150   while (('\0' != str[c]) && isspace(str[c]))
151     c++;
152   if (c > 0) 
153     {
154       for(i=c; ('\0' != str[i]); i++)
155         str[i-c] = str[i];
156       str[i-c] = '\0';
157     }
158 }
159
160 void rtrim (char *str)
161 {
162   int nul;
163
164   if (NULL == str)
165     return;
166
167   nul = strlen(str)-1;
168   while ((nul > 0) && ((str[nul] == ' ') || (str[nul] == '\t')) ) {
169     str[nul] = '\0';
170     nul--;
171   }
172 }
173
174 void trim (char *str)
175 {
176   ltrim (str);
177   rtrim (str);
178 }
179
180 char *
181 gmx_ctime_r(const time_t *clock,char *buf, int n)
182 {
183     char tmpbuf[STRLEN];
184   
185 #ifdef GMX_NATIVE_WINDOWS
186     /* Windows */
187     ctime_s( tmpbuf, STRLEN, clock );
188 #elif (defined(__sun))
189     /*Solaris*/
190     ctime_r(clock, tmpbuf, n);
191 #else
192     ctime_r(clock,tmpbuf);
193 #endif
194     strncpy(buf,tmpbuf,n-1);
195     buf[n-1]='\0';
196     
197     return buf;
198 }
199           
200 void nice_header (FILE *out,const char *fn)
201 {
202   const char *unk = "onbekend";
203   time_t clock;
204   const char *user=unk;
205   int    gh;
206   uid_t  uid;
207   char   buf[256]="";
208   char   timebuf[STRLEN];
209 #ifdef HAVE_PWD_H
210   struct passwd *pw;
211 #endif
212
213   /* Print a nice header above the file */
214   time(&clock);
215   fprintf (out,"%c\n",COMMENTSIGN);
216   fprintf (out,"%c\tFile '%s' was generated\n",COMMENTSIGN,fn ? fn : unk);
217   
218 #ifdef HAVE_PWD_H
219   uid = getuid();
220   pw  = getpwuid(uid);
221   gh  = gethostname(buf,255);
222   user= pw->pw_name;
223 #else
224   uid = 0;
225   gh  = -1;
226 #endif
227   
228   gmx_ctime_r(&clock,timebuf,STRLEN);
229   fprintf (out,"%c\tBy user: %s (%d)\n",COMMENTSIGN,
230            user ? user : unk,(int) uid);
231   fprintf(out,"%c\tOn host: %s\n",COMMENTSIGN,(gh == 0) ? buf : unk);
232
233   fprintf (out,"%c\tAt date: %s",COMMENTSIGN,timebuf);
234   fprintf (out,"%c\n",COMMENTSIGN);
235 }
236
237 int gmx_strcasecmp_min(const char *str1, const char *str2)
238 {
239   char ch1,ch2;
240   
241   do
242     {
243       do
244         ch1=toupper(*(str1++));
245       while ((ch1=='-') || (ch1=='_'));
246       do 
247         ch2=toupper(*(str2++));
248       while ((ch2=='-') || (ch2=='_'));
249       if (ch1!=ch2) return (ch1-ch2);
250     }
251   while (ch1);
252   return 0; 
253 }
254
255 int gmx_strncasecmp_min(const char *str1, const char *str2, int n)
256 {
257   char ch1,ch2;
258   char *stri1, *stri2;
259
260   stri1=(char *)str1;
261   stri2=(char *)str2;  
262   do
263     {
264       do
265         ch1=toupper(*(str1++));
266       while ((ch1=='-') || (ch1=='_'));
267       do 
268         ch2=toupper(*(str2++));
269       while ((ch2=='-') || (ch2=='_'));
270       if (ch1!=ch2) return (ch1-ch2);
271     }
272   while (ch1 && (str1-stri1<n) && (str2-stri2<n));
273   return 0; 
274 }
275
276 int gmx_strcasecmp(const char *str1, const char *str2)
277 {
278   char ch1,ch2;
279   
280   do
281     {
282       ch1=toupper(*(str1++));
283       ch2=toupper(*(str2++));
284       if (ch1!=ch2) return (ch1-ch2);
285     }
286   while (ch1);
287   return 0; 
288 }
289
290 int gmx_strncasecmp(const char *str1, const char *str2, int n)
291 {
292   char ch1,ch2;
293  
294   if(n==0) 
295     return 0;
296
297   do
298     {
299       ch1=toupper(*(str1++));
300       ch2=toupper(*(str2++));
301       if (ch1!=ch2) return (ch1-ch2);
302       n--;
303     }
304   while (ch1 && n);
305   return 0; 
306 }
307
308 char *gmx_strdup(const char *src)
309 {
310   char *dest;
311
312   snew(dest,strlen(src)+1);
313   strcpy(dest,src);
314   
315   return dest;
316 }
317
318 char *
319 gmx_strndup(const char *src, int n)
320 {
321     int   len;
322     char *dest;
323
324     len = strlen(src);
325     if (len > n) 
326     {
327         len = n;
328     }
329     snew(dest, len+1);
330     strncpy(dest, src, len);
331     dest[len] = 0;
332     return dest;
333 }
334
335 /*!
336  * \param[in] pattern  Pattern to match against.
337  * \param[in] str      String to match.
338  * \returns   0 on match, GMX_NO_WCMATCH if there is no match.
339  *
340  * Matches \p str against \p pattern, which may contain * and ? wildcards.
341  * All other characters are matched literally.
342  * Currently, it is not possible to match literal * or ?.
343  */
344 int
345 gmx_wcmatch(const char *pattern, const char *str)
346 {
347     while (*pattern)
348     {
349         if (*pattern == '*')
350         {
351             /* Skip multiple wildcards in a sequence */
352             while (*pattern == '*' || *pattern == '?')
353             {
354                 ++pattern;
355                 /* For ?, we need to check that there are characters left
356                  * in str. */
357                 if (*pattern == '?')
358                 {
359                     if (*str == 0)
360                     {
361                         return GMX_NO_WCMATCH;
362                     }
363                     else
364                     {
365                         ++str;
366                     }
367                 }
368             }
369             /* If the pattern ends after the star, we have a match */
370             if (*pattern == 0)
371             {
372                 return 0;
373             }
374             /* Match the rest against each possible suffix of str */
375             while (*str)
376             {
377                 /* Only do the recursive call if the first character
378                  * matches. We don't have to worry about wildcards here,
379                  * since we have processed them above. */
380                 if (*pattern == *str)
381                 {
382                     int rc;
383                     /* Match the suffix, and return if a match or an error */
384                     rc = gmx_wcmatch(pattern, str);
385                     if (rc != GMX_NO_WCMATCH)
386                     {
387                         return rc;
388                     }
389                 }
390                 ++str;
391             }
392             /* If no suffix of str matches, we don't have a match */
393             return GMX_NO_WCMATCH;
394         }
395         else if ((*pattern == '?' && *str != 0) || *pattern == *str)
396         {
397             ++str;
398         }
399         else
400         {
401             return GMX_NO_WCMATCH;
402         }
403         ++pattern;
404     }
405     /* When the pattern runs out, we have a match if the string has ended. */
406     return (*str == 0) ? 0 : GMX_NO_WCMATCH;
407 }
408
409 char *wrap_lines(const char *buf,int line_width, int indent,gmx_bool bIndentFirst)
410 {
411   char *b2;
412   int i,i0,i2,j,b2len,lspace=0,l2space=0;
413   gmx_bool bFirst,bFitsOnLine;
414
415   /* characters are copied from buf to b2 with possible spaces changed
416    * into newlines and extra space added for indentation.
417    * i indexes buf (source buffer) and i2 indexes b2 (destination buffer)
418    * i0 points to the beginning of the current line (in buf, source)
419    * lspace and l2space point to the last space on the current line
420    * bFirst is set to prevent indentation of first line
421    * bFitsOnLine says if the first space occurred before line_width, if 
422    * that is not the case, we have a word longer than line_width which 
423    * will also not fit on the next line, so we might as well keep it on 
424    * the current line (where it also won't fit, but looks better)
425    */
426   
427   b2=NULL;
428   b2len=strlen(buf)+1+indent;
429   snew(b2,b2len);
430   i0=i2=0;
431   if (bIndentFirst)
432     for(i2=0; (i2<indent); i2++)
433       b2[i2] = ' ';
434   bFirst=TRUE;
435   do {
436     l2space = -1;
437     /* find the last space before end of line */
438     for(i=i0; ((i-i0 < line_width) || (l2space==-1)) && (buf[i]); i++) {
439       b2[i2++] = buf[i];
440       /* remember the position of a space */
441       if (buf[i] == ' ') {
442         lspace = i;
443         l2space = i2-1;
444       }
445       /* if we have a newline before the line is full, reset counters */
446       if (buf[i]=='\n' && buf[i+1]) { 
447         i0=i+1;
448         b2len+=indent;
449         srenew(b2, b2len);
450         /* add indentation after the newline */
451         for(j=0; (j<indent); j++)
452           b2[i2++]=' ';
453       }
454     }
455     /* If we are at the last newline, copy it */
456     if (buf[i]=='\n' && !buf[i+1]) {
457       b2[i2++] = buf[i++];
458     }
459     /* if we're not at the end of the string */
460     if (buf[i]) {
461       /* check if one word does not fit on the line */
462       bFitsOnLine = (i-i0 <= line_width);
463       /* reset line counters to just after the space */
464       i0 = lspace+1;
465       i2 = l2space+1;
466       /* if the words fit on the line, and we're beyond the indentation part */
467       if ( (bFitsOnLine) && (l2space >= indent) ) {
468         /* start a new line */
469         b2[l2space] = '\n';
470         /* and add indentation */
471         if (indent) {
472           if (bFirst) {
473             line_width-=indent;
474             bFirst=FALSE;
475           }
476           b2len+=indent;
477           srenew(b2, b2len);
478           for(j=0; (j<indent); j++)
479             b2[i2++]=' ';
480           /* no extra spaces after indent; */
481           while(buf[i0]==' ')
482             i0++;
483         }
484       }
485     }
486   } while (buf[i]);
487   b2[i2] = '\0';
488   
489   return b2;
490 }
491
492 char **split(char sep,const char *str)
493 {
494   char **ptr = NULL;
495   int  n,nn,nptr = 0;
496   
497   if (str == NULL)
498     return NULL;
499   nn = strlen(str);
500   for(n=0; (n<nn); n++)
501     if (str[n] == sep)
502       nptr++;
503   snew(ptr,nptr+2);
504   nptr = 0;
505   while (*str != '\0') {
506     while ((*str != '\0') && (*str == sep))
507       str++;
508     if (*str != '\0') {
509       snew(ptr[nptr],1+strlen(str));
510       n = 0;
511       while ((*str != '\0') && (*str != sep)) {
512         ptr[nptr][n] = *str;
513         str++;
514         n++;
515       }
516       ptr[nptr][n] = '\0';
517       nptr++;
518     }
519   }
520   ptr[nptr] = NULL;
521   
522   return ptr;
523 }
524
525
526 gmx_large_int_t
527 str_to_large_int_t(const char *str, char **endptr)
528 {
529         int         sign = 1;
530         gmx_large_int_t  val  = 0;
531         char        ch;
532         const char  *p;
533         
534         p = str;
535         if(p==NULL)
536         {
537                 *endptr=NULL;
538                 return 0;
539         }
540         
541         /* Strip off initial white space */
542         while(isspace(*p))
543         {
544                 p++;
545         }
546         /* Conform to ISO C99 - return original pointer if string does not contain a number */
547         if(*str=='\0')
548         {
549                 *endptr=(char *)str;
550         }
551         
552         if(*p=='-')
553         {
554                 p++;
555                 sign *= -1;
556         }
557         
558         while( ((ch=*p) != '\0') && isdigit(ch) )
559         {
560                 /* Important to add sign here, so we dont overflow in final multiplication */
561                 ch = (ch-'0')*sign; 
562                 val = val*10 + ch;
563                 if(ch != val%10) 
564                 {
565                         /* Some sort of overflow has occured, set endptr to original string */
566                         *endptr=(char *)str;
567                         errno = ERANGE;
568                         return(0);
569                 }
570                 p++;
571         }
572         
573         *endptr=(char *)p;
574         
575         return val;
576 }
577
578 char *gmx_strsep(char **stringp, const char *delim)
579 {
580     char *ret;
581     int len=strlen(delim);
582     int i,j=0;
583     int found=0;
584
585     if (! *stringp)
586         return NULL;
587     ret=*stringp;
588     do
589     {
590         if ( (*stringp)[j] == '\0')
591         {
592             found=1;
593             *stringp=NULL;
594             break;
595         }
596         for (i=0;i<len;i++)
597         {
598             if ( (*stringp)[j]==delim[i])
599             {
600                 (*stringp)[j]='\0';
601                 *stringp=*stringp+j+1;
602                 found=1;
603                 break;
604             }
605         }
606         j++;
607     } while (!found);
608
609     return ret;
610 }
611