]> git.sur5r.net Git - openldap/blob - libraries/liblutil/utils.c
happy new year
[openldap] / libraries / liblutil / utils.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1998-2007 The OpenLDAP Foundation.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted only as authorized by the OpenLDAP
9  * Public License.
10  *
11  * A copy of this license is available in the file LICENSE in the
12  * top-level directory of the distribution or, alternatively, at
13  * <http://www.OpenLDAP.org/license.html>.
14  */
15
16 #include "portable.h"
17
18 #include <stdio.h>
19 #include <ac/stdlib.h>
20 #include <ac/string.h>
21 #include <ac/ctype.h>
22 #include <ac/unistd.h>
23 #include <ac/time.h>
24 #ifdef HAVE_IO_H
25 #include <io.h>
26 #endif
27 #ifdef HAVE_FCNTL_H
28 #include <fcntl.h>
29 #endif
30
31 #include "lutil.h"
32 #include "ldap_defaults.h"
33 #include "ldap_pvt.h"
34
35 #ifdef HAVE_EBCDIC
36 int _trans_argv = 1;
37 #endif
38
39 #ifdef _WIN32
40 /* Some Windows versions accept both forward and backslashes in
41  * directory paths, but we always use backslashes when generating
42  * and parsing...
43  */
44 void lutil_slashpath( char *path )
45 {
46         char *c, *p;
47
48         p = path;
49         while (( c=strchr( p, '/' ))) {
50                 *c++ = '\\';
51                 p = c;
52         }
53 }
54 #endif
55
56 char* lutil_progname( const char* name, int argc, char *argv[] )
57 {
58         char *progname;
59
60         if(argc == 0) {
61                 return (char *)name;
62         }
63
64 #ifdef HAVE_EBCDIC
65         if (_trans_argv) {
66                 int i;
67                 for (i=0; i<argc; i++) __etoa(argv[i]);
68                 _trans_argv = 0;
69         }
70 #endif
71         LUTIL_SLASHPATH( argv[0] );
72         progname = strrchr ( argv[0], *LDAP_DIRSEP );
73         progname = progname ? &progname[1] : argv[0];
74         return progname;
75 }
76
77 #if 0
78 size_t lutil_gentime( char *s, size_t smax, const struct tm *tm )
79 {
80         size_t ret;
81 #ifdef HAVE_EBCDIC
82 /* We've been compiling in ASCII so far, but we want EBCDIC now since
83  * strftime only understands EBCDIC input.
84  */
85 #pragma convlit(suspend)
86 #endif
87         ret = strftime( s, smax, "%Y%m%d%H%M%SZ", tm );
88 #ifdef HAVE_EBCDIC
89 #pragma convlit(resume)
90         __etoa( s );
91 #endif
92         return ret;
93 }
94 #endif
95
96 size_t lutil_localtime( char *s, size_t smax, const struct tm *tm, long delta )
97 {
98         size_t  ret;
99         char    *p;
100
101         if ( smax < 16 ) {      /* YYYYmmddHHMMSSZ */
102                 return 0;
103         }
104
105 #ifdef HAVE_EBCDIC
106 /* We've been compiling in ASCII so far, but we want EBCDIC now since
107  * strftime only understands EBCDIC input.
108  */
109 #pragma convlit(suspend)
110 #endif
111         ret = strftime( s, smax, "%Y%m%d%H%M%SZ", tm );
112 #ifdef HAVE_EBCDIC
113 #pragma convlit(resume)
114         __etoa( s );
115 #endif
116         if ( delta == 0 || ret == 0 ) {
117                 return ret;
118         }
119
120         if ( smax < 20 ) {      /* YYYYmmddHHMMSS+HHMM */
121                 return 0;
122         }
123
124         p = s + 14;
125
126         if ( delta < 0 ) {
127                 p[ 0 ] = '-';
128                 delta = -delta;
129         } else {
130                 p[ 0 ] = '+';
131         }
132         p++;
133
134         snprintf( p, smax - 15, "%02ld%02ld", delta / 3600,
135                         ( delta % 3600 ) / 60 );
136
137         return ret + 5;
138 }
139
140 int lutil_tm2time( struct lutil_tm *tm, struct lutil_timet *tt )
141 {
142         static int moffset[12] = {
143                 0, 31, 59, 90, 120,
144                 151, 181, 212, 243,
145                 273, 304, 334 }; 
146         int sec;
147
148         tt->tt_usec = tm->tm_usec;
149
150         /* special case 0000/01/01+00:00:00 is returned as zero */
151         if ( tm->tm_year == -1900 && tm->tm_mon == 0 && tm->tm_mday == 1 &&
152                 tm->tm_hour == 0 && tm->tm_min == 0 && tm->tm_sec == 0 ) {
153                 tt->tt_sec = 0;
154                 tt->tt_gsec = 0;
155                 return 0;
156         }
157
158         /* tm->tm_year is years since 1900 */
159         /* calculate days from years since 1970 (epoch) */ 
160         tt->tt_sec = tm->tm_year - 70; 
161         tt->tt_sec *= 365L; 
162
163         /* count leap days in preceding years */ 
164         tt->tt_sec += ((tm->tm_year -69) >> 2); 
165
166         /* calculate days from months */ 
167         tt->tt_sec += moffset[tm->tm_mon]; 
168
169         /* add in this year's leap day, if any */ 
170         if (((tm->tm_year & 3) == 0) && (tm->tm_mon > 1)) { 
171                 tt->tt_sec ++; 
172         } 
173
174         /* add in days in this month */ 
175         tt->tt_sec += (tm->tm_mday - 1); 
176
177         /* this function can handle a range of about 17408 years... */
178         /* 86400 seconds in a day, divided by 128 = 675 */
179         tt->tt_sec *= 675;
180
181         /* move high 7 bits into tt_gsec */
182         tt->tt_gsec = tt->tt_sec >> 25;
183         tt->tt_sec -= tt->tt_gsec << 25;
184
185         /* get hours */ 
186         sec = tm->tm_hour; 
187
188         /* convert to minutes */ 
189         sec *= 60L; 
190         sec += tm->tm_min; 
191
192         /* convert to seconds */ 
193         sec *= 60L; 
194         sec += tm->tm_sec; 
195         
196         /* add remaining seconds */
197         tt->tt_sec <<= 7;
198         tt->tt_sec += sec;
199
200         /* return success */
201         return 0; 
202 }
203
204 int lutil_parsetime( char *atm, struct lutil_tm *tm )
205 {
206         while (atm && tm) {
207                 char *ptr = atm;
208                 unsigned i, fracs;
209
210                 /* Is the stamp reasonably long? */
211                 for (i=0; isdigit((unsigned char) atm[i]); i++);
212                 if (i < sizeof("00000101000000")-1)
213                         break;
214
215                 /*
216                  * parse the time into a struct tm
217                  */
218                 /* 4 digit year to year - 1900 */
219                 tm->tm_year = *ptr++ - '0';
220                 tm->tm_year *= 10; tm->tm_year += *ptr++ - '0';
221                 tm->tm_year *= 10; tm->tm_year += *ptr++ - '0';
222                 tm->tm_year *= 10; tm->tm_year += *ptr++ - '0';
223                 tm->tm_year -= 1900;
224                 /* month 01-12 to 0-11 */
225                 tm->tm_mon = *ptr++ - '0';
226                 tm->tm_mon *=10; tm->tm_mon += *ptr++ - '0';
227                 if (tm->tm_mon < 1 || tm->tm_mon > 12) break;
228                 tm->tm_mon--;
229
230                 /* day of month 01-31 */
231                 tm->tm_mday = *ptr++ - '0';
232                 tm->tm_mday *=10; tm->tm_mday += *ptr++ - '0';
233                 if (tm->tm_mday < 1 || tm->tm_mday > 31) break;
234
235                 /* Hour 00-23 */
236                 tm->tm_hour = *ptr++ - '0';
237                 tm->tm_hour *=10; tm->tm_hour += *ptr++ - '0';
238                 if (tm->tm_hour < 0 || tm->tm_hour > 23) break;
239
240                 /* Minute 00-59 */
241                 tm->tm_min = *ptr++ - '0';
242                 tm->tm_min *=10; tm->tm_min += *ptr++ - '0';
243                 if (tm->tm_min < 0 || tm->tm_min > 59) break;
244
245                 /* Second 00-61 */
246                 tm->tm_sec = *ptr++ - '0';
247                 tm->tm_sec *=10; tm->tm_sec += *ptr++ - '0';
248                 if (tm->tm_sec < 0 || tm->tm_sec > 61) break;
249
250                 /* Fractions of seconds */
251                 if ( *ptr == '.' ) {
252                         ptr++;
253                         for (i = 0, fracs = 0; isdigit((unsigned char) *ptr); ) {
254                                 i*=10; i+= *ptr++ - '0';
255                                 fracs++;
256                         }
257                         tm->tm_usec = i;
258                         if (i) {
259                                 for (i = fracs; i<6; i++)
260                                         tm->tm_usec *= 10;
261                         }
262                 }
263
264                 /* Must be UTC */
265                 if (*ptr != 'Z') break;
266
267                 return 0;
268         }
269         return -1;
270 }
271
272 /* strcopy is like strcpy except it returns a pointer to the trailing NUL of
273  * the result string. This allows fast construction of catenated strings
274  * without the overhead of strlen/strcat.
275  */
276 char *
277 lutil_strcopy(
278         char *a,
279         const char *b
280 )
281 {
282         if (!a || !b)
283                 return a;
284         
285         while ((*a++ = *b++)) ;
286         return a-1;
287 }
288
289 /* strncopy is like strcpy except it returns a pointer to the trailing NUL of
290  * the result string. This allows fast construction of catenated strings
291  * without the overhead of strlen/strcat.
292  */
293 char *
294 lutil_strncopy(
295         char *a,
296         const char *b,
297         size_t n
298 )
299 {
300         if (!a || !b || n == 0)
301                 return a;
302         
303         while ((*a++ = *b++) && n-- > 0) ;
304         return a-1;
305 }
306
307 #ifndef HAVE_MKSTEMP
308 int mkstemp( char * template )
309 {
310 #ifdef HAVE_MKTEMP
311         return open ( mktemp ( template ), O_RDWR|O_CREAT|O_EXCL, 0600 );
312 #else
313         return -1;
314 #endif
315 }
316 #endif
317
318 #ifdef _MSC_VER
319 #include <windows.h>
320 struct dirent {
321         char *d_name;
322 };
323 typedef struct DIR {
324         HANDLE dir;
325         struct dirent data;
326         int first;
327         char buf[MAX_PATH+1];
328 } DIR;
329 DIR *opendir( char *path )
330 {
331         char tmp[32768];
332         int len = strlen(path);
333         DIR *d;
334         HANDLE h;
335         WIN32_FIND_DATA data;
336         
337         if (len+3 >= sizeof(tmp))
338                 return NULL;
339
340         strcpy(tmp, path);
341         tmp[len++] = '\\';
342         tmp[len++] = '*';
343         tmp[len] = '\0';
344
345         h = FindFirstFile( tmp, &data );
346         
347         if ( h == INVALID_HANDLE_VALUE )
348                 return NULL;
349
350         d = ber_memalloc( sizeof(DIR) );
351         if ( !d )
352                 return NULL;
353         d->dir = h;
354         d->data.d_name = d->buf;
355         d->first = 1;
356         strcpy(d->data.d_name, data.cFileName);
357         return d;
358 }
359 struct dirent *readdir(DIR *dir)
360 {
361         WIN32_FIND_DATA data;
362
363         if (dir->first) {
364                 dir->first = 0;
365         } else {
366                 if (!FindNextFile(dir->dir, &data))
367                         return NULL;
368                 strcpy(dir->data.d_name, data.cFileName);
369         }
370         return &dir->data;
371 }
372 void closedir(DIR *dir)
373 {
374         FindClose(dir->dir);
375         ber_memfree(dir);
376 }
377 #endif
378
379 /*
380  * Memory Reverse Search
381  */
382 void *
383 lutil_memrchr(const void *b, int c, size_t n)
384 {
385         if (n != 0) {
386                 const unsigned char *s, *bb = b, cc = c;
387
388                 for ( s = bb + n; s > bb; ) {
389                         if ( *--s == cc ) {
390                                 return (void *) s;
391                         }
392                 }
393         }
394
395         return NULL;
396 }
397
398 int
399 lutil_atoix( int *v, const char *s, int x )
400 {
401         char            *next;
402         long            i;
403
404         assert( s != NULL );
405         assert( v != NULL );
406
407         i = strtol( s, &next, x );
408         if ( next == s || next[ 0 ] != '\0' ) {
409                 return -1;
410         }
411
412         if ( (long)(int)i != i ) {
413                 return 1;
414         }
415
416         *v = (int)i;
417
418         return 0;
419 }
420
421 int
422 lutil_atoux( unsigned *v, const char *s, int x )
423 {
424         char            *next;
425         unsigned long   u;
426
427         assert( s != NULL );
428         assert( v != NULL );
429
430         /* strtoul() has an odd interface */
431         if ( s[ 0 ] == '-' ) {
432                 return -1;
433         }
434
435         u = strtoul( s, &next, x );
436         if ( next == s || next[ 0 ] != '\0' ) {
437                 return -1;
438         }
439
440         if ( (unsigned long)(unsigned)u != u ) {
441                 return 1;
442         }
443
444         *v = u;
445
446         return 0;
447 }
448
449 int
450 lutil_atolx( long *v, const char *s, int x )
451 {
452         char            *next;
453         long            l;
454
455         assert( s != NULL );
456         assert( v != NULL );
457
458         l = strtol( s, &next, x );
459         if ( next == s || next[ 0 ] != '\0' ) {
460                 return -1;
461         }
462
463         *v = l;
464
465         return 0;
466 }
467
468 int
469 lutil_atoulx( unsigned long *v, const char *s, int x )
470 {
471         char            *next;
472         unsigned long   ul;
473
474         assert( s != NULL );
475         assert( v != NULL );
476
477         /* strtoul() has an odd interface */
478         if ( s[ 0 ] == '-' ) {
479                 return -1;
480         }
481
482         ul = strtoul( s, &next, x );
483         if ( next == s || next[ 0 ] != '\0' ) {
484                 return -1;
485         }
486
487         *v = ul;
488
489         return 0;
490 }
491
492 static  char            time_unit[] = "dhms";
493
494 int
495 lutil_parse_time(
496         const char      *in,
497         unsigned long   *tp )
498 {
499         unsigned long   t = 0;
500         char            *s,
501                         *next;
502         int             sofar = -1,
503                         scale[] = { 86400, 3600, 60, 1 };
504
505         *tp = 0;
506
507         for ( s = (char *)in; s[ 0 ] != '\0'; ) {
508                 unsigned long   u;
509                 char            *what;
510
511                 /* strtoul() has an odd interface */
512                 if ( s[ 0 ] == '-' ) {
513                         return -1;
514                 }
515
516                 u = strtoul( s, &next, 10 );
517                 if ( next == s ) {
518                         return -1;
519                 }
520
521                 if ( next[ 0 ] == '\0' ) {
522                         /* assume seconds */
523                         t += u;
524                         break;
525                 }
526
527                 what = strchr( time_unit, next[ 0 ] );
528                 if ( what == NULL ) {
529                         return -1;
530                 }
531
532                 if ( what - time_unit <= sofar ) {
533                         return -1;
534                 }
535
536                 sofar = what - time_unit;
537                 t += u * scale[ sofar ];
538
539                 s = &next[ 1 ];
540         }
541
542         *tp = t;
543         return 0;
544 }
545
546 int
547 lutil_unparse_time(
548         char                    *buf,
549         size_t                  buflen,
550         unsigned long           t )
551 {
552         int             len, i;
553         unsigned long   v[ 4 ];
554         char            *ptr = buf;
555
556         v[ 0 ] = t/86400;
557         v[ 1 ] = (t%86400)/3600;
558         v[ 2 ] = (t%3600)/60;
559         v[ 3 ] = t%60;
560
561         for ( i = 0; i < 4; i++ ) {
562                 if ( v[i] > 0 || ( i == 3 && ptr == buf ) ) {
563                         len = snprintf( ptr, buflen, "%lu%c", v[ i ], time_unit[ i ] );
564                         if ( len < 0 || (unsigned)len >= buflen ) {
565                                 return -1;
566                         }
567                         buflen -= len;
568                         ptr += len;
569                 }
570         }
571
572         return 0;
573 }
574