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