Fixing more clang warnings
[gromacs.git] / src / gmxlib / string2.c
blob9f84eb75d84e85ed50c4569c57557a209ae113af
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
39 #include "gmx_header_config.h"
41 #ifdef GMX_CRAY_XT3
42 #undef HAVE_PWD_H
43 #endif
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>
52 #ifdef HAVE_SYS_TIME_H
53 #include <sys/time.h>
54 #endif
57 #ifdef HAVE_PWD_H
58 #include <pwd.h>
59 #endif
60 #include <time.h>
61 #include <assert.h>
63 #include "typedefs.h"
64 #include "smalloc.h"
65 #include "gmx_fatal.h"
66 #include "macros.h"
67 #include "string2.h"
68 #include "futil.h"
70 int continuing(char *s)
71 /* strip trailing spaces and if s ends with a CONTINUE remove that too.
72 * returns TRUE if s ends with a CONTINUE, FALSE otherwise.
75 int sl;
76 assert(s);
78 rtrim(s);
79 sl = strlen(s);
80 if ((sl > 0) && (s[sl-1] == CONTINUE)) {
81 s[sl-1] = 0;
82 return TRUE;
84 else
85 return FALSE;
90 char *fgets2(char *line, int n, FILE *stream)
91 /* This routine reads a string from stream of max length n
92 * and zero terminated, without newlines
93 * line should be long enough (>= n)
96 char *c;
97 if (fgets(line,n,stream) == NULL) {
98 return NULL;
100 if ((c=strchr(line,'\n')) != NULL) {
101 *c = '\0';
102 } else {
103 /* A line not ending in a newline can only occur at the end of a file,
104 * or because of n being too small.
105 * Since both cases occur very infrequently, we can check for EOF.
107 if (!gmx_eof(stream)) {
108 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);
111 if ((c=strchr(line,'\r')) != NULL) {
112 *c = '\0';
115 return line;
118 void strip_comment (char *line)
120 char *c;
122 if (!line)
123 return;
125 /* search for a comment mark and replace it by a zero */
126 if ((c = strchr(line,COMMENTSIGN)) != NULL)
127 (*c) = 0;
130 void upstring (char *str)
132 int i;
134 for (i=0; (i < (int)strlen(str)); i++)
135 str[i] = toupper(str[i]);
138 void ltrim (char *str)
140 char *tr;
141 int i,c;
143 if (NULL == str)
144 return;
146 c = 0;
147 while (('\0' != str[c]) && isspace(str[c]))
148 c++;
149 if (c > 0)
151 for(i=c; ('\0' != str[i]); i++)
152 str[i-c] = str[i];
153 str[i-c] = '\0';
157 void rtrim (char *str)
159 int nul;
161 if (NULL == str)
162 return;
164 nul = strlen(str)-1;
165 while ((nul > 0) && ((str[nul] == ' ') || (str[nul] == '\t')) ) {
166 str[nul] = '\0';
167 nul--;
171 void trim (char *str)
173 ltrim (str);
174 rtrim (str);
177 char *
178 gmx_ctime_r(const time_t *clock,char *buf, int n)
180 char tmpbuf[STRLEN];
182 #ifdef GMX_NATIVE_WINDOWS
183 /* Windows */
184 ctime_s( tmpbuf, STRLEN, clock );
185 #elif (defined(__sun))
186 /*Solaris*/
187 ctime_r(clock, tmpbuf, n);
188 #else
189 ctime_r(clock,tmpbuf);
190 #endif
191 strncpy(buf,tmpbuf,n-1);
192 buf[n-1]='\0';
194 return buf;
197 void nice_header (FILE *out,const char *fn)
199 const char *unk = "onbekend";
200 time_t clock;
201 const char *user=unk;
202 int gh;
203 uid_t uid;
204 char buf[256]="";
205 char timebuf[STRLEN];
206 #ifdef HAVE_PWD_H
207 struct passwd *pw;
208 #endif
210 /* Print a nice header above the file */
211 time(&clock);
212 fprintf (out,"%c\n",COMMENTSIGN);
213 fprintf (out,"%c\tFile '%s' was generated\n",COMMENTSIGN,fn ? fn : unk);
215 #ifdef HAVE_PWD_H
216 uid = getuid();
217 pw = getpwuid(uid);
218 gh = gethostname(buf,255);
219 user= pw->pw_name;
220 #else
221 uid = 0;
222 gh = -1;
223 #endif
225 gmx_ctime_r(&clock,timebuf,STRLEN);
226 fprintf (out,"%c\tBy user: %s (%d)\n",COMMENTSIGN,
227 user ? user : unk,(int) uid);
228 fprintf(out,"%c\tOn host: %s\n",COMMENTSIGN,(gh == 0) ? buf : unk);
230 fprintf (out,"%c\tAt date: %s",COMMENTSIGN,timebuf);
231 fprintf (out,"%c\n",COMMENTSIGN);
234 int gmx_strcasecmp_min(const char *str1, const char *str2)
236 char ch1,ch2;
241 ch1=toupper(*(str1++));
242 while ((ch1=='-') || (ch1=='_'));
244 ch2=toupper(*(str2++));
245 while ((ch2=='-') || (ch2=='_'));
246 if (ch1!=ch2) return (ch1-ch2);
248 while (ch1);
249 return 0;
252 int gmx_strncasecmp_min(const char *str1, const char *str2, int n)
254 char ch1,ch2;
255 char *stri1, *stri2;
257 stri1=(char *)str1;
258 stri2=(char *)str2;
262 ch1=toupper(*(str1++));
263 while ((ch1=='-') || (ch1=='_'));
265 ch2=toupper(*(str2++));
266 while ((ch2=='-') || (ch2=='_'));
267 if (ch1!=ch2) return (ch1-ch2);
269 while (ch1 && (str1-stri1<n) && (str2-stri2<n));
270 return 0;
273 int gmx_strcasecmp(const char *str1, const char *str2)
275 char ch1,ch2;
279 ch1=toupper(*(str1++));
280 ch2=toupper(*(str2++));
281 if (ch1!=ch2) return (ch1-ch2);
283 while (ch1);
284 return 0;
287 int gmx_strncasecmp(const char *str1, const char *str2, int n)
289 char ch1,ch2;
291 if(n==0)
292 return 0;
296 ch1=toupper(*(str1++));
297 ch2=toupper(*(str2++));
298 if (ch1!=ch2) return (ch1-ch2);
299 n--;
301 while (ch1 && n);
302 return 0;
305 char *gmx_strdup(const char *src)
307 char *dest;
309 snew(dest,strlen(src)+1);
310 strcpy(dest,src);
312 return dest;
315 char *
316 gmx_strndup(const char *src, int n)
318 int len;
319 char *dest;
321 len = strlen(src);
322 if (len > n)
324 len = n;
326 snew(dest, len+1);
327 strncpy(dest, src, len);
328 dest[len] = 0;
329 return dest;
333 * \param[in] pattern Pattern to match against.
334 * \param[in] str String to match.
335 * \returns 0 on match, GMX_NO_WCMATCH if there is no match.
337 * Matches \p str against \p pattern, which may contain * and ? wildcards.
338 * All other characters are matched literally.
339 * Currently, it is not possible to match literal * or ?.
342 gmx_wcmatch(const char *pattern, const char *str)
344 while (*pattern)
346 if (*pattern == '*')
348 /* Skip multiple wildcards in a sequence */
349 while (*pattern == '*' || *pattern == '?')
351 ++pattern;
352 /* For ?, we need to check that there are characters left
353 * in str. */
354 if (*pattern == '?')
356 if (*str == 0)
358 return GMX_NO_WCMATCH;
360 else
362 ++str;
366 /* If the pattern ends after the star, we have a match */
367 if (*pattern == 0)
369 return 0;
371 /* Match the rest against each possible suffix of str */
372 while (*str)
374 /* Only do the recursive call if the first character
375 * matches. We don't have to worry about wildcards here,
376 * since we have processed them above. */
377 if (*pattern == *str)
379 int rc;
380 /* Match the suffix, and return if a match or an error */
381 rc = gmx_wcmatch(pattern, str);
382 if (rc != GMX_NO_WCMATCH)
384 return rc;
387 ++str;
389 /* If no suffix of str matches, we don't have a match */
390 return GMX_NO_WCMATCH;
392 else if ((*pattern == '?' && *str != 0) || *pattern == *str)
394 ++str;
396 else
398 return GMX_NO_WCMATCH;
400 ++pattern;
402 /* When the pattern runs out, we have a match if the string has ended. */
403 return (*str == 0) ? 0 : GMX_NO_WCMATCH;
406 char *wrap_lines(const char *buf,int line_width, int indent,gmx_bool bIndentFirst)
408 char *b2;
409 int i,i0,i2,j,b2len,lspace=0,l2space=0;
410 gmx_bool bFirst,bFitsOnLine;
412 /* characters are copied from buf to b2 with possible spaces changed
413 * into newlines and extra space added for indentation.
414 * i indexes buf (source buffer) and i2 indexes b2 (destination buffer)
415 * i0 points to the beginning of the current line (in buf, source)
416 * lspace and l2space point to the last space on the current line
417 * bFirst is set to prevent indentation of first line
418 * bFitsOnLine says if the first space occurred before line_width, if
419 * that is not the case, we have a word longer than line_width which
420 * will also not fit on the next line, so we might as well keep it on
421 * the current line (where it also won't fit, but looks better)
424 b2=NULL;
425 b2len=strlen(buf)+1+indent;
426 snew(b2,b2len);
427 i0=i2=0;
428 if (bIndentFirst)
429 for(i2=0; (i2<indent); i2++)
430 b2[i2] = ' ';
431 bFirst=TRUE;
432 do {
433 l2space = -1;
434 /* find the last space before end of line */
435 for(i=i0; ((i-i0 < line_width) || (l2space==-1)) && (buf[i]); i++) {
436 b2[i2++] = buf[i];
437 /* remember the position of a space */
438 if (buf[i] == ' ') {
439 lspace = i;
440 l2space = i2-1;
442 /* if we have a newline before the line is full, reset counters */
443 if (buf[i]=='\n' && buf[i+1]) {
444 i0=i+1;
445 b2len+=indent;
446 srenew(b2, b2len);
447 /* add indentation after the newline */
448 for(j=0; (j<indent); j++)
449 b2[i2++]=' ';
452 /* If we are at the last newline, copy it */
453 if (buf[i]=='\n' && !buf[i+1]) {
454 b2[i2++] = buf[i++];
456 /* if we're not at the end of the string */
457 if (buf[i]) {
458 /* check if one word does not fit on the line */
459 bFitsOnLine = (i-i0 <= line_width);
460 /* reset line counters to just after the space */
461 i0 = lspace+1;
462 i2 = l2space+1;
463 /* if the words fit on the line, and we're beyond the indentation part */
464 if ( (bFitsOnLine) && (l2space >= indent) ) {
465 /* start a new line */
466 b2[l2space] = '\n';
467 /* and add indentation */
468 if (indent) {
469 if (bFirst) {
470 line_width-=indent;
471 bFirst=FALSE;
473 b2len+=indent;
474 srenew(b2, b2len);
475 for(j=0; (j<indent); j++)
476 b2[i2++]=' ';
477 /* no extra spaces after indent; */
478 while(buf[i0]==' ')
479 i0++;
483 } while (buf[i]);
484 b2[i2] = '\0';
486 return b2;
489 char **split(char sep,char *str)
491 char **ptr = NULL;
492 int n,nn,nptr = 0;
494 if (str == NULL)
495 return NULL;
496 nn = strlen(str);
497 for(n=0; (n<nn); n++)
498 if (str[n] == sep)
499 nptr++;
500 snew(ptr,nptr+2);
501 nptr = 0;
502 while (*str != '\0') {
503 while ((*str != '\0') && (*str == sep))
504 str++;
505 if (*str != '\0') {
506 snew(ptr[nptr],1+strlen(str));
507 n = 0;
508 while ((*str != '\0') && (*str != sep)) {
509 ptr[nptr][n] = *str;
510 str++;
511 n++;
513 ptr[nptr][n] = '\0';
514 nptr++;
517 ptr[nptr] = NULL;
519 return ptr;
523 gmx_large_int_t
524 str_to_large_int_t(const char *str, char **endptr)
526 int sign = 1;
527 gmx_large_int_t val = 0;
528 char ch;
529 const char *p;
531 p = str;
532 if(p==NULL)
534 *endptr=NULL;
535 return 0;
538 /* Strip off initial white space */
539 while(isspace(*p))
541 p++;
543 /* Conform to ISO C99 - return original pointer if string does not contain a number */
544 if(*str=='\0')
546 *endptr=(char *)str;
549 if(*p=='-')
551 p++;
552 sign *= -1;
555 while( ((ch=*p) != '\0') && isdigit(ch) )
557 /* Important to add sign here, so we dont overflow in final multiplication */
558 ch = (ch-'0')*sign;
559 val = val*10 + ch;
560 if(ch != val%10)
562 /* Some sort of overflow has occured, set endptr to original string */
563 *endptr=(char *)str;
564 errno = ERANGE;
565 return(0);
567 p++;
570 *endptr=(char *)p;
572 return val;
575 char *gmx_strsep(char **stringp, const char *delim)
577 char *ret;
578 int len=strlen(delim);
579 int i,j=0;
580 int found=0;
582 if (! *stringp)
583 return NULL;
584 ret=*stringp;
587 if ( (*stringp)[j] == '\0')
589 found=1;
590 *stringp=NULL;
591 break;
593 for (i=0;i<len;i++)
595 if ( (*stringp)[j]==delim[i])
597 (*stringp)[j]='\0';
598 *stringp=*stringp+j+1;
599 found=1;
600 break;
603 j++;
604 } while (!found);
606 return ret;