1 /* Copyright 1999 Enhanced Software Technologies Inc.
2  * Released for public use under a BSD-style license.
3  * See file "LICENSE" for more information.
4  *
5  * dstring.c -- dynamically allocated string functions.
6  *
7  * RCS CHANGE LOG
8  * $Log: dstring.c,v $
9  * Revision 1.1.1.1  2001/05/17 17:11:01  elgreen
10  * Initial checkin
11  *
12  * Revision 1.3  2000/12/12 16:41:21  eric
13  * aescrypt 0.6 (large patch by Peter Pentchev).
14  *
15  * Revision 1.2  2000/04/05 22:09:19  eric
16  * Daily checkin...
17  *
18  * Revision 1.1  2000/03/28 23:54:28  eric
19  * Initial checkin -- aescrypt/aesget
20  *
21  * Revision 1.8  1999/11/18 16:23:36  eric
22  * More mods to make it work. Start of the 'rsh' functionality.
23  *
24  * Revision 1.7  1999/11/09 18:57:29  eric
25  * Re-wrote 'trim' routines :-(.
26  *
27  * Revision 1.6  1999/11/03 23:26:43  eric
28  * Fixed some problems with headers and dstring.c :-(.
29  *
30  * Revision 1.5  1999/09/30 20:32:28  eric
31  * Refreshed after Richard foobared the CVS archive
32  *
33  * Revision 1.4  1999/09/28 19:33:53  eric
34  * Add d_lpad and d_rpad routines.
35  *
36  * Revision 1.3  1999/09/13 16:08:23  eric
37  * Added Ocotillo licensing info.
38  *
39  * Revision 1.2  1999/08/27 23:22:59  eric
40  * Misc. changes...
41  *
42  * Revision 1.1  1999/08/25 22:08:48  eric
43  * Initial revision, dynamic string routines for "C".
44  *
45  * $Date: 2001/05/17 17:11:01 $
46  */
47 
48 #include <stdio.h>
49 #include <string.h>
50 #include <ctype.h>
51 #include <stdlib.h>
52 
53 #include "dstring.h"
54 
55 static char *d_ltrim(char *src);
56 static char *d_rtrim(char *src);
57 
58 /* Returns a line of EXACTLY the length of input. Does have a limit, so we
59  * don't exhaust all virtual memory. Does use more CPU time alloc'ing and
60  * un-alloc'ing our temporary buffer, but so it goes :-(.
61  */
d_getline(FILE * file,int limit)62 char *d_getline(FILE *file, int limit) {
63   char *result;  /* result of fgets */
64   char *retvalue; /* return value, our new string. */
65   char *buffer = (char *)malloc(limit+1);
66   int newlen;
67 
68   if (!buffer) {
69     return NULL; /* sorry, could not malloc!  */
70   }
71   result = fgets(buffer,limit,file);
72   if (!result) {  /* We have an error! Return it to our caller */
73     free(buffer);
74     return NULL; /* Sorry! */
75   }
76   newlen=strlen(buffer);
77   retvalue=(char *)malloc(newlen+1);
78   if (!retvalue) {
79     free(buffer);
80     return NULL; /* sorry, could not malloc ! */
81   }
82   snprintf(retvalue, newlen + 1, "%s", buffer);
83   free(buffer);
84   return retvalue;
85 }
86 
87 
88 /********************************************************************
89  **** NOTICE ON D_LPAD AND D_RPAD!***
90  * These share a great deal of common code. In fact, there is
91  * exactly one line different between the two. This SHOULD be re-written
92  * to actually call a "d_pad" routine that has "left" and "right" flag
93  * e.g. 0=pad left, 1=pad right.  If anybody feels like doing it, go
94  * for it (and do an inline function or macro to convert d_lpad to
95  * d_pad(src,ch,len,direction).
96  *********************************************************************/
97 
98 /* add whitespace or other chars to left of a string to pad it out to a
99  * given length.
100  */
101 
d_lpad(char * src,int ch,int len)102 char *d_lpad(char *src, int ch, int len) {
103   char *result;
104   char *lpad;   /* leftmost chars to be inserted */
105   int curlen;
106   int numneeded;
107   int i;
108 
109   curlen=strlen(src);
110   if (curlen >= len) {
111     return d_dup(src); /* just duplicate it and return. */
112   }
113 
114   /* if we get here, it's shorter, and we need to pad some stuff.
115    * if it's 5 chars and we need 10, we would need a string of
116    * 10-5 (5) chars, plus allocate an extra for the trailing space.
117    */
118   numneeded=len-curlen;
119   lpad=(char *) malloc(numneeded+1);
120   if (!lpad) {
121     return NULL;  /* Out-of-memory error! */
122   }
123 
124   for (i=0;i<numneeded;i++) {
125     lpad[i]=(char)ch;
126   }
127   lpad[numneeded]=0;
128   result=d_cat(lpad,src);
129   free(lpad);            /* eliminate a potential memory leak! */
130   return result;         /* and done!  */
131 }
132 
133 /* add whitespace or other chars to right of a string to pad it out to a
134  * given length.
135  */
136 
d_rpad(char * src,int ch,int len)137 char *d_rpad(char *src, int ch, int len) {
138   char *result;
139   char *rpad;   /* leftmost chars to be inserted */
140   int curlen;
141   int numneeded;
142   int i;
143 
144   curlen=strlen(src);
145   if (curlen >= len) {
146     return d_dup(src); /* just duplicate it and return. */
147   }
148 
149   /* if we get here, it's shorter, and we need to pad some stuff.
150    * if it's 5 chars and we need 10, we would need a string of
151    * 10-5 (5) chars, plus allocate an extra for the trailing space.
152    */
153   numneeded=len-curlen;
154   rpad=(char *)malloc(numneeded+1);
155   if (!rpad) {
156     return NULL;  /* Out-of-memory error! */
157   }
158 
159   for (i=0;i<numneeded;i++) {
160     rpad[i]=(char)ch;
161   }
162   rpad[numneeded]=0;
163   result=d_cat(src,rpad);
164   free(rpad);            /* eliminate a potential memory leak! */
165   return result;         /* and done!  */
166 }
167 
168 /* Trim all the whitespace off the LEFT of a string, returning trimmed
169  * str.
170  */
171 
d_ltrim(char * src)172 static char *d_ltrim(char *src) {
173   char *dest;
174   char *walkptr;
175   size_t len;
176 
177   walkptr=src;
178   while (*walkptr && isspace(*walkptr)) {
179     walkptr++;
180   }
181 
182   len = strlen(walkptr);
183   dest=(char *)malloc(len + 1);
184   if (!dest) {
185     return NULL; /* sorry, out of memory! */
186   }
187   snprintf(dest, len + 1, "%s", walkptr);
188   return dest; /* and return! */
189 }
190 
191 /* Trim all the white space off the RIGHT of a string, returning trimmed
192  * str. Actually returns a pointer to same amount of malloc'ed space,
193  * I don't think that's going to be a problem...
194  */
d_rtrim(char * src)195 static char *d_rtrim(char *src) {
196   int i,j,len;
197   char *dest;
198 
199   len=strlen(src);
200   dest=(char *)malloc(len+1);
201   if (!dest) return NULL; /* sorry, out of memory! */
202   snprintf(dest, len + 1, "%s", src);
203 
204   if (!*dest) {
205     return dest; /* empty string! */
206   }
207 
208 
209 
210   i=0;
211   j=len;
212   while ( (i < j) && isspace(dest[j-1])) {
213     j--;
214   }
215   dest[j]=0;
216   return dest;
217 
218 }
219 
220 /* trim whitespace from left and right of a string, returning trimmed str
221  * we call ltrim last because it returns a block of memory that's the
222  * actual length of our newly-trimmed string (rtrim doesn't, due to
223  * efficiency reasons).
224  */
225 
d_trim(char * src)226 char *d_trim(char *src) {
227   char *ltrim;
228   char *rtrim;
229 
230   if (!*src) {
231     return src;
232   } else {
233     rtrim=d_rtrim(src);
234     if (!*rtrim) {  /* if it stripped whole thingy, just return */
235       return rtrim;
236     }
237     ltrim=d_ltrim(rtrim);
238     free(rtrim);
239     return ltrim;
240   }
241 }
242 
243 /* Duplicate a string, malloc'ing the buffer with it. */
d_dup(char * str)244 char *d_dup(char *str) {
245   char *buffer;
246   int newlen;
247 
248   newlen=strlen(str);
249   buffer=(char *)malloc(newlen+1);
250   if (!buffer) {
251     return NULL;
252   }
253   snprintf(buffer, newlen + 1, "%s", str);
254   return buffer;
255 }
256 
d_cat(char * str1,char * str2)257 char *d_cat(char *str1, char *str2) {
258   int len1;
259   int len2;
260   char *buffer;
261 
262   len1=strlen(str1);
263   len2=strlen(str2);
264   buffer=(char *)malloc(len1+len2+1);
265   if (!buffer) {
266     return NULL; /* Out-of-memory error */
267   }
268 
269   snprintf(buffer, len1 + len2 + 1, "%s%s", str1, str2);
270   return buffer;  /* and return the result! */
271 }
272 
273 /* split line into two pieces. */
d_split(char * src,int ch)274 struct d_split_array *d_split(char *src, int ch) {
275   unsigned char c;
276   int i,n;
277   int len;
278 
279   char *str1;
280   char *str2;
281   char *strptr;
282 
283   struct d_split_array *retvalue;
284 
285   len=strlen(src);
286   c=ch;
287   n=-1; /* guardian value. */
288   for (i=0;src[i];i++) {
289     if (src[i]==c) {
290       n=i;
291       break;
292     }
293   }
294   if (n==-1) {
295     return NULL;  /* sorry, could not split on that character! */
296   }
297 
298   str1=(char *) malloc(n+1); /* do the first string */
299   if (!str1) {
300     return NULL; /* could not malloc! */
301   }
302 
303   for (i=0;i<n;i++) {
304     str1[i]=src[i];
305   }
306   str1[n]=0; /* chop off the trailing character! */
307 
308   str2=(char *) malloc(len-n); /* for the rest... */
309   if (!str2) {
310     free(str1);
311     return NULL;
312   }
313   strptr=str2;
314   for (i=n+1;i<len;i++) {
315     *strptr++=src[i];
316   }
317   *strptr=0; /* and voila! */
318   /* now to malloc the return array: */
319   retvalue = (struct d_split_array *)malloc(sizeof(struct d_split_array));
320   if (!retvalue) { /* can't malloc! */
321     free(str1);
322     free(str2);
323     return NULL;
324   }
325   retvalue->str1=str1;
326   retvalue->str2=str2;
327   return retvalue;
328 }
329 
330 /* Split a string into three pieces... */
d_split2(char * src,int ch)331 struct d_split2_array *d_split2(char *src, int ch)
332 {
333   struct d_split_array *d1;
334   struct d_split_array *d2;
335   struct d_split2_array *result;
336 
337   d1=d_split(src,ch);  /* do the first split */
338   if (!d1) {
339     return NULL; /* sorry! */
340   }
341   d2=d_split(d1->str2,ch); /* split the second half into two strings */
342   if (!d2) {          /* un-leak memory, sigh */
343     free(d1->str1);
344     free(d1->str2);
345     free(d1);
346     return NULL;
347   }
348   /* we now have three strings, now to do something with them: */
349   result=(struct d_split2_array *)malloc(sizeof(struct d_split2_array));
350   if (!result) { /* arg, could not malloc! */
351     free(d1->str1);
352     free(d1->str2);
353     free(d1);
354     free(d2->str1);
355     free(d2->str2);
356     free(d2);  /* maybe freed up enough memory? */
357   }
358   /* we malloced, now copy and free up other stuff: */
359   result->str1=d1->str1;
360   result->str2=d2->str1;
361   result->str3=d2->str2;
362   free(d1->str2); /* this was a temp string no longer needed */
363   free(d1);
364   free(d2);
365   return result;
366 }
367 
368 #ifdef TEST_FUNCTION
369 
main(void)370 void main(void) {
371   char *result;
372   char *dup;
373   char *trimmed;
374   char *dupdup;
375   struct d_split_array *ary1;
376 
377   result=d_getline(stdin,1024);
378   trimmed=d_trim(result);  /* trimm! */
379   dup=d_dup(trimmed);
380   printf("dup=%s\n",dup);
381   dupdup=d_cat(trimmed,dup);
382   printf("dupdup=%s\n",dupdup);
383   ary1=d_split(result,':');
384   printf("str1=%s  str2=%s\n",ary1->str1,ary1->str2);
385 }
386 
387 #endif
388 
389 
390 
391