1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <ctype.h>
5 #include <limits.h>
6
7 #include "../include/xsw_ctype.h"
8 #include "../include/os.h"
9 #include "../include/string.h"
10 #include "../include/fio.h"
11
12 #ifdef MEMWATCH
13 # include "memwatch.h"
14 #endif
15
16
17 FILE *FOpen(const char *path, const char *mode);
18 void FClose(FILE *fp);
19
20 void FSeekNextLine(FILE *fp);
21 void FSeekPastSpaces(FILE *fp);
22 void FSeekPastChar(FILE *fp, char c);
23
24 int FSeekToParm(FILE *fp, const char *parm, char comment, char delim);
25 char *FSeekNextParm(FILE *fp, char *buf, char comment, char delim);
26
27 int FGetValuesI(FILE *fp, int *value, int nvalues);
28 int FGetValuesL(FILE *fp, long *value, int nvalues);
29 int FGetValuesF(FILE *fp, double *value, int nvalues);
30 char *FGetString(FILE *fp);
31 char *FGetStringLined(FILE *fp);
32 char *FGetStringLiteral(FILE *fp);
33
34 char *FReadNextLineAlloc(FILE *fp, char comment);
35 char *FReadNextLineAllocCount(
36 FILE *fp, char comment, int *line_count
37 );
38
39
40 #define ISCR(c) (((c) == '\n') || ((c) == '\r'))
41
42 /*
43 * Allocate memory while reading a line from file in chunk size
44 * of this many bytes:
45 */
46 #define FREAD_ALLOC_CHUNK_SIZE 8
47
48
49 #define ATOI(s) (((s) != NULL) ? atoi(s) : 0)
50 #define ATOL(s) (((s) != NULL) ? atol(s) : 0)
51 #define ATOF(s) (((s) != NULL) ? atof(s) : 0.0f)
52 #define STRDUP(s) (((s) != NULL) ? strdup(s) : NULL)
53
54 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
55 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
56 #define CLIP(a,l,h) (MIN(MAX((a),(l)),(h)))
57 #define STRLEN(s) (((s) != NULL) ? strlen(s) : 0)
58 #define STRISEMPTY(s) (((s) != NULL) ? (*(s) == '\0') : 1)
59
60
61 /*
62 * OS wrapper to open file using UNIX path notation.
63 *
64 * The returned FILE pointer can be used with all the ANSI C standard
65 * file IO functions.
66 */
FOpen(const char * path,const char * mode)67 FILE *FOpen(const char *path, const char *mode)
68 {
69 int len;
70 char *new_path, *strptr2;
71 const char *strptr1;
72 FILE *fp;
73
74 if(STRISEMPTY(path) || STRISEMPTY(mode))
75 return(NULL);
76
77 /* Get length of path and allocate new buffer */
78 len = STRLEN(path);
79 new_path = (char *)malloc((len + 1) * sizeof(char));
80 if(new_path == NULL)
81 return(NULL);
82
83 /* Copy path to new_path */
84 strptr1 = path;
85 strptr2 = new_path;
86 while(*strptr1 != '\0')
87 {
88 *strptr2 = *strptr1;
89
90 #ifdef __MSW__
91 if(*strptr2 == '/')
92 *strptr2 = '\\';
93 #endif /* __MSW__ */
94
95 strptr1++; strptr2++;
96 }
97 *strptr2 = '\0';
98
99 /* Open file */
100 fp = fopen(new_path, mode);
101
102 /* Delete coppied path */
103 free(new_path);
104
105 return(fp);
106 }
107
108 /*
109 * Closes the file opened by FOpen().
110 */
FClose(FILE * fp)111 void FClose(FILE *fp)
112 {
113 if(fp != NULL)
114 fclose(fp);
115 }
116
117 /*
118 * Seeks to next line, escape sequences will be parsed.
119 */
FSeekNextLine(FILE * fp)120 void FSeekNextLine(FILE *fp)
121 {
122 int c;
123
124 if(fp == NULL)
125 return;
126
127 do
128 {
129 c = fgetc(fp);
130
131 /* Escape sequence? */
132 if(c == '\\')
133 c = fgetc(fp);
134 /* New line? */
135 else if(ISCR(c))
136 break;
137
138 } while(c != EOF);
139 }
140
141 /*
142 * Seeks fp past any spaces.
143 */
FSeekPastSpaces(FILE * fp)144 void FSeekPastSpaces(FILE *fp)
145 {
146 int c;
147
148 if(fp == NULL)
149 return;
150
151 while(1)
152 {
153 c = fgetc(fp);
154 if(c == EOF)
155 break;
156
157 if(ISBLANK(c))
158 continue;
159
160 fseek(fp, -1, SEEK_CUR);
161 break;
162 }
163 }
164
165 /*
166 * Seeks fp past the first occurance of c or EOF.
167 */
FSeekPastChar(FILE * fp,char c)168 void FSeekPastChar(FILE *fp, char c)
169 {
170 int i;
171
172
173 if(fp == NULL)
174 return;
175
176 do
177 {
178 i = fgetc(fp);
179 if(i == c)
180 break;
181
182 } while(i != EOF);
183 }
184
185 /*
186 * Seeks fp to the beginning of the value of the specified
187 * parameter.
188 *
189 * The delim specifies the deliminator character between the
190 * parameter and the value. The delim can be '\0' to specify
191 * "any blanks" (in the case of no deliminators between the
192 * parameter and the value).
193 *
194 * Parameters are assumed to not contain spaces or escape sequences.
195 *
196 * Returns 0 on successful match or non-zero on error.
197 */
FSeekToParm(FILE * fp,const char * parm,char comment,char delim)198 int FSeekToParm(FILE *fp, const char *parm, char comment, char delim)
199 {
200 int c, parm_len;
201
202 if(fp == NULL)
203 return(-1);
204
205 parm_len = STRLEN(parm);
206 if(parm_len <= 0)
207 return(-1);
208
209 do
210 {
211 c = fgetc(fp);
212 if(c == EOF)
213 return(-1);
214
215 /* Seek past spaces */
216 if(ISBLANK(c))
217 FSeekPastSpaces(fp);
218
219 /* New line? */
220 if(ISCR(c))
221 continue;
222
223 /* First non-blank a comment character? */
224 if(c == comment)
225 {
226 FSeekNextLine(fp);
227 continue;
228 }
229
230 /* Matches parameter? */
231 if(c == *parm)
232 {
233 /* First char matches parm */
234 const char *strptr = parm + 1;
235
236
237 while(*strptr != '\0')
238 {
239 c = fgetc(fp);
240 if(c != *strptr)
241 break;
242
243 strptr++;
244 }
245 if(*strptr == '\0')
246 {
247 /* Got match, seek fp past deliminator */
248 if(delim == '\0')
249 {
250 FSeekPastSpaces(fp);
251 }
252 else
253 {
254 FSeekPastSpaces(fp);
255
256 /* Seek to delim or newline */
257 do
258 {
259 c = fgetc(fp);
260 if((c == EOF) || (c == delim))
261 break;
262
263 if(ISCR(c))
264 {
265 fseek(fp, -1, SEEK_CUR);
266 break;
267 }
268
269 } while(1);
270
271 FSeekPastSpaces(fp);
272 }
273
274 return(0);
275 }
276 else
277 {
278 /* No match, seek to next line */
279 FSeekNextLine(fp);
280 }
281 }
282 else
283 {
284 /* No match, seek to next line */
285 FSeekNextLine(fp);
286 }
287
288 } while(1);
289
290 return(-1);
291 }
292
293 /*
294 * Fetches the next parameter found at the file position fp.
295 *
296 * If buf is NULL then a newly allocated string will be returned
297 * containing the fetched parm. If buf is not NULL, then buf will
298 * be realloc()'ed and returned as a new pointer containing
299 * the fetched parm.
300 *
301 * If EOF is reached by the given fp position, then NULL will
302 * be returned and the given buf will have been free()ed by this
303 * function.
304 */
FSeekNextParm(FILE * fp,char * buf,char comment,char delim)305 char *FSeekNextParm(FILE *fp, char *buf, char comment, char delim)
306 {
307 int c, buf_pos = 0, buf_len, buf_inc = FREAD_ALLOC_CHUNK_SIZE;
308
309
310 if(fp == NULL)
311 {
312 free(buf);
313 return(NULL);
314 }
315
316 /* Get length of buf (less than actual allocated is okay) */
317 buf_len = (buf != NULL) ? strlen(buf) : 0;
318
319 /* Seek past spaces and comments to next parameter */
320 while(1)
321 {
322 FSeekPastSpaces(fp);
323 c = fgetc(fp);
324 if(c == EOF)
325 {
326 free(buf);
327 return(NULL);
328 }
329 else if(c == comment)
330 {
331 FSeekNextLine(fp);
332 continue;
333 }
334 else if(ISCR(c))
335 {
336 continue;
337 }
338 else
339 {
340 fseek(fp, -1, SEEK_CUR);
341 break;
342 }
343 }
344
345 /* Begin fetching this parm */
346 while(1)
347 {
348 /* Get next char */
349 c = fgetc(fp);
350 if(c == EOF)
351 {
352 break;
353 }
354
355 /* Blank character reached? */
356 if(ISBLANK(c))
357 {
358 /* Blank char reached, seek past delimiantor and position
359 * fp at beginning of value.
360 */
361 if(delim == '\0')
362 {
363 FSeekPastSpaces(fp);
364 }
365 else
366 {
367 FSeekPastSpaces(fp);
368
369 /* Seek to deim or newline */
370 do
371 {
372 c = fgetc(fp);
373 if((c == EOF) || (c == delim))
374 break;
375
376 if(ISCR(c))
377 {
378 fseek(fp, -1, SEEK_CUR);
379 break;
380 }
381
382 } while(1);
383
384 FSeekPastSpaces(fp);
385 }
386 break;
387 }
388
389 /* CR reached? */
390 if(ISCR(c))
391 {
392 fseek(fp, -1, SEEK_CUR);
393 break;
394 }
395
396 /* Deliminator reached? */
397 if(c == delim)
398 {
399 FSeekPastSpaces(fp);
400 break;
401 }
402
403 /* Need to allocate buffer? */
404 if(buf_pos <= buf_len)
405 {
406 buf_len += buf_inc;
407
408 buf = (char *)realloc(buf, buf_len * sizeof(char));
409 if(buf == NULL)
410 {
411 FSeekNextLine(fp);
412 return(NULL);
413 }
414 }
415
416 buf[buf_pos] = (char)c;
417 buf_pos++;
418 }
419
420 /* Put null terminating byte on buffer */
421 if(c == EOF)
422 {
423 free(buf);
424 buf = NULL;
425 }
426 else
427 {
428 if(buf_pos <= buf_len)
429 {
430 buf_len = buf_pos + 1;
431
432 buf = (char *)realloc(buf, buf_len * sizeof(char));
433 if(buf == NULL)
434 return(NULL);
435 }
436 buf[buf_pos] = '\0';
437 }
438
439 return(buf);
440 }
441
442 /*
443 * Loads values as ints from the file starting at the
444 * specified fp. Will not load more than nvalues.
445 *
446 * The fp will be positioned at the start of the next line.
447 *
448 * Returns non-zero on error.
449 */
FGetValuesI(FILE * fp,int * value,int nvalues)450 int FGetValuesI(FILE *fp, int *value, int nvalues)
451 {
452 int c, i, n, line_done = 0;
453 #define len 80
454 char num_str[len];
455
456
457 if(fp == NULL)
458 return(-1);
459
460 FSeekPastSpaces(fp);
461
462 /* Begin fetching values */
463 for(i = 0; i < nvalues; i++)
464 {
465 (*num_str) = '\0';
466
467 /* Read number */
468 for(n = 0; n < len; n++)
469 {
470 if(line_done)
471 break;
472
473 c = fgetc(fp);
474 if((c == EOF) || ISCR(c))
475 {
476 num_str[n] = '\0';
477 line_done = 1;
478 break;
479 }
480 /* Escape sequence? */
481 else if(c == '\\')
482 {
483 c = fgetc(fp);
484 if(c == EOF)
485 {
486 num_str[n] = '\0';
487 line_done = 1;
488 break;
489 }
490 if(c != '\\')
491 c = fgetc(fp);
492
493 if(c == EOF)
494 {
495 num_str[n] = '\0';
496 line_done = 1;
497 break;
498 }
499 }
500 /* Separator? */
501 else if(ISBLANK(c) || (c == ','))
502 {
503 num_str[n] = '\0';
504 FSeekPastSpaces(fp);
505 break;
506 }
507
508 num_str[n] = (char)c;
509 }
510 num_str[len - 1] = '\0';
511
512 value[i] = atoi(num_str);
513 }
514 if(!line_done)
515 FSeekNextLine(fp);
516 #undef len
517 return(0);
518 }
519
520 /*
521 * Loads values as longs from the file starting at the
522 * specified fp. Will not load more than nvalues.
523 *
524 * The fp will be positioned at the start of the next line.
525 *
526 * Returns non-zero on error.
527 */
FGetValuesL(FILE * fp,long * value,int nvalues)528 int FGetValuesL(FILE *fp, long *value, int nvalues)
529 {
530 int c, i, n, line_done = 0;
531 #define len 80
532 char num_str[len];
533
534
535 if(fp == NULL)
536 return(-1);
537
538 FSeekPastSpaces(fp);
539
540 /* Begin fetching values */
541 for(i = 0; i < nvalues; i++)
542 {
543 (*num_str) = '\0';
544
545 /* Read number */
546 for(n = 0; n < len; n++)
547 {
548 if(line_done)
549 break;
550
551 c = fgetc(fp);
552 if((c == EOF) || ISCR(c))
553 {
554 num_str[n] = '\0';
555 line_done = 1;
556 break;
557 }
558 /* Escape sequence? */
559 else if(c == '\\')
560 {
561 c = fgetc(fp);
562 if(c == EOF)
563 {
564 num_str[n] = '\0';
565 line_done = 1;
566 break;
567 }
568 if(c != '\\')
569 c = fgetc(fp);
570
571 if(c == EOF)
572 {
573 num_str[n] = '\0';
574 line_done = 1;
575 break;
576 }
577 }
578 /* Separator? */
579 else if(ISBLANK(c) || (c == ','))
580 {
581 num_str[n] = '\0';
582 FSeekPastSpaces(fp);
583 break;
584 }
585
586 num_str[n] = (char)c;
587 }
588 num_str[len - 1] = '\0';
589
590 value[i] = atol(num_str);
591 }
592 if(!line_done)
593 FSeekNextLine(fp);
594 #undef len
595 return(0);
596 }
597
598 /*
599 * Loads values as doubles from the file starting at the
600 * specified fp. Will not load more than nvalues.
601 *
602 * The fp will be positioned at the start of the next line.
603 *
604 * Returns non-zero on error.
605 */
FGetValuesF(FILE * fp,double * value,int nvalues)606 int FGetValuesF(FILE *fp, double *value, int nvalues)
607 {
608 int c, i, n, line_done = 0;
609 #define len 80
610 char num_str[len];
611
612
613 if(fp == NULL)
614 return(-1);
615
616 FSeekPastSpaces(fp);
617
618 /* Begin fetching values */
619 for(i = 0; i < nvalues; i++)
620 {
621 (*num_str) = '\0';
622
623 /* Read number */
624 for(n = 0; n < len; n++)
625 {
626 if(line_done)
627 break;
628
629 c = fgetc(fp);
630 if((c == EOF) || ISCR(c))
631 {
632 num_str[n] = '\0';
633 line_done = 1;
634 break;
635 }
636 /* Escape sequence? */
637 else if(c == '\\')
638 {
639 c = fgetc(fp);
640 if(c == EOF)
641 {
642 num_str[n] = '\0';
643 line_done = 1;
644 break;
645 }
646 if(c != '\\')
647 c = fgetc(fp);
648
649 if(c == EOF)
650 {
651 num_str[n] = '\0';
652 line_done = 1;
653 break;
654 }
655 }
656 /* Separator? */
657 else if(ISBLANK(c) || (c == ','))
658 {
659 num_str[n] = '\0';
660 FSeekPastSpaces(fp);
661 break;
662 }
663
664 num_str[n] = (char)c;
665 }
666 num_str[len - 1] = '\0';
667
668 value[i] = atof(num_str);
669 }
670 if(!line_done)
671 FSeekNextLine(fp);
672
673 #undef len
674 return(0);
675 }
676
677 /*
678 * Returns a dynamically allocated string containing the value as a
679 * string obtained from the file specified by fp. Reads from the
680 * current position of fp to the next new line character or EOF.
681 *
682 * Escape sequences will be parsed and spaces will be stripped.
683 *
684 * The fp is positioned after the new line or at the EOF.
685 */
FGetString(FILE * fp)686 char *FGetString(FILE *fp)
687 {
688 int c, i = 0, len = 0;
689 char *s = NULL, *s2;
690
691
692 if(fp == NULL)
693 return(s);
694
695 /* Begin reading string from file */
696
697 /* Skip initial spaces */
698 c = fgetc(fp);
699 while((c != EOF) && ISBLANK(c))
700 c = fgetc(fp);
701
702 if(c == EOF)
703 return(s);
704
705 /* Read string */
706 while(1)
707 {
708 /* Need to increase allocation? */
709 if(i >= len)
710 {
711 len = MAX(len + 128, i + 1);
712 s = (char *)realloc(s, len * sizeof(char));
713 if(s == NULL)
714 {
715 len = i = 0;
716 break;
717 }
718 }
719
720 /* Get pointer to current position in string */
721 s2 = s + i;
722
723 /* Set new character value */
724 *s2 = c;
725
726 /* End of file or end of the line? */
727 if((c == EOF) || ISCR(c))
728 {
729 *s2 = '\0';
730 break;
731 }
732 /* Escape sequence? */
733 else if(c == '\\')
734 {
735 /* Read next character after backslash */
736 c = fgetc(fp);
737 if((c == EOF) || (c == '\0'))
738 {
739 *s2 = '\0';
740 }
741 else if(ISCR(c))
742 {
743 /* New line (do not save this newline char) */
744 i--;
745 }
746 else if(c == '\\')
747 {
748 /* Literal backslash */
749 *s2 = '\\';
750 }
751 else if(c == '0')
752 {
753 /* Null */
754 *s2 = '\0';
755 }
756 else if(c == 'b')
757 {
758 /* Bell */
759 *s2 = '\b';
760 }
761 else if(c == 'n')
762 {
763 /* New line */
764 *s2 = '\n';
765 }
766 else if(c == 'r')
767 {
768 /* Line return */
769 *s2 = '\r';
770 }
771 else if(c == 't')
772 {
773 /* Tab */
774 *s2 = '\t';
775 }
776 else
777 {
778 /* Unsupported escape sequence, store it as is */
779 *s2 = c;
780 }
781
782 /* Read next character and increment position */
783 c = fgetc(fp);
784 i++;
785 }
786 /* Regular character */
787 else
788 {
789 /* Read next character and increment position */
790 c = fgetc(fp);
791 i++;
792 }
793 }
794
795 /* Cut off tailing spaces */
796 if(s != NULL)
797 {
798 s2 = s + i - 1;
799
800 while(ISBLANK(*s2) && (s2 >= s))
801 *s2 = '\0';
802 }
803
804 return(s);
805 }
806
807
808 /*
809 * Works just like FGetString() except the string is loaded
810 * literally and the only escape sequence to be handled will
811 * be the two characters '\\' '\n', when those characters
812 * are encountered the character '\n' will be saved into the return
813 * string.
814 *
815 * Spaces will not be striped, the fp will be positioned after the
816 * newline or EOF (whichever is encountered first).
817 */
FGetStringLined(FILE * fp)818 char *FGetStringLined(FILE *fp)
819 {
820 int c, i = 0, len = 0;
821 char *s = NULL, *s2;
822
823
824 if(fp == NULL)
825 return(s);
826
827 /* Begin reading string from file */
828
829 /* Get first character */
830 c = fgetc(fp);
831 if(c == EOF)
832 return(s);
833
834 /* Read string */
835 while(1)
836 {
837 /* Need to increase allocation? */
838 if(i >= len)
839 {
840 len = MAX(len + 128, i + 1);
841 s = (char *)realloc(s, len * sizeof(char));
842 if(s == NULL)
843 {
844 len = i = 0;
845 break;
846 }
847 }
848
849 /* Get pointer to current position in string */
850 s2 = s + i;
851
852 /* Set new character value */
853 *s2 = c;
854
855 /* End of file or end of line? */
856 if((c == EOF) || ISCR(c))
857 {
858 *s2 = '\0';
859 break;
860 }
861 /* Escape sequence? */
862 else if(c == '\\')
863 {
864 /* Read next character after backslash */
865 c = fgetc(fp);
866 if(c == EOF)
867 {
868 i++;
869 continue;
870 }
871 else if(ISCR(c))
872 {
873 /* New line, store it as is */
874 *s2 = c;
875 }
876 else
877 {
878 /* All other escaped characters leave as is
879 * it will be set on the next loop
880 */
881 i++;
882 continue;
883 }
884
885 /* Read next character and increment position */
886 c = fgetc(fp);
887 i++;
888 }
889 /* Regular character */
890 else
891 {
892 /* Read next character and increment position */
893 c = fgetc(fp);
894 i++;
895 }
896 }
897
898 return(s);
899 }
900
901 /*
902 * Works just like FGetString() except the string is loaded
903 * literally and no escape sequences parsed, that would be all
904 * characters from the current given fp position to the first
905 * encountered newline ('\n') character (escaped or not).
906 *
907 * Spaces will not be striped, the fp will be positioned after the
908 * newline or EOF (whichever is encountered first).
909 */
FGetStringLiteral(FILE * fp)910 char *FGetStringLiteral(FILE *fp)
911 {
912 int c, i = 0, len = 0;
913 char *s = NULL, *s2;
914
915
916 if(fp == NULL)
917 return(s);
918
919 /* Begin reading string from file */
920
921 /* Get first character */
922 c = fgetc(fp);
923 if(c == EOF)
924 return(s);
925
926 /* Read string */
927 while(1)
928 {
929 /* Need to increase allocation? */
930 if(i >= len)
931 {
932 len = MAX(len + 128, i + 1);
933 s = (char *)realloc(s, len * sizeof(char));
934 if(s == NULL)
935 {
936 len = i = 0;
937 break;
938 }
939 }
940
941 /* Get pointer to current position in string */
942 s2 = s + i;
943
944 /* Set new character value */
945 *s2 = c;
946
947 /* End of file or end of line? */
948 if((c == EOF) || ISCR(c))
949 {
950 *s2 = '\0';
951 break;
952 }
953 else
954 {
955 /* Read next character and increment position */
956 c = fgetc(fp);
957 i++;
958 }
959 }
960
961 return(s);
962 }
963
964
965 /*
966 * Returns an allocated string containing the entire
967 * line or NULL on error or EOF.
968 *
969 * If comment is '\0' then the next line is read regardless
970 * if it is a comment or not.
971 *
972 * Calling function must free() the returned pointer.
973 */
FReadNextLineAlloc(FILE * fp,char comment)974 char *FReadNextLineAlloc(FILE *fp, char comment)
975 {
976 return(FReadNextLineAllocCount(fp, comment, NULL));
977 }
978
FReadNextLineAllocCount(FILE * fp,char comment,int * line_count)979 char *FReadNextLineAllocCount(
980 FILE *fp,
981 char comment,
982 int *line_count
983 )
984 {
985 int i, m, n;
986 char *strptr;
987
988
989 if(fp == NULL)
990 return(NULL);
991
992 /* Is comment character specified? */
993 if(comment != '\0')
994 {
995 /* Comment character is specified */
996
997 /* Read past spaces, newlines, and comments */
998 i = fgetc(fp);
999 if(i == EOF)
1000 return(NULL);
1001
1002 while((i == ' ') || (i == '\t') || (i == '\n') || (i == '\r') ||
1003 (i == comment)
1004 )
1005 {
1006 if(i == EOF)
1007 return(NULL);
1008
1009 /* If newline, then increment line count */
1010 if((i == '\n') ||
1011 (i == '\r')
1012 )
1013 {
1014 if(line_count != NULL)
1015 *line_count += 1;
1016 }
1017
1018 /* If comment, then skip to next line */
1019 if(i == comment)
1020 {
1021 i = fgetc(fp);
1022 while((i != '\n') && (i != '\r'))
1023 {
1024 if(i == EOF)
1025 return(NULL);
1026 i = fgetc(fp);
1027 }
1028 if(line_count != NULL)
1029 *line_count += 1;
1030 }
1031
1032 /* Get next character */
1033 i = fgetc(fp);
1034 }
1035
1036 /* Begin adding characters to string */
1037 m = 0; /* mem size */
1038 n = 1; /* chars read */
1039 strptr = NULL;
1040
1041 while((i != '\n') && (i != '\r') && (i != '\0'))
1042 {
1043 /* Escape character? */
1044 if(i == '\\')
1045 {
1046 /* Read next character */
1047 i = fgetc(fp);
1048
1049 /* Skip newlines internally */
1050 if((i == '\n') || (i == '\r'))
1051 {
1052 i = fgetc(fp);
1053
1054 /* Still counts as a line though! */
1055 if(line_count != NULL)
1056 *line_count += 1;
1057 }
1058 }
1059
1060 if(i == EOF)
1061 break;
1062
1063 /* Allocate more memory as needed */
1064 if(m < n)
1065 {
1066 /* Allocate FREAD_ALLOC_CHUNK_SIZE more bytes */
1067 m += FREAD_ALLOC_CHUNK_SIZE;
1068
1069 strptr = (char *)realloc(strptr, m * sizeof(char));
1070 if(strptr == NULL)
1071 return(NULL);
1072 }
1073
1074 strptr[n - 1] = (char)i;
1075
1076 /* Read next character from file */
1077 i = fgetc(fp);
1078 n++; /* Increment characters read */
1079 }
1080
1081 /* Add newline and null terminate */
1082 m += 2; /* 2 more chars */
1083 strptr = (char *)realloc(strptr, m * sizeof(char));
1084 if(strptr == NULL)
1085 return(NULL);
1086 strptr[n - 1] = '\n';
1087 strptr[n] = '\0';
1088
1089 /* Increment line count */
1090 if(line_count != NULL)
1091 *line_count += 1;
1092 }
1093 else
1094 {
1095 /* Comment character is not specified */
1096
1097 i = fgetc(fp);
1098 if(i == EOF)
1099 return(NULL);
1100
1101 /* Begin adding characters to string */
1102 m = 0; /* Memory size */
1103 n = 1; /* Characters read */
1104 strptr = NULL; /* Return string */
1105
1106 while((i != '\n') && (i != '\r') && (i != '\0'))
1107 {
1108 /* Escape character? */
1109 if(i == '\\')
1110 {
1111 /* Read next character */
1112 i = fgetc(fp);
1113
1114 /* Skip newlines internally */
1115 if((i == '\n') || (i == '\r'))
1116 {
1117 i = fgetc(fp);
1118
1119 /* Still counts as a line though! */
1120 if(line_count != NULL)
1121 *line_count += 1;
1122 }
1123 }
1124
1125 if(i == EOF)
1126 break;
1127
1128 /* Allocate more memory as needed */
1129 if(m < n)
1130 {
1131 /* Allocate FREAD_ALLOC_CHUNK_SIZE more bytes */
1132 m += FREAD_ALLOC_CHUNK_SIZE;
1133
1134 strptr = (char *)realloc(strptr, m * sizeof(char));
1135 if(strptr == NULL)
1136 return(NULL);
1137 }
1138
1139 strptr[n - 1] = (char)i;
1140
1141 /* Read next character from file */
1142 i = fgetc(fp);
1143 n++; /* Increment characters read */
1144 }
1145
1146 /* Add newline and null terminate */
1147 m += 2; /* 2 more chars */
1148 strptr = (char *)realloc(strptr, m * sizeof(char));
1149 strptr[n - 1] = '\n';
1150 strptr[n] = '\0';
1151
1152 /* Increment line count */
1153 if(line_count != NULL)
1154 *line_count += 1;
1155 }
1156
1157
1158 return(strptr);
1159 }
1160