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