Revertiing my fake merge to make history consistent
[gromacs/adressmacs.git] / src / gmxlib / string2.c
blob43e57cf1d05cd5df8abda9f48eb571f23a49b254
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.
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.
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.
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.
30 * For more info, check our website at http://www.gromacs.org
32 * And Hey:
33 * GROningen Mixture of Alchemy and Childrens' Stories
35 /* This file is completely threadsafe - keep it that way! */
36 #ifdef HAVE_CONFIG_H
37 #include <config.h>
38 #endif
40 #ifdef GMX_CRAY_XT3
41 #undef HAVE_PWD_H
42 #endif
44 #include <stdio.h>
45 #include <ctype.h>
46 #include <stdlib.h>
47 #include <errno.h>
48 #include <sys/types.h>
50 #ifdef HAVE_PWD_H
51 #include <pwd.h>
52 #endif
53 #include <time.h>
55 #include "typedefs.h"
56 #include "smalloc.h"
57 #include "gmx_fatal.h"
58 #include "macros.h"
59 #include "string2.h"
60 #include "futil.h"
62 int continuing(char *s)
63 /* strip trailing spaces and if s ends with a CONTINUE remove that too.
64 * returns TRUE if s ends with a CONTINUE, FALSE otherwise.
67 int sl;
69 rtrim(s);
70 sl = strlen(s);
71 if ((sl > 0) && (s[sl-1] == CONTINUE)) {
72 s[sl-1] = 0;
73 return TRUE;
75 else
76 return FALSE;
81 char *fgets2(char *line, int n, FILE *stream)
82 /* This routine reads a string from stream of max length n
83 * and zero terminated, without newlines
84 * line should be long enough (>= n)
87 char *c;
88 if (fgets(line,n,stream) == NULL) {
89 return NULL;
91 if ((c=strchr(line,'\n')) != NULL) {
92 *c = '\0';
93 } else {
94 /* A line not ending in a newline can only occur at the end of a file,
95 * or because of n being too small.
96 * Since both cases occur very infrequently, we can check for EOF.
98 if (!gmx_eof(stream)) {
99 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);
102 if ((c=strchr(line,'\r')) != NULL) {
103 *c = '\0';
106 return line;
109 void strip_comment (char *line)
111 char *c;
113 if (!line)
114 return;
116 /* search for a comment mark and replace it by a zero */
117 if ((c = strchr(line,COMMENTSIGN)) != NULL)
118 (*c) = 0;
121 void upstring (char *str)
123 int i;
125 for (i=0; (i < (int)strlen(str)); i++)
126 str[i] = toupper(str[i]);
129 void ltrim (char *str)
131 char *tr;
132 int i,c;
134 if (NULL == str)
135 return;
137 c = 0;
138 while (('\0' != str[c]) && isspace(str[c]))
139 c++;
140 if (c > 0)
142 for(i=c; ('\0' != str[i]); i++)
143 str[i-c] = str[i];
144 str[i-c] = '\0';
148 void rtrim (char *str)
150 int nul;
152 if (NULL == str)
153 return;
155 nul = strlen(str)-1;
156 while ((nul > 0) && ((str[nul] == ' ') || (str[nul] == '\t')) ) {
157 str[nul] = '\0';
158 nul--;
162 void trim (char *str)
164 ltrim (str);
165 rtrim (str);
168 char *
169 gmx_ctime_r(const time_t *clock,char *buf, int n)
171 char tmpbuf[STRLEN];
173 #if ((defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64) && !defined __CYGWIN__ && !defined __CYGWIN32__)
174 /* Windows */
175 ctime_s( tmpbuf, STRLEN, clock );
176 #else
177 ctime_r(clock,tmpbuf);
178 #endif
179 strncpy(buf,tmpbuf,n-1);
180 buf[n-1]='\0';
182 return buf;
185 void nice_header (FILE *out,const char *fn)
187 const char *unk = "onbekend";
188 time_t clock;
189 char *user=NULL;
190 int gh;
191 uid_t uid;
192 char buf[256];
193 char timebuf[STRLEN];
194 #ifdef HAVE_PWD_H
195 struct passwd *pw;
196 #endif
198 /* Print a nice header above the file */
199 time(&clock);
200 fprintf (out,"%c\n",COMMENTSIGN);
201 fprintf (out,"%c\tFile '%s' was generated\n",COMMENTSIGN,fn ? fn : unk);
203 #ifdef HAVE_PWD_H
204 uid = getuid();
205 pw = getpwuid(uid);
206 gh = gethostname(buf,255);
207 user= pw->pw_name;
208 #else
209 uid = 0;
210 gh = -1;
211 #endif
213 gmx_ctime_r(&clock,timebuf,STRLEN);
214 fprintf (out,"%c\tBy user: %s (%d)\n",COMMENTSIGN,
215 user ? user : unk,(int) uid);
216 fprintf(out,"%c\tOn host: %s\n",COMMENTSIGN,(gh == 0) ? buf : unk);
218 fprintf (out,"%c\tAt date: %s",COMMENTSIGN,timebuf);
219 fprintf (out,"%c\n",COMMENTSIGN);
222 int strcasecmp_min(const char *str1, const char *str2)
224 char ch1,ch2;
229 ch1=toupper(*(str1++));
230 while ((ch1=='-') || (ch1=='_'));
232 ch2=toupper(*(str2++));
233 while ((ch2=='-') || (ch2=='_'));
234 if (ch1!=ch2) return (ch1-ch2);
236 while (ch1);
237 return 0;
240 int strncasecmp_min(const char *str1, const char *str2, int n)
242 char ch1,ch2;
243 char *stri1, *stri2;
245 stri1=(char *)str1;
246 stri2=(char *)str2;
250 ch1=toupper(*(str1++));
251 while ((ch1=='-') || (ch1=='_'));
253 ch2=toupper(*(str2++));
254 while ((ch2=='-') || (ch2=='_'));
255 if (ch1!=ch2) return (ch1-ch2);
257 while (ch1 && (str1-stri1<n) && (str2-stri2<n));
258 return 0;
261 int gmx_strcasecmp(const char *str1, const char *str2)
263 char ch1,ch2;
267 ch1=toupper(*(str1++));
268 ch2=toupper(*(str2++));
269 if (ch1!=ch2) return (ch1-ch2);
271 while (ch1);
272 return 0;
275 int gmx_strncasecmp(const char *str1, const char *str2, int n)
277 char ch1,ch2;
279 if(n==0)
280 return 0;
284 ch1=toupper(*(str1++));
285 ch2=toupper(*(str2++));
286 if (ch1!=ch2) return (ch1-ch2);
287 n--;
289 while (ch1 && n);
290 return 0;
293 char *gmx_strdup(const char *src)
295 char *dest;
297 snew(dest,strlen(src)+1);
298 strcpy(dest,src);
300 return dest;
303 char *
304 gmx_strndup(const char *src, int n)
306 int len;
307 char *dest;
309 len = strlen(src);
310 if (len > n)
312 len = n;
314 snew(dest, len+1);
315 strncpy(dest, src, len);
316 dest[len] = 0;
317 return dest;
321 * \param[in] pattern Pattern to match against.
322 * \param[in] str String to match.
323 * \returns 0 on match, GMX_NO_WCMATCH if there is no match.
325 * Matches \p str against \p pattern, which may contain * and ? wildcards.
326 * All other characters are matched literally.
327 * Currently, it is not possible to match literal * or ?.
330 gmx_wcmatch(const char *pattern, const char *str)
332 while (*pattern)
334 if (*pattern == '*')
336 /* Skip multiple wildcards in a sequence */
337 while (*pattern == '*' || *pattern == '?')
339 ++pattern;
340 /* For ?, we need to check that there are characters left
341 * in str. */
342 if (*pattern == '?')
344 if (*str == 0)
346 return GMX_NO_WCMATCH;
348 else
350 ++str;
354 /* If the pattern ends after the star, we have a match */
355 if (*pattern == 0)
357 return 0;
359 /* Match the rest against each possible suffix of str */
360 while (*str)
362 /* Only do the recursive call if the first character
363 * matches. We don't have to worry about wildcards here,
364 * since we have processed them above. */
365 if (*pattern == *str)
367 int rc;
368 /* Match the suffix, and return if a match or an error */
369 rc = gmx_wcmatch(pattern, str);
370 if (rc != GMX_NO_WCMATCH)
372 return rc;
375 ++str;
377 /* If no suffix of str matches, we don't have a match */
378 return GMX_NO_WCMATCH;
380 else if ((*pattern == '?' && *str != 0) || *pattern == *str)
382 ++str;
384 else
386 return GMX_NO_WCMATCH;
388 ++pattern;
390 /* When the pattern runs out, we have a match if the string has ended. */
391 return (*str == 0) ? 0 : GMX_NO_WCMATCH;
394 char *wrap_lines(const char *buf,int line_width, int indent,bool bIndentFirst)
396 char *b2;
397 int i,i0,i2,j,b2len,lspace=0,l2space=0;
398 bool bFirst,bFitsOnLine;
400 /* characters are copied from buf to b2 with possible spaces changed
401 * into newlines and extra space added for indentation.
402 * i indexes buf (source buffer) and i2 indexes b2 (destination buffer)
403 * i0 points to the beginning of the current line (in buf, source)
404 * lspace and l2space point to the last space on the current line
405 * bFirst is set to prevent indentation of first line
406 * bFitsOnLine says if the first space occurred before line_width, if
407 * that is not the case, we have a word longer than line_width which
408 * will also not fit on the next line, so we might as well keep it on
409 * the current line (where it also won't fit, but looks better)
412 b2=NULL;
413 b2len=strlen(buf)+1+indent;
414 snew(b2,b2len);
415 i0=i2=0;
416 if (bIndentFirst)
417 for(i2=0; (i2<indent); i2++)
418 b2[i2] = ' ';
419 bFirst=TRUE;
420 do {
421 l2space = -1;
422 /* find the last space before end of line */
423 for(i=i0; ((i-i0 < line_width) || (l2space==-1)) && (buf[i]); i++) {
424 b2[i2++] = buf[i];
425 /* remember the position of a space */
426 if (buf[i] == ' ') {
427 lspace = i;
428 l2space = i2-1;
430 /* if we have a newline before the line is full, reset counters */
431 if (buf[i]=='\n' && buf[i+1]) {
432 i0=i+1;
433 b2len+=indent;
434 srenew(b2, b2len);
435 /* add indentation after the newline */
436 for(j=0; (j<indent); j++)
437 b2[i2++]=' ';
440 /* If we are at the last newline, copy it */
441 if (buf[i]=='\n' && !buf[i+1]) {
442 b2[i2++] = buf[i++];
444 /* if we're not at the end of the string */
445 if (buf[i]) {
446 /* check if one word does not fit on the line */
447 bFitsOnLine = (i-i0 <= line_width);
448 /* reset line counters to just after the space */
449 i0 = lspace+1;
450 i2 = l2space+1;
451 /* if the words fit on the line, and we're beyond the indentation part */
452 if ( (bFitsOnLine) && (l2space >= indent) ) {
453 /* start a new line */
454 b2[l2space] = '\n';
455 /* and add indentation */
456 if (indent) {
457 if (bFirst) {
458 line_width-=indent;
459 bFirst=FALSE;
461 b2len+=indent;
462 srenew(b2, b2len);
463 for(j=0; (j<indent); j++)
464 b2[i2++]=' ';
465 /* no extra spaces after indent; */
466 while(buf[i0]==' ')
467 i0++;
471 } while (buf[i]);
472 b2[i2] = '\0';
474 return b2;
477 char **split(char sep,const char *str)
479 char **ptr = NULL;
480 int n,nn,nptr = 0;
482 if (str == NULL)
483 return NULL;
484 nn = strlen(str);
485 for(n=0; (n<nn); n++)
486 if (str[n] == sep)
487 nptr++;
488 snew(ptr,nptr+2);
489 nptr = 0;
490 while (*str != '\0') {
491 while ((*str != '\0') && (*str == sep))
492 str++;
493 if (*str != '\0') {
494 snew(ptr[nptr],1+strlen(str));
495 n = 0;
496 while ((*str != '\0') && (*str != sep)) {
497 ptr[nptr][n] = *str;
498 str++;
499 n++;
501 ptr[nptr][n] = '\0';
502 nptr++;
505 ptr[nptr] = NULL;
507 return ptr;
511 gmx_large_int_t
512 str_to_large_int_t(const char *str, char **endptr)
514 int sign = 1;
515 gmx_large_int_t val = 0;
516 char ch;
517 const char *p;
519 p = str;
520 if(p==NULL)
522 *endptr=NULL;
523 return 0;
526 /* Strip off initial white space */
527 while(isspace(*p))
529 p++;
531 /* Conform to ISO C99 - return original pointer if string does not contain a number */
532 if(*str=='\0')
534 *endptr=(char *)str;
537 if(*p=='-')
539 p++;
540 sign *= -1;
543 while( ((ch=*p) != '\0') && isdigit(ch) )
545 /* Important to add sign here, so we dont overflow in final multiplication */
546 ch = (ch-'0')*sign;
547 val = val*10 + ch;
548 if(ch != val%10)
550 /* Some sort of overflow has occured, set endptr to original string */
551 *endptr=(char *)str;
552 errno = ERANGE;
553 return(0);
555 p++;
558 *endptr=(char *)p;
560 return val;
563 char *gmx_strsep(char **stringp, const char *delim)
565 char *ret;
566 int len=strlen(delim);
567 int i,j=0;
568 int found=0;
570 if (! *stringp)
571 return NULL;
572 ret=*stringp;
575 if ( (*stringp)[j] == '\0')
577 found=1;
578 *stringp=NULL;
579 break;
581 for (i=0;i<len;i++)
583 if ( (*stringp)[j]==delim[i])
585 (*stringp)[j]='\0';
586 *stringp=*stringp+j+1;
587 found=1;
588 break;
591 j++;
592 } while (!found);
594 return ret;