1 /* @source ajfile *************************************************************
2 **
3 ** AJAX file routines
4 **
5 ** @author Copyright (C) 1999 Peter Rice
6 ** @version $Revision: 1.208 $
7 ** @modified May 14 Jon Ison Added ajFileExtnTrim & ajFileDirExtnTrim
8 ** @modified $Date: 2013/01/31 13:25:12 $ by $Author: rice $
9 ** @@
10 **
11 ** This library is free software; you can redistribute it and/or
12 ** modify it under the terms of the GNU Lesser General Public
13 ** License as published by the Free Software Foundation; either
14 ** version 2.1 of the License, or (at your option) any later version.
15 **
16 ** This library is distributed in the hope that it will be useful,
17 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 ** Lesser General Public License for more details.
20 **
21 ** You should have received a copy of the GNU Lesser General Public
22 ** License along with this library; if not, write to the Free Software
23 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
24 ** MA 02110-1301, USA.
25 **
26 ******************************************************************************/
27
28 /* ========================================================================= */
29 /* ============================= include files ============================= */
30 /* ========================================================================= */
31
32
33 #include "ajlib.h"
34
35 #include "ajfile.h"
36 #include "ajsys.h"
37 #include "ajreg.h"
38 #include "ajnam.h"
39 #include "ajhttp.h"
40 #include "ajutil.h"
41 #include "ajmath.h"
42 #include "ajarr.h"
43 #include "ajfileio.h"
44
45 #include <sys/stat.h>
46 #include <sys/types.h>
47 #include <string.h>
48 #include <errno.h>
49 #include <time.h>
50 #include <limits.h>
51 /*#include <fcntl.h>*/
52
53
54 #ifndef WIN32
55 #include <dirent.h>
56 #else /* WIN32 */
57 #include "win32.h"
58 #include "dirent_w32.h"
59 #include <direct.h>
60 #endif /* !WIN32 */
61
62
63 #ifndef WIN32
64 #include <sys/wait.h>
65 #endif /* !WIN32 */
66
67
68 #ifndef WIN32
69 #include <unistd.h>
70 #endif /* !WIN32 */
71
72
73
74
75
76 /* ========================================================================= */
77 /* =============================== constants =============================== */
78 /* ========================================================================= */
79
80 #ifdef WIN32
81 #define PATH_MAX _MAX_PATH
82 #define getcwd _getcwd
83 #define fileno _fileno
84 #endif /* WIN32 */
85
86 #define FILERECURSLV 20
87
88 #ifdef __CYGWIN__
89 #define fopen(a,b) ajSysFuncFopen(a,b)
90 #endif /* __CYGWIN__ */
91
92
93
94
95 /* ========================================================================= */
96 /* =========================== global variables ============================ */
97 /* ========================================================================= */
98
99
100
101
102 /* ========================================================================= */
103 /* ============================= private data ============================== */
104 /* ========================================================================= */
105
106
107
108
109 /* ========================================================================= */
110 /* =========================== private constants =========================== */
111 /* ========================================================================= */
112
113
114
115
116 /* ========================================================================= */
117 /* =========================== private variables =========================== */
118 /* ========================================================================= */
119
120 static ajuint fileBuffSize = 2049;
121 static AjBool fileUsedStdin = AJFALSE;
122 static AjBool fileUsedStdout = AJFALSE;
123 static AjBool fileUsedStderr = AJFALSE;
124
125 static ajint fileHandle = 0;
126 static ajint fileOpenCnt = 0;
127 static ajint fileOpenMax = 0;
128 static ajint fileCloseCnt = 0;
129 static ajint fileOpenTot = 0;
130
131 static AjPStr fileNameFix = NULL;
132 static AjPStr fileNameStrTmp = NULL;
133 static AjPStr fileNameTmp = NULL;
134 static AjPStr fileDirfixTmp = NULL;
135 static AjPStr fileCwd = NULL;
136 static AjPStr fileTmpStr = NULL;
137 static AjPStr fileTempFilename = NULL;
138 static AjPStr fileDirectory = NULL;
139
140 static AjPRegexp fileUserExp = NULL;
141 static AjPRegexp fileWildExp = NULL;
142 static AjPRegexp fileEntryExp = NULL;
143 static AjPRegexp fileFileExp = NULL;
144 static AjPRegexp fileRestExp = NULL;
145 static AjPRegexp fileDirExp = NULL;
146 static AjPRegexp fileFilenameExp = NULL;
147
148
149
150
151 /* ========================================================================= */
152 /* =========================== private functions =========================== */
153 /* ========================================================================= */
154
155 static void fileBuffLineDel(AjPFilebuff thys);
156 static AjBool fileBuffLineNext(AjPFilebuff thys);
157 static void fileClose(AjPFile thys);
158 static void fileListRecurs(const AjPStr file, AjPList list, ajint *recurs);
159 static DIR* fileOpenDir(AjPStr *dir);
160 static void filebuffFreeClear(AjPFilebuff buff);
161 static void filePrintname(const AjPStr name, AjPStr* Pprintname);
162
163
164
165
166 /* ========================================================================= */
167 /* ======================= All functions by section ======================== */
168 /* ========================================================================= */
169
170
171
172
173 /* @filesection ajfile ********************************************************
174 **
175 ** @nam1rule aj Function belongs to the AJAX library.
176 **
177 ******************************************************************************/
178
179
180
181
182 /* @datasection [AjPDir] Directory ********************************************
183 **
184 ** Function is for manipulating directories and returns or takes at least one
185 ** AjPDir argument.
186 **
187 ** @nam2rule Dir
188 **
189 ******************************************************************************/
190
191
192
193
194 /* @section Directory constructors ********************************************
195 **
196 ** All constructors return a directory object by pointer.
197 ** It is the responsibility of the user to first destroy any previous
198 ** directory pointer. The target pointer
199 ** does not need to be initialised to NULL, but it is good programming practice
200 ** to do so anyway.
201 **
202 ** To replace or reuse an existing file, see instead
203 ** the file assignments and file modifiers functions.
204 **
205 ** The range of constructors is provided to allow flexibility in how
206 ** applications can open files to read various kinds of data.
207 **
208 ** @nam3rule New Constructor
209 ** @nam4rule Path Input file directory path
210 ** @suffix Pre Filename prefix(es) specified
211 ** @suffix Ext Filename extension(s) specified
212 **
213 ** @argrule Path path [const AjPStr] Path (full or relative) to directory
214 ** @argrule Pre prefix [const AjPStr] List of prefix wildcards for filename
215 ** prefixes to be used
216 ** @argrule Ext ext [const AjPStr] List of prefix wildcards for filename
217 ** extensions to be used
218 **
219 ** @valrule * [AjPDir] Directory object
220 **
221 ** @fcategory new
222 **
223 ** @fdata [AjPDir]
224 **
225 ******************************************************************************/
226
227
228
229
230 /* @func ajDirNewPath *********************************************************
231 **
232 ** Creates a new directory object.
233 **
234 ** @param [r] path [const AjPStr] Directory name
235 ** @return [AjPDir] New directory object.
236 **
237 ** @release 6.0.0
238 ** @@
239 ******************************************************************************/
240
ajDirNewPath(const AjPStr path)241 AjPDir ajDirNewPath(const AjPStr path)
242 {
243 AjPDir thys;
244
245 AJNEW0(thys);
246 ajStrAssignS(&thys->Name, path);
247 filePrintname(thys->Name, &thys->Printname);
248 thys->Prefix = NULL;
249 thys->Extension = NULL;
250
251 return thys;
252 }
253
254
255
256
257 /* @func ajDirNewPathExt ******************************************************
258 **
259 ** Creates a new directory object.
260 **
261 ** @param [r] path [const AjPStr] Directory name
262 ** @param [r] ext [const AjPStr] File extension
263 ** @return [AjPDir] New directory object.
264 **
265 ** @release 6.0.0
266 ** @@
267 ******************************************************************************/
268
ajDirNewPathExt(const AjPStr path,const AjPStr ext)269 AjPDir ajDirNewPathExt(const AjPStr path, const AjPStr ext)
270 {
271 AjPDir thys;
272
273 AJNEW0(thys);
274 ajStrAssignS(&thys->Name, path);
275 filePrintname(thys->Name, &thys->Printname);
276
277 if (ajStrMatchC(ext, " "))
278 ajStrAssignC(&thys->Extension, "");
279 else if (ajStrGetLen(ext))
280 ajStrAssignS(&thys->Extension, ext);
281
282 return thys;
283 }
284
285
286
287
288 /* @func ajDirNewPathPreExt ***************************************************
289 **
290 ** Creates a new directory object.
291 **
292 ** @param [r] path [const AjPStr] Directory name
293 ** @param [r] prefix [const AjPStr] Filename prefix
294 ** @param [r] ext [const AjPStr] Filename extension
295 ** @return [AjPDir] New directory object.
296 **
297 ** @release 6.0.0
298 ** @@
299 ******************************************************************************/
300
ajDirNewPathPreExt(const AjPStr path,const AjPStr prefix,const AjPStr ext)301 AjPDir ajDirNewPathPreExt(const AjPStr path,
302 const AjPStr prefix, const AjPStr ext)
303 {
304 AjPDir thys;
305
306 AJNEW0(thys);
307 ajStrAssignS(&thys->Name, path);
308 filePrintname(thys->Name, &thys->Printname);
309
310 if (ajStrMatchC(prefix, " "))
311 ajStrAssignC(&thys->Prefix, "");
312 else if (ajStrGetLen(prefix))
313 ajStrAssignS(&thys->Prefix, prefix);
314
315 if (ajStrMatchC(ext, " "))
316 ajStrAssignC(&thys->Extension, "");
317 else if (ajStrGetLen(ext))
318 ajStrAssignS(&thys->Extension, ext);
319
320 return thys;
321 }
322
323
324
325
326 /* @section Directory destructors *********************************************
327 **
328 ** Destruction is achieved by deleting the object.
329 **
330 ** @nam3rule Del Destructor
331 **
332 ** @argrule Del Pdir [AjPDir*] Directory to be deleted
333 **
334 ** @valrule * [void]
335 **
336 ** @fcategory delete
337 **
338 ** @fdata [AjPDir]
339 **
340 ******************************************************************************/
341
342
343
344
345 /* @func ajDirDel *************************************************************
346 **
347 ** Close and free a directory object.
348 **
349 ** @param [d] Pdir [AjPDir*] Directory object.
350 ** @return [void]
351 **
352 ** @release 2.9.0
353 ** @@
354 ******************************************************************************/
355
ajDirDel(AjPDir * Pdir)356 void ajDirDel(AjPDir* Pdir)
357 {
358 AjPDir thys;
359
360 thys = *Pdir;
361
362 if(!thys)
363 return;
364
365 ajStrDel(&thys->Name);
366 ajStrDel(&thys->Printname);
367 ajStrDel(&thys->Prefix);
368 ajStrDel(&thys->Extension);
369 AJFREE(*Pdir);
370
371 return;
372 }
373
374
375
376
377 /* @section Directory element retrieval ***************************************
378 **
379 ** Returns attributes of a directory
380 **
381 ** @nam3rule Get Return attribute value
382 ** @nam4rule Ext Return file extension
383 ** @nam4rule Prefix Return filename prefix
384 ** @nam4rule Path Return directory path
385 ** @nam4rule Printpath Return directory printable path
386 **
387 ** @argrule Get thys [const AjPDir] Directory
388 **
389 ** @valrule * [const AjPStr] String value
390 **
391 ** @fcategory use
392 **
393 ** @fdata [AjPDir]
394 **
395 ******************************************************************************/
396
397
398
399
400 /* @func ajDirGetExt **********************************************************
401 **
402 ** Returns the extension(s) of a directory object
403 **
404 ** @param [r] thys [const AjPDir] Directory object.
405 ** @return [const AjPStr] Directory name
406 **
407 ** @release 6.0.0
408 ** @@
409 ******************************************************************************/
410
ajDirGetExt(const AjPDir thys)411 const AjPStr ajDirGetExt(const AjPDir thys)
412 {
413 if (!thys)
414 return NULL;
415
416 return thys->Extension;
417 }
418
419
420
421
422 /* @func ajDirGetPath *********************************************************
423 **
424 ** Returns the full path of a directory object
425 **
426 ** @param [r] thys [const AjPDir] Directory object.
427 ** @return [const AjPStr] Directory name
428 **
429 ** @release 6.0.0
430 ** @@
431 ******************************************************************************/
432
ajDirGetPath(const AjPDir thys)433 const AjPStr ajDirGetPath(const AjPDir thys)
434 {
435 if (!thys)
436 return NULL;
437
438 return thys->Name;
439 }
440
441
442
443
444 /* @func ajDirGetPrefix *******************************************************
445 **
446 ** Returns the filename prefix(es) of a directory object
447 **
448 ** @param [r] thys [const AjPDir] Directory object.
449 ** @return [const AjPStr] Directory name
450 **
451 ** @release 6.0.0
452 ** @@
453 ******************************************************************************/
454
ajDirGetPrefix(const AjPDir thys)455 const AjPStr ajDirGetPrefix(const AjPDir thys)
456 {
457 if (!thys)
458 return NULL;
459 return thys->Prefix;
460 }
461
462
463
464
465 /* @func ajDirGetPrintpath ****************************************************
466 **
467 ** Returns the full printable path of a directory object
468 **
469 ** @param [r] thys [const AjPDir] Directory object.
470 ** @return [const AjPStr] Directory printable name
471 **
472 ** @release 6.4.0
473 ** @@
474 ******************************************************************************/
475
ajDirGetPrintpath(const AjPDir thys)476 const AjPStr ajDirGetPrintpath(const AjPDir thys)
477 {
478 if (!thys)
479 return NULL;
480
481 return thys->Printname;
482 }
483
484
485
486
487 /* @datasection [AjPDirout] Output directory **********************************
488 **
489 ** Function is for manipulating output directories and returns or
490 ** takes at least one AjPDirout argument.
491 **
492 ** @nam2rule Dirout
493 **
494 ******************************************************************************/
495
496
497
498
499 /* @section Output directory constructors *************************************
500 **
501 ** All constructors return a directory object by pointer.
502 ** It is the responsibility of the user to first destroy any previous
503 ** directory pointer. The target pointer
504 ** does not need to be initialised to NULL, but it is good programming practice
505 ** to do so anyway.
506 **
507 ** To replace or reuse an existing file, see instead
508 ** the {File Assignments} and {File Modifiers} functions.
509 **
510 ** The range of constructors is provided to allow flexibility in how
511 ** applications can open files to read various kinds of data.
512 **
513 ** @nam3rule New Constructor
514 ** @nam4rule Path Output file directory path
515 ** @suffix Pre Filename prefix(es) specified
516 ** @suffix Ext Filename extension(s) specified
517 **
518 ** @argrule Path path [const AjPStr] Path (full or relative) to directory
519 ** @argrule Pre prefix [const AjPStr] List of prefix wildcards for filename
520 ** prefixes to be used
521 ** @argrule Ext ext [const AjPStr] List of prefix wildcards for filename
522 ** extensions to be used
523 **
524 ** @valrule * [AjPDirout] Output directory object
525 **
526 ** @fcategory new
527 **
528 ** @fdata [AjPDirout]
529 **
530 ******************************************************************************/
531
532
533
534
535 /* @func ajDiroutNewPath ******************************************************
536 **
537 ** Creates a new directory output object.
538 **
539 ** @param [r] path [const AjPStr] Directory name
540 ** @return [AjPDirout] New directory object.
541 **
542 ** @release 6.0.0
543 ** @@
544 ******************************************************************************/
545
ajDiroutNewPath(const AjPStr path)546 AjPDirout ajDiroutNewPath(const AjPStr path)
547 {
548 AjPDirout thys;
549
550 AJNEW0(thys);
551 ajStrAssignS(&thys->Name, path);
552 filePrintname(thys->Name, &thys->Printname);
553 thys->Extension = NULL;
554
555 return thys;
556 }
557
558
559
560
561 /* @func ajDiroutNewPathExt ***************************************************
562 **
563 ** Creates a new directory output object.
564 **
565 ** @param [r] path [const AjPStr] Directory name
566 ** @param [r] ext [const AjPStr] File extension
567 ** @return [AjPDirout] New directory object.
568 **
569 ** @release 6.0.0
570 ** @@
571 ******************************************************************************/
572
ajDiroutNewPathExt(const AjPStr path,const AjPStr ext)573 AjPDirout ajDiroutNewPathExt(const AjPStr path, const AjPStr ext)
574 {
575 AjPDirout thys;
576
577 AJNEW0(thys);
578 ajStrAssignS(&thys->Name, path);
579 filePrintname(thys->Name, &thys->Printname);
580
581 if (ajStrGetLen(ext))
582 ajStrAssignS(&thys->Extension, ext);
583
584 return thys;
585 }
586
587
588
589
590 /* @section Output directory destructors **************************************
591 **
592 ** Destruction is achieved by deleting the object.
593 **
594 ** @nam3rule Del Destructor
595 **
596 ** @argrule Del Pdir [AjPDirout*] Directory to be deleted
597 **
598 ** @valrule * [void]
599 **
600 ** @fcategory delete
601 **
602 ** @fdata [AjPDirout]
603 **
604 ******************************************************************************/
605
606
607
608
609 /* @func ajDiroutDel **********************************************************
610 **
611 ** Close and free a directory object.
612 **
613 ** @param [d] Pdir [AjPDirout*] Directory object.
614 ** @return [void]
615 **
616 ** @release 2.9.0
617 ** @@
618 ******************************************************************************/
619
ajDiroutDel(AjPDirout * Pdir)620 void ajDiroutDel(AjPDirout* Pdir)
621 {
622 AjPDirout thys;
623
624 thys = *Pdir;
625
626 if(!thys)
627 return;
628
629 ajStrDel(&thys->Name);
630 ajStrDel(&thys->Printname);
631 ajStrDel(&thys->Extension);
632 AJFREE(*Pdir);
633
634 return;
635 }
636
637
638
639
640 /* @section Output directory element retrieval ********************************
641 **
642 ** Returns attributes of a directory
643 **
644 ** @nam3rule Get Return attribute value
645 ** @nam4rule Ext Return file extension
646 ** @nam4rule Path Return directory path
647 ** @nam4rule Printpath Return directory printable path
648 **
649 ** @argrule Get thys [const AjPDirout] Directory
650 **
651 ** @valrule * [const AjPStr] String value
652 **
653 ** @fdata [AjPDirout]
654 ** @fcategory use
655 **
656 ******************************************************************************/
657
658
659
660
661 /* @func ajDiroutGetExt *******************************************************
662 **
663 ** Returns the extension of an output directory object
664 **
665 ** @param [r] thys [const AjPDirout] Directory object.
666 ** @return [const AjPStr] Directory name
667 **
668 ** @release 6.0.0
669 ** @@
670 ******************************************************************************/
671
ajDiroutGetExt(const AjPDirout thys)672 const AjPStr ajDiroutGetExt(const AjPDirout thys)
673 {
674 if (!thys)
675 return NULL;
676
677 return thys->Extension;
678 }
679
680
681
682
683 /* @func ajDiroutGetPath ******************************************************
684 **
685 ** Returns the name of an output directory object
686 **
687 ** @param [r] thys [const AjPDirout] Directory object.
688 ** @return [const AjPStr] Directory name
689 **
690 ** @release 6.0.0
691 ** @@
692 ******************************************************************************/
693
ajDiroutGetPath(const AjPDirout thys)694 const AjPStr ajDiroutGetPath(const AjPDirout thys)
695 {
696 if (!thys)
697 return NULL;
698
699 return thys->Name;
700 }
701
702
703
704
705 /* @func ajDiroutGetPrintpath *************************************************
706 **
707 ** Returns the printable name of an output directory object
708 **
709 ** @param [r] thys [const AjPDirout] Directory object.
710 ** @return [const AjPStr] Directory printable name
711 **
712 ** @release 6.4.0
713 ** @@
714 ******************************************************************************/
715
ajDiroutGetPrintpath(const AjPDirout thys)716 const AjPStr ajDiroutGetPrintpath(const AjPDirout thys)
717 {
718 if (!thys)
719 return NULL;
720
721 return thys->Printname;
722 }
723
724
725
726
727 /* @section Output directory element tests ************************************
728 **
729 ** Modifies attributes of a directory
730 **
731 ** @nam3rule Created tests whether directory is newly created
732 ** @nam3rule Exists tests whether directory exists already
733 **
734 ** @argrule * thys [AjPDirout] Directory
735 **
736 ** @valrule * [AjBool] True on success
737 **
738 ** @fcategory use
739 **
740 ** @fdata [AjPDirout]
741 **
742 ******************************************************************************/
743
744
745
746
747 /* @func ajDiroutCreated ******************************************************
748 **
749 ** Tests if an output directory was created when it did not already exist
750 **
751 ** @param [u] thys [AjPDirout] Directory name
752 ** @return [AjBool] True if a newly cteated directory
753 **
754 ** @release 6.5.0
755 ** @@
756 ******************************************************************************/
757
ajDiroutCreated(AjPDirout thys)758 AjBool ajDiroutCreated(AjPDirout thys)
759 {
760 if(!thys)
761 return ajFalse;
762
763 return thys->Created;
764 }
765
766
767
768
769 /* @func ajDiroutExists *******************************************************
770 **
771 ** Tests a directory output object is for an existing directory
772 **
773 ** @param [u] thys [AjPDirout] Directory name
774 ** @return [AjBool] True on success.
775 **
776 ** @release 6.1.0
777 ** @@
778 ******************************************************************************/
779
ajDiroutExists(AjPDirout thys)780 AjBool ajDiroutExists(AjPDirout thys)
781 {
782 #ifdef WIN32
783 if(ajStrMatchC(thys->Name, "."))
784 {
785 ajStrAssignC(&thys->Name, "");
786 ajStrAssignC(&thys->Printname, "");
787 return ajTrue;
788 }
789 #endif /* WIN32 */
790
791 if(ajStrGetCharLast(thys->Name) != SLASH_CHAR)
792 {
793 ajStrAppendC(&thys->Name, SLASH_STRING);
794 filePrintname(thys->Name, &thys->Printname);
795 }
796
797 if(!ajFilenameExistsDir(thys->Name))
798 return ajFalse;
799
800 return ajTrue;
801 }
802
803
804
805
806 /* @section Output directory element modifiers ********************************
807 **
808 ** Modifies attributes of a directory
809 **
810 ** @nam3rule Open Open the directory, creating if needed
811 **
812 ** @argrule * thys [AjPDirout] Directory
813 **
814 ** @valrule * [AjBool] True on success
815 **
816 ** @fcategory modify
817 **
818 ** @fdata [AjPDirout]
819 **
820 ******************************************************************************/
821
822
823
824
825 /* @func ajDiroutOpen *********************************************************
826 **
827 ** Opens a directory output object, creating it if it does not already exist
828 **
829 ** @param [u] thys [AjPDirout] Directory name
830 ** @return [AjBool] True on success.
831 **
832 ** @release 6.1.0
833 ** @@
834 ******************************************************************************/
835
ajDiroutOpen(AjPDirout thys)836 AjBool ajDiroutOpen(AjPDirout thys)
837 {
838 #ifdef WIN32
839 if(ajStrMatchC(thys->Name, "."))
840 {
841 ajStrAssignC(&thys->Name, "");
842 ajStrAssignC(&thys->Printname, "");
843 return ajTrue;
844 }
845 #endif /* WIN32 */
846
847 if(ajStrGetCharLast(thys->Name) != SLASH_CHAR)
848 {
849 ajStrAppendC(&thys->Name, SLASH_STRING);
850 filePrintname(thys->Name, &thys->Printname);
851 }
852
853 if(!ajFilenameExists(thys->Name))
854 {
855 ajSysCommandMakedirS(thys->Name);
856 thys->Created = ajTrue;
857 }
858
859 if(!ajFilenameExistsDir(thys->Name))
860 return ajFalse;
861
862 return ajTrue;
863 }
864
865
866
867
868 /* @datasection [AjPFile] File object *****************************************
869 **
870 ** Function is for manipulating buffered files and returns or takes at least
871 ** one AjSFileBuff argument.
872 **
873 ** Function is for manipulating file and file-related objects and usually
874 ** processes an AjSOutfile, AjSDir, AjSFileBuff, AjSFileBuffList or AjSFile
875 ** object.
876 **
877 ** @nam2rule File
878 ******************************************************************************/
879
880
881
882
883 /* @section File constructors *************************************************
884 **
885 ** All constructors return a new open file by pointer. It is the responsibility
886 ** of the user to first destroy any previous file pointer. The target pointer
887 ** does not need to be initialised to NULL, but it is good programming practice
888 ** to do so anyway.
889 **
890 ** The range of constructors is provided to allow flexibility in how
891 ** applications can open files to read and write various kinds of data.
892 **
893 ** @nam3rule New Constructor
894 ** @nam4rule From Create from an already open file
895 ** @nam4rule In Input file
896 ** @nam4rule Listin List of one or more input files
897 ** @nam4rule Out Output file created or rewritten
898 ** @nam4rule Outappend Output file appended to existing content
899 ** @nam5rule Block File opened for block read with internal system functions
900 ** @nam5rule FromCfile C FILE* structure used to create file object
901 ** @nam5rule Pipe Read from piped output of command
902 ** @nam5rule ListinList List of files specified
903 ** @nam5rule InPath Input directory path specified
904 ** @nam5rule OutPath Output directory path specified
905 ** @nam5rule Dir Input directory specified
906 ** @nam6rule ListinNameDir Input directory specified
907 ** @nam6rule OutNameDir Output directory specified
908 **
909 ** @suffix Name Existing filename specified
910 ** @suffix C Filename as C character string
911 ** @suffix S Filename as string
912 ** @suffix Pre Filename prefix(es) specified
913 ** @suffix Ext Filename extension(s) specified
914 ** @suffix Dir Input directory specified
915 ** @suffix Path Input directory path specified
916 ** @suffix Wild Wildcard filename
917 ** @suffix Exclude Filename exclusion wildcard(s)
918 **
919 **
920 **
921 ** @argrule C name [const char*] Filename
922 ** @argrule S name [const AjPStr] Filename
923 **
924 ** @argrule Block blocksize [ajuint] Block size for buffered system reads
925 ** @argrule Cfile file [FILE*] C file pointer
926 ** @argrule Pipe command [const AjPStr] Commandline
927 ** @argrule ListinList list [AjPList] List of filenames as strings
928 ** @argrule ListinNameDir dir [const AjPDir] Input directory
929 ** @argrule ListinDir dir [const AjPDir] Input directory
930 ** @argrule InNameDir dir [const AjPDir] Input directory
931 ** @argrule OutNameDir dir [const AjPDirout] Output directory
932 ** @argrule Path path [const AjPStr] Input directory path
933 ** @argrule OutPath path [const AjPStr] Output directory path
934 ** @argrule Pre prefix [const AjPStr] List of prefix wildcards for filename
935 ** prefixes to be used
936 ** @argrule Wild wildname [const AjPStr] Wildcard filename
937 ** @argrule Exclude exclude [const AjPStr] Filename exclusion wildcard(s)
938 ** @argrule Ext ext [const AjPStr] List of wildcards for filename
939 ** extensions to be used
940 **
941 ** @valrule * [AjPFile] New file object
942 ** @fcategory new
943 **
944 ** @fdata [AjPFile]
945 **
946 ******************************************************************************/
947
948
949
950
951 /* @func ajFileNewFromCfile ***************************************************
952 **
953 ** Creates a new file object from an open C file.
954 **
955 ** The file is for input, output, or append - depending on how the C FILE
956 ** pointer was opened.
957 **
958 ** @param [u] file [FILE*] C file.
959 ** @return [AjPFile] New file object.
960 **
961 ** @release 6.0.0
962 ** @@
963 ******************************************************************************/
964
ajFileNewFromCfile(FILE * file)965 AjPFile ajFileNewFromCfile(FILE* file)
966 {
967 AjPFile thys;
968
969 if(!file)
970 ajFatal("Trying to create an AJAX file from a bad C RTL FILE*");
971
972 AJNEW0(thys);
973 thys->fp = file;
974 thys->Handle = ++fileHandle;
975
976 if(file == stdout)
977 thys->Name = ajStrNewC("stdout");
978 else if(file == stderr)
979 thys->Name = ajStrNewC("stderr");
980 else if(file == stdin)
981 thys->Name = ajStrNewC("stdin");
982 else
983 thys->Name = ajStrNew();
984
985 ajStrAssignS(&thys->Printname, thys->Name);
986
987 thys->End = ajFalse;
988
989 fileOpenCnt++;
990 fileOpenTot++;
991
992 if(fileOpenCnt > fileOpenMax)
993 fileOpenMax = fileOpenCnt;
994
995 if(file == stdin)
996 fileUsedStdin = ajTrue;
997 else if(file == stdout)
998 fileUsedStdout = ajTrue;
999 else if(file == stderr)
1000 fileUsedStderr = ajTrue;
1001
1002 ajDebug("Created file from C FILE %p\n", file);
1003
1004 return thys;
1005 }
1006
1007
1008
1009
1010 /* @funcstatic fileNew ********************************************************
1011 **
1012 ** Creates a new file object.
1013 **
1014 ** @return [AjPFile] New file object.
1015 **
1016 ** @release 6.0.0
1017 ** @@
1018 ******************************************************************************/
1019
fileNew(void)1020 static AjPFile fileNew(void)
1021 {
1022 AjPFile thys;
1023
1024 AJNEW0(thys);
1025 thys->fp = NULL;
1026 thys->Handle = 0;
1027 thys->Name = ajStrNew();
1028 thys->Printname = ajStrNew();
1029 thys->Buff = ajStrNewRes(fileBuffSize);
1030 thys->Buffsize = fileBuffSize;
1031 thys->List = NULL;
1032 thys->End = ajFalse;
1033
1034 fileOpenCnt++;
1035 fileOpenTot++;
1036
1037 if(fileOpenCnt > fileOpenMax)
1038 fileOpenMax = fileOpenCnt;
1039
1040 return thys;
1041 }
1042
1043
1044
1045
1046 /* @func ajFileNewInBlockS ****************************************************
1047 **
1048 ** Creates a new file object to read a named file using blocked fread calls.
1049 **
1050 ** If the filename ends with a pipe character then a pipe is opened
1051 ** using ajFileNewInPipe.
1052 **
1053 ** @param [r] name [const AjPStr] File name.
1054 ** @param [r] blocksize [ajuint] Block size
1055 ** @return [AjPFile] New file object.
1056 **
1057 ** @release 6.0.0
1058 ** @@
1059 ******************************************************************************/
1060
ajFileNewInBlockS(const AjPStr name,ajuint blocksize)1061 AjPFile ajFileNewInBlockS(const AjPStr name, ajuint blocksize)
1062 {
1063 AjPFile ret;
1064 ret = ajFileNewInNameS(name);
1065 ret->Blocksize = blocksize;
1066
1067 if(blocksize)
1068 {
1069 ret->Workbuffer = ajCharNewRes(blocksize);
1070 /*setvbuf(ret->fp, ret->Workbuffer, _IOFBF, blocksize);*/
1071 ret->Readblock = ajCharNewRes(blocksize+1);
1072 ret->Blockpos = 0;
1073 ret->Blocklen = 0;
1074 ret->Blocksize = blocksize;
1075 }
1076
1077 ajDebug("ajFileNewInBlock '%S' blocksize:%u\n", name, blocksize);
1078
1079 return ret;
1080 }
1081
1082
1083
1084
1085 /* @func ajFileNewInNameC *****************************************************
1086 **
1087 ** Creates a new file object to read a named file.
1088 **
1089 ** If the filename begins with a pipe character then a pipe is opened
1090 ** using ajFileNewInPipe.
1091 **
1092 ** @param [r] name [const char*] File name.
1093 ** @return [AjPFile] New file object.
1094 **
1095 ** @release 6.2.0
1096 ** @@
1097 ******************************************************************************/
1098
ajFileNewInNameC(const char * name)1099 AjPFile ajFileNewInNameC(const char *name)
1100 {
1101 ajStrAssignC(&fileNameStrTmp, name);
1102
1103 return ajFileNewInNameS(fileNameStrTmp);
1104 }
1105
1106
1107
1108
1109 /* @func ajFileNewInNameS *****************************************************
1110 **
1111 ** Creates a new file object to read a named file.
1112 **
1113 ** If the filename ends with a pipe character then a pipe is opened
1114 ** using ajFileNewInPipe.
1115 **
1116 ** @param [r] name [const AjPStr] File name.
1117 ** @return [AjPFile] New file object.
1118 **
1119 ** @release 6.0.0
1120 ** @@
1121 ******************************************************************************/
1122
ajFileNewInNameS(const AjPStr name)1123 AjPFile ajFileNewInNameS(const AjPStr name)
1124 {
1125 AjPFile thys = NULL;
1126 AjPStr userstr = NULL;
1127 AjPStr reststr = NULL;
1128
1129 AjPStr dirname = NULL;
1130 AjPStr wildname = NULL;
1131 AjPFile ptr;
1132
1133 char *hdir = NULL;
1134
1135 ajDebug("ajFileNewInNameS '%S'\n", name);
1136
1137 if(ajStrMatchC(name, "stdin"))
1138 {
1139 thys = ajFileNewFromCfile(stdin);
1140 ajStrAssignC(&thys->Name, "stdin");
1141 ajStrAssignS(&thys->Printname, thys->Name);
1142 return thys;
1143 }
1144
1145 ajStrAssignS(&fileNameTmp, name);
1146
1147 if(ajStrGetCharLast(name) == '|') /* pipe character at end */
1148 return ajFileNewInPipe(name);
1149
1150 if(ajStrGetCharFirst(fileNameTmp) == '~')
1151 {
1152 ajDebug("starts with '~'\n");
1153
1154 if(!fileUserExp)
1155 fileUserExp = ajRegCompC("^~([^/\\\\]*)");
1156
1157 ajRegExec(fileUserExp, fileNameTmp);
1158 ajRegSubI(fileUserExp, 1, &userstr);
1159 ajRegPost(fileUserExp, &reststr);
1160 ajDebug(" user: '%S' rest: '%S'\n", userstr, reststr);
1161
1162 if(ajStrGetLen(userstr))
1163 {
1164 /* username specified */
1165 hdir = ajSysGetHomedirFromName(ajStrGetPtr(userstr));
1166
1167 if(!hdir)
1168 {
1169 ajStrDel(&userstr);
1170 ajStrDelStatic(&fileNameTmp);
1171 ajStrDel(&reststr);
1172
1173 return NULL;
1174 }
1175
1176 ajFmtPrintS(&fileNameTmp, "%s%S", hdir, reststr);
1177 AJFREE(hdir);
1178
1179 ajDebug("use getpwnam: '%S'\n", fileNameTmp);
1180 }
1181 else
1182 {
1183 /* just ~/ */
1184 hdir = ajSysGetHomedir();
1185
1186 if(hdir)
1187 {
1188 ajFmtPrintS(&fileNameTmp, "%s%S", hdir, reststr);
1189 AJFREE(hdir);
1190 }
1191 else
1192 ajFmtPrintS(&fileNameTmp,"%S",reststr);
1193
1194 ajDebug("use HOME: '%S'\n", fileNameTmp);
1195 }
1196 }
1197
1198 ajStrDel(&userstr);
1199 ajStrDel(&reststr);
1200
1201 if(!fileWildExp)
1202 fileWildExp = ajRegCompC("(.*/)?([^/]*[*?][^/]*)$");
1203
1204 if(ajRegExec(fileWildExp, fileNameTmp))
1205 {
1206 /* wildcard file names */
1207 ajRegSubI(fileWildExp, 1, &dirname);
1208 ajRegSubI(fileWildExp, 2, &wildname);
1209 ajDebug("wild dir '%S' files '%S'\n", dirname, wildname);
1210 ptr = ajFileNewListinPathWild(dirname, wildname);
1211 ajStrDelStatic(&fileNameTmp);
1212 ajStrDel(&dirname);
1213 ajStrDel(&wildname);
1214
1215 return ptr;
1216 }
1217
1218
1219
1220 AJNEW0(thys);
1221 ajStrAssignS(&thys->Name, fileNameTmp);
1222 ajStrDelStatic(&fileNameTmp);
1223
1224 ajNamResolve(&thys->Name);
1225
1226 #ifdef WIN32
1227 if(ajStrMatchC(thys->Name, "/dev/null"))
1228 thys->fp = fopen("NUL", "rb");
1229 else
1230 #endif /* WIN32 */
1231 thys->fp = fopen(ajStrGetPtr(thys->Name), "rb");
1232
1233 if(!thys->fp)
1234 {
1235 ajStrDel(&thys->Name);
1236 AJFREE(thys);
1237 /* thys->Handle = 0;*/
1238 return NULL;
1239 }
1240
1241 filePrintname(thys->Name, &thys->Printname);
1242
1243 thys->Handle = ++fileHandle;
1244 thys->List = NULL;
1245 thys->End = ajFalse;
1246
1247 fileOpenCnt++;
1248 fileOpenTot++;
1249 if(fileOpenCnt > fileOpenMax)
1250 fileOpenMax = fileOpenCnt;
1251
1252 return thys;
1253 }
1254
1255
1256
1257
1258 /* @func ajFileNewInNamePathC *************************************************
1259 **
1260 ** Opens directory "dir".
1261 ** Looks for file "file"
1262 **
1263 ** @param [r] name [const char*] Filename.
1264 ** @param [r] path [const AjPStr] Directory
1265 ** @return [AjPFile] New file object.
1266 **
1267 ** @release 6.0.0
1268 ** @@
1269 ******************************************************************************/
1270
ajFileNewInNamePathC(const char * name,const AjPStr path)1271 AjPFile ajFileNewInNamePathC(const char* name, const AjPStr path)
1272 {
1273 ajStrAssignC(&fileNameStrTmp, name);
1274
1275 return ajFileNewInNamePathS(fileNameStrTmp, path);
1276 }
1277
1278
1279
1280
1281 /* @func ajFileNewInNamePathS *************************************************
1282 **
1283 ** Opens directory "dir".
1284 ** Looks for file "file"
1285 **
1286 ** @param [r] name [const AjPStr] Filename.
1287 ** @param [r] path [const AjPStr] Directory
1288 ** @return [AjPFile] New file object.
1289 **
1290 ** @release 6.0.0
1291 ** @@
1292 ******************************************************************************/
1293
ajFileNewInNamePathS(const AjPStr name,const AjPStr path)1294 AjPFile ajFileNewInNamePathS(const AjPStr name, const AjPStr path)
1295 {
1296 if(ajStrGetLen(path))
1297 ajStrAssignS(&fileNameFix, path);
1298 else
1299 ajStrAssignC(&fileNameFix, CURRENT_DIR);
1300
1301 if(ajStrGetCharLast(fileNameFix) != SLASH_CHAR)
1302 ajStrAppendC(&fileNameFix, SLASH_STRING);
1303
1304 ajStrAppendS(&fileNameFix, name);
1305
1306 return ajFileNewInNameS(fileNameFix);
1307 }
1308
1309
1310
1311
1312 /* @func ajFileNewInPipe ******************************************************
1313 **
1314 ** Creates a new file object to read the output from a command.
1315 **
1316 ** @param [r] command [const AjPStr] Command string.
1317 ** The string may end with a trailing pipe character.
1318 ** @return [AjPFile] New file object.
1319 **
1320 ** @release 1.0.0
1321 ** @@
1322 ******************************************************************************/
1323
ajFileNewInPipe(const AjPStr command)1324 AjPFile ajFileNewInPipe(const AjPStr command)
1325 {
1326 AjPFile thys = NULL;
1327
1328 thys = ajSysCreateInpipeS(command);
1329
1330 if(!thys)
1331 return NULL;
1332
1333 thys->Handle = ++fileHandle;
1334
1335 ajStrAssignS(&thys->Name, command);
1336 ajStrAssignS(&thys->Printname, thys->Name);
1337
1338 thys->End = ajFalse;
1339
1340 fileOpenCnt++;
1341 fileOpenTot++;
1342 if(fileOpenCnt > fileOpenMax)
1343 fileOpenMax = fileOpenCnt;
1344
1345 return thys;
1346 }
1347
1348
1349
1350
1351 /* @func ajFileNewListinDirPre ************************************************
1352 **
1353 ** Opens directory "dir".
1354 ** Looks for file "file" with the extension (if any) specified
1355 ** for the directory
1356 **
1357 ** @param [r] dir [const AjPDir] Directory
1358 ** @param [r] prefix [const AjPStr] Wildcard Filename.
1359 ** @return [AjPFile] New file object.
1360 **
1361 ** @release 6.0.0
1362 ** @@
1363 ******************************************************************************/
1364
ajFileNewListinDirPre(const AjPDir dir,const AjPStr prefix)1365 AjPFile ajFileNewListinDirPre(const AjPDir dir, const AjPStr prefix)
1366 {
1367 if(ajStrGetLen(dir->Name))
1368 ajStrAssignS(&fileNameFix, dir->Name);
1369 else
1370 ajStrAssignC(&fileNameFix, CURRENT_DIR);
1371
1372 if(ajStrGetCharLast(fileNameFix) != SLASH_CHAR)
1373 ajStrAppendC(&fileNameFix, SLASH_STRING);
1374
1375 ajStrAppendS(&fileNameFix, prefix);
1376 ajFilenameReplaceExtS(&fileNameFix, dir->Extension);
1377
1378 return ajFileNewInNameS(fileNameFix);
1379 }
1380
1381
1382
1383
1384 /* @func ajFileNewListinList **************************************************
1385 **
1386 ** Creates a new file object with a list of input file names.
1387 **
1388 ** @param [u] list [AjPList] List of input filenames as strings.
1389 ** @return [AjPFile] New file object.
1390 **
1391 ** @release 6.0.0
1392 ** @@
1393 ******************************************************************************/
1394
ajFileNewListinList(AjPList list)1395 AjPFile ajFileNewListinList(AjPList list)
1396 {
1397 AjPFile thys;
1398
1399 AJNEW0(thys);
1400
1401 thys->List = list;
1402 thys->Name = NULL;
1403 ajListstrTrace(thys->List);
1404 ajListstrPop(thys->List, &thys->Name);
1405 ajDebug("ajFileNewListinList pop '%S'\n", thys->Name);
1406 ajListstrTrace(thys->List);
1407 ajNamResolve(&thys->Name);
1408
1409 #ifdef WIN32
1410 if(ajStrMatchC(thys->Name, "/dev/null"))
1411 thys->fp = fopen("NUL", "rb");
1412 else
1413 #endif /* WIN32 */
1414 thys->fp = fopen(ajStrGetPtr(thys->Name), "rb");
1415
1416
1417 if(!thys->fp)
1418 {
1419 ajDebug("ajFileNewListinList fopen failed\n");
1420 ajStrDel(&thys->Name);
1421 thys->Handle = 0;
1422 AJFREE(thys);
1423 return NULL;
1424 }
1425
1426 filePrintname(thys->Name, &thys->Printname);
1427
1428 thys->Handle = ++fileHandle;
1429 thys->End = ajFalse;
1430
1431 fileOpenCnt++;
1432 fileOpenTot++;
1433
1434 if(fileOpenCnt > fileOpenMax)
1435 fileOpenMax = fileOpenCnt;
1436
1437 return thys;
1438 }
1439
1440
1441
1442
1443 /* @func ajFileNewListinNameDirS **********************************************
1444 **
1445 ** Opens directory "dir" and looks for file "filename".
1446 **
1447 ** @param [r] name [const AjPStr] Wildcard Filename.
1448 ** @param [r] dir [const AjPDir] Directory
1449 ** @return [AjPFile] New file object.
1450 **
1451 ** @release 6.0.0
1452 ** @@
1453 ******************************************************************************/
1454
ajFileNewListinNameDirS(const AjPStr name,const AjPDir dir)1455 AjPFile ajFileNewListinNameDirS(const AjPStr name, const AjPDir dir)
1456 {
1457 if(ajStrGetLen(dir->Name))
1458 ajStrAssignS(&fileNameFix, dir->Name);
1459 else
1460 ajStrAssignC(&fileNameFix, CURRENT_DIR);
1461
1462 if(ajStrGetCharLast(fileNameFix) != SLASH_CHAR)
1463 ajStrAppendC(&fileNameFix, SLASH_STRING);
1464
1465 ajStrAppendS(&fileNameFix, name);
1466
1467 return ajFileNewInNameS(fileNameFix);
1468 }
1469
1470
1471
1472
1473 /* @func ajFileNewListinPathWild **********************************************
1474 **
1475 ** Opens directory "dir"
1476 ** Looks for file(s) matching "file"
1477 ** Opens them as a list of files using a simple file object.
1478 **
1479 ** @param [r] path [const AjPStr] Directory
1480 ** @param [r] wildname [const AjPStr] Wildcard filename.
1481 ** @return [AjPFile] New file object.
1482 **
1483 ** @release 6.0.0
1484 ** @@
1485 ******************************************************************************/
1486
ajFileNewListinPathWild(const AjPStr path,const AjPStr wildname)1487 AjPFile ajFileNewListinPathWild(const AjPStr path, const AjPStr wildname)
1488 {
1489 DIR* dp;
1490 #if defined(AJ_IRIXLF)
1491 struct dirent64 *de;
1492 #else /* !AJ_IRIXLF */
1493 struct dirent* de;
1494 #endif /* AJ_IRIXLF */
1495 ajint dirsize;
1496 AjPList list = NULL;
1497 AjPStr name = NULL;
1498 #ifdef _POSIX_C_SOURCE
1499 char buf[sizeof(struct dirent)+MAXNAMLEN];
1500 #endif /* _POSIX_C_SOURCE */
1501
1502 if(ajStrGetLen(path))
1503 ajStrAssignS(&fileDirfixTmp, path);
1504 else
1505 ajStrAssignC(&fileDirfixTmp, CURRENT_DIR);
1506
1507 if(ajStrGetCharLast(fileDirfixTmp) != SLASH_CHAR)
1508 ajStrAppendC(&fileDirfixTmp, SLASH_STRING);
1509
1510 dp = fileOpenDir(&fileDirfixTmp);
1511
1512 if(!dp)
1513 return NULL;
1514
1515 dirsize = 0;
1516 list = ajListstrNew();
1517
1518 while(
1519 #if defined(AJ_IRIXLF)
1520 #ifdef _POSIX_C_SOURCE
1521 !readdir64_r(dp,(struct dirent64 *)buf,&de)
1522 #else /* !_POSIX_C_SOURCE */
1523 (de=readdir64(dp))
1524 #endif /* _POSIX_C_SOURCE */
1525 #else /* !AJ_IRIXLF */
1526 #ifdef _POSIX_C_SOURCE
1527 !readdir_r(dp,(struct dirent *)buf,&de)
1528 #else /* _POSIX_C_SOURCE */
1529 (de=readdir(dp))
1530 #endif /* _POSIX_C_SOURCE */
1531 #endif /* AJ_IRIXLF */
1532 )
1533 {
1534 #ifdef _POSIX_C_SOURCE
1535 if(!de)
1536 break;
1537 #endif /* _POSIX_C_SOURCE */
1538 /* skip deleted files with inode zero */
1539 #ifndef __CYGWIN__
1540 if(!de->d_ino)
1541 continue;
1542 #endif /* !__CYGWIN__ */
1543
1544 if(ajCharMatchC(de->d_name, "."))
1545 continue;
1546
1547 if(ajCharMatchC(de->d_name, ".."))
1548 continue;
1549
1550 if(!ajCharMatchWildS(de->d_name, wildname))
1551 continue;
1552
1553 dirsize++;
1554 ajDebug("accept '%s'\n", de->d_name);
1555 name = NULL;
1556 ajFmtPrintS(&name, "%S%s", fileDirfixTmp, de->d_name);
1557 ajListstrPushAppend(list, name);
1558 }
1559
1560 closedir(dp);
1561 ajDebug("%d files for '%S' '%S'\n", dirsize, path, wildname);
1562
1563 return ajFileNewListinList(list);
1564 }
1565
1566
1567
1568
1569 /* @func ajFileNewListinPathWildExclude ***************************************
1570 **
1571 ** Opens directory "dir".
1572 ** Looks for file(s) matching "file".
1573 ** Skip files matching excluded files wildcard.
1574 ** Opens them as a list of files using a simple file object.
1575 **
1576 ** @param [r] path [const AjPStr] Directory path
1577 ** @param [r] wildname [const AjPStr] Wildcard filename.
1578 ** @param [r] exclude [const AjPStr] Wildcard excluded filename.
1579 ** @return [AjPFile] New file object.
1580 **
1581 ** @release 6.0.0
1582 ** @@
1583 ******************************************************************************/
1584
ajFileNewListinPathWildExclude(const AjPStr path,const AjPStr wildname,const AjPStr exclude)1585 AjPFile ajFileNewListinPathWildExclude(const AjPStr path,
1586 const AjPStr wildname,
1587 const AjPStr exclude)
1588 {
1589 DIR* dp;
1590 #if defined(AJ_IRIXLF)
1591 struct dirent64 *de;
1592 #else /* !AJ_IRIXLF */
1593 struct dirent* de;
1594 #endif /* AJ_IRIXLF */
1595 ajint dirsize;
1596 AjPList list = NULL;
1597 AjPStr name = NULL;
1598 #ifdef _POSIX_C_SOURCE
1599 char buf[sizeof(struct dirent)+MAXNAMLEN];
1600 #endif /* _POSIX_C_SOURCE */
1601 ajDebug("ajFileNewListinPathWildExclude "
1602 "path '%S' wildname '%S' exclude '%S\n",
1603 path, wildname, exclude);
1604
1605 if(ajStrGetLen(path))
1606 ajStrAssignS(&fileDirfixTmp, path);
1607 else
1608 ajStrAssignC(&fileDirfixTmp, CURRENT_DIR);
1609
1610 if(ajStrGetCharLast(fileDirfixTmp) != SLASH_CHAR)
1611 ajStrAppendC(&fileDirfixTmp, SLASH_STRING);
1612
1613 dp = fileOpenDir(&fileDirfixTmp);
1614 if(!dp)
1615 return NULL;
1616
1617 dirsize = 0;
1618 list = ajListstrNew();
1619
1620 while(
1621 #if defined(AJ_IRIXLF)
1622 #ifdef _POSIX_C_SOURCE
1623 !readdir64_r(dp,(struct dirent64 *)buf,&de)
1624 #else /* !_POSIX_C_SOURCE */
1625 (de=readdir64(dp))
1626 #endif /* _POSIX_C_SOURCE */
1627 #else /* !AJ_IRIXLF */
1628 #ifdef _POSIX_C_SOURCE
1629 !readdir_r(dp,(struct dirent *)buf,&de)
1630 #else /* !_POSIX_C_SOURCE */
1631 (de=readdir(dp))
1632 #endif /* _POSIX_C_SOURCE */
1633 #endif /* AJ_IRIXLF */
1634 )
1635 {
1636 #ifdef _POSIX_C_SOURCE
1637 if(!de)
1638 break;
1639 #endif /* _POSIX_C_SOURCE */
1640 /* skip deleted files with inode zero */
1641 #ifndef __CYGWIN__
1642 if(!de->d_ino)
1643 continue;
1644 #endif /* !__CYGWIN__ */
1645
1646 if(ajCharMatchC(de->d_name, "."))
1647 continue;
1648
1649 if(ajCharMatchC(de->d_name, ".."))
1650 continue;
1651
1652 ajStrAssignC(&fileNameTmp, de->d_name);
1653
1654 if(!ajFilenameTestExclude(fileNameTmp, exclude, wildname))
1655 continue;
1656
1657 dirsize++;
1658 ajDebug("accept '%s'\n", de->d_name);
1659 name = NULL;
1660 ajFmtPrintS(&name, "%S%s", fileDirfixTmp, de->d_name);
1661 ajListstrPushAppend(list, name);
1662 }
1663
1664 closedir(dp);
1665 ajDebug("%d files for '%S' '%S'\n", dirsize, path, wildname);
1666
1667 return ajFileNewListinList(list);
1668 }
1669
1670
1671
1672
1673 /* @func ajFileNewOutNameC ****************************************************
1674 **
1675 ** Creates a new output file object with a specified name.
1676 **
1677 ** 'stdout' and 'stderr' are special names for standard output and
1678 ** standard error respectively.
1679 **
1680 ** @param [r] name [const char*] File name.
1681 ** @return [AjPFile] New file object.
1682 **
1683 ** @release 6.0.0
1684 ** @@
1685 ******************************************************************************/
1686
ajFileNewOutNameC(const char * name)1687 AjPFile ajFileNewOutNameC(const char* name)
1688 {
1689 ajStrAssignC(&fileNameStrTmp, name);
1690
1691 return ajFileNewOutNameS(fileNameStrTmp);
1692 }
1693
1694
1695
1696
1697 /* @func ajFileNewOutNameS ****************************************************
1698 **
1699 ** Creates a new output file object with a specified name.
1700 **
1701 ** 'stdout' and 'stderr' are special names for standard output and
1702 ** standard error respectively.
1703 **
1704 ** @param [r] name [const AjPStr] File name.
1705 ** @return [AjPFile] New file object.
1706 **
1707 ** @release 6.0.0
1708 ** @@
1709 ******************************************************************************/
1710
ajFileNewOutNameS(const AjPStr name)1711 AjPFile ajFileNewOutNameS(const AjPStr name)
1712 {
1713 AjPFile thys;
1714
1715 if(ajStrMatchC(name, "stdout"))
1716 {
1717 thys = ajFileNewFromCfile(stdout);
1718 ajStrAssignC(&thys->Name, "stdout");
1719 ajStrAssignS(&thys->Printname, thys->Name);
1720 return thys;
1721 }
1722
1723 if(ajStrMatchC(name, "stderr"))
1724 {
1725 thys = ajFileNewFromCfile(stderr);
1726 ajStrAssignC(&thys->Name, "stderr");
1727 ajStrAssignS(&thys->Printname, thys->Name);
1728 return thys;
1729 }
1730
1731 AJNEW0(thys);
1732
1733 #ifdef WIN32
1734 if(ajStrMatchC(name, "/dev/null"))
1735 thys->fp = fopen(ajStrGetPtr(name), "wb");
1736 else
1737 #endif /* WIN32 */
1738 thys->fp = fopen(ajStrGetPtr(name), "wb");
1739
1740 if(!thys->fp)
1741 {
1742 ajWarn("Failed to open output file '%S' error:%d '%s'",
1743 name, errno, strerror(errno));
1744 thys->Handle = 0;
1745 return NULL;
1746 }
1747
1748 thys->Handle = ++fileHandle;
1749 ajStrAssignS(&thys->Name, name);
1750 filePrintname(thys->Name, &thys->Printname);
1751 thys->End = ajFalse;
1752
1753 fileOpenCnt++;
1754 fileOpenTot++;
1755
1756 if(fileOpenCnt > fileOpenMax)
1757 fileOpenMax = fileOpenCnt;
1758
1759 thys->App = ajFalse;
1760
1761 return thys;
1762 }
1763
1764
1765
1766
1767 /* @func ajFileNewOutNameDirS *************************************************
1768 **
1769 ** Creates a new output file object with a specified directory and name.
1770 ** Uses the default extension (if any) specified for the directory.
1771 **
1772 ** 'stdout' and 'stderr' are special names for standard output and
1773 ** standard error respectively.
1774 **
1775 ** If the filename already has a directory specified,
1776 ** the "dir" argument is ignored.
1777 **
1778 ** @param [r] name [const AjPStr] File name.
1779 ** @param [rN] dir [const AjPDirout] Directory
1780 ** (optional, can be empty or NULL).
1781 ** @return [AjPFile] New file object.
1782 **
1783 ** @release 6.0.0
1784 ** @@
1785 ******************************************************************************/
1786
ajFileNewOutNameDirS(const AjPStr name,const AjPDirout dir)1787 AjPFile ajFileNewOutNameDirS(const AjPStr name, const AjPDirout dir)
1788 {
1789 AjPFile thys;
1790
1791 ajDebug("ajFileNewOutNameDirS('%S' '%S')\n", dir->Name, name);
1792
1793 AJNEW0(thys);
1794
1795 if(!dir)
1796 {
1797 #ifdef WIN32
1798 if(ajStrMatchC(name, "/dev/null"))
1799 thys->fp = fopen("NUL", "wb");
1800 else
1801 #endif /* WIN32 */
1802 thys->fp = fopen(ajStrGetPtr(name), "wb");
1803 ajDebug("ajFileNewOutNameDirS open name '%S'\n", name);
1804 }
1805 else
1806 {
1807 if(ajFilenameHasPath(name))
1808 ajStrAssignS(&fileDirfixTmp, name);
1809 else
1810 {
1811 ajStrAssignS(&fileDirfixTmp, dir->Name);
1812
1813 if(ajStrGetCharLast(dir->Name) != SLASH_CHAR)
1814 ajStrAppendC(&fileDirfixTmp, SLASH_STRING);
1815
1816 ajStrAppendS(&fileDirfixTmp, name);
1817 }
1818
1819 ajFilenameSetExtS(&fileDirfixTmp, dir->Extension);
1820
1821 thys->fp = fopen(ajStrGetPtr(fileDirfixTmp), "wb");
1822 ajDebug("ajFileNewOutNameDirS open dirfix '%S'\n", fileDirfixTmp);
1823 }
1824
1825 if(!thys->fp)
1826 {
1827 ajWarn("Failed to open output file '%S' in directory '%S' "
1828 "error:%d '%s'",
1829 name, dir, errno, strerror(errno));
1830 thys->Handle = 0;
1831 return NULL;
1832 }
1833
1834 thys->Handle = ++fileHandle;
1835 ajStrAssignS(&thys->Name, name);
1836 filePrintname(thys->Name, &thys->Printname);
1837 thys->End = ajFalse;
1838
1839 fileOpenCnt++;
1840 fileOpenTot++;
1841
1842 if(fileOpenCnt > fileOpenMax)
1843 fileOpenMax = fileOpenCnt;
1844
1845 return thys;
1846 }
1847
1848
1849
1850
1851 /* @func ajFileNewOutNamePathS ************************************************
1852 **
1853 ** Creates a new output file object with a specified directory and name.
1854 **
1855 ** 'stdout' and 'stderr' are special names for standard output and
1856 ** standard error respectively.
1857 **
1858 ** If the filename already has a directory specified,
1859 ** the "dir" argument is ignored.
1860 **
1861 ** @param [r] name [const AjPStr] File name.
1862 ** @param [rN] path [const AjPStr] Directory (optional, can be empty or NULL).
1863 ** @return [AjPFile] New file object.
1864 **
1865 ** @release 6.0.0
1866 ** @@
1867 ******************************************************************************/
1868
ajFileNewOutNamePathS(const AjPStr name,const AjPStr path)1869 AjPFile ajFileNewOutNamePathS(const AjPStr name, const AjPStr path)
1870 {
1871 AjPFile thys;
1872
1873 ajDebug("ajFileNewOutNamePathS('%S' '%S')\n", path, name);
1874
1875 if(ajStrMatchC(name, "stdout"))
1876 return ajFileNewFromCfile(stdout);
1877
1878 if(ajStrMatchC(name, "stderr"))
1879 return ajFileNewFromCfile(stderr);
1880
1881 AJNEW0(thys);
1882
1883 if(!ajStrGetLen(path))
1884 {
1885 #ifdef WIN32
1886 if(ajStrMatchC(name, "/dev/null"))
1887 thys->fp = fopen("NUL", "wb");
1888 else
1889 #endif /* WIN32 */
1890 thys->fp = fopen(ajStrGetPtr(name), "wb");
1891 ajDebug("ajFileNewOutNamePathS open name '%S'\n", name);
1892 }
1893 else
1894 {
1895 if(ajFilenameHasPath(name))
1896 ajStrAssignS(&fileDirfixTmp, name);
1897 else
1898 {
1899 ajStrAssignS(&fileDirfixTmp, path);
1900
1901 if(ajStrGetCharLast(path) != SLASH_CHAR)
1902 ajStrAppendC(&fileDirfixTmp, SLASH_STRING);
1903
1904 ajStrAppendS(&fileDirfixTmp, name);
1905 }
1906
1907 thys->fp = fopen(ajStrGetPtr(fileDirfixTmp), "wb");
1908 ajDebug("ajFileNewOutNamePathS open dirfix '%S'\n", fileDirfixTmp);
1909 }
1910
1911 if(!thys->fp)
1912 {
1913 ajWarn("Failed to open output file '%S' in directory '%S' "
1914 "error:%d '%s'",
1915 name, path, errno, strerror(errno));
1916 thys->Handle = 0;
1917 return NULL;
1918 }
1919
1920 thys->Handle = ++fileHandle;
1921 ajStrAssignS(&thys->Name, name);
1922 filePrintname(thys->Name, &thys->Printname);
1923 thys->End = ajFalse;
1924
1925 fileOpenCnt++;
1926 fileOpenTot++;
1927
1928 if(fileOpenCnt > fileOpenMax)
1929 fileOpenMax = fileOpenCnt;
1930
1931 return thys;
1932 }
1933
1934
1935
1936
1937 /* @func ajFileNewOutappendNameS **********************************************
1938 **
1939 ** Creates an output file object with a specified name.
1940 ** The file is opened for append so it either appends to an existing file
1941 ** or opens a new one.
1942 **
1943 ** @param [r] name [const AjPStr] File name.
1944 ** @return [AjPFile] New file object.
1945 **
1946 ** @release 6.0.0
1947 ** @@
1948 ******************************************************************************/
1949
ajFileNewOutappendNameS(const AjPStr name)1950 AjPFile ajFileNewOutappendNameS(const AjPStr name)
1951 {
1952 AjPFile thys;
1953
1954 AJNEW0(thys);
1955
1956 #ifdef WIN32
1957 if(ajStrMatchC(name, "/dev/null"))
1958 thys->fp = fopen("NUL", "ab");
1959 else
1960 #endif /* WIN32 */
1961 thys->fp = fopen(ajStrGetPtr(name), "ab");
1962
1963 if(!thys->fp)
1964 {
1965 thys->Handle = 0;
1966 return NULL;
1967 }
1968
1969 thys->Handle = ++fileHandle;
1970 ajStrAssignS(&thys->Name, name);
1971 filePrintname(thys->Name, &thys->Printname);
1972 thys->End = ajFalse;
1973
1974 fileOpenCnt++;
1975 fileOpenTot++;
1976
1977 if(fileOpenCnt > fileOpenMax)
1978 fileOpenMax = fileOpenCnt;
1979
1980 thys->App = ajTrue;
1981
1982 return thys;
1983 }
1984
1985
1986
1987
1988 /* @section File destructors **************************************************
1989 **
1990 ** Destruction is achieved by closing the file.
1991 **
1992 ** Unlike ANSI C, there are tests to ensure a file is not closed twice.
1993 **
1994 ** @nam3rule Close Close file and destroy object
1995 **
1996 ** @argrule Close Pfile [AjPFile*] File to be closed and deleted
1997 **
1998 ** @valrule Close [void]
1999 **
2000 ** @fcategory delete
2001 **
2002 ** @fdata [AjPFile]
2003 **
2004 ******************************************************************************/
2005
2006
2007
2008
2009 /* @func ajFileClose **********************************************************
2010 **
2011 ** Close and free a file object.
2012 **
2013 ** @param [d] Pfile [AjPFile*] File.
2014 ** @return [void]
2015 **
2016 ** @release 1.0.0
2017 ** @@
2018 ******************************************************************************/
2019
ajFileClose(AjPFile * Pfile)2020 void ajFileClose(AjPFile* Pfile)
2021 {
2022 AjPFile thys;
2023
2024 thys = Pfile ? *Pfile : 0;
2025
2026 if(!Pfile)
2027 return;
2028
2029 if(!*Pfile)
2030 return;
2031
2032 fileClose(thys);
2033 AJFREE(*Pfile);
2034
2035 return;
2036 }
2037
2038
2039
2040
2041 /* @funcstatic fileClose ******************************************************
2042 **
2043 ** Closes a file object. Used as part of the public destructor and
2044 ** other public functions.
2045 **
2046 ** @param [w] thys [AjPFile] File.
2047 ** @return [void]
2048 **
2049 ** @release 1.0.0
2050 ** @@
2051 ******************************************************************************/
2052
fileClose(AjPFile thys)2053 static void fileClose(AjPFile thys)
2054 {
2055 int sleepcount = 0;
2056 int status = 0;
2057 int maxsleep = 60;
2058 #ifndef WIN32
2059 pid_t retval;
2060 #endif /* !WIN32 */
2061
2062 if(!thys)
2063 return;
2064
2065 #ifndef WIN32
2066
2067 /*
2068 ** Only wait for the PID to close if we have read everything.
2069 ** Otherwise ... we will wait for ever as it will not
2070 ** go away until its output is read or closed
2071 */
2072
2073 if (thys->Pid && thys->End)
2074 {
2075 while((retval=waitpid(thys->Pid,&status,WNOHANG))!= thys->Pid)
2076 {
2077 if(sleepcount > maxsleep)
2078 break;
2079
2080 sleepcount++;
2081 sleep(1);
2082
2083 /*ajDebug("fileClose waitpid returns %d status %d\n",
2084 retval, status);*/
2085
2086 if(retval == -1)
2087 if(errno != EINTR)
2088 break;
2089
2090 status = 0;
2091 }
2092 }
2093 #else /* WIN32 */
2094 if(thys->Process && thys->End)
2095 {
2096 WaitForSingleObject(thys->Process,INFINITE);
2097 CloseHandle(thys->Process);
2098 CloseHandle(thys->Thread);
2099 }
2100
2101 #endif /* !WIN32 */
2102
2103 if(thys->Handle)
2104 {
2105 if(thys->fp)
2106 {
2107 if(thys->fp == stdout)
2108 fileUsedStdout = ajFalse;
2109 else if(thys->fp == stderr)
2110 fileUsedStderr = ajFalse;
2111 else if(thys->fp == stdin)
2112 fileUsedStdin = ajFalse;
2113 else
2114 {
2115 if(fclose(thys->fp))
2116 ajFatal("File close problem in fileClose error:%d '%s'",
2117 errno, strerror(errno));
2118 }
2119 }
2120
2121 thys->Handle = 0;
2122
2123 fileCloseCnt++;
2124 fileOpenCnt--;
2125 }
2126 else
2127 ajDebug("file already closed\n");
2128
2129 ajStrDel(&thys->Name);
2130 ajStrDel(&thys->Printname);
2131 ajStrDel(&thys->Buff);
2132 ajListstrFreeData(&thys->List);
2133 AJFREE(thys->Workbuffer);
2134 AJFREE(thys->Readblock);
2135
2136 return;
2137 }
2138
2139
2140
2141
2142 /* @section File reopen *******************************************************
2143 **
2144 ** These functions close a file and open a new file with the same file object
2145 **
2146 ** @nam3rule Reopen Reopen an existing input file object
2147 ** @nam4rule Name Reopen using a new filename
2148 ** @nam4rule Next Reopen using the next filename in the input file list
2149 **
2150 ** @argrule Reopen file [AjPFile] File object
2151 ** @argrule Name name [const AjPStr] Filename to open
2152 **
2153 ** @valrule * [AjBool] True on success
2154 **
2155 ** @fcategory modify
2156 **
2157 ** @fdata [AjPFile]
2158 **
2159 ******************************************************************************/
2160
2161
2162
2163
2164 /* @func ajFileReopenName *****************************************************
2165 **
2166 ** Reopens an input file with a new name
2167 **
2168 ** @param [u] file [AjPFile] Input file.
2169 ** @param [r] name [const AjPStr] name of file.
2170 ** @return [AjBool] True on success
2171 **
2172 ** @release 6.0.0
2173 ** @@
2174 ******************************************************************************/
2175
ajFileReopenName(AjPFile file,const AjPStr name)2176 AjBool ajFileReopenName(AjPFile file, const AjPStr name)
2177 {
2178 ajStrAssignS(&file->Name, name);
2179 filePrintname(file->Name, &file->Printname);
2180
2181 if(!freopen(MAJSTRGETPTR(file->Name), "rb", file->fp))
2182 return ajFalse;
2183
2184 return ajTrue;
2185 }
2186
2187
2188
2189
2190 /* @func ajFileReopenNext *****************************************************
2191 **
2192 ** Given a file object that includes a list of input files, closes the
2193 ** current input file and opens the next one.
2194 **
2195 ** @param [u] file [AjPFile] File object.
2196 ** @return [AjBool] ajTrue on success.
2197 **
2198 ** @release 6.0.0
2199 ** @@
2200 ******************************************************************************/
2201
ajFileReopenNext(AjPFile file)2202 AjBool ajFileReopenNext(AjPFile file)
2203 {
2204 static AjPStr name = NULL;
2205
2206 if(!file->List)
2207 {
2208 ajDebug("ajFileReopenNext for non-list file %F\n", file);
2209 return ajFalse;
2210 }
2211
2212 ajDebug("ajFileReopenNext for non-list file %F name '%S'\n",
2213 file, file->Name);
2214
2215 /*ajListTrace(file->List);*/
2216 if(!ajListPop(file->List, (void*) &name))
2217 {
2218 /* end of list */
2219 ajDebug("ajFileReopenNext failed - list completed\n");
2220
2221 return ajFalse;
2222 }
2223
2224 ajDebug("ajFileReopenNext filename '%S'\n", name);
2225
2226 if(!ajFileReopenName(file, name))
2227 {
2228 /* popped from the list */
2229 ajStrDel(&name);
2230
2231 return ajFalse;
2232 }
2233
2234 /* popped from the list */
2235 ajStrDel(&name);
2236 file->End = ajFalse;
2237
2238 ajDebug("ajFileNext success\n");
2239
2240 return ajTrue;
2241 }
2242
2243
2244
2245
2246 /* @section File modifiers ****************************************************
2247 **
2248 ** Modifying file object attributes, reset file position.
2249 **
2250 ** @nam3rule Fix Reset all file attribute that may have been changed
2251 ** by non-AJAX calls
2252 ** @nam3rule Reset Reset a file attribute that may have been changed
2253 ** by non-AJAX calls
2254 ** @nam3rule Seek Call system file seek function
2255 ** @nam3rule Set Set a file attribute
2256 ** @nam4rule ResetEof Reset the end of file value using the system
2257 ** 'feof' function
2258 ** @nam4rule ResetPos Reset the file position using the system
2259 ** 'ftell' function
2260 ** @nam4rule SetEof Set the end of file value for a file that has been read
2261 ** without going past the last record.
2262 ** @nam4rule SetUnbuffer Set file unbuffered
2263 **
2264 ** @argrule * file [AjPFile] File object
2265 ** @argrule Seek offset [ajlong] File offset to pass to system seek call
2266 ** @argrule Seek wherefrom [ajint] File wherefrom value to pass to
2267 ** system seek call
2268 **
2269 ** @valrule Seek [ajint] Return value from seek
2270 ** @valrule SetUnbuffer [void]
2271 ** @valrule Fix [AjBool] End of file reached
2272 ** @valrule Eof [AjBool] End of file reached
2273 ** @valrule Pos [ajlong] File position from ftell
2274 **
2275 ** @fcategory modify
2276 **
2277 ** @fdata [AjPFile]
2278 **
2279 ******************************************************************************/
2280
2281
2282
2283
2284 /* @func ajFileFix ************************************************************
2285 **
2286 ** Resets internal file attribute after non-AJAX operations.
2287 **
2288 ** @param [u] file [AjPFile] File.
2289 ** @return [AjBool] True if end of file is reached
2290 **
2291 ** @release 6.0.0
2292 ** @@
2293 ******************************************************************************/
2294
ajFileFix(AjPFile file)2295 AjBool ajFileFix(AjPFile file)
2296 {
2297 ajFileResetPos(file);
2298
2299 return ajFileResetEof(file);
2300 }
2301
2302
2303
2304
2305 /* @func ajFileResetEof *******************************************************
2306 **
2307 ** Resets the end of file attribute after non-AJAX operations.
2308 **
2309 ** @param [u] file [AjPFile] File.
2310 ** @return [AjBool] True if end of file is set
2311 **
2312 ** @release 6.0.0
2313 ** @@
2314 ******************************************************************************/
2315
ajFileResetEof(AjPFile file)2316 AjBool ajFileResetEof(AjPFile file)
2317 {
2318 if(feof(file->fp))
2319 file->End = ajTrue;
2320 else
2321 file->End = ajFalse;
2322
2323 return file->End;
2324 }
2325
2326
2327
2328
2329 /* @func ajFileResetPos *******************************************************
2330 **
2331 ** Resets and returns the current position in an open file.
2332 **
2333 ** @param [u] file [AjPFile] File.
2334 ** @return [ajlong] Result of 'ftell'
2335 **
2336 ** @release 6.0.0
2337 ** @@
2338 ******************************************************************************/
2339
ajFileResetPos(AjPFile file)2340 ajlong ajFileResetPos(AjPFile file)
2341 {
2342 if(!file->fp)
2343 return 0;
2344
2345 file->Filepos = ftell(file->fp);
2346
2347 return file->Filepos;
2348 }
2349
2350
2351
2352
2353 /* @func ajFileSeek ***********************************************************
2354 **
2355 ** Sets the current position in an open file.
2356 **
2357 ** Resets the end-of-file flag End for cases where end-of-file was
2358 ** reached and then we seek back somewhere in the file.
2359 **
2360 ** @param [u] file [AjPFile] File.
2361 ** @param [r] offset [ajlong] Offset
2362 ** @param [r] wherefrom [ajint] Start of offset, as defined for 'fseek'.
2363 ** @return [ajint] Result of 'fseek'
2364 **
2365 ** @release 1.0.0
2366 ** @@
2367 ******************************************************************************/
2368
ajFileSeek(AjPFile file,ajlong offset,ajint wherefrom)2369 ajint ajFileSeek(AjPFile file, ajlong offset, ajint wherefrom)
2370 {
2371 ajint ret;
2372
2373 clearerr(file->fp);
2374 ret = fseek(file->fp, offset, wherefrom);
2375
2376 if(feof(file->fp))
2377 {
2378 file->End = ajTrue;
2379 ajDebug("EOF ajFileSeek file %F\n", file);
2380 }
2381 else
2382 file->End = ajFalse;
2383
2384 return ret;
2385 }
2386
2387
2388
2389
2390 /* @func ajFileSetEof *********************************************************
2391 **
2392 ** Ensures a binary file has reached the end of file and sets the
2393 ** end of file attribute
2394 **
2395 ** @param [u] file [AjPFile] File.
2396 ** @return [AjBool] True if end of file was already
2397 **
2398 ** @release 6.5.0
2399 ** @@
2400 ******************************************************************************/
2401
ajFileSetEof(AjPFile file)2402 AjBool ajFileSetEof(AjPFile file)
2403 {
2404 AjBool ret = file->End;
2405 char c;
2406
2407 fseek(file->fp, 0, SEEK_END);
2408 fread(&c, 1, 1, file->fp);
2409
2410 if(feof(file->fp))
2411 file->End = ajTrue;
2412 else
2413 file->End = ajFalse;
2414
2415 return ret;
2416 }
2417
2418
2419
2420
2421 /* @func ajFileSetUnbuffer ****************************************************
2422 **
2423 ** Turns off system buffering of an output file, for example to allow
2424 ** debug output to appear even in the event of a program abort.
2425 **
2426 ** @param [u] file [AjPFile] File object.
2427 ** @return [void]
2428 **
2429 ** @release 6.0.0
2430 ** @@
2431 ******************************************************************************/
2432
ajFileSetUnbuffer(AjPFile file)2433 void ajFileSetUnbuffer(AjPFile file)
2434 {
2435 setbuf(file->fp, NULL);
2436
2437 return;
2438 }
2439
2440
2441
2442
2443 /* @section File casts ********************************************************
2444 **
2445 ** Returns attributes of a file object
2446 **
2447 ** @nam3rule Get Return attribute of a file object
2448 ** @nam4rule GetFileptr Return C file pointer
2449 ** @nam4rule GetName Return filename
2450 ** @nam4rule GetPrintname Return printable filename
2451 ** @nam3rule Is Return true if attribute is set
2452 ** @nam4rule IsAppend Test file is open for appending output
2453 ** @nam4rule IsEof Test end of file has been reached
2454 ** @nam4rule IsFile Test file is a regular file, not a pipe or terminal
2455 ** @nam4rule IsStderr Test file is writing to standard error
2456 ** @nam4rule IsStdin test file is reading from standard input
2457 ** @nam4rule IsStdout test file is writing to standard output
2458 **
2459 ** @suffix C Return a C character string
2460 ** @suffix S return a string object
2461 **
2462 ** @argrule * file [const AjPFile] File object
2463 **
2464 ** @valrule C [const char*] C character string
2465 ** @valrule S [const AjPStr] String object
2466 ** @valrule Is [AjBool] True on success
2467 ** @valrule GetFileptr [FILE*] C file pointer
2468 **
2469 ** @fdata [AjPFile]
2470 ** @fcategory cast
2471 **
2472 ******************************************************************************/
2473
2474
2475
2476
2477 /* @func ajFileGetFileptr *****************************************************
2478 **
2479 ** Returns the C file pointer for an open file.
2480 **
2481 ** Warning: Using the C file pointer will make internals of the file
2482 ** object invalid. The file position can be reset with ajFileResetPos.
2483 **
2484 ** @param [r] file [const AjPFile] File.
2485 ** @return [FILE*] C file pointer for the file.
2486 **
2487 ** @release 6.0.0
2488 ** @@
2489 ******************************************************************************/
2490
ajFileGetFileptr(const AjPFile file)2491 FILE* ajFileGetFileptr(const AjPFile file)
2492 {
2493 if(!file)
2494 return NULL;
2495
2496 return file->fp;
2497 }
2498
2499
2500
2501
2502 /* @func ajFileGetNameC *******************************************************
2503 **
2504 ** Returns the file name for a file object. The filename returned is a pointer
2505 ** to the real string internally, so the user must take care not to change
2506 ** it and cannot trust the value if the file object is deleted.
2507 **
2508 ** @param [r] file [const AjPFile] File.
2509 ** @return [const char*] Filename as a C character string.
2510 **
2511 ** @release 6.0.0
2512 ** @@
2513 ******************************************************************************/
2514
ajFileGetNameC(const AjPFile file)2515 const char* ajFileGetNameC(const AjPFile file)
2516 {
2517 if(!file)
2518 return "";
2519
2520 return ajStrGetPtr(file->Name);
2521 }
2522
2523
2524
2525
2526 /* @func ajFileGetNameS *******************************************************
2527 **
2528 ** Returns the file name for a file object. The filename returned is a pointer
2529 ** to the real string internally, so the user must take care not to change
2530 ** it and cannot trust the value if the file object is deleted.
2531 **
2532 ** @param [r] file [const AjPFile] File.
2533 ** @return [const AjPStr] Filename as a C character string.
2534 **
2535 ** @release 6.0.0
2536 ** @@
2537 ******************************************************************************/
2538
ajFileGetNameS(const AjPFile file)2539 const AjPStr ajFileGetNameS(const AjPFile file)
2540 {
2541 if(!file)
2542 return NULL;
2543
2544 return file->Name;
2545 }
2546
2547
2548
2549
2550 /* @func ajFileGetPrintnameC **************************************************
2551 **
2552 ** Returns the file name for a file object. The filename returned is a pointer
2553 ** to the real string internally, so the user must take care not to change
2554 ** it and cannot trust the value if the file object is deleted.
2555 **
2556 ** @param [r] file [const AjPFile] File.
2557 ** @return [const char*] Printable filename as a C character string.
2558 **
2559 ** @release 6.4.0
2560 ** @@
2561 ******************************************************************************/
2562
ajFileGetPrintnameC(const AjPFile file)2563 const char* ajFileGetPrintnameC(const AjPFile file)
2564 {
2565 if(!file)
2566 return "";
2567
2568 return ajStrGetPtr(file->Printname);
2569 }
2570
2571
2572
2573
2574 /* @func ajFileGetPrintnameS **************************************************
2575 **
2576 ** Returns the file name for a file object. The filename returned is a pointer
2577 ** to the real string internally, so the user must take care not to change
2578 ** it and cannot trust the value if the file object is deleted.
2579 **
2580 ** @param [r] file [const AjPFile] File.
2581 ** @return [const AjPStr] Printable filename as a C character string.
2582 **
2583 ** @release 6.4.0
2584 ** @@
2585 ******************************************************************************/
2586
ajFileGetPrintnameS(const AjPFile file)2587 const AjPStr ajFileGetPrintnameS(const AjPFile file)
2588 {
2589 if(!file)
2590 return NULL;
2591
2592 return file->Printname;
2593 }
2594
2595
2596
2597
2598 /* @func ajFileIsAppend *******************************************************
2599 **
2600 ** Returns the App element for a file object. The App element is True if the
2601 ** file was opened for appending to, False otherwise.
2602 **
2603 ** @param [r] file [const AjPFile] File.
2604 ** @return [AjBool] App element, True if if file was opened for appending to,
2605 ** False otherwise.
2606 **
2607 ** @release 6.0.0
2608 ** @@
2609 ******************************************************************************/
2610
ajFileIsAppend(const AjPFile file)2611 AjBool ajFileIsAppend(const AjPFile file)
2612 {
2613 if(!file)
2614 return ajFalse;
2615
2616 return file->App;
2617 }
2618
2619
2620
2621
2622 /* @func ajFileIsEof **********************************************************
2623 **
2624 ** Tests whether we have reached end of file already
2625 **
2626 ** @param [r] file [const AjPFile] File
2627 ** @return [AjBool] ajTrue if we already set end-of-file
2628 **
2629 ** @release 6.0.0
2630 ** @@
2631 ******************************************************************************/
2632
ajFileIsEof(const AjPFile file)2633 AjBool ajFileIsEof(const AjPFile file)
2634 {
2635 if(!file)
2636 return ajTrue;
2637
2638 return file->End;
2639 }
2640
2641
2642
2643
2644 /* @func ajFileIsFile *********************************************************
2645 **
2646 ** Tests whether a file object is really a regular file.
2647 **
2648 ** Used to test for character devices, for example standard input from
2649 ** a terminal.
2650 **
2651 ** @param [r] file [const AjPFile] File object.
2652 ** @return [AjBool] ajTrue if the file matches stderr.
2653 **
2654 ** @release 6.3.0
2655 ** @@
2656 ******************************************************************************/
2657
ajFileIsFile(const AjPFile file)2658 AjBool ajFileIsFile(const AjPFile file)
2659 {
2660 #if defined(AJ_IRIXLF)
2661 struct stat64 buf;
2662 #else /* !AJ_IRIXLF */
2663 struct stat buf;
2664 #endif /* AJ_IRIXLF */
2665
2666 if(
2667 #if defined(AJ_IRIXLF)
2668 !fstat64(fileno(file->fp), &buf)
2669 #else /* !AJ_IRIXLF */
2670 !fstat(fileno(file->fp), &buf)
2671 #endif /* AJ_IRIXLF */
2672 )
2673 if((ajuint)buf.st_mode & AJ_FILE_R)
2674 return ajTrue;
2675
2676 return ajFalse;
2677 }
2678
2679
2680
2681
2682 /* @func ajFileIsStderr *******************************************************
2683 **
2684 ** Tests whether a file object is really stderr.
2685 **
2686 ** @param [r] file [const AjPFile] File object.
2687 ** @return [AjBool] ajTrue if the file matches stderr.
2688 **
2689 ** @release 6.0.0
2690 ** @@
2691 ******************************************************************************/
2692
ajFileIsStderr(const AjPFile file)2693 AjBool ajFileIsStderr(const AjPFile file)
2694 {
2695 if(!file)
2696 return ajFalse;
2697
2698 if(file->fp == stderr)
2699 return ajTrue;
2700
2701 return ajFalse;
2702 }
2703
2704
2705
2706
2707 /* @func ajFileIsStdin ********************************************************
2708 **
2709 ** Tests whether a file object is really stdin.
2710 **
2711 ** @param [r] file [const AjPFile] File object.
2712 ** @return [AjBool] ajTrue if the file matches stdin.
2713 **
2714 ** @release 6.0.0
2715 ** @@
2716 ******************************************************************************/
2717
ajFileIsStdin(const AjPFile file)2718 AjBool ajFileIsStdin(const AjPFile file)
2719 {
2720 if(!file)
2721 return ajFalse;
2722
2723 if(file->fp == stdin)
2724 return ajTrue;
2725
2726 return ajFalse;
2727 }
2728
2729
2730
2731
2732 /* @func ajFileIsStdout *******************************************************
2733 **
2734 ** Tests whether a file object is really stdout.
2735 **
2736 ** @param [r] file [const AjPFile] File object.
2737 ** @return [AjBool] ajTrue if the file matches stdout.
2738 **
2739 ** @release 6.0.0
2740 ** @@
2741 ******************************************************************************/
2742
ajFileIsStdout(const AjPFile file)2743 AjBool ajFileIsStdout(const AjPFile file)
2744 {
2745 if(!file)
2746 return ajFalse;
2747
2748 if(file->fp == stdout)
2749 return ajTrue;
2750
2751 return ajFalse;
2752 }
2753
2754
2755
2756
2757
2758 /* @section File debug ********************************************************
2759 **
2760 ** report file object contents for debugging
2761 **
2762 **
2763 ** @nam3rule Trace Print report to debug file (if any)
2764 **
2765 ** @argrule * file [const AjPFile]
2766 **
2767 ** @valrule * [void]
2768 **
2769 ** @fcategory misc
2770 ** @fdata [AjPFile]
2771 **
2772 ******************************************************************************/
2773
2774
2775
2776
2777 /* @func ajFileTrace **********************************************************
2778 **
2779 ** Writes debug messages to trace the contents of a file object.
2780 **
2781 ** @param [r] file [const AjPFile] File.
2782 ** @return [void]
2783 **
2784 ** @release 1.0.0
2785 ** @@
2786 ******************************************************************************/
2787
ajFileTrace(const AjPFile file)2788 void ajFileTrace(const AjPFile file)
2789 {
2790 ajulong i;
2791 ajulong j;
2792 AjIList iter;
2793
2794 ajDebug("File: '%S'\n", file->Name);
2795 ajDebug("Print: '%S'\n", file->Printname);
2796 ajDebug(" Handle: %d\n", file->Handle);
2797 ajDebug(" End: %B\n", file->End);
2798 ajDebug(" Append: %B\n", file->App);
2799 ajDebug(" Filepos: %ld\n", file->Filepos);
2800 #ifndef WIN32
2801 ajDebug(" PID: %d\n", file->Pid);
2802 #endif /* !WIN32 */
2803 ajDebug(" feof: %d\n", feof(file->fp));
2804 ajDebug(" ftell: %ld\n", ftell(file->fp));
2805 i = ajListGetLength(file->List);
2806 ajDebug(" List: %Lu\n", i);
2807
2808 if(i)
2809 {
2810 j = 0;
2811 iter = ajListIterNewread(file->List);
2812
2813 while (!ajListIterDone(iter))
2814 ajDebug(" %3Ld: '%S'\n", ++j, ajListstrIterGet(iter));
2815 }
2816
2817 return;
2818 }
2819
2820
2821
2822
2823 /* @section File exit *********************************************************
2824 **
2825 ** Cleanup memory on program exit
2826 **
2827 ** @fnote general exit functions, no arguments
2828 **
2829 ** @nam3rule Exit Cleanup and report on exit
2830 **
2831 ** @valrule * [void]
2832 **
2833 ** @fcategory misc
2834 **
2835 ** @fdata [AjPFile]
2836 **
2837 ******************************************************************************/
2838
2839
2840
2841
2842 /* @func ajFileExit ***********************************************************
2843 **
2844 ** Prints a summary of file usage with debug calls
2845 **
2846 ** @return [void]
2847 **
2848 ** @release 1.0.0
2849 ** @@
2850 ******************************************************************************/
2851
ajFileExit(void)2852 void ajFileExit(void)
2853 {
2854 ajDebug("File usage : %d opened, %d closed, %d max, %d total\n",
2855 fileOpenCnt, fileCloseCnt, fileOpenMax, fileOpenTot);
2856
2857 ajStrDel(&fileNameFix);
2858 ajStrDel(&fileNameTmp);
2859 ajStrDel(&fileNameStrTmp);
2860 ajStrDel(&fileDirfixTmp);
2861 ajStrDel(&fileCwd);
2862 ajStrDel(&fileTmpStr);
2863 ajStrDel(&fileTempFilename);
2864 ajStrDel(&fileDirectory);
2865
2866 ajRegFree(&fileUserExp);
2867 ajRegFree(&fileWildExp);
2868 ajRegFree(&fileEntryExp);
2869 ajRegFree(&fileFileExp);
2870 ajRegFree(&fileRestExp);
2871 ajRegFree(&fileDirExp);
2872 ajRegFree(&fileFilenameExp);
2873
2874 return;
2875 }
2876
2877
2878
2879
2880 /* @datasection [AjPFilebuff] Buffered file object ****************************
2881 **
2882 ** Function is for manipulating buffered files and returns or takes at least
2883 ** one AjSFileBuff argument.
2884 **
2885 ** @nam2rule Filebuff
2886 **
2887 ******************************************************************************/
2888
2889
2890
2891
2892 /* @section Buffered file constructors ****************************************
2893 **
2894 ** All constructors return a new open file by pointer. It is the responsibility
2895 ** of the user to first destroy any previous file pointer. The target pointer
2896 ** does not need to be initialised to NULL, but it is good programming practice
2897 ** to do so anyway.
2898 **
2899 ** To replace or reuse an existing file, see instead
2900 ** the {File Assignments} and {File Modifiers} functions.
2901 **
2902 ** The range of constructors is provided to allow flexibility in how
2903 ** applications can open files to read various kinds of data.
2904 **
2905 ** @nam3rule New Constructor
2906 ** @nam4rule From Create from an already open file
2907 ** @nam4rule Nofile Create without an input file for use as a text buffer
2908 ** @nam5rule FromFile AjPfile object used to create buffered file object
2909 ** @nam5rule FromCfile C FILE* structure used to create buffered file object
2910 ** @nam4rule Line Create buffer with line of text
2911 ** @nam4rule Listin List of one or more input files
2912 ** @nam5rule ListinList List of files specified
2913 **
2914 ** @suffix Name Existing filename specified
2915 ** @suffix C Filename as C character string
2916 ** @suffix S Filename as string
2917 ** @suffix Path Input directory path specified
2918 ** @suffix Wild Wildcard filename
2919 ** @suffix Exclude Filename exclusion wildcard(s)
2920 **
2921 ** @argrule Cfile file [FILE*] C file pointer
2922 ** @argrule ListinList list [AjPList] List of filenames as strings
2923 ** @argrule C name [const char*] Filename
2924 ** @argrule S name [const AjPStr] Filename
2925 ** @argrule Line line [const AjPStr] First line of new buffer
2926 ** @argrule FromFile file [AjPFile] Input file object
2927 ** @argrule Path path [const AjPStr] Input directory path
2928 ** @argrule Wild wildname [const AjPStr] Wildcard filename
2929 ** @argrule Exclude exclude [const AjPStr] Filename exclusion wildcard(s)
2930 **
2931 ** @valrule * [AjPFilebuff] New buffered file object
2932 **
2933 ** @fcategory new
2934 **
2935 ** @fdata [AjPFilebuff]
2936 **
2937 ******************************************************************************/
2938
2939
2940
2941
2942 /* @func ajFilebuffNewFromCfile ***********************************************
2943 **
2944 ** Creates a new buffered input file from an already open C file.
2945 **
2946 ** @param [u] file [FILE*] Open C file.
2947 ** @return [AjPFilebuff] New buffered file object.
2948 **
2949 ** @release 6.0.0
2950 ** @@
2951 ******************************************************************************/
2952
ajFilebuffNewFromCfile(FILE * file)2953 AjPFilebuff ajFilebuffNewFromCfile(FILE* file)
2954 {
2955 AjPFile tmpcfile;
2956
2957 tmpcfile = ajFileNewFromCfile(file);
2958
2959 if(!tmpcfile)
2960 return NULL;
2961
2962 return ajFilebuffNewFromFile(tmpcfile);
2963 }
2964
2965
2966
2967
2968 /* @func ajFilebuffNewFromFile ************************************************
2969 **
2970 ** Creates a new buffered input file object from an open file.
2971 **
2972 ** @param [u] file [AjPFile] File object to be buffered.
2973 ** @return [AjPFilebuff] New buffered file object.
2974 **
2975 ** @release 6.0.0
2976 ** @@
2977 ******************************************************************************/
2978
ajFilebuffNewFromFile(AjPFile file)2979 AjPFilebuff ajFilebuffNewFromFile(AjPFile file)
2980 {
2981 AjPFilebuff thys;
2982
2983 if(!file)
2984 return NULL;
2985
2986 AJNEW0(thys);
2987 thys->File = file;
2988
2989 thys->Last = thys->Curr = thys->Prev = thys->Lines = NULL;
2990 thys->Freelines = thys->Freelast = NULL;
2991 thys->Pos = thys->Size = 0;
2992
2993 return thys;
2994 }
2995
2996
2997
2998
2999 /* @func ajFilebuffNewLine ****************************************************
3000 **
3001 ** Creates a new buffered input file object with no file but with
3002 ** one line of buffered data provided.
3003 **
3004 ** @param [r] line [const AjPStr] One line of buffered data.
3005 ** @return [AjPFilebuff] New buffered file object.
3006 **
3007 ** @release 6.0.0
3008 ** @@
3009 ******************************************************************************/
3010
ajFilebuffNewLine(const AjPStr line)3011 AjPFilebuff ajFilebuffNewLine(const AjPStr line)
3012 {
3013 AjPFilebuff thys;
3014 AjPFile file;
3015
3016 file = fileNew();
3017 file->End = ajTrue;
3018 ajDebug("EOF ajFilebuffNewLine file <none>\n");
3019
3020 thys = ajFilebuffNewFromFile(file);
3021
3022 thys->Lines = AJNEW0(thys->Last);
3023 ajStrAssignS(&thys->Last->Line,line);
3024
3025 thys->Curr = thys->Lines;
3026 thys->Pos = 0;
3027 thys->Size = 1;
3028
3029 return thys;
3030 }
3031
3032
3033
3034
3035 /* @func ajFilebuffNewListinList **********************************************
3036 **
3037 ** Creates a new buffered file object from a list of filenames.
3038 **
3039 ** @param [u] list [AjPList] List of filenames as strings.
3040 ** @return [AjPFilebuff] New buffered file object.
3041 **
3042 ** @release 6.0.0
3043 ** @@
3044 ******************************************************************************/
3045
ajFilebuffNewListinList(AjPList list)3046 AjPFilebuff ajFilebuffNewListinList(AjPList list)
3047 {
3048 AjPFile file;
3049
3050 file = ajFileNewListinList(list);
3051
3052 if(!file)
3053 return NULL;
3054
3055 return ajFilebuffNewFromFile(file);
3056 }
3057
3058
3059
3060
3061 /* @func ajFilebuffNewNameS ***************************************************
3062 **
3063 ** Creates a new buffered input file object with an opened named file.
3064 **
3065 ** @param [r] name [const AjPStr] File name.
3066 ** @return [AjPFilebuff] New buffered file object.
3067 **
3068 ** @release 6.0.0
3069 ** @@
3070 ******************************************************************************/
3071
ajFilebuffNewNameS(const AjPStr name)3072 AjPFilebuff ajFilebuffNewNameS(const AjPStr name)
3073 {
3074 AjPFile file;
3075
3076 file = ajFileNewInNameS(name);
3077
3078 return ajFilebuffNewFromFile(file);
3079 }
3080
3081
3082
3083
3084 /* @func ajFilebuffNewNamePathC ***********************************************
3085 **
3086 ** Opens directory "dir", finds and opens file "name"
3087 **
3088 ** @param [r] name [const char*] Filename.
3089 ** @param [r] path [const AjPStr] Directory. If empty uses current directory.
3090 ** @return [AjPFilebuff] New buffered file object.
3091 **
3092 ** @release 6.0.0
3093 ** @@
3094 ******************************************************************************/
3095
ajFilebuffNewNamePathC(const char * name,const AjPStr path)3096 AjPFilebuff ajFilebuffNewNamePathC(const char* name, const AjPStr path)
3097 {
3098 if(ajStrGetLen(path))
3099 ajStrAssignS(&fileNameFix, path);
3100 else
3101 ajStrAssignC(&fileNameFix, CURRENT_DIR);
3102
3103 if(ajStrGetCharLast(fileNameFix) != SLASH_CHAR)
3104 ajStrAppendC(&fileNameFix, SLASH_STRING);
3105
3106 ajStrAppendC(&fileNameFix, name);
3107
3108 return ajFilebuffNewNameS(fileNameFix);
3109 }
3110
3111
3112
3113
3114 /* @func ajFilebuffNewNamePathS ***********************************************
3115 **
3116 ** Opens directory "dir", finds and opens file "name"
3117 **
3118 ** @param [r] name [const AjPStr] Filename.
3119 ** @param [r] path [const AjPStr] Directory. If empty uses current directory.
3120 ** @return [AjPFilebuff] New buffered file object.
3121 **
3122 ** @release 6.0.0
3123 ** @@
3124 ******************************************************************************/
3125
ajFilebuffNewNamePathS(const AjPStr name,const AjPStr path)3126 AjPFilebuff ajFilebuffNewNamePathS(const AjPStr name, const AjPStr path)
3127 {
3128 if(ajStrGetLen(path))
3129 ajStrAssignS(&fileNameFix, path);
3130 else
3131 ajStrAssignC(&fileNameFix, CURRENT_DIR);
3132
3133 if(ajStrGetCharLast(fileNameFix) != SLASH_CHAR)
3134 ajStrAppendC(&fileNameFix, SLASH_STRING);
3135
3136 ajStrAppendS(&fileNameFix, name);
3137
3138 return ajFilebuffNewNameS(fileNameFix);
3139 }
3140
3141
3142
3143
3144 /* @func ajFilebuffNewNofile **************************************************
3145 **
3146 ** Creates a new buffered input file object with an undefined file
3147 ** to be used as a text buffer.
3148 **
3149 ** @return [AjPFilebuff] New buffered file object.
3150 **
3151 ** @release 6.0.0
3152 ** @@
3153 ******************************************************************************/
3154
ajFilebuffNewNofile(void)3155 AjPFilebuff ajFilebuffNewNofile(void)
3156 {
3157 AjPFile file;
3158
3159 file = fileNew(); /* dummy file */
3160
3161 return ajFilebuffNewFromFile(file);
3162 }
3163
3164
3165
3166
3167 /* @func ajFilebuffNewPathWild ************************************************
3168 **
3169 ** Opens directory "dir"
3170 ** Looks for file(s) matching "file"
3171 ** Opens them as a list of files using a buffered file object.
3172 **
3173 ** @param [r] path [const AjPStr] Directory
3174 ** @param [r] wildname [const AjPStr] Wildcard filename.
3175 ** @return [AjPFilebuff] New buffered file object.
3176 **
3177 ** @release 6.0.0
3178 ** @@
3179 ******************************************************************************/
3180
ajFilebuffNewPathWild(const AjPStr path,const AjPStr wildname)3181 AjPFilebuff ajFilebuffNewPathWild(const AjPStr path,
3182 const AjPStr wildname)
3183 {
3184 DIR* dp;
3185 #if defined(AJ_IRIXLF)
3186 struct dirent64 *de;
3187 #else /* !AJ_IRIXLF */
3188 struct dirent* de;
3189 #endif /* AJ_IRIXLF */
3190 ajint dirsize;
3191 AjPList list = NULL;
3192 AjPStr name = NULL;
3193 #ifdef _POSIX_C_SOURCE
3194 char buf[sizeof(struct dirent)+MAXNAMLEN];
3195 #endif /* _POSIX_C_SOURCE */
3196
3197 if(ajStrGetLen(path))
3198 ajStrAssignS(&fileDirfixTmp, path);
3199 else
3200 ajStrAssignC(&fileDirfixTmp, CURRENT_DIR);
3201
3202 if(ajStrGetCharLast(fileDirfixTmp) != SLASH_CHAR)
3203 ajStrAppendC(&fileDirfixTmp, SLASH_STRING);
3204
3205 dp = fileOpenDir(&fileDirfixTmp);
3206
3207 if(!dp)
3208 return NULL;
3209
3210 dirsize = 0;
3211 list = ajListstrNew();
3212
3213 while(
3214 #if defined(AJ_IRIXLF)
3215 #ifdef _POSIX_C_SOURCE
3216 !readdir64_r(dp,(struct dirent64 *)buf,&de)
3217 #else /* !_POSIX_C_SOURCE */
3218 (de=readdir64(dp))
3219 #endif /* _POSIX_C_SOURCE */
3220 #else /* !AJ_IRIXLF */
3221 #ifdef _POSIX_C_SOURCE
3222 !readdir_r(dp,(struct dirent *)buf,&de)
3223 #else /* !_POSIX_C_SOURCE */
3224 (de=readdir(dp))
3225 #endif /* _POSIX_C_SOURCE */
3226 #endif /* AJ_IRIXLF */
3227 )
3228 {
3229 #ifdef _POSIX_C_SOURCE
3230 if(!de)
3231 break;
3232 #endif /* _POSIX_C_SOURCE */
3233 /* skip deleted files with inode zero */
3234 #ifndef __CYGWIN__
3235 if(!de->d_ino)
3236 continue;
3237 #endif /* !__CYGWIN__ */
3238 if(ajCharMatchC(de->d_name, "."))
3239 continue;
3240
3241 if(ajCharMatchC(de->d_name, ".."))
3242 continue;
3243
3244 if(!ajCharMatchWildS(de->d_name, wildname))
3245 continue;
3246
3247 dirsize++;
3248 ajDebug("accept '%s'\n", de->d_name);
3249 name = NULL;
3250 ajFmtPrintS(&name, "%S%s", fileDirfixTmp, de->d_name);
3251 ajListstrPushAppend(list, name);
3252 }
3253
3254 closedir(dp);
3255 ajDebug("%d files for '%S' '%S'\n", dirsize, path, wildname);
3256
3257 return ajFilebuffNewListinList(list);
3258 }
3259
3260
3261
3262
3263 /* @func ajFilebuffNewPathWildExclude *****************************************
3264 **
3265 ** Opens directory "dir"
3266 ** Looks for file(s) matching "file"
3267 ** Skip files matching excluded files wildcard
3268 ** Opens them as a list of files using a buffered file object.
3269 **
3270 ** @param [r] path [const AjPStr] Directory
3271 ** @param [r] wildname [const AjPStr] Wildcard filename.
3272 ** @param [r] exclude [const AjPStr] Wildcard excluded filename.
3273 ** @return [AjPFilebuff] New buffered file object.
3274 **
3275 ** @release 6.0.0
3276 ** @@
3277 ******************************************************************************/
3278
ajFilebuffNewPathWildExclude(const AjPStr path,const AjPStr wildname,const AjPStr exclude)3279 AjPFilebuff ajFilebuffNewPathWildExclude(const AjPStr path,
3280 const AjPStr wildname,
3281 const AjPStr exclude)
3282 {
3283 DIR* dp;
3284 #if defined(AJ_IRIXLF)
3285 struct dirent64 *de;
3286 #else /* !AJ_IRIXLF */
3287 struct dirent* de;
3288 #endif /* AJ_IRIXLF */
3289 ajint dirsize;
3290 AjPList list = NULL;
3291 AjPStr name = NULL;
3292 #ifdef _POSIX_C_SOURCE
3293 char buf[sizeof(struct dirent)+MAXNAMLEN];
3294 #endif /* _POSIX_C_SOURCE */
3295
3296 ajDebug("ajFilebuffNewPathWildExclude "
3297 "path '%S' wildname '%S' exclude '%S\n",
3298 path, wildname, exclude);
3299
3300 if(ajStrGetLen(path))
3301 ajStrAssignS(&fileDirfixTmp, path);
3302 else
3303 ajStrAssignC(&fileDirfixTmp, CURRENT_DIR);
3304
3305 if(ajStrGetCharLast(fileDirfixTmp) != SLASH_CHAR)
3306 ajStrAppendC(&fileDirfixTmp, SLASH_STRING);
3307
3308 dp = fileOpenDir(&fileDirfixTmp);
3309
3310 if(!dp)
3311 return NULL;
3312
3313 dirsize = 0;
3314 list = ajListstrNew();
3315
3316 while(
3317 #if defined(AJ_IRIXLF)
3318 #ifdef _POSIX_C_SOURCE
3319 !readdir64_r(dp,(struct dirent64 *)buf,&de)
3320 #else /* !_POSIX_C_SOURCE */
3321 (de=readdir64(dp))
3322 #endif /* _POSIX_C_SOURCE */
3323 #else /* !AJ_IRIXLF */
3324 #ifdef _POSIX_C_SOURCE
3325 !readdir_r(dp,(struct dirent *)buf,&de)
3326 #else /* !_POSIX_C_SOURCE */
3327 (de=readdir(dp))
3328 #endif /* _POSIX_C_SOURCE */
3329 #endif /* AJ_IRIXLF */
3330 )
3331 {
3332 #ifdef _POSIX_C_SOURCE
3333 if(!de)
3334 break;
3335 #endif /* _POSIX_C_SOURCE */
3336 /* skip deleted files with inode zero */
3337 #ifndef __CYGWIN__
3338 if(!de->d_ino)
3339 continue;
3340 #endif /* !__CYGWIN__ */
3341 if(ajCharMatchC(de->d_name, "."))
3342 continue;
3343
3344 if(ajCharMatchC(de->d_name, ".."))
3345 continue;
3346
3347 ajStrAssignC(&fileNameTmp, de->d_name);
3348 ajDebug("testing '%s'\n", de->d_name);
3349
3350 if(!ajFilenameTestExclude(fileNameTmp, exclude, wildname))
3351 continue;
3352
3353 dirsize++;
3354 ajDebug("accept '%s'\n", de->d_name);
3355 name = NULL;
3356 ajFmtPrintS(&name, "%S%s", fileDirfixTmp, de->d_name);
3357 ajListstrPushAppend(list, name);
3358 }
3359
3360 closedir(dp);
3361 ajDebug("%d files for '%S' '%S'\n", dirsize, path, wildname);
3362 ajStrDelStatic(&fileNameTmp);
3363
3364 return ajFilebuffNewListinList(list);
3365 }
3366
3367
3368
3369
3370 /* @funcstatic fileOpenDir ****************************************************
3371 **
3372 ** Runs 'opendir' on the specified directory. If the directory name
3373 ** has no trailing slash (on Unix) then one is added. This is why the
3374 ** directory name must be writable.
3375 **
3376 ** @param [u] dir [AjPStr*] Directory name.
3377 ** @return [DIR*] result of the opendir call.
3378 **
3379 ** @release 1.0.0
3380 ** @@
3381 ******************************************************************************/
3382
fileOpenDir(AjPStr * dir)3383 static DIR* fileOpenDir(AjPStr* dir)
3384 {
3385 AjBool moved = ajFalse;
3386 AjPStr cwdpath = NULL;
3387 AjPStr userstr = NULL;
3388 AjPStr reststr = NULL;
3389 char *hdir = NULL;
3390
3391 if(ajStrGetCharLast(*dir) != SLASH_CHAR)
3392 ajStrAppendC(dir, SLASH_STRING);
3393
3394 /* going up */
3395 while(ajStrPrefixC(*dir, UP_DIR))
3396 {
3397 if(!moved)
3398 cwdpath = ajStrNewS(ajFileValueCwd());
3399
3400 moved = ajTrue;
3401 ajDirnameUp(&cwdpath);
3402 ajStrKeepRange(dir, 3, -1);
3403 ajDebug("Going up '%S' '%S'\n", *dir, fileCwd);
3404 }
3405
3406 if(moved)
3407 ajStrInsertS(dir, 0, cwdpath);
3408
3409 if(moved)
3410 ajStrDel(&cwdpath);
3411
3412 ajStrAssignS(&fileNameTmp, *dir);
3413 if(ajStrGetCharFirst(fileNameTmp) == '~')
3414 {
3415 ajDebug("starts with '~'\n");
3416
3417 if(!fileUserExp)
3418 fileUserExp = ajRegCompC("^~([^/\\\\]*)");
3419
3420 ajRegExec(fileUserExp, fileNameTmp);
3421 ajRegSubI(fileUserExp, 1, &userstr);
3422 ajRegPost(fileUserExp, &reststr);
3423 ajDebug(" user: '%S' rest: '%S'\n", userstr, reststr);
3424
3425 if(ajStrGetLen(userstr))
3426 {
3427 /* username specified */
3428 hdir = ajSysGetHomedirFromName(ajStrGetPtr(userstr));
3429
3430 if(!hdir)
3431 {
3432 ajStrDel(&userstr);
3433 ajStrDelStatic(&fileNameTmp);
3434 ajStrDel(&reststr);
3435
3436 return NULL;
3437 }
3438
3439 ajFmtPrintS(&fileNameTmp, "%s%S", hdir, reststr);
3440 AJFREE(hdir);
3441
3442 ajDebug("use getpwnam: '%S'\n", fileNameTmp);
3443 }
3444 else
3445 {
3446 /* just ~/ */
3447 hdir = ajSysGetHomedir();
3448
3449 if(hdir)
3450 {
3451 ajFmtPrintS(&fileNameTmp, "%s%S", hdir, reststr);
3452 AJFREE(hdir);
3453 }
3454 else
3455 ajFmtPrintS(&fileNameTmp,"%S",reststr);
3456
3457 ajDebug("use HOME: '%S'\n", fileNameTmp);
3458 }
3459 ajStrAssignS(dir, fileNameTmp);
3460 }
3461
3462 ajStrDel(&userstr);
3463 ajStrDel(&reststr);
3464
3465 ajDebug("fileOpenDir opened '%S'\n", *dir);
3466
3467 return opendir(ajStrGetPtr(*dir));
3468 }
3469
3470
3471
3472
3473 /* @section Buffered file destructors *****************************************
3474 **
3475 ** Destruction is achieved by closing the file.
3476 **
3477 ** Unlike ANSI C, there are tests to ensure a file is not closed twice.
3478 **
3479 ** @nam3rule Del Destructor
3480 **
3481 ** @argrule Del Pbuff [AjPFilebuff*] Buffered file to be deleted
3482 **
3483 ** @valrule * [void]
3484 **
3485 ** @fcategory delete
3486 **
3487 ** @fdata [AjPFilebuff]
3488 **
3489 ******************************************************************************/
3490
3491
3492
3493
3494 /* @func ajFilebuffDel ********************************************************
3495 **
3496 ** Destructor for a buffered file object.
3497 **
3498 ** @param [d] Pbuff [AjPFilebuff*] Buffered file object.
3499 ** @return [void]
3500 **
3501 ** @release 6.0.0
3502 ** @@
3503 ******************************************************************************/
3504
ajFilebuffDel(AjPFilebuff * Pbuff)3505 void ajFilebuffDel(AjPFilebuff* Pbuff)
3506 {
3507 AjPFilebuff thys;
3508
3509 if(!Pbuff)
3510 return;
3511
3512 thys = *Pbuff;
3513
3514 if(!thys)
3515 return;
3516
3517 if(thys->File)
3518 ajDebug("ajFilebuffDel '%F' fp: %p size:%u\n",
3519 thys->File, thys->File->fp, thys->Size);
3520
3521 ajFilebuffClear(thys, -1);
3522 filebuffFreeClear(thys);
3523 ajFileClose(&thys->File);
3524 AJFREE(*Pbuff);
3525
3526 return;
3527 }
3528
3529
3530
3531
3532 /* @section Buffered file reopen **********************************************
3533 **
3534 ** These functions close a file and open a new file with the same file object
3535 **
3536 ** @nam3rule Reopen Reopen an existing buffered file object
3537 ** @nam4rule File Reopen using a new file object
3538 **
3539 ** @argrule Reopen Pbuff [AjPFilebuff*] Buffered file object
3540 ** @argrule Reopen file [AjPFile] File object
3541 **
3542 ** @valrule * [AjBool] True on success
3543 **
3544 ** @fcategory modify
3545 **
3546 ** @fdata [AjPFilebuff]
3547 **
3548 ******************************************************************************/
3549
3550
3551
3552
3553 /* @func ajFilebuffReopenFile *************************************************
3554 **
3555 ** Sets buffered input file to use a new open file.
3556 **
3557 ** The AjPFile pointer is a clone, so we should simply overwrite
3558 ** whatever was there before, but we do need to clear the previous buffer
3559 ** contents.
3560 **
3561 ** @param [w] Pbuff [AjPFilebuff*] Buffered file object.
3562 ** @param [u] file [AjPFile] File object to be buffered.
3563 ** @return [AjBool] ajTrue on success
3564 **
3565 ** @release 6.0.0
3566 ** @@
3567 ******************************************************************************/
3568
ajFilebuffReopenFile(AjPFilebuff * Pbuff,AjPFile file)3569 AjBool ajFilebuffReopenFile(AjPFilebuff* Pbuff, AjPFile file)
3570 {
3571 AjPFilebuff thys;
3572
3573 if(!file)
3574 {
3575 ajFatal("used ajFilebuffReopenFile with deleted file buffer");
3576 ajFilebuffDel(Pbuff);
3577 return ajFalse;
3578 }
3579
3580 if(!*Pbuff)
3581 {
3582 *Pbuff = ajFilebuffNewFromFile(file);
3583 thys = *Pbuff;
3584 return ajTrue;
3585 }
3586
3587 thys = *Pbuff;
3588
3589 ajFilebuffClear(thys, -1);
3590
3591 thys->File = file;
3592
3593 return ajTrue;
3594 }
3595
3596
3597
3598
3599 /* @section Buffered file modifiers *******************************************
3600 **
3601 ** These functions use the attributes of a buffered file object and
3602 ** update them.
3603 **
3604 ** @nam3rule Clear Removes processed lines from the buffer
3605 ** @nam3rule Fix Resets the pointer and current record of a file buffer
3606 ** after buffer contents have been edited
3607 ** @nam3rule Reset Reset buffered file attributes and contents.
3608 ** @nam3rule Set Set file attribute
3609 ** @nam4rule Pos Reset file pointer to start of buffer
3610 ** @nam5rule Buffered Set file unbuffered
3611 ** @nam4rule Buffered Set file buffered
3612 ** @nam4rule Unbuffered Set file unbuffered
3613 **
3614 ** @suffix Store Reset test store buffer
3615 **
3616 ** @argrule * buff [AjPFilebuff] Buffered input file object
3617 ** @argrule C line [const char*] Line of text
3618 ** @argrule S line [const AjPStr] Line of text
3619 ** @argrule Clear lines [ajint] Number of lines to retain
3620 ** (-1 to clear whole buffer)
3621 ** @argrule ClearStore lastline [const AjPStr] Last line of input
3622 ** @argrule Store dostore [AjBool] If true, use the text store buffer
3623 ** @argrule Store Pstore [AjPStr*] Original text store buffer
3624 **
3625 ** @valrule * [void]
3626 ** @valrule *Set [AjBool] Previous buffer setting
3627 **
3628 ** @fcategory modify
3629 **
3630 ** @fdata [AjPFilebuff]
3631 **
3632 ******************************************************************************/
3633
3634
3635
3636
3637 /* @func ajFilebuffClear ******************************************************
3638 **
3639 ** Deletes processed lines from a file buffer. The buffer has a record
3640 ** (Pos) of the next unprocessed line in the buffer.
3641 **
3642 ** Unbuffered files need special handling. The buffer can be turned off
3643 ** while it still contains data. If so, we have to carefully run it down.
3644 ** If this runs it to zero, we may want to save the last line read.
3645 **
3646 ** @param [u] buff [AjPFilebuff] File buffer
3647 ** @param [r] lines [ajint] Number of lines to retain. -1 deletes everything.
3648 ** @return [void]
3649 **
3650 ** @release 6.0.0
3651 ** @@
3652 ******************************************************************************/
3653
ajFilebuffClear(AjPFilebuff buff,ajint lines)3654 void ajFilebuffClear(AjPFilebuff buff, ajint lines)
3655 {
3656 ajint i = 0;
3657 AjPFilebufflist list;
3658 AjPFilebufflist next;
3659 ajint first;
3660 ajint ifree = 0;
3661
3662 ajDebug("ajFilebuffClear (%d) Nobuff: %B size: %u\n",
3663 lines, buff->Nobuff, buff->Size);
3664 /*FilebuffTraceFull(buff, buff->Size, 100);*/
3665
3666 if(!buff)
3667 return;
3668
3669 if(!buff->File)
3670 return;
3671
3672 if(lines < 0)
3673 first = buff->Size;
3674 else
3675 first = buff->Pos - lines;
3676
3677 if(first < 0)
3678 first = 0;
3679
3680 /* nobuff, and all read */
3681 if(buff->Nobuff && buff->Pos == buff->Size)
3682 /* delete any old saved line */
3683 first = buff->Pos;
3684
3685 list = buff->Lines;
3686 for(i=0; i < first; i++)
3687 {
3688 /* we save one line at a time */
3689 next = list->Next;
3690 /* so keep a note of the next one for later */
3691 /*ajDebug("Try to reuse %x size: %d use: %d\n",
3692 list->Line, ajStrGetRes(list->Line), ajStrGetUse(list->Line));*/
3693
3694 if(buff->Nobuff)
3695 {
3696 ajStrDel(&list->Line);
3697 AJFREE(list); /* deleted, kill the list item */
3698 }
3699 else
3700 {
3701 if(ajStrDelStatic(&list->Line))
3702 {
3703 /* move free line to the end */
3704
3705 /*ajDebug("can save to free list %x %d bytes\n",
3706 list->Line, ajStrGetRes(list->Line));*/
3707
3708 ifree++;
3709 /* just save the one line */
3710 list->Next = NULL;
3711
3712 if(!buff->Freelines)
3713 {
3714 /* start a new free list */
3715 buff->Freelines = list;
3716 buff->Freelast = list;
3717 /*ajDebug("start list Free %x Freelast %x \n",
3718 buff->Freelines, buff->Freelast);*/
3719 }
3720 else
3721 {
3722 /* append to free list */
3723 buff->Freelast->Next = list;
3724 buff->Freelast = buff->Freelast->Next;
3725 /*ajDebug("append list Free %x Freelast %x \n",
3726 buff->Freelines, buff->Freelast);*/
3727 }
3728 }
3729 else
3730 {
3731 ajDebug("ajStrDelReuse was false\n");
3732 }
3733 }
3734 list = next;
3735 }
3736
3737 buff->Pos = 0;
3738 buff->Size -= i;
3739
3740 /*
3741 // if(!buff->Size)
3742 // {
3743 // ajDebug("size 0: Lines: %x Curr: %x Prev: %x Last: %x Free: "
3744 // "%x Freelast: %x\n",
3745 // buff->Lines, buff->Curr, buff->Prev, buff->Last,
3746 // buff->Freelines, buff->Freelast);
3747 // }
3748 */
3749
3750 buff->Lines = buff->Curr = list;
3751
3752 /*
3753 // ajDebug("ajFilebuffClear '%F' (%d lines)\n"
3754 // " %b size: %d pos: %d removed %d lines add to free: %d\n",
3755 // buff->File, lines, buff->Nobuff, buff->Size, buff->Pos, i, ifree);
3756 */
3757
3758 /* ajFilebuffTrace(buff);*/
3759
3760 if(buff->Nobuff && !buff->Size && lines == 1)
3761 {
3762 /* unbuffered - can only save last line */
3763 if(buff->Lines)
3764 ajFatal("Buffer error clearing unbuffered file "
3765 "in ajFilebuffClear\n");
3766
3767 buff->Lines = AJNEW0(buff->Last);
3768
3769 ajStrAssignS(&buff->Last->Line, buff->File->Buff);
3770 buff->Curr = buff->Last;
3771 buff->Curr->Fpos = buff->Fpos;
3772 buff->Last->Next = NULL;
3773 buff->Pos = 0;
3774 buff->Size = 1;
3775 }
3776
3777 return;
3778 }
3779
3780
3781
3782
3783 /* @func ajFilebuffClearStore *************************************************
3784 **
3785 ** Deletes processed lines from a file buffer. The buffer has a record
3786 ** (Pos) of the next unprocessed line in the buffer.
3787 **
3788 ** Unbuffered files need special handling. The buffer can be turned off
3789 ** while it still contains data. If so, we have to carefully run it down.
3790 ** If this runs it to zero, we may want to save the last line read.
3791 **
3792 ** @param [u] buff [AjPFilebuff] File buffer
3793 ** @param [r] lines [ajint] Number of lines to retain. -1 deletes everything.
3794 ** @param [r] lastline [const AjPStr] Last line of input.
3795 ** Used to count characters to be saved
3796 ** @param [r] dostore [AjBool] append if true
3797 ** @param [w] Pstore [AjPStr*] Caller's record of the processed lines
3798 ** @return [void]
3799 **
3800 ** @release 6.0.0
3801 ** @@
3802 ******************************************************************************/
3803
ajFilebuffClearStore(AjPFilebuff buff,ajint lines,const AjPStr lastline,AjBool dostore,AjPStr * Pstore)3804 void ajFilebuffClearStore(AjPFilebuff buff, ajint lines, const AjPStr lastline,
3805 AjBool dostore, AjPStr *Pstore)
3806 {
3807 ajFilebuffClear(buff, lines);
3808
3809 if(dostore && ajStrGetLen(lastline))
3810 ajStrCutEnd(Pstore, ajStrGetLen(lastline));
3811
3812 return;
3813 }
3814
3815
3816
3817
3818 /* @func ajFilebuffFix ********************************************************
3819 **
3820 ** Resets the pointer and current record of a file buffer so the next
3821 ** read starts at the first buffered line. Fixes buffer size after the
3822 ** buffer has been edited.
3823 **
3824 ** @param [u] buff [AjPFilebuff] File buffer
3825 ** @return [void]
3826 **
3827 ** @release 6.0.0
3828 ** @@
3829 ******************************************************************************/
3830
ajFilebuffFix(AjPFilebuff buff)3831 void ajFilebuffFix(AjPFilebuff buff)
3832 {
3833 AjPFilebufflist list;
3834 ajint i = 1;
3835
3836 ajFilebuffReset(buff);
3837 buff->Pos = 0;
3838 buff->Curr = buff->Lines;
3839
3840 list = buff->Lines;
3841
3842 if(!list)
3843 {
3844 buff->Size = 0;
3845 return;
3846 }
3847
3848 while(list->Next)
3849 {
3850 i++;
3851 list = list->Next;
3852 }
3853
3854 if(i != buff->Size)
3855 ajDebug("ajFilebuffFix size was %d now %d\n", buff->Size, i);
3856
3857 buff->Size=i;
3858 return;
3859 }
3860
3861
3862
3863
3864 /* @func ajFilebuffReset ******************************************************
3865 **
3866 ** Resets the pointer and current record of a file buffer so the next read
3867 ** starts at the first buffered line.
3868 **
3869 ** @param [u] buff [AjPFilebuff] File buffer
3870 ** @return [void]
3871 **
3872 ** @release 6.0.0
3873 ** @@
3874 ******************************************************************************/
3875
ajFilebuffReset(AjPFilebuff buff)3876 void ajFilebuffReset(AjPFilebuff buff)
3877 {
3878 ajDebug("ajFilebuffReset '%F' size: %u\n", buff->File, buff->Size);
3879 buff->Pos = 0;
3880 buff->Curr = buff->Lines;
3881 buff->Prev = NULL;
3882
3883 return;
3884 }
3885
3886
3887
3888
3889 /* @func ajFilebuffResetPos ***************************************************
3890 **
3891 ** Resets the pointer and current record of a file buffer so the next read
3892 ** starts at the first buffered line.
3893 **
3894 ** Also resets the file position to the last known read, to undo the
3895 ** damage done by (for example) ajseqabi functions.
3896 **
3897 ** @param [u] buff [AjPFilebuff] File buffer
3898 ** @return [void]
3899 **
3900 ** @release 6.0.0
3901 ** @@
3902 ******************************************************************************/
3903
ajFilebuffResetPos(AjPFilebuff buff)3904 void ajFilebuffResetPos(AjPFilebuff buff)
3905 {
3906 ajDebug("ajFilebuffResetPos End: %B Fpos: %ld ftell: %ld\n",
3907 buff->File->End, buff->Fpos, ftell(buff->File->fp));
3908 /*ajFilebuffTraceFull(buff, 10, 10);*/
3909
3910 buff->Pos = 0;
3911 buff->Curr = buff->Lines;
3912
3913 if(!buff->File->End && (buff->File->fp != stdin))
3914 ajFileSeek(buff->File, buff->File->Filepos, SEEK_SET);
3915
3916 buff->File->Filepos = buff->Fpos;
3917
3918 /*ajFilebuffTraceFull(buff,10,10);*/
3919
3920 return;
3921 }
3922
3923
3924
3925
3926 /* @func ajFilebuffResetStore *************************************************
3927 **
3928 ** Resets the pointer and current record of a file buffer so the next read
3929 ** starts at the first buffered line.
3930 **
3931 ** @param [u] buff [AjPFilebuff] File buffer
3932 ** @param [r] dostore [AjBool] True if text is stored
3933 ** @param [w] Pstore [AjPStr*] Stored string cleared if store is true
3934 ** @return [void]
3935 **
3936 ** @release 6.0.0
3937 ** @@
3938 ******************************************************************************/
3939
ajFilebuffResetStore(AjPFilebuff buff,AjBool dostore,AjPStr * Pstore)3940 void ajFilebuffResetStore(AjPFilebuff buff, AjBool dostore, AjPStr *Pstore)
3941 {
3942 ajFilebuffReset(buff);
3943
3944 if(dostore)
3945 ajStrAssignClear(Pstore);
3946
3947 return;
3948 }
3949
3950
3951
3952
3953 /* @funcstatic filebuffFreeClear **********************************************
3954 **
3955 ** Deletes freed lines from a file buffer. The free list is used to avoid
3956 ** reallocating space for new records and must be deleted as part of
3957 ** the destructor.
3958 **
3959 ** @param [u] buff [AjPFilebuff] File buffer
3960 ** @return [void]
3961 **
3962 ** @release 6.0.0
3963 ** @@
3964 ******************************************************************************/
3965
filebuffFreeClear(AjPFilebuff buff)3966 static void filebuffFreeClear(AjPFilebuff buff)
3967 {
3968 AjPFilebufflist list;
3969
3970 if(!buff)
3971 return;
3972
3973 /*ajDebug("filebuffFreeClear %x\n", buff->Freelines);*/
3974
3975 while(buff->Freelines)
3976 {
3977 list = buff->Freelines;
3978 buff->Freelines = buff->Freelines->Next;
3979 ajStrDel(&list->Line);
3980 AJFREE(list);
3981 }
3982
3983 return;
3984 }
3985
3986
3987
3988
3989 /* @func ajFilebuffSetBuffered ************************************************
3990 **
3991 ** Sets file to be buffered. If it already has buffered data, we have to
3992 ** first run down the buffer.
3993 **
3994 ** @param [u] buff [AjPFilebuff] Buffered file object.
3995 ** @return [AjBool] ajTrue if the file was unbuffered before
3996 **
3997 ** @release 6.0.0
3998 ** @@
3999 ******************************************************************************/
4000
ajFilebuffSetBuffered(AjPFilebuff buff)4001 AjBool ajFilebuffSetBuffered(AjPFilebuff buff)
4002 {
4003 AjBool ret;
4004
4005 if(!buff)
4006 return ajFalse;
4007
4008 ret = buff->Nobuff;
4009 ajDebug("ajFilebuffSetBuffered %F buffsize: %d\n",
4010 buff->File, buff->Size);
4011 buff->Nobuff = ajFalse;
4012
4013 return ret;
4014 }
4015
4016
4017
4018
4019 /* @func ajFilebuffSetUnbuffered **********************************************
4020 **
4021 ** Sets file to be unbuffered. If it already has buffered data, we have to
4022 ** first run down the buffer.
4023 **
4024 ** @param [u] buff [AjPFilebuff] Buffered file object.
4025 ** @return [AjBool] ajTrue if the file was unbuffered before
4026 **
4027 ** @release 6.0.0
4028 ** @@
4029 ******************************************************************************/
4030
ajFilebuffSetUnbuffered(AjPFilebuff buff)4031 AjBool ajFilebuffSetUnbuffered(AjPFilebuff buff)
4032 {
4033 AjBool ret;
4034
4035 if(!buff)
4036 return ajFalse;
4037
4038 ret = buff->Nobuff;
4039 ajDebug("ajFilebuffSetUnbuffered '%F' fsize: %d\n", buff->File, buff->Size);
4040 buff->Nobuff = ajTrue;
4041
4042 return ret;
4043 }
4044
4045
4046
4047
4048 /* @section Buffered file content modifiers ***********************************
4049 **
4050 ** These functions use the buffer contents of a buffered file object
4051 ** and update them.
4052 **
4053 ** @nam3rule Html Modify HTML tags in the buffer
4054 ** @nam4rule HtmlPre Reduce to a pre-formatted section if found in HTML
4055 ** @nam4rule HtmlNoheader Remove HTML header in the buffer
4056 ** @nam4rule HtmlStrip Remove all HTML tags in the buffer
4057 ** @nam3rule Load Add text to the buffer
4058 ** @nam4rule LoadAll Read all file lines into buffer
4059 ** @nam4rule Readurl Replace buffer with results from a URL
4060 **
4061 ** @suffix C Character string text
4062 ** @suffix S String object text
4063 **
4064 ** @argrule * buff [AjPFilebuff] Buffered file object
4065 ** @argrule C line [const char*] Line of text
4066 ** @argrule S line [const AjPStr] Line of text
4067 ** @argrule Readurl url [const AjPStr] URL to be read
4068 **
4069 ** @valrule * [void]
4070 ** @valrule *Noheader [ajuint] HTTP error code
4071 ** @valrule *HtmlPre [AjBool] True if changed
4072 ** @valrule *Readurl [AjBool] True on success
4073 **
4074 ** @fcategory modify
4075 **
4076 ** @fdata [AjPFilebuff]
4077 **
4078 ******************************************************************************/
4079
4080
4081
4082
4083 /* @func ajFilebuffHtmlNoheader ***********************************************
4084 **
4085 ** Processes data in the file buffer, removing HTML titles and
4086 ** decoding possible chunked input
4087 **
4088 ** @param [u] buff [AjPFilebuff] Buffered file with data loaded
4089 ** in the buffer.
4090 ** @return [ajuint] HTTP error code
4091 **
4092 ** @release 6.2.0
4093 ** @@
4094 ******************************************************************************/
4095
ajFilebuffHtmlNoheader(AjPFilebuff buff)4096 ajuint ajFilebuffHtmlNoheader(AjPFilebuff buff)
4097 {
4098 AjPRegexp httpexp = NULL;
4099 AjPRegexp nullexp = NULL;
4100 AjPRegexp chunkexp = NULL;
4101 AjPRegexp hexexp = NULL;
4102 AjPRegexp redirexp = NULL;
4103
4104 AjBool doChunk = ajFalse;
4105 ajint ichunk;
4106 ajint chunkSize;
4107 ajint iline;
4108 AjPStr saveLine = NULL;
4109 AjPStr hexstr = NULL;
4110 AjPStr codestr = NULL;
4111 AjPStr newurl = NULL;
4112 ajuint httpcode = 0;
4113
4114 AjBool isheader = ajFalse;
4115
4116 /* first take out the HTTP header (HTTP 1.0 onwards) */
4117 if(!buff || !buff->Size)
4118 return 0;
4119
4120 httpexp = ajRegCompC("^HTTP/\\S+\\s+(\\d+)");
4121 nullexp = ajRegCompC("^\r?\n?$");
4122
4123 /*ajFilebuffTraceTitle(buff, "Before ajFilebuffHtmlNoheader");*/
4124
4125
4126 ajDebug("ajFilebuffHtmlNoheader: First line [%d] '%S' \n",
4127 ajStrGetUse(buff->Curr->Line), buff->Curr->Line);
4128
4129 if(ajRegExec(httpexp, buff->Curr->Line))
4130 {
4131 isheader = ajTrue;
4132 ajRegSubI(httpexp, 1, &codestr);
4133 ajStrToUint(codestr, &httpcode);
4134 ajStrDel(&codestr);
4135 fileBuffLineDel(buff);
4136 }
4137
4138 if(isheader)
4139 {
4140 /*
4141 * ajHttpRedirect() function should be called
4142 * before calling this function to follow redirections
4143 * rather than using http redirection support here
4144 */
4145 if(httpcode >= 301 && httpcode <= 302)
4146 {
4147 redirexp = ajRegCompC("^Location: (\\S+)");
4148
4149 while(buff->Pos < buff->Size &&
4150 !ajRegExec(nullexp, buff->Curr->Line))
4151 {
4152 /* to empty line */
4153 if(ajRegExec(redirexp, buff->Curr->Line))
4154 {
4155 ajRegSubI(redirexp, 1, &newurl);
4156
4157 ajRegFree(&httpexp);
4158 ajRegFree(&nullexp);
4159 ajRegFree(&redirexp);
4160
4161 ajFilebuffClear(buff, -1);
4162 ajFileClose(&buff->File);
4163
4164 ajFilebuffLoadReadurl(buff, newurl);
4165
4166 ajStrDel(&newurl);
4167
4168 return ajFilebuffHtmlNoheader(buff);
4169 }
4170
4171 fileBuffLineDel(buff);
4172 }
4173
4174 /* blank line after header */
4175 fileBuffLineDel(buff);
4176 ajRegFree(&redirexp);
4177 }
4178 else
4179 {
4180 /* HTTP header processing */
4181 if(httpcode >= 300)
4182 {
4183 ajWarn("HTTP code %u", httpcode);
4184 ajRegFree(&httpexp);
4185 ajRegFree(&nullexp);
4186 return httpcode;
4187 }
4188
4189 chunkexp = ajRegCompC("^Transfer-Encoding: +chunked");
4190 while(buff->Pos < buff->Size &&
4191 !ajRegExec(nullexp, buff->Curr->Line))
4192 {
4193 if(ajRegExec(chunkexp, buff->Curr->Line))
4194 {
4195 ajDebug("Chunk encoding: %S", buff->Curr->Line);
4196 /* chunked - see later */
4197 doChunk = ajTrue;
4198 }
4199
4200 fileBuffLineDel(buff);
4201 }
4202
4203 /* blank line after header */
4204 fileBuffLineDel(buff);
4205 ajRegFree(&chunkexp);
4206 }
4207 }
4208
4209 if(doChunk)
4210 {
4211 /*ajFilebuffTraceFull(buff, 999999, 0);*/
4212
4213 hexexp = ajRegCompC("^([0-9a-fA-F]+) *\r?\n?$");
4214 if(!ajRegExec(hexexp, buff->Curr->Line))
4215 {
4216 ajFatal("Bad chunk data from HTTP, expect chunk size got '%S'",
4217 buff->Curr->Line);
4218 }
4219
4220 ajRegSubI(hexexp, 1, &hexstr);
4221 ajStrToHex(hexstr, &chunkSize);
4222
4223 ajDebug("chunkSize hex:%x %d\n", chunkSize, chunkSize);
4224 fileBuffLineDel(buff); /* chunk size */
4225
4226 ichunk = 0;
4227 iline = 0;
4228
4229 while(chunkSize && buff->Curr)
4230 {
4231 iline++;
4232 /* get the chunk size - zero is the end */
4233 /* process the chunk */
4234 ichunk += ajStrGetLen(buff->Curr->Line);
4235
4236 /*ajDebug("++input line [%d] ichunk=%d:%d %d:%S",
4237 iline, ichunk, chunkSize,
4238 ajStrGetLen(buff->Curr->Line), buff->Curr->Line);*/
4239
4240 if(ichunk >= chunkSize) /* end of chunk */
4241 {
4242 if(ichunk == chunkSize)
4243 {
4244 /* end-of-chunk at end-of-line */
4245 fileBuffLineNext(buff);
4246 ajStrAssignClear(&saveLine);
4247 /*ajDebug("end-of-chunk at end-of-line: '%S'\n",
4248 saveLine);*/
4249 }
4250 else
4251 {
4252 /* end-of-chunk in mid-line, patch up the input */
4253 ajDebug("end-of-chunk in mid-line, %d:%d have input size:"
4254 " %d\n",
4255 ichunk, chunkSize,
4256 ajStrGetLen(buff->Curr->Line));
4257 ajStrAssignSubS(&saveLine, buff->Curr->Line, 0,
4258 -(ichunk-chunkSize+1));
4259 ajStrKeepRange(&buff->Curr->Line, -(ichunk-chunkSize), -1);
4260 }
4261
4262 /* skip a blank line */
4263
4264 if(!ajRegExec(nullexp, buff->Curr->Line))
4265 {
4266 ajFilebuffTraceTitle(buff, "Blank line not found");
4267 ajFatal("Bad chunk data from HTTP, expect blank line"
4268 " got '%S'", buff->Curr->Line);
4269 }
4270
4271 fileBuffLineDel(buff);
4272
4273 /** read the next chunk size */
4274
4275 if(!ajRegExec(hexexp, buff->Curr->Line))
4276 {
4277 ajFilebuffTraceTitle(buff, "Chunk size not found");
4278 ajFatal("Bad chunk data from HTTP, expect chunk size "
4279 "got '%S'",
4280 buff->Curr->Line);
4281 }
4282
4283 ajRegSubI(hexexp, 1, &hexstr);
4284 ajStrToHex(hexstr, &chunkSize);
4285 ichunk = 0;
4286 fileBuffLineDel(buff);
4287 }
4288
4289 if(saveLine)
4290 {
4291 if(ajStrGetLen(saveLine))
4292 {
4293 ichunk = ajStrGetLen(buff->Curr->Line);
4294 ajDebug("curr-line/chunk: '%S'\n", buff->Curr->Line);
4295 /* preserve the line split by chunk size */
4296 ajStrInsertS(&buff->Curr->Line, 0, saveLine);
4297
4298 if(ichunk < chunkSize)
4299 {
4300 /* process the next line */
4301 fileBuffLineNext(buff); /* after restored line */
4302 }
4303 else
4304 {
4305 /* we already have the whole chunk! */
4306 ichunk -= ajStrGetLen(buff->Curr->Line);
4307 }
4308 }
4309 else
4310 {
4311 /* just a chunk size, skip */
4312 if(buff->Curr && chunkSize)
4313 {
4314 /*fileBuffLineDel(buff);*/
4315 }
4316 else if (chunkSize)/* final non-zero chunk size */
4317 {
4318 fileBuffLineDel(buff);
4319 }
4320 }
4321
4322 ajStrDel(&saveLine);
4323 }
4324 else
4325 {
4326 /* next line */
4327 fileBuffLineNext(buff);
4328 }
4329 }
4330
4331 ajFilebuffFix(buff);
4332 /*ajFilebuffTraceFull(buff, 999999, 0);*/
4333 ajStrDel(&hexstr);
4334 /*ajFilebuffTraceTitle(buff, "Chunks resolved");*/
4335 }
4336
4337 ajFilebuffReset(buff);
4338
4339 ajRegFree(&httpexp);
4340 ajRegFree(&nullexp);
4341 ajRegFree(&hexexp);
4342
4343 return 0;
4344 }
4345
4346
4347
4348
4349 /* @func ajFilebuffHtmlPre ****************************************************
4350 **
4351 ** If we only have one pre-formatted section in HTML, that is all we keep.
4352 **
4353 ** @param [u] buff [AjPFilebuff] buffer
4354 ** @return [AjBool] ajTrue=cleaned ajFalse=unchanged
4355 **
4356 ** @release 6.0.0
4357 ** @@
4358 ******************************************************************************/
4359
ajFilebuffHtmlPre(AjPFilebuff buff)4360 AjBool ajFilebuffHtmlPre(AjPFilebuff buff)
4361 {
4362 AjPFilebufflist lptr = NULL;
4363 AjPFilebufflist tptr = NULL;
4364 AjPRegexp preexp = NULL;
4365 AjPRegexp endexp = NULL;
4366 ajint ifound = 0;
4367
4368 lptr = buff->Curr;
4369
4370 preexp = ajRegCompC("<[Pp][Rr][Ee]>");
4371
4372 lptr=buff->Curr;
4373
4374 ajDebug("ajFilebuffHtmlPre testing for <pre> line(s)\n");
4375
4376 while(lptr)
4377 {
4378 if(ajRegExec(preexp, lptr->Line))
4379 ifound++;
4380
4381 lptr = lptr->Next;
4382 }
4383
4384 if(!ifound)
4385 {
4386 ajRegFree(&preexp);
4387
4388 return ajFalse;
4389 }
4390
4391 if (ifound > 1)
4392 {
4393 ajRegFree(&preexp);
4394
4395 return ajFalse;
4396 }
4397
4398 lptr=buff->Curr;
4399
4400
4401 while(lptr && !ajRegExec(preexp, lptr->Line))
4402 {
4403 tptr = lptr;
4404 lptr = lptr->Next;
4405 ajStrDel(&tptr->Line);
4406 AJFREE(tptr);
4407 buff->Size--;
4408 }
4409
4410 buff->Lines = buff->Curr = lptr;
4411 ajRegPost(preexp, &lptr->Line);
4412 ajRegFree(&preexp);
4413
4414 endexp = ajRegCompC("</[Pp][Rr][Ee]>");
4415
4416 while(lptr && !ajRegExec(endexp,lptr->Line))
4417 {
4418 lptr = lptr->Next;
4419 }
4420
4421 ajRegPre(endexp, &lptr->Line);
4422 buff->Last = lptr;
4423 lptr = lptr->Next;
4424 ajRegFree(&endexp);
4425
4426 while(lptr)
4427 {
4428 tptr = lptr;
4429 lptr = lptr->Next;
4430 ajStrDel(&tptr->Line);
4431 AJFREE(tptr);
4432 buff->Size--;
4433 }
4434
4435 buff->Last->Next = NULL;
4436 ajFilebuffReset(buff);
4437 ajFilebuffTraceTitle(buff, "ajFilebuffHtmlPre completed");
4438
4439 return ajTrue;
4440 }
4441
4442
4443
4444
4445 /* @func ajFilebuffHtmlStrip **************************************************
4446 **
4447 ** Processes data in the file buffer, removing HTML tokens between
4448 ** angle brackets, plus any TITLE. This seems to be enough to make HTML
4449 ** output readable.
4450 **
4451 ** @param [u] buff [AjPFilebuff] Buffered file with data loaded
4452 ** in the buffer.
4453 ** @return [void]
4454 **
4455 ** @release 6.0.0
4456 ** @@
4457 ******************************************************************************/
4458
ajFilebuffHtmlStrip(AjPFilebuff buff)4459 void ajFilebuffHtmlStrip(AjPFilebuff buff)
4460 {
4461 AjPRegexp tagexp = NULL;
4462 AjPRegexp fullexp = NULL;
4463 AjPRegexp httpexp = NULL;
4464 AjPRegexp nullexp = NULL;
4465 AjPRegexp chunkexp = NULL;
4466 AjPRegexp hexexp = NULL;
4467 AjPRegexp ncbiexp = NULL;
4468 AjPRegexp ncbiexp2 = NULL;
4469 AjPRegexp srsdbexp = NULL;
4470
4471 AjPStr s1 = NULL;
4472 AjPStr s2 = NULL;
4473 AjPStr s3 = NULL;
4474 ajint i;
4475 AjBool doChunk = ajFalse;
4476 ajint ichunk;
4477 ajint chunkSize;
4478 ajint iline;
4479 AjPStr saveLine = NULL;
4480 AjPStr hexstr = NULL;
4481
4482 /* first take out the HTTP header (HTTP 1.0 onwards) */
4483 if(!buff->Size)
4484 return;
4485
4486 tagexp = ajRegCompC("^(.*)(<[!/A-Za-z][^>]*>)(.*)$");
4487 fullexp = ajRegCompC("^(.*)(<([A-Za-z]+)[^>]*>.*</\\3>)(.*)$");
4488 httpexp = ajRegCompC("^HTTP/");
4489 nullexp = ajRegCompC("^\r?\n?$");
4490 chunkexp = ajRegCompC("^Transfer-Encoding: +chunked");
4491 hexexp = ajRegCompC("^([0-9a-fA-F]+) *\r?\n?$");
4492 ncbiexp = ajRegCompC("^Entrez Reports\r?\n$");
4493 ncbiexp2 = ajRegCompC("^----------------\r?\n$");
4494 srsdbexp = ajRegCompC("^([A-Za-z0-9_-]+)(:)([A-Za-z0-9_-]+)");
4495
4496 /* ajFilebuffTraceTitle(buff, "Before ajFilebuffHtmlStrip");*/
4497
4498 i = 0;
4499
4500 /* ajDebug("First line [%d] '%S' \n",
4501 ajStrGetUse(buff->Curr->Line), buff->Curr->Line);*/
4502
4503 if(ajRegExec(httpexp, buff->Curr->Line))
4504 {
4505 /* ^HTTP header processing */
4506 while(buff->Pos < buff->Size &&
4507 !ajRegExec(nullexp, buff->Curr->Line))
4508 {
4509 /* to empty line */
4510 if(ajRegExec(chunkexp, buff->Curr->Line))
4511 {
4512 /*ajDebug("Chunk encoding: %S", buff->Curr->Line);*/
4513 /* chunked - see later */
4514 doChunk = ajTrue;
4515 }
4516 fileBuffLineDel(buff);
4517 }
4518
4519 /* blank line after header */
4520 fileBuffLineDel(buff);
4521 }
4522
4523 if(doChunk)
4524 {
4525 /*ajFilebuffTraceFull(buff, 999999, 0);*/
4526
4527 if(!ajRegExec(hexexp, buff->Curr->Line))
4528 {
4529 ajFatal("Bad chunk data from HTTP, expect chunk size got '%S'",
4530 buff->Curr->Line);
4531 }
4532
4533 ajRegSubI(hexexp, 1, &hexstr);
4534 ajStrToHex(hexstr, &chunkSize);
4535
4536 /*ajDebug("chunkSize hex:%x %d\n", chunkSize, chunkSize);*/
4537 fileBuffLineDel(buff); /* chunk size */
4538
4539 ichunk = 0;
4540 iline = 0;
4541
4542 while(chunkSize && buff->Curr)
4543 {
4544 iline++;
4545 /* get the chunk size - zero is the end */
4546 /* process the chunk */
4547 ichunk += ajStrGetLen(buff->Curr->Line);
4548
4549 /*ajDebug("++input line [%d] ichunk=%d:%d %d:%S",
4550 iline, ichunk, chunkSize,
4551 ajStrGetLen(buff->Curr->Line), buff->Curr->Line);*/
4552
4553 if(ichunk >= chunkSize) /* end of chunk */
4554 {
4555 if(ichunk == chunkSize)
4556 {
4557 /* end-of-chunk at end-of-line */
4558 fileBuffLineNext(buff);
4559 ajStrAssignClear(&saveLine);
4560 /*ajDebug("end-of-chunk at end-of-line: '%S'\n",
4561 saveLine); */
4562 }
4563 else
4564 {
4565 /* end-of-chunk in mid-line, patch up the input */
4566 /*ajDebug("end-of-chunk in mid-line, %d:%d have input: "
4567 "%d '%S'\n",
4568 ichunk, chunkSize,
4569 ajStrGetLen(buff->Curr->Line),
4570 buff->Curr->Line);*/
4571 ajStrAssignSubS(&saveLine, buff->Curr->Line, 0,
4572 -(ichunk-chunkSize+1));
4573 ajStrKeepRange(&buff->Curr->Line, -(ichunk-chunkSize), -1);
4574 }
4575
4576 /* skip a blank line */
4577
4578 if(!ajRegExec(nullexp, buff->Curr->Line))
4579 {
4580 ajFilebuffTraceTitle(buff, "Blank line not found");
4581 ajFatal("Bad chunk data from HTTP, expect blank line"
4582 " got '%S'", buff->Curr->Line);
4583 }
4584
4585 fileBuffLineDel(buff);
4586
4587 /** read the next chunk size */
4588
4589 if(!ajRegExec(hexexp, buff->Curr->Line))
4590 {
4591 ajFilebuffTraceTitle(buff, "Chunk size not found");
4592 ajFatal("Bad chunk data from HTTP, expect chunk size "
4593 "got '%S'",
4594 buff->Curr->Line);
4595 }
4596
4597 ajRegSubI(hexexp, 1, &hexstr);
4598 ajStrToHex(hexstr, &chunkSize);
4599 ichunk = 0;
4600 fileBuffLineDel(buff);
4601 }
4602
4603 if(saveLine)
4604 {
4605 if(ajStrGetLen(saveLine))
4606 {
4607 ichunk = ajStrGetLen(buff->Curr->Line);
4608 /* preserve the line split by chunk size */
4609 ajStrInsertS(&buff->Curr->Line, 0, saveLine);
4610
4611 if(ichunk < chunkSize)
4612 {
4613 /* process the next line */
4614 fileBuffLineNext(buff); /* after restored line */
4615 }
4616 else
4617 {
4618 /* we already have the whole chunk! */
4619 ichunk -= ajStrGetLen(buff->Curr->Line);
4620 }
4621 }
4622 else
4623 {
4624 /* just a chunk size, skip */
4625 if(buff->Curr && chunkSize)
4626 {
4627 /*fileBuffLineDel(buff);*/
4628 }
4629 else if (chunkSize)/* final non-zero chunk size */
4630 {
4631 fileBuffLineDel(buff);
4632 }
4633 }
4634
4635 ajStrDel(&saveLine);
4636 }
4637 else
4638 {
4639 /* next line */
4640 fileBuffLineNext(buff);
4641 }
4642 }
4643
4644 ajFilebuffFix(buff);
4645 /*ajFilebuffTraceFull(buff, 999999, 0);*/
4646 ajStrDel(&hexstr);
4647 /*ajFilebuffTraceTitle(buff, "Chunks resolved");*/
4648 }
4649
4650 ajFilebuffReset(buff);
4651
4652 /*
4653 ** Now we have a clean single file to process
4654 */
4655
4656 /*ajFilebuffTraceTitle(buff, "About to preprocess");*/
4657 ajFilebuffHtmlPre(buff);
4658
4659 while(buff->Curr)
4660 {
4661 if(ajRegExec(ncbiexp, buff->Curr->Line))
4662 ajStrAssignC(&buff->Curr->Line, "\n");
4663
4664 if(ajRegExec(ncbiexp2, buff->Curr->Line))
4665 ajStrAssignC(&buff->Curr->Line, "\n");
4666
4667 while(ajRegExec(fullexp, buff->Curr->Line))
4668 {
4669 ajRegSubI(fullexp, 1, &s1);
4670 ajRegSubI(fullexp, 2, &s2);
4671 ajRegSubI(fullexp, 4, &s3);
4672 ajFmtPrintS(&buff->Curr->Line, "%S%S", s1, s3);
4673 }
4674
4675 while(ajRegExec(tagexp, buff->Curr->Line))
4676 {
4677 ajRegSubI(tagexp, 1, &s1);
4678 ajRegSubI(tagexp, 2, &s2);
4679 ajRegSubI(tagexp, 3, &s3);
4680 ajFmtPrintS(&buff->Curr->Line, "%S%S", s1, s3);
4681 }
4682
4683 if(ajRegExec(srsdbexp, buff->Curr->Line))
4684 {
4685 ajRegSubI(srsdbexp,1,&s1);
4686 ajRegSubI(srsdbexp,2,&s2);
4687 ajRegSubI(srsdbexp,3,&s3);
4688 fileBuffLineDel(buff);
4689 ++i;
4690 continue;
4691 }
4692
4693 if(ajRegExec(nullexp, buff->Curr->Line))
4694 {
4695 /* allow for newline */
4696 fileBuffLineDel(buff);
4697 }
4698 else
4699 fileBuffLineNext(buff);
4700
4701 i++;
4702 }
4703
4704 ajFilebuffReset(buff);
4705
4706 ajStrDel(&s1);
4707 ajStrDel(&s2);
4708 ajStrDel(&s3);
4709
4710 /* free the regular expressions - we expect to use them once only */
4711
4712 ajRegFree(&tagexp);
4713 ajRegFree(&fullexp);
4714 ajRegFree(&httpexp);
4715 ajRegFree(&nullexp);
4716 ajRegFree(&chunkexp);
4717 ajRegFree(&hexexp);
4718 ajRegFree(&ncbiexp);
4719 ajRegFree(&ncbiexp2);
4720 ajRegFree(&srsdbexp);
4721
4722 /*ajFilebuffTraceTitle(buff, "After ajFilebuffHtmlStrip");*/
4723
4724 return;
4725 }
4726
4727
4728
4729
4730 /* @func ajFilebuffLoadC ******************************************************
4731 **
4732 ** Adds a line to the buffer.
4733 **
4734 ** Intended for cases where the file data must be pre-processed before
4735 ** being seen by the sequence reading routines. The first case was
4736 ** for stripping HTML tags after reading via HTTP.
4737 **
4738 ** @param [u] buff [AjPFilebuff] Buffered file.
4739 ** @param [r] line [const char*] Line of input.
4740 ** @return [void]
4741 **
4742 ** @release 6.0.0
4743 ** @@
4744 ******************************************************************************/
4745
ajFilebuffLoadC(AjPFilebuff buff,const char * line)4746 void ajFilebuffLoadC(AjPFilebuff buff, const char* line)
4747 {
4748 if(!buff->Lines)
4749 buff->Curr = buff->Lines = AJNEW0(buff->Last);
4750 else
4751 buff->Last = AJNEW0(buff->Last->Next);
4752
4753 ajStrAssignC(&buff->Last->Line,line);
4754 buff->Last->Next = NULL;
4755 buff->Size++;
4756
4757 return;
4758 }
4759
4760
4761
4762
4763 /* @func ajFilebuffLoadS ******************************************************
4764 **
4765 ** Adds a copy of a line to the buffer.
4766 **
4767 ** Intended for cases where the file data must be pre processed before
4768 ** being seen by the sequence reading routines. The first case was
4769 ** for stripping HTML tags after reading via HTTP.
4770 **
4771 ** @param [u] buff [AjPFilebuff] Buffered file.
4772 ** @param [r] line [const AjPStr] Line of input.
4773 ** @return [void]
4774 **
4775 ** @release 6.0.0
4776 ** @@
4777 ******************************************************************************/
4778
ajFilebuffLoadS(AjPFilebuff buff,const AjPStr line)4779 void ajFilebuffLoadS(AjPFilebuff buff, const AjPStr line)
4780 {
4781 if(!buff->Lines)
4782 buff->Curr = buff->Lines = AJNEW0(buff->Last);
4783 else
4784 buff->Last = AJNEW0(buff->Last->Next);
4785
4786 ajStrAssignS(&buff->Last->Line,line);
4787 buff->Last->Next = NULL;
4788 buff->Size++;
4789
4790 return;
4791 }
4792
4793
4794
4795
4796 /* @func ajFilebuffLoadAll ****************************************************
4797 **
4798 ** Reads all input lines from a file into the buffer.
4799 **
4800 ** Intended for cases where the file data must be pre-processed before
4801 ** being seen by the sequence reading routines. The first case was
4802 ** for stripping HTML tags after reading via HTTP.
4803 **
4804 ** @param [u] buff [AjPFilebuff] Buffered file.
4805 ** @return [void]
4806 **
4807 ** @release 6.0.0
4808 ** @@
4809 ******************************************************************************/
4810
ajFilebuffLoadAll(AjPFilebuff buff)4811 void ajFilebuffLoadAll(AjPFilebuff buff)
4812 {
4813 AjPStr rdline = NULL;
4814 AjBool status = ajTrue;
4815
4816 while(status)
4817 {
4818 status = ajBuffreadLine(buff, &rdline);
4819 /*ajDebug("read: <%S>\n", rdline);*/
4820 }
4821
4822 ajFilebuffReset(buff);
4823 ajStrDel(&rdline);
4824
4825 /*ajFilebuffTrace(buff);*/
4826
4827 return;
4828 }
4829
4830
4831
4832
4833 /* @func ajFilebuffLoadReadurl ************************************************
4834 **
4835 ** Reads from a URL and loads all input lines into the buffer.
4836 **
4837 ** @param [u] buff [AjPFilebuff] Buffered file.
4838 ** @param [r] url [const AjPStr] URL
4839 ** @return [AjBool] True on success
4840 **
4841 ** @release 6.4.0
4842 ** @@
4843 ******************************************************************************/
4844
ajFilebuffLoadReadurl(AjPFilebuff buff,const AjPStr url)4845 AjBool ajFilebuffLoadReadurl(AjPFilebuff buff, const AjPStr url)
4846 {
4847 AjPStr host = NULL;
4848 AjPStr urlget = NULL;
4849 AjPStr get = NULL;
4850 AjPStr proxyName = NULL; /* host for proxy access.*/
4851 AjPStr proxyAuth = NULL;
4852 AjPStr proxyCred = NULL;
4853 AjPStr httpver = NULL; /* HTTP version 1.0, 1.1, ... */
4854 ajint iport = 80;
4855 ajint proxyPort;
4856 FILE *fp;
4857 AjOSysTimeout timo;
4858 AjOSysSocket sock;
4859
4860 AjPStr dbproxy = ajStrNew();
4861
4862 ajHttpUrlDeconstruct(url, &iport, &host, &urlget);
4863
4864 ajHttpGetVersion(NULL, &httpver);
4865
4866 if(ajHttpGetProxyinfo(dbproxy, &proxyPort, &proxyName,
4867 &proxyAuth, &proxyCred))
4868 ajFmtPrintS(&get, "GET http://%S:%d%S HTTP/%S\n",
4869 host, iport, urlget, httpver);
4870 else
4871 ajFmtPrintS(&get, "GET %S HTTP/%S\n", urlget, httpver);
4872
4873 if(ajStrGetLen(proxyName))
4874 fp = ajHttpOpenProxy(dbproxy, proxyName, proxyPort,
4875 proxyAuth, proxyCred,
4876 host, iport,
4877 get, &sock);
4878 else
4879 fp = ajHttpOpen(NULL, host, iport, get, &sock);
4880
4881 buff->File = ajFileNewFromCfile(fp);
4882
4883 if(!buff)
4884 {
4885 ajDebug("socket buffer attach failed\n");
4886 ajErr("socket buffer attach failed for '%S'", url);
4887
4888 return ajFalse;
4889 }
4890
4891 ajDebug("Ready to read errno %d msg '%s'\n",
4892 errno, ajMessGetSysmessageC());
4893
4894 timo.seconds = 180;
4895 ajSysTimeoutSet(&timo);
4896
4897 ajFilebuffLoadAll(buff);
4898
4899 ajSysTimeoutUnset(&timo);
4900
4901 return ajTrue;
4902 }
4903
4904
4905
4906
4907 /* @section Buffered file operators *******************************************
4908 **
4909 ** These functions use the contents of a file object but do not make
4910 ** any changes.
4911 **
4912 ** @nam3rule Get Return an attribute value
4913 ** @nam4rule GetFile Return the file object
4914 ** @nam4rule GetFileptr Return the C file pointer
4915 ** @nam4rule GetFirst Return the first line in the buffer
4916 ** @nam3rule Is Tests a condition
4917 ** @nam4rule IsBuffered Tests whether file input is buffered
4918 ** @nam4rule IsEmpty Tests whether buffer is exhausted for all input files
4919 ** @nam4rule IsEnded Tests whether buffer is at end of current file and empty
4920 ** @nam4rule IsEof Tests whether buffer is at end of file
4921 **
4922 ** @argrule * buff [const AjPFilebuff] Buffered file object
4923 **
4924 ** @valrule GetFileptr [FILE*] C file pointer
4925 ** @valrule GetFile [AjPFile] File object
4926 ** @valrule GetFirst [const AjPStr] First line of buffer
4927 ** @valrule IsBuffered [AjBool] True if file is buffered
4928 ** @valrule IsEmpty [AjBool] True if buffer is empty
4929 ** @valrule IsEnded [AjBool] True if buffer is ended for this file
4930 ** @valrule IsEof [AjBool] True if buffer has read to end of this file
4931 **
4932 ** @fcategory use
4933 **
4934 ** @fdata [AjPFilebuff]
4935 **
4936 ******************************************************************************/
4937
4938
4939
4940
4941 /* @func ajFilebuffGetFile ****************************************************
4942 **
4943 ** Returns the file object from a buffered file object.
4944 **
4945 ** @param [r] buff [const AjPFilebuff] Buffered file.
4946 ** @return [AjPFile] File object.
4947 **
4948 ** @release 6.0.0
4949 ** @@
4950 ******************************************************************************/
4951
ajFilebuffGetFile(const AjPFilebuff buff)4952 AjPFile ajFilebuffGetFile(const AjPFilebuff buff)
4953 {
4954 if(!buff)
4955 return NULL;
4956
4957 return buff->File;
4958 }
4959
4960
4961
4962
4963 /* @func ajFilebuffGetFileptr *************************************************
4964 **
4965 ** Returns the C file pointer for an open buffered file.
4966 **
4967 ** @param [r] buff [const AjPFilebuff] Buffered file.
4968 ** @return [FILE*] C file pointer for the file.
4969 **
4970 ** @release 6.0.0
4971 ** @@
4972 ******************************************************************************/
4973
ajFilebuffGetFileptr(const AjPFilebuff buff)4974 FILE* ajFilebuffGetFileptr(const AjPFilebuff buff)
4975 {
4976 if(!buff)
4977 return NULL;
4978
4979 return buff->File->fp;
4980 }
4981
4982
4983
4984
4985 /* @func ajFilebuffGetFirst ***************************************************
4986 **
4987 ** Returns the first line of a file buffer
4988 **
4989 ** @param [r] buff [const AjPFilebuff] File buffer
4990 ** @return [const AjPStr] First line
4991 **
4992 **
4993 ** @release 6.4.0
4994 ******************************************************************************/
4995
ajFilebuffGetFirst(const AjPFilebuff buff)4996 const AjPStr ajFilebuffGetFirst(const AjPFilebuff buff)
4997 {
4998 if(!buff)
4999 return NULL;
5000
5001 if(!buff->Lines)
5002 return NULL;
5003
5004 return buff->Lines->Line;
5005 }
5006
5007
5008
5009
5010 /* @func ajFilebuffIsBuffered *************************************************
5011 **
5012 ** Tests whether an input file is buffered.
5013 **
5014 ** @param [r] buff [const AjPFilebuff] Buffered file object.
5015 ** @return [AjBool] ajTrue if the file was unbuffered before
5016 **
5017 ** @release 6.0.0
5018 ** @@
5019 ******************************************************************************/
5020
ajFilebuffIsBuffered(const AjPFilebuff buff)5021 AjBool ajFilebuffIsBuffered(const AjPFilebuff buff)
5022 {
5023 if(!buff)
5024 return ajFalse;
5025
5026 if(buff->Nobuff)
5027 return ajFalse;
5028
5029 return ajTrue;
5030 }
5031
5032
5033
5034
5035 /* @func ajFilebuffIsEmpty ****************************************************
5036 **
5037 ** Tests whether a file buffer is empty, including testing for a
5038 ** possible next file
5039 **
5040 ** @param [r] buff [const AjPFilebuff] Buffered file.
5041 ** @return [AjBool] ajTrue if the buffer is empty.
5042 **
5043 ** @release 6.0.0
5044 ** @@
5045 ******************************************************************************/
5046
ajFilebuffIsEmpty(const AjPFilebuff buff)5047 AjBool ajFilebuffIsEmpty(const AjPFilebuff buff)
5048 {
5049 /*ajDebug("ajFilebuffIsEmpty Size: %d Pos: %d End: %b Handle: %d "
5050 "Fp: %x List; %d\n",
5051 buff->Size, buff->Pos, buff->File->End, buff->File->Handle,
5052 buff->File->fp, ajListstrGetLength(buff->File->List));*/
5053
5054 if(!buff)
5055 return ajTrue;
5056
5057 if(!buff->File)
5058 return ajTrue;
5059
5060 if(buff->Pos < buff->Size)
5061 return ajFalse;
5062
5063 /* not open */
5064 if(!buff->File->fp || !buff->File->Handle)
5065 return ajTrue;
5066
5067 if(buff->File->End && !ajListstrGetLength(buff->File->List))
5068 /* EOF and done */
5069 return ajTrue;
5070
5071 ajDebug("ajFilebuffIsEmpty false\n");
5072
5073 return ajFalse;
5074 }
5075
5076
5077
5078
5079 /* @func ajFilebuffIsEnded ****************************************************
5080 **
5081 ** Tests whether the current file is exhausted.
5082 ** This means end of file is reached and the buffer is empty.
5083 **
5084 ** It is possible that further files are defined in the input list
5085 ** (see ajFilebuffIsEmpty)
5086 **
5087 ** @param [r] buff [const AjPFilebuff] File buffer
5088 ** @return [AjBool] ajTrue if we already set end-of-file
5089 **
5090 ** @release 6.0.0
5091 ** @@
5092 ******************************************************************************/
5093
ajFilebuffIsEnded(const AjPFilebuff buff)5094 AjBool ajFilebuffIsEnded(const AjPFilebuff buff)
5095 {
5096 if(!buff)
5097 return ajTrue;
5098
5099 ajDebug("ajFilebuffIsEnded End: %B Size: %d\n",
5100 buff->File->End, buff->Size);
5101
5102 /* not reached EOF yet */
5103 if(!buff->File->End)
5104 return ajFalse;
5105
5106 /* Something in the buffer*/
5107 if(buff->Size != 0)
5108 return ajFalse;
5109
5110 return ajTrue;
5111 }
5112
5113
5114
5115
5116 /* @func ajFilebuffIsEof ******************************************************
5117 **
5118 ** Tests whether we have reached end of file already
5119 **
5120 ** @param [r] buff [const AjPFilebuff] File buffer
5121 ** @return [AjBool] ajTrue if we already set end-of-file
5122 **
5123 ** @release 6.0.0
5124 ** @@
5125 ******************************************************************************/
5126
ajFilebuffIsEof(const AjPFilebuff buff)5127 AjBool ajFilebuffIsEof(const AjPFilebuff buff)
5128 {
5129 if(!buff)
5130 return ajTrue;
5131
5132 if(!buff->File)
5133 return ajTrue;
5134
5135 return buff->File->End;
5136 }
5137
5138
5139
5140
5141 /* @section Buffered file debug ***********************************************
5142 **
5143 ** Report file object contents for debugging
5144 **
5145 **
5146 ** @nam3rule Trace Print report to debug file (if any)
5147 ** @nam4rule TraceFull Print full contents report to debug file (if any)
5148 ** @nam4rule TraceTitle Print report with a set title
5149 **
5150 ** @argrule * buff [const AjPFilebuff]
5151 ** @argrule Full nlines [size_t] Maximum number of lines to report
5152 ** @argrule Full nfree [size_t] Maximum number of free lines to report
5153 ** @argrule Title title [const char*] Report title
5154 **
5155 ** @valrule * [void]
5156 **
5157 ** @fcategory misc
5158 ** @fdata [AjPFilebuff]
5159 **
5160 ******************************************************************************/
5161
5162
5163
5164
5165 /* @func ajFilebuffTrace ******************************************************
5166 **
5167 ** Writes debug messages to indicate the contents of a buffered file.
5168 **
5169 ** @param [r] buff [const AjPFilebuff] Buffered file.
5170 ** @return [void]
5171 **
5172 ** @release 6.0.0
5173 ** @@
5174 ******************************************************************************/
5175
ajFilebuffTrace(const AjPFilebuff buff)5176 void ajFilebuffTrace(const AjPFilebuff buff)
5177 {
5178 AjPFilebufflist test;
5179 ajint i = 0;
5180 ajint j = -1;
5181
5182 ajDebug("Trace buffer file '%S'\n"
5183 " Pos: %d Size: %d FreeSize: %d Fpos: %Ld End: %b\n",
5184 buff->File->Name, buff->Pos, buff->Size,buff->FreeSize,
5185 buff->Fpos, buff->File->End);
5186
5187 if(buff->Size)
5188 {
5189 ajDebug(" Lines: %u\n", buff->Size);
5190
5191 if(buff->Curr)
5192 ajDebug(" Curr: %8Ld %x %x %u <%S>\n",
5193 buff->Curr->Fpos,
5194 buff->Curr->Line, buff->Curr->Next,
5195 ajStrGetLen(buff->Curr->Line),
5196 buff->Curr->Line);
5197 else
5198 ajDebug(" Curr: <null>\n");
5199
5200 if(buff->Lines)
5201 ajDebug(" From: %8Ld %x %x %u <%S>\n",
5202 buff->Lines->Fpos,
5203 buff->Lines->Line, buff->Lines->Next,
5204 ajStrGetLen(buff->Lines->Line),
5205 buff->Lines->Line);
5206 else
5207 ajDebug(" From: <null>\n");
5208
5209 if(buff->Last)
5210 ajDebug(" To: %8Ld %x %x %u <%S>\n",
5211 buff->Last->Fpos,
5212 buff->Last->Line, buff->Last->Next,
5213 ajStrGetLen(buff->Last->Line),
5214 buff->Last->Line);
5215 else
5216 ajDebug(" To: <null>\n");
5217 }
5218
5219 if(buff->Freelines)
5220 for(test = buff->Freelines; test; test=test->Next)
5221 {
5222 i++;
5223
5224 if(test == buff->Freelast)
5225 j = i;
5226 }
5227
5228 ajDebug(" Free: %d Last: %d\n", i, j);
5229
5230 return;
5231 }
5232
5233
5234
5235
5236 /* @func ajFilebuffTraceFull **************************************************
5237 **
5238 ** Writes debug messages to show the full contents of a buffered file.
5239 **
5240 ** @param [r] buff [const AjPFilebuff] Buffered file.
5241 ** @param [r] nlines [size_t] Maximum number of lines to trace.
5242 ** @param [r] nfree [size_t] Maximum number of free lines to trace.
5243 ** @return [void]
5244 **
5245 ** @release 6.0.0
5246 ** @@
5247 ******************************************************************************/
5248
ajFilebuffTraceFull(const AjPFilebuff buff,size_t nlines,size_t nfree)5249 void ajFilebuffTraceFull(const AjPFilebuff buff, size_t nlines,
5250 size_t nfree)
5251 {
5252 ajint i;
5253 AjPFilebufflist line;
5254 AjBool last = ajFalse;
5255
5256 ajDebug("Trace buffer file '%S' End: %B\n"
5257 " Pos: %d Size: %d Nobuff: %B Fpos: %Ld\n",
5258 buff->File->Name, buff->File->End,
5259 buff->Pos, buff->Size, buff->Nobuff, buff->Fpos);
5260
5261 line = buff->Lines;
5262
5263 for(i=1; line && (i <= (ajint)nlines); i++)
5264 {
5265 if(line == buff->Curr)
5266 ajDebug("*Line %x %d: %5d %5d <%-20S>\n",
5267 line->Line, i,
5268 ajStrGetLen(line->Line), strlen(ajStrGetPtr(line->Line)),
5269 line->Line);
5270 else
5271 ajDebug(" Line %x %d: %5d %5d <%-20S>\n",
5272 line->Line, i,
5273 ajStrGetLen(line->Line), strlen(ajStrGetPtr(line->Line)),
5274 line->Line);
5275 line = line->Next;
5276 }
5277
5278 line = buff->Freelines;
5279
5280 for(i=1; line && (i <= (ajint)nfree); i++)
5281 {
5282 if(line == buff->Freelast)
5283 last = ajTrue;
5284
5285 ajDebug(" Free %x %d: %d bytes %B\n",
5286 line->Line, i, ajStrGetRes(line->Line), last);
5287 line = line->Next;
5288 }
5289
5290 return;
5291 }
5292
5293
5294
5295
5296 /* @func ajFilebuffTraceTitle *************************************************
5297 **
5298 ** Writes the full contents of a buffered file to the debug file
5299 **
5300 ** @param [r] buff [const AjPFilebuff] Buffered file.
5301 ** @param [r] title [const char*] Report title
5302 ** @return [void]
5303 **
5304 ** @release 6.0.0
5305 ** @@
5306 ******************************************************************************/
5307
ajFilebuffTraceTitle(const AjPFilebuff buff,const char * title)5308 void ajFilebuffTraceTitle(const AjPFilebuff buff, const char* title)
5309 {
5310 ajint i;
5311 AjPFilebufflist line;
5312 ajint last = 0;
5313
5314 ajDebug("=== File Buffer: %s ===\n", title);
5315 line = buff->Lines;
5316
5317 for(i=1; line; i++)
5318 {
5319 ajStrAssignS(&fileTmpStr, line->Line);
5320 ajStrRemoveLastNewline(&fileTmpStr);
5321
5322 if(line == buff->Curr)
5323 ajDebug("* %x %S\n", line->Line, fileTmpStr);
5324 else
5325 ajDebug(" %x %S\n", line->Line, fileTmpStr);
5326
5327 line = line->Next;
5328 }
5329
5330 line = buff->Freelines;
5331
5332 for(i=1; line; i++)
5333 {
5334 if(line == buff->Freelast)
5335 last = i;
5336
5337 if(line == buff->Freelast)
5338 ajDebug("F %x %S\n", line->Line, fileTmpStr);
5339 else
5340 ajDebug("f %x %S\n", line->Line, fileTmpStr);
5341
5342 line = line->Next;
5343 }
5344
5345 if (!last)
5346 last = i;
5347 ajDebug("=== end of file, free list %d lines ===\n", last);
5348
5349 return;
5350 }
5351
5352
5353
5354
5355 /* @funcstatic fileBuffLineDel ************************************************
5356 **
5357 ** Delete a line from a buffer.
5358 **
5359 ** @param [u] buff [AjPFilebuff] File buffer
5360 ** @return [void]
5361 **
5362 ** @release 2.5.0
5363 ******************************************************************************/
5364
fileBuffLineDel(AjPFilebuff buff)5365 static void fileBuffLineDel(AjPFilebuff buff)
5366 {
5367 AjPFilebufflist saveprev;
5368
5369 if(!buff->Curr)
5370 return;
5371
5372 /*ajDebug("fileBuffLineDel removing line [%d%s%d], '%S' len %d\n",
5373 buff->Pos, SLASH_STRING, buff->Size, buff->Curr->Line,
5374 ajStrGetLen(buff->Curr->Line));*/
5375
5376 /* first line */
5377 if(!buff->Prev)
5378 {
5379 buff->Prev = buff->Lines;
5380 buff->Curr = buff->Lines = buff->Lines->Next;
5381 ajStrDel(&buff->Prev->Line);
5382 AJFREE(buff->Prev);
5383 --buff->Size;
5384
5385 return;
5386 }
5387
5388 /* last line */
5389 if(!buff->Curr->Next)
5390 {
5391 saveprev = buff->Prev;
5392 buff->Prev = buff->Lines;
5393
5394 while(buff->Prev && buff->Prev->Next != saveprev)
5395 buff->Prev = buff->Prev->Next;
5396
5397 saveprev->Next = NULL;
5398
5399 ajStrDel(&buff->Curr->Line);
5400 AJFREE(buff->Curr);
5401 buff->Curr = NULL;
5402 buff->Last = saveprev;
5403 --buff->Size;
5404 buff->Pos = buff->Size;
5405
5406 return;
5407 }
5408
5409 buff->Prev->Next = buff->Curr->Next;
5410 ajStrDel(&buff->Curr->Line);
5411 AJFREE(buff->Curr);
5412 buff->Curr = buff->Prev->Next;
5413 --buff->Size;
5414
5415 return;
5416 }
5417
5418
5419
5420
5421 /* @funcstatic fileBuffLineNext ***********************************************
5422 **
5423 ** Steps the Curr pointer to the next line in a buffer.
5424 **
5425 ** Not for use when reading from a file. This steps through the buffer
5426 **
5427 ** @param [u] buff [AjPFilebuff] File buffer
5428 ** @return [AjBool] ajTrue if there was another line
5429 **
5430 ** @release 2.5.0
5431 ******************************************************************************/
5432
fileBuffLineNext(AjPFilebuff buff)5433 static AjBool fileBuffLineNext(AjPFilebuff buff)
5434 {
5435 if(buff->Pos < buff->Size)
5436 {
5437 buff->Prev = buff->Curr;
5438 buff->Curr = buff->Curr->Next;
5439 buff->Pos++;
5440
5441 return ajTrue;
5442 }
5443
5444 return ajFalse;
5445 }
5446
5447
5448
5449
5450 /* @datasection [AjPOutfile] Output file object *******************************
5451 **
5452 ** Function is for manipulating output files
5453 ** and their attributes.
5454 **
5455 ** @nam2rule Outfile
5456 ******************************************************************************/
5457
5458
5459
5460
5461 /* @section Outfile constructors **********************************************
5462 **
5463 ** All constructors return a new open file by pointer. It is the responsibility
5464 ** of the user to first destroy any previous file pointer. The target pointer
5465 ** does not need to be initialised to NULL, but it is good programming practice
5466 ** to do so anyway.
5467 **
5468 ** To replace or reuse an existing file, see instead
5469 ** the {File Assignments} and {File Modifiers} functions.
5470 **
5471 ** The range of constructors is provided to allow flexibility in how
5472 ** applications can open files to read various kinds of data.
5473 **
5474 ** @nam3rule New Output file object constructor
5475 ** @suffix Name File name
5476 ** @suffix S File name as a string
5477 **
5478 ** @argrule S name [const AjPStr] Output filename
5479 **
5480 ** @valrule * [AjPOutfile] Output file
5481 **
5482 ** @fcategory new
5483 **
5484 ** @fdata [AjPOutfile]
5485 **
5486 ******************************************************************************/
5487
5488
5489
5490
5491 /* @func ajOutfileNewNameS ****************************************************
5492 **
5493 ** Creates a new formatted output file object with a specified name.
5494 **
5495 ** 'stdout' and 'stderr' are special names for standard output and
5496 ** standard error respectively.
5497 **
5498 ** @param [r] name [const AjPStr] File name.
5499 ** @return [AjPOutfile] New output file object.
5500 **
5501 ** @release 6.0.0
5502 ** @@
5503 ******************************************************************************/
5504
ajOutfileNewNameS(const AjPStr name)5505 AjPOutfile ajOutfileNewNameS(const AjPStr name)
5506 {
5507 AjPOutfile thys;
5508 ajlong ipos;
5509 AjPStr tmpname = NULL;
5510
5511 AJNEW0(thys);
5512
5513 ipos = ajStrFindC(name, "::");
5514 if(ipos > 0)
5515 {
5516 ajStrAssignSubS(&thys->Formatstr, name, 0, ipos-1);
5517 ajStrAssignSubS(&tmpname, name, ipos+2, -1);
5518 thys->File = ajFileNewOutNameS(tmpname);
5519 ajStrDel(&tmpname);
5520 }
5521 else
5522 {
5523 thys->File = ajFileNewOutNameS(name);
5524 }
5525
5526 if(!thys->File)
5527 return NULL;
5528
5529 return thys;
5530 }
5531
5532
5533
5534
5535 /* @section Outfile destructors ***********************************************
5536 **
5537 ** Destruction is achieved by closing the file.
5538 **
5539 ** Unlike ANSI C, there are tests to ensure a file is not closed twice.
5540 **
5541 ** @nam3rule Close Close file and delete output file object
5542 **
5543 ** @argrule * Pfile [AjPOutfile*] Output file object pointer
5544 **
5545 ** @valrule * [void]
5546 **
5547 ** @fcategory delete
5548 **
5549 ** @fdata [AjPOutfile]
5550 **
5551 ******************************************************************************/
5552
5553
5554
5555
5556 /* @func ajOutfileClose *******************************************************
5557 **
5558 ** Close and free an outfile object.
5559 **
5560 ** @param [d] Pfile [AjPOutfile*] Output file.
5561 ** @return [void]
5562 **
5563 ** @release 2.9.0
5564 ** @@
5565 ******************************************************************************/
5566
ajOutfileClose(AjPOutfile * Pfile)5567 void ajOutfileClose(AjPOutfile* Pfile)
5568 {
5569 AjPOutfile thys;
5570
5571 thys = Pfile ? *Pfile : 0;
5572
5573 if(!Pfile)
5574 return;
5575
5576 if(!*Pfile)
5577 return;
5578
5579 fileClose(thys->File);
5580 AJFREE(thys->File);
5581 ajStrDel(&thys->Type);
5582 ajStrDel(&thys->Formatstr);
5583 AJFREE(*Pfile);
5584
5585 return;
5586 }
5587
5588
5589
5590
5591 /* @section Outfile casts *****************************************************
5592 **
5593 ** These functions examine the contents of an outfile object and return some
5594 ** derived information. Some of them provide access to the internal
5595 ** components of a file object. They are provided for programming convenience
5596 ** but should be used with caution.
5597 **
5598 ** @nam3rule Get Return an output file attribute value
5599 ** @nam4rule GetFile Return the file object
5600 ** @nam4rule GetFileptr Return the C file pointer
5601 ** @nam4rule GetFormat Return the output format name
5602 ** @nam4rule GetFormatindex Return the output format index number
5603 **
5604 ** @argrule * file [const AjPOutfile] Output file object
5605 **
5606 ** @valrule GetFile [AjPFile] File object
5607 ** @valrule GetFileptr [FILE*] C file pointer
5608 ** @valrule GetFormat [const AjPStr] Filename as a string
5609 ** @valrule GetFormatindex [ajuint] Index in internal formats
5610 **
5611 ** @fcategory cast
5612 **
5613 ** @fdata [AjPOutfile]
5614 **
5615 ******************************************************************************/
5616
5617
5618
5619
5620 /* @func ajOutfileGetFile *****************************************************
5621 **
5622 ** Returns the AjPFile for an AjPOutfile object
5623 **
5624 ** @param [r] file [const AjPOutfile] Outfile object
5625 ** @return [AjPFile] AjPFile object
5626 **
5627 ** @release 6.0.0
5628 ******************************************************************************/
5629
ajOutfileGetFile(const AjPOutfile file)5630 AjPFile ajOutfileGetFile (const AjPOutfile file)
5631 {
5632 return file->File;
5633 }
5634
5635
5636
5637
5638 /* @func ajOutfileGetFileptr **************************************************
5639 **
5640 ** Returns the C FILE* for an AjPOutfile object
5641 **
5642 ** @param [r] file [const AjPOutfile] Outfile object
5643 ** @return [FILE*] C file pointer
5644 **
5645 ** @release 6.0.0
5646 ******************************************************************************/
5647
ajOutfileGetFileptr(const AjPOutfile file)5648 FILE* ajOutfileGetFileptr (const AjPOutfile file)
5649 {
5650 return file->File->fp;
5651 }
5652
5653
5654
5655
5656 /* @func ajOutfileGetFormat ***************************************************
5657 **
5658 ** Returns the file format name for an AjPOutfile object
5659 **
5660 ** @param [r] file [const AjPOutfile] Outfile object
5661 ** @return [const AjPStr] Format name
5662 **
5663 ** @release 6.0.0
5664 ******************************************************************************/
5665
ajOutfileGetFormat(const AjPOutfile file)5666 const AjPStr ajOutfileGetFormat (const AjPOutfile file)
5667 {
5668 return file->Formatstr;
5669 }
5670
5671
5672
5673
5674 /* @func ajOutfileGetFormatindex **********************************************
5675 **
5676 ** Returns the file format name for an AjPOutfile object
5677 **
5678 ** @param [r] file [const AjPOutfile] Outfile object
5679 ** @return [ajuint] Format name
5680 **
5681 ** @release 6.4.0
5682 ******************************************************************************/
5683
ajOutfileGetFormatindex(const AjPOutfile file)5684 ajuint ajOutfileGetFormatindex (const AjPOutfile file)
5685 {
5686 return file->Format;
5687 }
5688
5689
5690
5691
5692 /* @section Outfile modifiers *************************************************
5693 **
5694 ** These functions modify an output file object and its asociated output file
5695 **
5696 ** @nam3rule Reset
5697 **
5698 ** @argrule * outf [AjPOutfile] Output file object
5699 **
5700 ** @valrule * [void]
5701 **
5702 ** @fcategory modify
5703 **
5704 ** @fdata [AjPOutfile]
5705 **
5706 ******************************************************************************/
5707
5708
5709
5710
5711 /* @func ajOutfileReset *******************************************************
5712 **
5713 ** Close and free an outfile object.
5714 **
5715 ** @param [u] outf [AjPOutfile] Output file.
5716 ** @return [void]
5717 **
5718 ** @release 6.5.0
5719 ** @@
5720 ******************************************************************************/
5721
ajOutfileReset(AjPOutfile outf)5722 void ajOutfileReset(AjPOutfile outf)
5723 {
5724 if(!outf)
5725 return;
5726
5727 if(!outf->Cleanup)
5728 return;
5729
5730 outf->Cleanup(outf);
5731
5732 return;
5733 }
5734
5735
5736
5737
5738 /* @datasection [AjPStr] Filename functions ***********************************
5739 **
5740 ** Functions operating on strings containing filenames
5741 **
5742 ** @nam2rule Filename Operations on filename strings
5743 **
5744 ******************************************************************************/
5745
5746
5747
5748
5749 /* @section Filename tests ****************************************************
5750 **
5751 ** Tests on filenames and searching the file system
5752 **
5753 ** @nam3rule Exists tests whether file exists in current directory
5754 ** @nam4rule Dir Tests whether file exists and is a directory
5755 ** @nam4rule Exec Tests whether file exists and is executable by the user
5756 ** @nam4rule Read Tests whether file exists and is readable by the user
5757 ** @nam4rule Write Tests whether file exists and is writable by the user
5758 ** @nam3rule Get Return a filename element
5759 ** @nam4rule GetSize Return the file size
5760 ** @nam3rule Has Filename contains element
5761 ** @nam4rule Ext Filename extension
5762 ** @nam4rule Path Directory path
5763 ** @nam3rule Test Test a filename
5764 ** @nam4rule TestExclude Test a filename against a list of files to include.
5765 ** Any file not in the list is excluded.
5766 ** @nam4rule TestInclude Test a filename against a list of files to exclude
5767 ** Any file not in the list is included.
5768 ** @suffix Path Include the file path in tests
5769 **
5770 ** @argrule * filename [const AjPStr] Filename string
5771 ** @argrule Stat mode [ajint] Mode
5772 ** @argrule Test exclude [const AjPStr] Excluded filenames wildcard
5773 ** @argrule Test include [const AjPStr] Included filenames wildcard
5774 **
5775 ** @valrule Exists [AjBool] True if file exists with any requested access
5776 ** @valrule GetSize [ajlong] File size or -1 if not found
5777 ** @valrule Has [AjBool] True if file has attribute
5778 ** @valrule Test [AjBool] True if file passed test
5779 ** @fcategory use
5780 **
5781 ** @fdata [AjPStr]
5782 **
5783 ******************************************************************************/
5784
5785
5786
5787
5788 /* @func ajFilenameExists *****************************************************
5789 **
5790 ** Returns true if file exists
5791 **
5792 ** @param [r] filename [const AjPStr] Filename.
5793 ** @return [AjBool] ajTrue on success
5794 **
5795 ** @release 6.0.0
5796 ** @@
5797 ******************************************************************************/
5798
ajFilenameExists(const AjPStr filename)5799 AjBool ajFilenameExists(const AjPStr filename)
5800 {
5801 #if defined(AJ_IRIXLF)
5802 struct stat64 buf;
5803 #else /* !AJ_IRIXLF */
5804 struct stat buf;
5805 #endif /* AJ_IRIXLF */
5806
5807 if(ajStrMatchC(filename, "stdin"))
5808 return ajTrue;
5809
5810 if(
5811 #if defined(AJ_IRIXLF)
5812 !stat64(ajStrGetPtr(filename), &buf)
5813 #else /* !AJ_IRIXLF */
5814 !stat(ajStrGetPtr(filename), &buf)
5815 #endif /* AJ_IRIXLF */
5816 )
5817 return ajTrue;
5818
5819 return ajFalse;
5820 }
5821
5822
5823
5824
5825 /* @func ajFilenameExistsDir **************************************************
5826 **
5827 ** Returns true if file exists and is a directory
5828 **
5829 ** @param [r] filename [const AjPStr] Filename.
5830 ** @return [AjBool] ajTrue on success
5831 **
5832 ** @release 6.0.0
5833 ** @@
5834 ******************************************************************************/
5835
ajFilenameExistsDir(const AjPStr filename)5836 AjBool ajFilenameExistsDir(const AjPStr filename)
5837 {
5838 #if defined(AJ_IRIXLF)
5839 struct stat64 buf;
5840 #else /* !AJ_IRIXLF */
5841 struct stat buf;
5842 #endif /* AJ_IRIXLF */
5843
5844 #ifdef WIN32
5845 if(!ajStrGetLen(filename))
5846 return ajTrue;
5847 #endif /* WIN32 */
5848
5849 if(
5850 #if defined(AJ_IRIXLF)
5851 !stat64(ajStrGetPtr(filename), &buf)
5852 #else /* !AJ_IRIXLF */
5853 !stat(ajStrGetPtr(filename), &buf)
5854 #endif /* AJ_IRIXLF */
5855 )
5856 if((ajuint)buf.st_mode & AJ_FILE_DIR)
5857 return ajTrue;
5858
5859 return ajFalse;
5860 }
5861
5862
5863
5864
5865 /* @func ajFilenameExistsExec *************************************************
5866 **
5867 ** Returns true if file exists and is executable by the user
5868 **
5869 ** @param [r] filename [const AjPStr] Filename.
5870 ** @return [AjBool] ajTrue on success
5871 **
5872 ** @release 6.0.0
5873 ** @@
5874 ******************************************************************************/
5875
ajFilenameExistsExec(const AjPStr filename)5876 AjBool ajFilenameExistsExec(const AjPStr filename)
5877 {
5878 #if defined(AJ_IRIXLF)
5879 struct stat64 buf;
5880 #else /* !AJ_IRIXLF */
5881 struct stat buf;
5882 #endif /* AJ_IRIXLF */
5883
5884 if(
5885 #if defined(AJ_IRIXLF)
5886 !stat64(ajStrGetPtr(filename), &buf)
5887 #else /* !AJ_IRIXLF */
5888 !stat(ajStrGetPtr(filename), &buf)
5889 #endif /* AJ_IRIXLF */
5890 )
5891 if((ajuint)buf.st_mode & AJ_FILE_X)
5892 return ajTrue;
5893
5894 return ajFalse;
5895 }
5896
5897
5898
5899
5900 /* @func ajFilenameExistsRead *************************************************
5901 **
5902 ** Returns true if file exists and is readable by the user
5903 **
5904 ** @param [r] filename [const AjPStr] Filename.
5905 ** @return [AjBool] ajTrue on success
5906 **
5907 ** @release 6.0.0
5908 ** @@
5909 ******************************************************************************/
5910
ajFilenameExistsRead(const AjPStr filename)5911 AjBool ajFilenameExistsRead(const AjPStr filename)
5912 {
5913 #if defined(AJ_IRIXLF)
5914 struct stat64 buf;
5915 #else /* !AJ_IRIXLF */
5916 struct stat buf;
5917 #endif /* AJ_IRIXLF */
5918
5919 if(
5920 #if defined(AJ_IRIXLF)
5921 !stat64(ajStrGetPtr(filename), &buf)
5922 #else /* !AJ_IRIXLF */
5923 !stat(ajStrGetPtr(filename), &buf)
5924 #endif /* AJ_IRIXLF */
5925 )
5926 if((ajuint)buf.st_mode & AJ_FILE_R)
5927 return ajTrue;
5928
5929 return ajFalse;
5930 }
5931
5932
5933
5934
5935 /* @func ajFilenameExistsWrite ************************************************
5936 **
5937 ** Returns true if file exists and is writable by the user
5938 **
5939 ** @param [r] filename [const AjPStr] Filename.
5940 ** @return [AjBool] ajTrue on success
5941 **
5942 ** @release 6.0.0
5943 ** @@
5944 ******************************************************************************/
5945
ajFilenameExistsWrite(const AjPStr filename)5946 AjBool ajFilenameExistsWrite(const AjPStr filename)
5947 {
5948 #if defined(AJ_IRIXLF)
5949 struct stat64 buf;
5950 #else /* !AJ_IRIXLF */
5951 struct stat buf;
5952 #endif /* AJ_IRIXLF */
5953
5954 if(
5955 #if defined(AJ_IRIXLF)
5956 !stat64(ajStrGetPtr(filename), &buf)
5957 #else /* !AJ_IRIXLF */
5958 !stat(ajStrGetPtr(filename), &buf)
5959 #endif /* AJ_IRIXLF */
5960 )
5961 if((ajuint)buf.st_mode & AJ_FILE_W)
5962 return ajTrue;
5963
5964 return ajFalse;
5965 }
5966
5967
5968
5969
5970 /* @func ajFilenameGetSize ****************************************************
5971 **
5972 ** Returns the length of a file
5973 **
5974 ** @param [r] filename [const AjPStr] Filename.
5975 ** @return [ajlong] length or -1 if file doesn't exist
5976 **
5977 ** @release 6.0.0
5978 ** @@
5979 ******************************************************************************/
5980
ajFilenameGetSize(const AjPStr filename)5981 ajlong ajFilenameGetSize(const AjPStr filename)
5982 {
5983 #if defined(AJ_IRIXLF)
5984 struct stat64 buf;
5985 #else /* !AJ_IRIXLF */
5986 struct stat buf;
5987 #endif /* AJ_IRIXLF */
5988
5989 #if defined(AJ_IRIXLF)
5990 if(!stat64(ajStrGetPtr(filename), &buf))
5991 return (ajlong)buf.st_size;
5992 #else /* !AJ_IRIXLF */
5993 if(!stat(ajStrGetPtr(filename), &buf))
5994 return (ajlong)buf.st_size;
5995 #endif /* AJ_IRIXLF */
5996
5997 return -1;
5998 }
5999
6000
6001
6002
6003 /* @func ajFilenameHasPath ****************************************************
6004 **
6005 ** Tests whether a filename includes a directory specification.
6006 **
6007 ** @param [r] filename [const AjPStr] File name.
6008 ** @return [AjBool] ajTrue if directory filename syntax was found
6009 **
6010 ** @release 6.0.0
6011 ** @@
6012 ******************************************************************************/
6013
ajFilenameHasPath(const AjPStr filename)6014 AjBool ajFilenameHasPath(const AjPStr filename)
6015 {
6016 if(ajStrFindC(filename, SLASH_STRING) < 0)
6017 return ajFalse;
6018
6019 return ajTrue;
6020 }
6021
6022
6023
6024
6025 /* @func ajFilenameTestExclude ************************************************
6026 **
6027 ** Tests a filename against wildcard
6028 ** lists of file names to be included and excluded.
6029 **
6030 ** The path (if any) is removed before checking.
6031 **
6032 ** By default files are excluded. The inclusion list is used to select
6033 ** files, and the exclusion list is then used to exclude selected
6034 ** files again.
6035 **
6036 ** @param [r] filename [const AjPStr] File to test
6037 ** @param [r] exclude [const AjPStr] List of wildcard names to exclude
6038 ** @param [r] include [const AjPStr] List of wildcard names to include
6039 ** @return [AjBool] ajTrue if the filename is accepted.
6040 **
6041 ** @release 6.0.0
6042 ** @@
6043 ******************************************************************************/
6044
ajFilenameTestExclude(const AjPStr filename,const AjPStr exclude,const AjPStr include)6045 AjBool ajFilenameTestExclude(const AjPStr filename,
6046 const AjPStr exclude,
6047 const AjPStr include)
6048 {
6049 AjBool ret = ajFalse;
6050
6051 AjPStrTok handle = NULL;
6052 AjPStr token = NULL;
6053
6054 ajDebug("ajFilenameTestExclude "
6055 "filename '%S' exclude '%S' include '%S'\n",
6056 filename, exclude, include);
6057
6058 ajStrAssignS(&fileNameTmp, filename);
6059 ajFilenameTrimPath(&fileNameTmp);
6060
6061 if(ajStrGetLen(include))
6062 {
6063 ajStrTokenAssignC(&handle, include, " \t,;\n");
6064
6065 while(ajStrTokenNextParse(handle, &token))
6066 if(ajStrMatchWildS(filename, token) ||
6067 ajStrMatchWildS(fileNameTmp, token))
6068 ret = ajTrue;
6069
6070 ajStrTokenReset(handle);
6071 }
6072
6073 if(ajStrGetLen(exclude))
6074 { /* nokeep, test exclude last */
6075 ajStrTokenAssignC(&handle, exclude, " \t,;\n");
6076
6077 while(ajStrTokenNextParse(handle, &token))
6078 if(ajStrMatchWildS(filename, token) ||
6079 ajStrMatchWildS(fileNameTmp, token))
6080 ret = ajFalse;
6081
6082 ajStrTokenReset(handle);
6083 }
6084
6085 ajStrTokenDel(&handle);
6086 ajStrDel(&token);
6087
6088 return ret;
6089 }
6090
6091
6092
6093
6094 /* @func ajFilenameTestExcludePath ********************************************
6095 **
6096 ** Tests a full path filename against wildcard
6097 ** lists of file names to be included and excluded.
6098 **
6099 ** The full path is retained and included in the tests.
6100 **
6101 ** By default files are excluded. The inclusion list is used to select
6102 ** files, and the exclusion list is then used to exclude selected
6103 ** files again.
6104 **
6105 ** @param [r] filename [const AjPStr] File to test
6106 ** @param [r] exclude [const AjPStr] List of wildcard names to exclude
6107 ** @param [r] include [const AjPStr] List of wildcard names to include
6108 ** @return [AjBool] ajTrue if the filename is accepted.
6109 **
6110 ** @release 6.0.0
6111 ** @@
6112 ******************************************************************************/
6113
ajFilenameTestExcludePath(const AjPStr filename,const AjPStr exclude,const AjPStr include)6114 AjBool ajFilenameTestExcludePath(const AjPStr filename,
6115 const AjPStr exclude,
6116 const AjPStr include)
6117 {
6118 AjBool ret = ajFalse;
6119
6120 AjPStrTok handle = NULL;
6121 AjPStr token = NULL;
6122
6123 ajDebug("ajFilenameTestExcludePath "
6124 "filename '%S' exclude '%S' include '%S'\n",
6125 filename, exclude, include);
6126
6127 if(ajStrGetLen(include))
6128 {
6129 ajStrTokenAssignC(&handle, include, " \t,;\n");
6130
6131 while(ajStrTokenNextParse(handle, &token))
6132 if(ajStrMatchWildS(filename, token))
6133 ret = ajTrue;
6134
6135 ajStrTokenReset(handle);
6136 }
6137
6138 if(ajStrGetLen(exclude))
6139 { /* nokeep, test exclude last */
6140 ajStrTokenAssignC(&handle, exclude, " \t,;\n");
6141
6142 while(ajStrTokenNextParse(handle, &token))
6143 if(ajStrMatchWildS(filename, token))
6144 ret = ajFalse;
6145
6146 ajStrTokenReset(handle);
6147 }
6148
6149 ajStrTokenDel(&handle);
6150 ajStrDel(&token);
6151
6152 return ret;
6153 }
6154
6155
6156
6157
6158 /* @func ajFilenameTestInclude ************************************************
6159 **
6160 ** Tests a filename against wildcard
6161 ** lists of file names to be included and excluded.
6162 **
6163 ** By default files are included. The exclusion list is used to trim
6164 ** out files, and the inclusion list is then used to add selected
6165 ** files again.
6166 **
6167 ** @param [r] filename [const AjPStr] File to test
6168 ** @param [r] exclude [const AjPStr] List of wildcard names to exclude
6169 ** @param [r] include [const AjPStr] List of wildcard names to include
6170 ** @return [AjBool] ajTrue if the filename is accepted.
6171 **
6172 ** @release 6.0.0
6173 ** @@
6174 ******************************************************************************/
6175
ajFilenameTestInclude(const AjPStr filename,const AjPStr exclude,const AjPStr include)6176 AjBool ajFilenameTestInclude(const AjPStr filename,
6177 const AjPStr exclude,
6178 const AjPStr include)
6179 {
6180 AjBool ret = ajTrue;
6181
6182 AjPStrTok handle = NULL;
6183 AjPStr token = NULL;
6184
6185 ajStrAssignS(&fileNameTmp, filename);
6186 ajFilenameTrimPath(&fileNameTmp);
6187
6188 ajDebug("ajFilenameTestInclude "
6189 "filename '%S' exclude '%S' include '%S'\n",
6190 filename, exclude, include);
6191
6192 if(ajStrGetLen(exclude))
6193 {
6194 /* keep, so test exclude first */
6195 ajStrTokenAssignC(&handle, exclude, " \t,;\n");
6196
6197 while(ajStrTokenNextParse(handle, &token))
6198 if(ajStrMatchWildS(filename, token) ||
6199 ajStrMatchWildS(fileNameTmp, token))
6200 ret = ajFalse;
6201
6202 ajStrTokenReset(handle);
6203 }
6204
6205 if(ajStrGetLen(include))
6206 {
6207 ajStrTokenAssignC(&handle, include, " \t,;\n");
6208
6209 while(ajStrTokenNextParse(handle, &token))
6210 if(ajStrMatchWildS(filename, token) ||
6211 ajStrMatchWildS(fileNameTmp, token))
6212 ret = ajTrue;
6213
6214 ajStrTokenReset(handle);
6215 }
6216
6217 ajStrTokenDel(&handle);
6218 ajStrDel(&token);
6219
6220 return ret;
6221 }
6222
6223
6224
6225
6226 /* @func ajFilenameTestIncludePath ********************************************
6227 **
6228 ** Tests a filename against wildcard
6229 ** lists of file names to be included and excluded.
6230 **
6231 ** By default files are included. The exclusion list is used to trim
6232 ** out files, and the inclusion list is then used to add selected
6233 ** files again.
6234 **
6235 ** @param [r] filename [const AjPStr] File to test
6236 ** @param [r] exclude [const AjPStr] List of wildcard names to exclude
6237 ** @param [r] include [const AjPStr] List of wildcard names to include
6238 ** @return [AjBool] ajTrue if the filename is accepted.
6239 **
6240 ** @release 6.0.0
6241 ** @@
6242 ******************************************************************************/
6243
ajFilenameTestIncludePath(const AjPStr filename,const AjPStr exclude,const AjPStr include)6244 AjBool ajFilenameTestIncludePath(const AjPStr filename,
6245 const AjPStr exclude,
6246 const AjPStr include)
6247 {
6248 AjBool ret = ajTrue;
6249
6250 AjPStrTok handle = NULL;
6251 AjPStr token = NULL;
6252
6253 ajDebug("ajFilenameTestIncludePath "
6254 "filename '%S' exclukde '%S' include '%S\n",
6255 filename, exclude, include);
6256
6257 if(ajStrGetLen(exclude))
6258 {
6259 /* keep, so test exclude first */
6260 ajStrTokenAssignC(&handle, exclude, " \t,;\n");
6261
6262 while(ajStrTokenNextParse(handle, &token))
6263 if(ajStrMatchWildS(filename, token))
6264 ret = ajFalse;
6265
6266 ajStrTokenReset(handle);
6267 }
6268
6269 if(ajStrGetLen(include))
6270 {
6271 ajStrTokenAssignC(&handle, include, " \t,;\n");
6272
6273 while(ajStrTokenNextParse(handle, &token))
6274 if(ajStrMatchWildS(filename, token))
6275 ret = ajTrue;
6276
6277 ajStrTokenReset(handle);
6278 }
6279
6280 ajStrTokenDel(&handle);
6281 ajStrDel(&token);
6282
6283 return ret;
6284 }
6285
6286
6287
6288
6289 /* @section Filename modifiers ************************************************
6290 **
6291 ** These functions overwrite a previous filename
6292 **
6293 ** @nam3rule Replace Replace part of a filename
6294 ** @nam3rule Set Set undefined part of a filename
6295 ** @nam4rule Tempname Set a new temporary filename
6296 ** @nam3rule Trim Remove part of a filename
6297 ** @nam4rule TrimAll Remove path and extension and trailing :identifier
6298 ** to leave the file basename
6299 **
6300 ** @suffix Ext Filename extension
6301 ** @suffix Path Filename path
6302 ** @suffix C New character value
6303 ** @suffix S New string value
6304 **
6305 ** @argrule * Pfilename [AjPStr*] Filename
6306 ** @argrule C txt [const char*] New character value
6307 ** @argrule S str [const AjPStr] New string value
6308 **
6309 ** @valrule * [AjBool] True on success
6310 **
6311 ** @fcategory modify
6312 **
6313 ** @fdata [AjPStr]
6314 **
6315 ******************************************************************************/
6316
6317
6318
6319
6320 /* @func ajFilenameReplaceExtC ************************************************
6321 **
6322 ** Replaces the extension part of a filename
6323 **
6324 ** @param [u] Pfilename [AjPStr*] Filename.
6325 ** @param [r] txt [const char*] New file extension
6326 ** @return [AjBool] ajTrue if the replacement succeeded.
6327 **
6328 ** @release 6.0.0
6329 ** @@
6330 ******************************************************************************/
6331
ajFilenameReplaceExtC(AjPStr * Pfilename,const char * txt)6332 AjBool ajFilenameReplaceExtC(AjPStr* Pfilename, const char* txt)
6333 {
6334 AjBool doext;
6335 char *p = NULL;
6336
6337 doext = ajTrue;
6338 if(!txt || !*txt)
6339 doext = ajFalse;
6340
6341
6342 /*ajDebug("ajFilenameReplaceExtC '%S' '%s'\n", *Pfilename, txt);*/
6343
6344 ajStrAssignS(&fileTmpStr,*Pfilename);
6345
6346 /* Skip any directory path */
6347 p = strrchr(ajStrGetuniquePtr(&fileTmpStr),SLASH_CHAR);
6348
6349 if (!p)
6350 p = ajStrGetuniquePtr(&fileTmpStr);
6351
6352 p = strrchr(p,'.');
6353
6354 if(p)
6355 {
6356 *p='\0';
6357 fileTmpStr->Len = p - ajStrGetPtr(fileTmpStr);
6358 }
6359
6360
6361 if(doext)
6362 {
6363 ajStrAppendC(&fileTmpStr,".");
6364 ajStrAppendC(&fileTmpStr,txt);
6365 }
6366
6367 ajStrAssignS(Pfilename,fileTmpStr);
6368
6369 /*ajDebug("result '%S'\n", *Pfilename);*/
6370
6371 return ajTrue;
6372 }
6373
6374
6375
6376
6377 /* @func ajFilenameReplaceExtS ************************************************
6378 **
6379 ** Replaces the extension part of a filename
6380 **
6381 ** @param [u] Pfilename [AjPStr*] Filename.
6382 ** @param [r] str [const AjPStr] New file extension
6383 ** @return [AjBool] ajTrue if the replacement succeeded.
6384 **
6385 ** @release 6.0.0
6386 ** @@
6387 ******************************************************************************/
6388
ajFilenameReplaceExtS(AjPStr * Pfilename,const AjPStr str)6389 AjBool ajFilenameReplaceExtS(AjPStr* Pfilename, const AjPStr str)
6390 {
6391 if(!str)
6392 return ajFilenameReplaceExtC(Pfilename, NULL);
6393
6394 return ajFilenameReplaceExtC(Pfilename, ajStrGetPtr(str));
6395 }
6396
6397
6398
6399
6400 /* @func ajFilenameReplacePathC ***********************************************
6401 **
6402 ** Sets the directory part of a filename
6403 **
6404 ** @param [u] Pfilename [AjPStr*] Filename.
6405 ** @param [r] txt [const char*] Directory
6406 ** @return [AjBool] ajTrue if the replacement succeeded.
6407 **
6408 ** @release 6.0.0
6409 ** @@
6410 ******************************************************************************/
6411
ajFilenameReplacePathC(AjPStr * Pfilename,const char * txt)6412 AjBool ajFilenameReplacePathC(AjPStr* Pfilename, const char* txt)
6413 {
6414 AjPStr tmpname = NULL;
6415 AjPStr tmpdir = NULL;
6416
6417 if(!txt)
6418 return ajFalse;
6419
6420 if(!fileFilenameExp)
6421 #ifndef WIN32
6422 fileFilenameExp = ajRegCompC("(.*/)?([^/]+)$");
6423 #else /* WIN32 */
6424 fileFilenameExp = ajRegCompC("(.*[/\\\\])?([^/\\\\]+)$");
6425 #endif /* !WIN32 */
6426
6427 if(ajRegExec(fileFilenameExp, *Pfilename))
6428 {
6429 ajRegSubI(fileFilenameExp, 1, &tmpdir);
6430
6431 /* we already have a directory */
6432 if(ajStrGetLen(tmpdir))
6433 {
6434 ajStrDel(&tmpdir);
6435 return ajFalse;
6436 }
6437
6438 ajRegSubI(fileFilenameExp, 2, &tmpname);
6439
6440 if(txt[strlen(txt)-1] == SLASH_CHAR)
6441 ajFmtPrintS(Pfilename, "%s%S", txt, tmpname);
6442 else
6443 ajFmtPrintS(Pfilename, "%s%s%S", txt, SLASH_STRING,tmpname);
6444
6445 ajStrDel(&tmpname);
6446 }
6447
6448 return ajTrue;
6449 }
6450
6451
6452
6453
6454 /* @func ajFilenameReplacePathS ***********************************************
6455 **
6456 ** Sets the directory part of a filename
6457 **
6458 ** @param [u] Pfilename [AjPStr*] Filename.
6459 ** @param [r] str [const AjPStr] New directory
6460 ** @return [AjBool] ajTrue if the replacement succeeded.
6461 **
6462 ** @release 6.0.0
6463 ** @@
6464 ******************************************************************************/
6465
ajFilenameReplacePathS(AjPStr * Pfilename,const AjPStr str)6466 AjBool ajFilenameReplacePathS(AjPStr* Pfilename, const AjPStr str)
6467 {
6468 if(!ajStrGetLen(str))
6469 return ajFalse;
6470
6471 return ajFilenameReplacePathC(Pfilename, ajStrGetPtr(str));
6472 }
6473
6474
6475
6476
6477 /* @func ajFilenameSetExtC ****************************************************
6478 **
6479 ** Sets the extension part of a filename
6480 **
6481 ** @param [u] Pfilename [AjPStr*] Filename.
6482 ** @param [r] txt [const char*] New file extension
6483 ** @return [AjBool] ajTrue if the replacement succeeded.
6484 **
6485 ** @release 6.3.0
6486 ** @@
6487 ******************************************************************************/
6488
ajFilenameSetExtC(AjPStr * Pfilename,const char * txt)6489 AjBool ajFilenameSetExtC(AjPStr* Pfilename, const char* txt)
6490 {
6491 char *p = NULL;
6492
6493 if(!txt || !*txt)
6494 return ajFalse;
6495
6496 /*ajDebug("ajFilenameSetExtC '%S' '%s'\n", *Pfilename, txt);*/
6497
6498 ajStrAssignS(&fileTmpStr,*Pfilename);
6499
6500 /* Skip any directory path */
6501 p = strrchr(ajStrGetuniquePtr(&fileTmpStr),SLASH_CHAR);
6502
6503 if (!p)
6504 p = ajStrGetuniquePtr(&fileTmpStr);
6505
6506 ajStrAppendC(&fileTmpStr,".");
6507 ajStrAppendC(&fileTmpStr,txt);
6508
6509 ajStrAssignS(Pfilename,fileTmpStr);
6510
6511 /*ajDebug("result '%S'\n", *Pfilename);*/
6512
6513 return ajTrue;
6514 }
6515
6516
6517
6518
6519 /* @func ajFilenameSetExtS ****************************************************
6520 **
6521 ** Sets the extension part of a base filename
6522 **
6523 ** @param [u] Pfilename [AjPStr*] Filename.
6524 ** @param [r] str [const AjPStr] New file extension
6525 ** @return [AjBool] ajTrue if the replacement succeeded.
6526 **
6527 ** @release 6.3.0
6528 ** @@
6529 ******************************************************************************/
6530
ajFilenameSetExtS(AjPStr * Pfilename,const AjPStr str)6531 AjBool ajFilenameSetExtS(AjPStr* Pfilename, const AjPStr str)
6532 {
6533 if(!str)
6534 return ajFalse;
6535
6536 return ajFilenameSetExtC(Pfilename, ajStrGetPtr(str));
6537 }
6538
6539
6540
6541
6542 /* @func ajFilenameSetTempname ************************************************
6543 **
6544 ** Returns an available temporary filename that can be opened for writing
6545 ** Filename will be of the form progname-time.randomnumber
6546 ** Tries 5 times to find a new filename. Returns ajFalse if not
6547 ** successful or the file cannot be opened for writing.
6548 ** This function returns only the filename, not a file pointer.
6549 **
6550 ** @param [w] Pfilename [AjPStr*] Filename of new temporary file
6551 ** @return [AjBool] True on success
6552 **
6553 ** @release 6.0.0
6554 ** @@
6555 ******************************************************************************/
6556
ajFilenameSetTempname(AjPStr * Pfilename)6557 AjBool ajFilenameSetTempname(AjPStr* Pfilename)
6558 {
6559 #if defined(AJ_IRIXLF)
6560 struct stat64 buf;
6561 #else /* !AJ_IRIXLF */
6562 struct stat buf;
6563 #endif /* AJ_IRIXLF */
6564 ajint retry;
6565 AjBool ok;
6566 AjPFile outf;
6567
6568 if(!fileTempFilename)
6569 fileTempFilename = ajStrNew();
6570
6571 ajStrAssignC(&fileDirectory,".");
6572 ajDirnameFix(&fileDirectory);
6573
6574 ajFmtPrintS(&fileTempFilename,
6575 "%S%S-%d.%d",fileDirectory,ajUtilGetProgram(),time(0),
6576 ajRandomNumber());
6577
6578 retry = 5;
6579 ok = ajTrue;
6580
6581 while(
6582 #if defined(AJ_IRIXLF)
6583 !stat64(ajStrGetPtr(fileTempFilename),&buf) && retry
6584 #else /* !AJ_IRIXLF */
6585 !stat(ajStrGetPtr(fileTempFilename),&buf) && retry
6586 #endif /* AJ_IRIXLF */
6587 )
6588 {
6589 ajFmtPrintS(&fileTempFilename,
6590 "%S%S-%d.%d",fileDirectory,ajUtilGetProgram(),time(0),
6591 ajRandomNumber());
6592 --retry;
6593 }
6594
6595 if(!retry)
6596 {
6597 ajDebug("Cannot find a unique filename [last try %S]\n",
6598 fileTempFilename);
6599 ok = ajFalse;
6600 }
6601
6602 if(!(outf = ajFileNewOutNameS(fileTempFilename)))
6603 {
6604 ajDebug("Cannot write to file %S\n",fileTempFilename);
6605 ok = ajFalse;
6606 }
6607 else
6608 {
6609 ajFileClose(&outf);
6610 ajSysFileUnlinkS(fileTempFilename);
6611 }
6612
6613 ajStrAssignS(Pfilename,fileTempFilename);
6614
6615 return ok;
6616 }
6617
6618
6619
6620
6621 /* @func ajFilenameSetTempnamePathC *******************************************
6622 **
6623 ** Returns an available temporary filename that can be opened for writing
6624 ** Filename will be of the form progname-time.randomnumber
6625 ** Tries 5 times to find a new filename. Returns ajFalse if not
6626 ** successful or the file cannot be opened for writing.
6627 ** This function returns only the filename, not a file pointer.
6628 **
6629 ** @param [w] Pfilename [AjPStr*] Filename of new temporary file
6630 ** @param [r] txt [const char*] Directory path
6631 ** @return [AjBool] True on success
6632 **
6633 ** @release 6.0.0
6634 ** @@
6635 ******************************************************************************/
6636
ajFilenameSetTempnamePathC(AjPStr * Pfilename,const char * txt)6637 AjBool ajFilenameSetTempnamePathC(AjPStr* Pfilename, const char* txt)
6638 {
6639 #if defined(AJ_IRIXLF)
6640 struct stat64 buf;
6641 #else /* !AJ_IRIXLF */
6642 struct stat buf;
6643 #endif /* AJ_IRIXLF */
6644 ajint retry;
6645 AjBool ok;
6646 AjPFile outf;
6647
6648 if(!fileTempFilename)
6649 fileTempFilename = ajStrNew();
6650
6651 ajStrAssignC(&fileDirectory,txt);
6652 ajDirnameFix(&fileDirectory);
6653
6654 ajFmtPrintS(&fileTempFilename,
6655 "%S%S-%d.%d",fileDirectory,ajUtilGetProgram(),time(0),
6656 ajRandomNumber());
6657
6658 retry = 5;
6659 ok = ajTrue;
6660
6661 while(
6662 #if defined(AJ_IRIXLF)
6663 !stat64(ajStrGetPtr(fileTempFilename),&buf) && retry
6664 #else /* !AJ_IRIXLF */
6665 !stat(ajStrGetPtr(fileTempFilename),&buf) && retry
6666 #endif /* AJ_IRIXLF */
6667 )
6668 {
6669 ajFmtPrintS(&fileTempFilename,
6670 "%S%S-%d.%d",fileDirectory,ajUtilGetProgram(),time(0),
6671 ajRandomNumber());
6672 --retry;
6673 }
6674
6675 if(!retry)
6676 {
6677 ajDebug("Cannot find a unique filename [last try %S]\n",
6678 fileTempFilename);
6679 ok = ajFalse;
6680 }
6681
6682 if(!(outf = ajFileNewOutNameS(fileTempFilename)))
6683 {
6684 ajDebug("Cannot write to file %S\n",fileTempFilename);
6685 ok = ajFalse;
6686 }
6687 else
6688 {
6689 ajFileClose(&outf);
6690 ajSysFileUnlinkS(fileTempFilename);
6691 }
6692
6693 ajStrAssignS(Pfilename,fileTempFilename);
6694
6695 return ok;
6696 }
6697
6698
6699
6700
6701 /* @func ajFilenameSetTempnamePathS *******************************************
6702 **
6703 ** Returns an available temporary filename that can be opened for writing
6704 ** Filename will be of the form progname-time.randomnumber
6705 ** Tries 5 times to find a new filename. Returns ajFalse if not
6706 ** successful or the file cannot be opened for writing.
6707 ** This function returns only the filename, not a file pointer.
6708 **
6709 ** @param [w] Pfilename [AjPStr*] Filename of new temporary file
6710 ** @param [r] str [const AjPStr] Directory path
6711 ** @return [AjBool] True on success
6712 **
6713 ** @release 6.0.0
6714 ** @@
6715 ******************************************************************************/
6716
ajFilenameSetTempnamePathS(AjPStr * Pfilename,const AjPStr str)6717 AjBool ajFilenameSetTempnamePathS(AjPStr* Pfilename, const AjPStr str)
6718 {
6719 #if defined(AJ_IRIXLF)
6720 struct stat64 buf;
6721 #else /* !AJ_IRIXLF */
6722 struct stat buf;
6723 #endif /* AJ_IRIXLF */
6724 ajint retry;
6725 AjBool ok;
6726 AjPFile outf;
6727
6728 if(!fileTempFilename)
6729 fileTempFilename = ajStrNew();
6730
6731 ajStrAssignS(&fileDirectory,str);
6732 ajDirnameFix(&fileDirectory);
6733
6734 ajFmtPrintS(&fileTempFilename,
6735 "%S%S-%d.%d",fileDirectory,ajUtilGetProgram(),time(0),
6736 ajRandomNumber());
6737
6738 retry = 5;
6739 ok = ajTrue;
6740
6741 while(
6742 #if defined(AJ_IRIXLF)
6743 !stat64(ajStrGetPtr(fileTempFilename),&buf) && retry
6744 #else /* !AJ_IRIXLF */
6745 !stat(ajStrGetPtr(fileTempFilename),&buf) && retry
6746 #endif /* AJ_IRIXLF */
6747 )
6748 {
6749 ajFmtPrintS(&fileTempFilename,
6750 "%S%S-%d.%d",fileDirectory,ajUtilGetProgram(),time(0),
6751 ajRandomNumber());
6752 --retry;
6753 }
6754
6755 if(!retry)
6756 {
6757 ajDebug("Cannot find a unique filename [last try %S]\n",
6758 fileTempFilename);
6759 ok = ajFalse;
6760 }
6761
6762 if(!(outf = ajFileNewOutNameS(fileTempFilename)))
6763 {
6764 ajDebug("Cannot write to file %S\n",fileTempFilename);
6765 ok = ajFalse;
6766 }
6767 else
6768 {
6769 ajFileClose(&outf);
6770 ajSysFileUnlinkS(fileTempFilename);
6771 }
6772
6773 ajStrAssignS(Pfilename,fileTempFilename);
6774
6775 return ok;
6776 }
6777
6778
6779
6780
6781 /* @func ajFilenameTrimAll ****************************************************
6782 **
6783 ** Truncates a filename to a basic file name.
6784 **
6785 ** @param [uP] Pfilename [AjPStr*] File name
6786 ** @return [AjBool] ajTrue on success, and returns a filename.
6787 ** ajFalse on failure, and returns an empty string.
6788 **
6789 ** @release 6.0.0
6790 ** @@
6791 ******************************************************************************/
6792
ajFilenameTrimAll(AjPStr * Pfilename)6793 AjBool ajFilenameTrimAll(AjPStr* Pfilename)
6794 {
6795 /* entryname at end */
6796 if(!fileEntryExp)
6797 fileEntryExp = ajRegCompC(":([A-Za-z0-9_-]+)$");
6798
6799 if(ajRegExec(fileEntryExp, *Pfilename))
6800 {
6801 ajRegSubI(fileEntryExp, 1, Pfilename);
6802 return ajTrue;
6803 }
6804
6805 /* name.ext */
6806 if(!fileFileExp)
6807 fileFileExp = ajRegCompC("([A-Za-z0-9_-]+)[.][A-Za-z0-9_-]+$");
6808
6809 if(ajRegExec(fileFileExp, *Pfilename))
6810 {
6811 ajRegSubI(fileFileExp, 1, Pfilename);
6812 return ajTrue;
6813 }
6814
6815 /* last valid word */
6816 if(!fileRestExp)
6817 fileRestExp = ajRegCompC("([A-Za-z0-9_-]+)[^A-Za-z0-9_-]*$");
6818
6819 if(ajRegExec(fileRestExp, *Pfilename))
6820 {
6821 ajRegSubI(fileRestExp, 1, Pfilename);
6822 return ajTrue;
6823 }
6824
6825 ajStrAssignClear(Pfilename);
6826
6827 return ajFalse;
6828 }
6829
6830
6831
6832
6833 /* @func ajFilenameTrimExt ****************************************************
6834 **
6835 ** Trims the extension (if any) from a filename
6836 **
6837 ** @param [u] Pfilename [AjPStr*] Filename
6838 ** @return [AjBool] ajTrue is there was an extension
6839 **
6840 ** @release 6.0.0
6841 ******************************************************************************/
6842
ajFilenameTrimExt(AjPStr * Pfilename)6843 AjBool ajFilenameTrimExt(AjPStr* Pfilename)
6844 {
6845 ajlong i;
6846 ajlong len;
6847
6848 if(!ajStrGetLen(*Pfilename))
6849 return ajFalse;
6850
6851 len = ajStrGetLen(*Pfilename);
6852 i = ajStrFindlastC(*Pfilename, ".");
6853
6854 if(i < 0)
6855 return ajFalse;
6856
6857 ajStrCutEnd(Pfilename, (size_t) (len-i));
6858
6859 return ajTrue;
6860 }
6861
6862
6863
6864
6865 /* @func ajFilenameTrimPath ***************************************************
6866 **
6867 ** Trims the directory path (if any) from a filename
6868 **
6869 ** @param [u] Pfilename [AjPStr*] Filename
6870 ** @return [AjBool] ajTrue is there was a directory
6871 **
6872 ** @release 6.0.0
6873 ******************************************************************************/
6874
ajFilenameTrimPath(AjPStr * Pfilename)6875 AjBool ajFilenameTrimPath(AjPStr* Pfilename)
6876 {
6877 ajlong i;
6878
6879 if(!ajStrGetLen(*Pfilename))
6880 return ajFalse;
6881
6882 i = ajStrFindlastC(*Pfilename, SLASH_STRING);
6883
6884 if(i < 0)
6885 return ajFalse;
6886
6887 ajStrCutStart(Pfilename, (size_t) (i+1));
6888
6889 return ajTrue;
6890 }
6891
6892
6893
6894
6895 /* @func ajFilenameTrimPathExt ************************************************
6896 **
6897 ** Trims the directory path (if any) and extension (if any) from a filename.
6898 **
6899 ** @param [u] Pfilename [AjPStr*] Filename
6900 ** @return [AjBool] ajTrue is there was a directory path or extension.
6901 **
6902 ** @release 6.0.0
6903 ******************************************************************************/
6904
ajFilenameTrimPathExt(AjPStr * Pfilename)6905 AjBool ajFilenameTrimPathExt(AjPStr* Pfilename)
6906 {
6907 ajlong i;
6908 ajlong j;
6909 ajlong len;
6910
6911 if(!ajStrGetLen(*Pfilename))
6912 return ajFalse;
6913
6914 i = ajStrFindlastC(*Pfilename, SLASH_STRING);
6915
6916 if(i >= 0)
6917 ajStrCutStart(Pfilename, (size_t) (i+1));
6918
6919 len = ajStrGetLen(*Pfilename);
6920 j = ajStrFindlastC(*Pfilename, ".");
6921
6922 if(j >= 0)
6923 ajStrCutEnd(Pfilename, (size_t) (len-j));
6924
6925 if((i < 0) && (j < 0))
6926 return ajFalse;
6927
6928 return ajTrue;
6929 }
6930
6931
6932
6933
6934 /* @datasection [AjPStr] Filename wildcard functions **************************
6935 **
6936 ** Functions operating on strings containing filenames with possible wildcards
6937 **
6938 ** @nam2rule Filewildname Operations on wildcard filename strings
6939 **
6940 ******************************************************************************/
6941
6942
6943
6944
6945 /* @section Filename tests ****************************************************
6946 **
6947 ** Tests on filenames and searching the file system
6948 **
6949 ** @nam3rule Exists tests whether file exists in current directory
6950 ** @nam4rule Dir Tests whether file exists and is a directory
6951 **
6952 ** @argrule * wildname [const AjPStr] Filename string
6953 ** @argrule Dir path [const AjPStr] Directory path
6954 **
6955 ** @valrule Exists [AjBool] True if file exists with any requested access
6956 ** @fcategory use
6957 **
6958 ** @fdata [AjPStr]
6959 **
6960 ******************************************************************************/
6961
6962
6963
6964
6965 /* @func ajFilewildnameExists *************************************************
6966 **
6967 ** Returns true if wildcard filename matches an existing file
6968 **
6969 ** @param [r] wildname [const AjPStr] Wildcard filename.
6970 ** @return [AjBool] ajTrue on success
6971 **
6972 ** @release 6.6.0
6973 ** @@
6974 ******************************************************************************/
6975
ajFilewildnameExists(const AjPStr wildname)6976 AjBool ajFilewildnameExists(const AjPStr wildname)
6977 {
6978 AjBool ret = ajFalse;
6979
6980 AjPStr userstr = NULL;
6981 AjPStr reststr = NULL;
6982
6983 AjPStr dirname = NULL;
6984 AjPStr wildfilename = NULL;
6985
6986 char *hdir = NULL;
6987
6988 ajDebug("ajFilewildnameExists '%S'\n", wildname);
6989
6990 if(ajStrMatchC(wildname, "stdin"))
6991 return ajTrue;
6992
6993 if(ajStrGetCharLast(wildname) == '|') /* pipe character at end */
6994 return ajTrue;
6995
6996 /* keep a copy of the filename */
6997
6998 ajStrAssignS(&fileNameTmp, wildname);
6999
7000 /* replace ~user/ or ~/ with directory */
7001
7002 if(ajStrGetCharFirst(fileNameTmp) == '~')
7003 {
7004 ajDebug("starts with '~'\n");
7005
7006 if(!fileUserExp)
7007 fileUserExp = ajRegCompC("^~([^/\\\\]*)");
7008
7009 ajRegExec(fileUserExp, fileNameTmp);
7010 ajRegSubI(fileUserExp, 1, &userstr);
7011 ajRegPost(fileUserExp, &reststr);
7012 ajDebug(" user: '%S' rest: '%S'\n", userstr, reststr);
7013
7014 if(ajStrGetLen(userstr))
7015 {
7016 /* username specified */
7017 hdir = ajSysGetHomedirFromName(ajStrGetPtr(userstr));
7018
7019 if(!hdir)
7020 {
7021 ajStrDel(&userstr);
7022 ajStrDelStatic(&fileNameTmp);
7023 ajStrDel(&reststr);
7024
7025 return ajFalse;
7026 }
7027
7028 ajFmtPrintS(&fileNameTmp, "%s%S", hdir, reststr);
7029 AJFREE(hdir);
7030
7031 ajDebug("use getpwnam: '%S'\n", fileNameTmp);
7032 }
7033 else
7034 {
7035 /* just ~/ */
7036 hdir = ajSysGetHomedir();
7037
7038 if(hdir)
7039 {
7040 ajFmtPrintS(&fileNameTmp, "%s%S", hdir, reststr);
7041 AJFREE(hdir);
7042 }
7043 else
7044 ajFmtPrintS(&fileNameTmp,"%S",reststr);
7045
7046 ajDebug("use HOME: '%S'\n", fileNameTmp);
7047 }
7048
7049 ajStrDel(&userstr);
7050 ajStrDel(&reststr);
7051 }
7052
7053
7054 if(!fileWildExp)
7055 fileWildExp = ajRegCompC("(.*/)?([^/]*[*?][^/]*)$");
7056
7057 /* wildcard file names (directory names do not allow wildcards) */
7058
7059 if(ajRegExec(fileWildExp, fileNameTmp))
7060 {
7061 ajRegSubI(fileWildExp, 1, &dirname);
7062 ajRegSubI(fileWildExp, 2, &wildfilename);
7063 ajDebug("wild dir '%S' files '%S'\n", dirname, wildfilename);
7064 ret = ajFilewildnameExistsDir(wildfilename, dirname);
7065 ajStrDelStatic(&fileNameTmp);
7066 ajStrDel(&dirname);
7067 ajStrDel(&wildfilename);
7068
7069 return ret;
7070 }
7071
7072 #ifdef WIN32
7073 if(ajStrMatchC(wildname, "/dev/null"))
7074 {
7075 ajStrDelStatic(&fileNameTmp);
7076 return ajTrue;
7077 }
7078 else
7079 #endif /* WIN32 */
7080
7081 ret = ajFilenameExists(fileNameTmp);
7082 ajStrDelStatic(&fileNameTmp);
7083
7084 return ret;
7085 }
7086
7087
7088
7089
7090 /* @func ajFilewildnameExistsDir **********************************************
7091 **
7092 ** Opens directory "dir"
7093 ** Looks for file(s) matching wildcard filename
7094 **
7095 ** @param [r] wildname [const AjPStr] Wildcard filename.
7096 ** @param [r] path [const AjPStr] Directory
7097 ** @return [AjBool] True if one or more files matched.
7098 **
7099 ** @release 6.6.0
7100 ** @@
7101 ******************************************************************************/
7102
ajFilewildnameExistsDir(const AjPStr wildname,const AjPStr path)7103 AjBool ajFilewildnameExistsDir(const AjPStr wildname, const AjPStr path)
7104 {
7105 DIR* dp;
7106 #if defined(AJ_IRIXLF)
7107 struct dirent64 *de;
7108 #else /* !AJ_IRIXLF */
7109 struct dirent* de;
7110 #endif /* AJ_IRIXLF */
7111
7112 #ifdef _POSIX_C_SOURCE
7113 char buf[sizeof(struct dirent)+MAXNAMLEN];
7114 #endif /* _POSIX_C_SOURCE */
7115
7116 if(ajStrGetLen(path))
7117 ajStrAssignS(&fileDirfixTmp, path);
7118 else
7119 ajStrAssignC(&fileDirfixTmp, CURRENT_DIR);
7120
7121 if(ajStrGetCharLast(fileDirfixTmp) != SLASH_CHAR)
7122 ajStrAppendC(&fileDirfixTmp, SLASH_STRING);
7123
7124 dp = fileOpenDir(&fileDirfixTmp);
7125
7126 if(!dp)
7127 return ajFalse;
7128
7129 while(
7130 #if defined(AJ_IRIXLF)
7131 #ifdef _POSIX_C_SOURCE
7132 !readdir64_r(dp,(struct dirent64 *)buf,&de)
7133 #else /* !_POSIX_C_SOURCE */
7134 (de=readdir64(dp))
7135 #endif /* _POSIX_C_SOURCE */
7136 #else /* !AJ_IRIXLF */
7137 #ifdef _POSIX_C_SOURCE
7138 !readdir_r(dp,(struct dirent *)buf,&de)
7139 #else /* _POSIX_C_SOURCE */
7140 (de=readdir(dp))
7141 #endif /* _POSIX_C_SOURCE */
7142 #endif /* AJ_IRIXLF */
7143 )
7144 {
7145 #ifdef _POSIX_C_SOURCE
7146 if(!de)
7147 break;
7148 #endif /* _POSIX_C_SOURCE */
7149 /* skip deleted files with inode zero */
7150 #ifndef __CYGWIN__
7151 if(!de->d_ino)
7152 continue;
7153 #endif /* !__CYGWIN__ */
7154
7155 if(ajCharMatchC(de->d_name, "."))
7156 continue;
7157
7158 if(ajCharMatchC(de->d_name, ".."))
7159 continue;
7160
7161 if(!ajCharMatchWildS(de->d_name, wildname))
7162 continue;
7163
7164 ajDebug("accept '%s'\n", de->d_name);
7165 closedir(dp);
7166 return ajTrue;
7167 }
7168
7169 ajDebug("no files for '%S' '%S'\n", path, wildname);
7170 closedir(dp);
7171
7172 return ajFalse;
7173 }
7174
7175
7176
7177
7178 /* @datasection [AjPStr] Directory name functions *****************************
7179 **
7180 ** Functions operating on strings containing directory names
7181 **
7182 ** @nam2rule Dirname Operations on directory name strings
7183 **
7184 ******************************************************************************/
7185
7186
7187
7188
7189 /* @section Directory name modifiers ******************************************
7190 **
7191 ** These functions overwrite a previous filename
7192 **
7193 ** @nam3rule Fill Fill in all parts of incomplete directory name
7194 ** @nam3rule Fix Fix incomplete directory name
7195 ** @nam4rule FixExists Fix incomplete directory name and test it can be opened
7196 ** @nam3rule Up Change to parent directory
7197 **
7198 ** @suffix Ext Filename extension
7199 ** @suffix Path Filename path
7200 ** @suffix C New character value
7201 ** @suffix S New string value
7202 **
7203 ** @argrule * Pdirname [AjPStr*] Filename
7204 ** @argrule C txt [const char*] New character value
7205 ** @argrule S str [const AjPStr] New string value
7206 **
7207 ** @valrule * [void]
7208 ** @valrule *Exists [AjBool] True on success
7209 ** @valrule *Fill [AjBool] True on success
7210 ** @valrule *Up [AjBool] True on success
7211 **
7212 ** @fcategory modify
7213 **
7214 ** @fdata [AjPStr]
7215 **
7216 ******************************************************************************/
7217
7218
7219
7220
7221 /* @func ajDirnameFillPath ****************************************************
7222 **
7223 ** Checks that a string is a valid directory, and makes sure it has the
7224 ** full path definition.
7225 **
7226 ** @param [u] Pdirname [AjPStr*] Directory path
7227 ** @return [AjBool] true if a valid directory.
7228 **
7229 ** @release 6.0.0
7230 ** @@
7231 ******************************************************************************/
7232
ajDirnameFillPath(AjPStr * Pdirname)7233 AjBool ajDirnameFillPath(AjPStr* Pdirname)
7234 {
7235 DIR* odir;
7236 AjPStr cwdpath = NULL;
7237
7238 ajDebug("ajDirnameFillPath '%S'\n", *Pdirname);
7239
7240 /* appends trailing slash if needed */
7241 odir = fileOpenDir(Pdirname);
7242
7243 if(!odir)
7244 return ajFalse;
7245
7246 free(odir);
7247
7248 ajDebug("So far '%S'\n", *Pdirname);
7249
7250 /* full path already */
7251 if(*ajStrGetPtr(*Pdirname) == SLASH_CHAR)
7252 return ajTrue;
7253
7254 /* current directory */
7255 if(ajStrMatchC(*Pdirname, CURRENT_DIR))
7256 {
7257 ajStrAssignS(Pdirname, ajFileValueCwd());
7258 ajDebug("Current '%S'\n", *Pdirname);
7259
7260 return ajTrue;
7261 }
7262
7263 /* going up */
7264 ajStrAssignS(&cwdpath, ajFileValueCwd());
7265
7266 while(ajStrPrefixC(*Pdirname, UP_DIR))
7267 {
7268 ajDirnameUp(&cwdpath);
7269 ajStrKeepRange(Pdirname, 3, -1);
7270 ajDebug("Going up '%S' '%S'\n", *Pdirname, cwdpath);
7271 }
7272
7273 ajStrInsertS(Pdirname, 0, cwdpath);
7274
7275 ajDebug("Full path '%S'\n", *Pdirname);
7276
7277 ajStrDel(&cwdpath);
7278
7279 return ajTrue;
7280 }
7281
7282
7283
7284
7285 /* @func ajDirnameFix *********************************************************
7286 **
7287 ** If the directory name has no trailing slash (on Unix) then one is
7288 ** added. This is why the directory name must be writable.
7289 **
7290 ** @param [u] Pdirname [AjPStr*] Directory name.
7291 ** @return [void]
7292 **
7293 ** @release 6.0.0
7294 ** @@
7295 ******************************************************************************/
7296
ajDirnameFix(AjPStr * Pdirname)7297 void ajDirnameFix(AjPStr* Pdirname)
7298 {
7299 if(ajStrGetCharLast(*Pdirname) != SLASH_CHAR)
7300 ajStrAppendC(Pdirname, SLASH_STRING);
7301
7302 return;
7303 }
7304
7305
7306
7307
7308 /* @func ajDirnameFixExists ***************************************************
7309 **
7310 ** Checks that a string is a valid existing directory, and appends a
7311 ** trailing '/' if it is missing.
7312 **
7313 ** @param [u] Pdirname [AjPStr*] Directory path
7314 ** @return [AjBool] true if a valid directory.
7315 **
7316 ** @release 6.0.0
7317 ** @@
7318 ******************************************************************************/
7319
ajDirnameFixExists(AjPStr * Pdirname)7320 AjBool ajDirnameFixExists(AjPStr* Pdirname)
7321 {
7322 DIR* odir;
7323
7324 odir = fileOpenDir(Pdirname); /* appends trailing slash if needed */
7325
7326 if(!odir)
7327 return ajFalse;
7328
7329 closedir(odir);
7330
7331 return ajTrue;
7332 }
7333
7334
7335
7336
7337 /* @func ajDirnameUp **********************************************************
7338 **
7339 ** Changes directory name to one level up
7340 **
7341 ** @param [u] Pdirname [AjPStr*] Directory name.
7342 ** @return [AjBool] ajTrue on success.
7343 **
7344 ** @release 6.0.0
7345 ** @@
7346 ******************************************************************************/
7347
ajDirnameUp(AjPStr * Pdirname)7348 AjBool ajDirnameUp(AjPStr* Pdirname)
7349 {
7350 AjBool modded = ajFalse;
7351
7352 const char *p;
7353 const char *q;
7354 ajint len;
7355
7356 len = ajStrGetLen(*Pdirname);
7357 p = ajStrGetPtr(*Pdirname);
7358 q = p + len -2;
7359
7360 if(q > p)
7361 {
7362 while(q!=p && *q==SLASH_CHAR)
7363 --q;
7364
7365 while(q!=p && *q!=SLASH_CHAR)
7366 --q;
7367
7368 if(q-p > 1)
7369 {
7370 ajStrCutEnd(Pdirname, len-(q-p)-1);
7371 modded = ajTrue;
7372 }
7373 }
7374
7375 return modded;
7376 }
7377
7378
7379
7380
7381 /* @section Directory name functions ******************************************
7382 **
7383 ** Functions using a directory name
7384 **
7385 ** @nam3rule Print Print directory or filenames
7386 ** @nam4rule Recursive Step through subdirectories
7387 **
7388 ** @suffix Ignore Process list of sub directory names to ignore
7389 ** @argrule * path [const AjPStr] directory name
7390 ** @argrule Ignore ignorelist [AjPList] List of names to ignore
7391 ** @argrule Print outfile [AjPFile] Output file
7392 **
7393 ** @valrule * [void]
7394 **
7395 ** @fcategory use
7396 **
7397 ** @fdata [AjPStr]
7398 **
7399 ******************************************************************************/
7400
7401
7402
7403
7404 /* @func ajDirnamePrintRecursiveIgnore ****************************************
7405 **
7406 ** Recursively scan through a directory, printing directory and file names
7407 **
7408 ** @param [r] path [const AjPStr] Directory to scan
7409 ** @param [u] ignorelist [AjPList] List of directories to ignore
7410 ** @param [u] outfile [AjPFile] File for "show" results (or NULL)
7411 **
7412 ** @return [void]
7413 **
7414 ** @release 6.0.0
7415 ** @@
7416 ******************************************************************************/
7417
ajDirnamePrintRecursiveIgnore(const AjPStr path,AjPList ignorelist,AjPFile outfile)7418 void ajDirnamePrintRecursiveIgnore(const AjPStr path,
7419 AjPList ignorelist, AjPFile outfile)
7420 {
7421 AjPList dirs = NULL;
7422 AjIList iter = NULL;
7423 DIR *indir;
7424 #if defined(AJ_IRIXLF)
7425 struct dirent64 *dp;
7426 #else /* !AJ_IRIXLF */
7427 struct dirent *dp;
7428 #endif /* AJ_IRIXLF */
7429 AjPStr s = NULL;
7430 AjPStr t = NULL;
7431
7432 AjPStr tstr = NULL;
7433
7434 AjBool flag;
7435 AjPStr tpath = NULL;
7436 AjPList plist = NULL;
7437
7438 #ifdef _POSIX_C_SOURCE
7439 char buf[sizeof(struct dirent)+MAXNAMLEN];
7440 #endif /* _POSIX_C_SOURCE */
7441
7442 tpath = ajStrNewS(path);
7443
7444 ajFmtPrintF(outfile,"\n\nDIRECTORY: %S\n\n",path);
7445
7446 if(!ajDirnameFixExists(&tpath))
7447 {
7448 ajStrDel(&tpath);
7449
7450 return;
7451 }
7452
7453
7454 if(!(indir=opendir(ajStrGetPtr(tpath))))
7455 {
7456 ajStrDel(&tpath);
7457
7458 return;
7459 }
7460
7461
7462 s = ajStrNew();
7463 dirs = ajListNew();
7464 plist = ajListNew();
7465
7466 while(
7467 #if defined(AJ_IRIXLF)
7468 #ifdef _POSIX_C_SOURCE
7469 !readdir64_r(indir,(struct dirent64 *)buf,&dp)
7470 #else /* !_POSIX_C_SOURCE */
7471 (dp=readdir64(indir))
7472 #endif /* _POSIX_C_SOURCE */
7473 #else /* !AJ_IRIXLF */
7474 #ifdef _POSIX_C_SOURCE
7475 !readdir_r(indir,(struct dirent *)buf,&dp)
7476 #else /* !_POSIX_C_SOURCE */
7477 (dp=readdir(indir))
7478 #endif /* _POSIX_C_SOURCE */
7479 #endif /* AJ_IRIXLF */
7480 )
7481 {
7482 #ifdef _POSIX_C_SOURCE
7483 if(!dp)
7484 break;
7485 #endif /* _POSIX_C_SOURCE */
7486 #ifndef __CYGWIN__
7487 if(!dp->d_ino ||
7488 !strcmp(dp->d_name,".") ||
7489 !strcmp(dp->d_name,".."))
7490 continue;
7491 #else /* __CYGWIN__ */
7492 if(!strcmp(dp->d_name,".") ||
7493 !strcmp(dp->d_name,".."))
7494 continue;
7495 #endif /* !__CYGWIN__ */
7496 ajStrAssignS(&s,tpath);
7497 /* ajStrAppendC(&s,SLASH_STRING);*/
7498 ajStrAppendC(&s,dp->d_name);
7499
7500 /* Its a directory */
7501 if(ajFilenameExistsDir(s))
7502 {
7503 /* Ignore selected directories */
7504 if(ajListGetLength(ignorelist))
7505 {
7506 flag = ajFalse;
7507 iter = ajListIterNewread(ignorelist);
7508
7509 while(!ajListIterDone(iter))
7510 {
7511 t = ajListIterGet(iter);
7512
7513 if(!strcmp(ajStrGetPtr(t),dp->d_name))
7514 {
7515 flag = ajTrue;
7516 break;
7517 }
7518 }
7519
7520 ajListIterDel(&iter);
7521
7522 if(flag)
7523 continue;
7524 }
7525
7526 if(!ajFilenameExistsRead(s) || !ajFilenameExistsExec(s))
7527 continue;
7528
7529 t = ajStrNewC(ajStrGetPtr(s));
7530 ajListPushAppend(dirs,(void *)t);
7531 }
7532 else if(ajFilenameExistsRead(s))
7533 {
7534 tstr = ajStrNew();
7535 ajStrAssignC(&tstr,dp->d_name);
7536 ajListPush(plist, (void *)tstr);
7537
7538
7539 }
7540 }
7541
7542 closedir(indir);
7543
7544 ajListSort(plist, &ajStrVcmp);
7545 while(ajListPop(plist,(void **)&tstr))
7546 {
7547 ajFmtPrintF(outfile," %S\n",tstr);
7548 ajStrDel(&tstr);
7549 }
7550
7551 ajListFree(&plist);
7552
7553 while(ajListPop(dirs,(void **)&t))
7554 {
7555 ajDirnamePrintRecursiveIgnore(t, ignorelist, outfile);
7556 ajStrDel(&t);
7557 }
7558
7559 ajStrDel(&s);
7560 ajStrDel(&tpath);
7561 ajListFree(&dirs);
7562
7563
7564 return;
7565 }
7566
7567
7568
7569
7570 /* @datasection [AjPlist] Lists of filenames **********************************
7571 **
7572 ** Functions building and managing lists of filenames
7573 **
7574 ** @nam2rule Filelist
7575 **
7576 ******************************************************************************/
7577
7578
7579
7580
7581 /* @section File list addition ************************************************
7582 **
7583 ** Functions that add filenames to a list
7584 **
7585 ** @nam3rule Add Adds names to a list
7586 ** @nam4rule Path Directory path provided
7587 ** @nam5rule Wild Wildcard filename provided
7588 ** @suffix Recursive Process subdirectories
7589 ** @suffix Ignore List of subdirectories to be ignored
7590 ** @suffix Directory Directory object provided
7591 ** @suffix Dir Include directories in the list
7592 ** @nam4rule Listname List of files or lists
7593 **
7594 ** @argrule * list [AjPList] Filename list
7595 ** @argrule Listname listname [const AjPStr] Commandline list of filenames
7596 ** @argrule Directory dir [const AjPDir] Directory object
7597 ** @argrule Path path [const AjPStr] Pathname of directory
7598 ** @argrule Wild wildname [const AjPStr] Wildcard filename to add
7599 ** @argrule Ignore ignorelist [AjPList] Subdirectory name list to ignore
7600 **
7601 ** @valrule * [ajint] Number of entries added to the list
7602 **
7603 ** @fcategory modify
7604 **
7605 ** @fdata [AjPlist]
7606 **
7607 ******************************************************************************/
7608
7609
7610
7611
7612 /* @func ajFilelistAddDirectory ***********************************************
7613 **
7614 ** Scan through a directory object returning all filenames that are
7615 ** not directories. Uses the file extension and any other attributes
7616 ** of the directory object. An empty string as a file extension accepts
7617 ** only files that have no extension.
7618 **
7619 ** @param [u] list [AjPList] List for matching entries
7620 ** @param [r] dir [const AjPDir] Directory to scan
7621 **
7622 ** @return [ajint] number of entries in list
7623 **
7624 ** @release 6.3.0
7625 ** @@
7626 ******************************************************************************/
7627
ajFilelistAddDirectory(AjPList list,const AjPDir dir)7628 ajint ajFilelistAddDirectory(AjPList list,
7629 const AjPDir dir)
7630 {
7631 ajulong oldsize;
7632 DIR *indir;
7633 #if defined(AJ_IRIXLF)
7634 struct dirent64 *dp;
7635 #else /* !AJ_IRIXLF */
7636 struct dirent *dp;
7637 #endif /* AJ_IRIXLF */
7638 AjPStr f = NULL;
7639 AjPStr s = NULL;
7640 AjPStr t = NULL;
7641 AjPStr e = NULL;
7642
7643 AjPStr tpath = NULL;
7644 #ifdef _POSIX_C_SOURCE
7645 char buf[sizeof(struct dirent)+MAXNAMLEN];
7646 #endif /* _POSIX_C_SOURCE */
7647
7648 AjBool doprefix = AJFALSE;
7649 AjBool doextension = AJFALSE;
7650
7651 if(!dir)
7652 return 0;
7653
7654 if(dir->Prefix)
7655 doprefix = ajTrue;
7656 if(dir->Extension)
7657 {
7658 if(ajStrGetCharFirst(dir->Extension) == '.')
7659 e = ajStrNewS(dir->Extension);
7660 else if(ajStrGetLen(dir->Extension))
7661 ajFmtPrintS(&e, ".%S", dir->Extension);
7662
7663 doextension = ajTrue;
7664 }
7665
7666 oldsize = ajListGetLength(list);
7667
7668 tpath = ajStrNewS(dir->Name);
7669
7670 ajDebug("ajFilelistAddDir '%S' oldsize:%Lu\n",
7671 tpath, oldsize);
7672
7673 if(!ajDirnameFixExists(&tpath))
7674 {
7675 ajDebug("... not a directory '%S'\n", tpath);
7676 ajStrDel(&tpath);
7677
7678 return 0;
7679 }
7680
7681
7682 if(!(indir=opendir(ajStrGetPtr(tpath))))
7683 {
7684 ajDebug("... failed to open directory '%S'\n", tpath);
7685 ajStrDel(&tpath);
7686
7687 return 0;
7688 }
7689
7690
7691 s = ajStrNew();
7692 f = ajStrNew();
7693
7694 while(
7695 #if defined(AJ_IRIXLF)
7696 #ifdef _POSIX_C_SOURCE
7697 !readdir64_r(indir,(struct dirent64 *)buf,&dp)
7698 #else /* !_POSIX_C_SOURCE */
7699 (dp=readdir64(indir))
7700 #endif /* _POSIX_C_SOURCE */
7701 #else /* !AJ_IRIXLF */
7702 #ifdef _POSIX_C_SOURCE
7703 !readdir_r(indir,(struct dirent *)buf,&dp)
7704 #else /* !_POSIX_C_SOURCE */
7705 (dp=readdir(indir))
7706 #endif /* _POSIX_C_SOURCE */
7707 #endif /* AJ_IRIXLF */
7708 )
7709 {
7710 #ifdef _POSIX_C_SOURCE
7711 if(!dp)
7712 break;
7713 #endif /* _POSIX_C_SOURCE */
7714 #ifndef __CYGWIN__
7715 if(!dp->d_ino ||
7716 !strcmp(dp->d_name,".") ||
7717 !strcmp(dp->d_name,".."))
7718 continue;
7719 #else /* __CYGWIN__ */
7720 if(!strcmp(dp->d_name,".") ||
7721 !strcmp(dp->d_name,".."))
7722 continue;
7723 #endif /* !__CYGWIN__ */
7724
7725 ajStrAssignC(&f,dp->d_name);
7726
7727 if(doprefix && !ajStrPrefixS(f, dir->Prefix))
7728 continue;
7729
7730 if(doextension)
7731 {
7732 if(e)
7733 {
7734 if(!ajStrSuffixS(f, e))
7735 continue;
7736 }
7737 else
7738 {
7739 if(ajStrFindAnyK(f,'.') >= 0)
7740 continue;
7741 }
7742 }
7743
7744 ajStrAssignS(&s,tpath);
7745 ajStrAppendS(&s,f);
7746
7747 if(ajFilenameExistsDir(s))
7748 continue;
7749
7750 ajDebug("... add to list '%S'\n",
7751 s);
7752
7753 t = ajStrNewS(s);
7754 ajListPushAppend(list,(void *)t);
7755
7756 }
7757 closedir(indir);
7758
7759
7760 ajStrDel(&e);
7761 ajStrDel(&f);
7762 ajStrDel(&s);
7763 ajStrDel(&tpath);
7764
7765 return (ajuint) (ajListGetLength(list) - oldsize);
7766 }
7767
7768
7769
7770
7771 /* @func ajFilelistAddListname ************************************************
7772 **
7773 ** Adds to a list of files that match a comma-separated string of
7774 ** filenames which can include wildcards or listfiles
7775 **
7776 ** @param [u] list [AjPList] List of filenames
7777 ** @param [r] listname [const AjPStr] comma-separated filename list
7778 **
7779 ** @return [ajint] Number of entries added to list
7780 **
7781 ** @release 6.0.0
7782 ** @@
7783 ******************************************************************************/
7784
ajFilelistAddListname(AjPList list,const AjPStr listname)7785 ajint ajFilelistAddListname(AjPList list, const AjPStr listname)
7786 {
7787 ajulong oldsize;
7788 AjPStr *fstr = NULL;
7789 ajint ncl;
7790 ajint i;
7791 ajint rlevel = 0;
7792
7793 oldsize = ajListGetLength(list);
7794 ncl = ajArrCommaList(listname,&fstr);
7795
7796 for(i=0;i<ncl;++i)
7797 {
7798 fileListRecurs(fstr[i],list,&rlevel);
7799 ajStrDel(&fstr[i]);
7800 }
7801
7802 AJFREE(fstr);
7803
7804 return (ajuint) (ajListGetLength(list) - oldsize);
7805 }
7806
7807
7808
7809
7810 /* @func ajFilelistAddPath ****************************************************
7811 **
7812 ** Scan through a directory returning all filenames excluding directory names
7813 **
7814 ** @param [u] list [AjPList] List for matching entries
7815 ** @param [r] path [const AjPStr] Directory to scan
7816 **
7817 ** @return [ajint] number of entries in list
7818 **
7819 ** @release 6.0.0
7820 ** @@
7821 ******************************************************************************/
7822
ajFilelistAddPath(AjPList list,const AjPStr path)7823 ajint ajFilelistAddPath(AjPList list,
7824 const AjPStr path)
7825 {
7826 ajulong oldsize;
7827 DIR *indir;
7828 #if defined(AJ_IRIXLF)
7829 struct dirent64 *dp;
7830 #else /* !AJ_IRIXLF */
7831 struct dirent *dp;
7832 #endif /* AJ_IRIXLF */
7833 AjPStr s = NULL;
7834 AjPStr t = NULL;
7835 AjPStr tpath = NULL;
7836 #ifdef _POSIX_C_SOURCE
7837 char buf[sizeof(struct dirent)+MAXNAMLEN];
7838 #endif /* _POSIX_C_SOURCE */
7839
7840 oldsize = ajListGetLength(list);
7841
7842 tpath = ajStrNewS(path);
7843
7844 ajDebug("ajFilelistAddPath '%S' oldsize:%Lu\n",
7845 path, oldsize);
7846
7847 if(!ajDirnameFixExists(&tpath))
7848 {
7849 ajDebug("... not a directory '%S'\n", tpath);
7850 ajStrDel(&tpath);
7851
7852 return 0;
7853 }
7854
7855
7856 if(!(indir=opendir(ajStrGetPtr(tpath))))
7857 {
7858 ajDebug("... failed to open directory '%S'\n", tpath);
7859 ajStrDel(&tpath);
7860
7861 return 0;
7862 }
7863
7864
7865 s = ajStrNew();
7866
7867 while(
7868 #if defined(AJ_IRIXLF)
7869 #ifdef _POSIX_C_SOURCE
7870 !readdir64_r(indir,(struct dirent64 *)buf,&dp)
7871 #else /* !_POSIX_C_SOURCE */
7872 (dp=readdir64(indir))
7873 #endif /* _POSIX_C_SOURCE */
7874 #else /* !AJ_IRIXLF */
7875 #ifdef _POSIX_C_SOURCE
7876 !readdir_r(indir,(struct dirent *)buf,&dp)
7877 #else /* !_POSIX_C_SOURCE */
7878 (dp=readdir(indir))
7879 #endif /* _POSIX_C_SOURCE */
7880 #endif /* AJ_IRIXLF */
7881 )
7882 {
7883 #ifdef _POSIX_C_SOURCE
7884 if(!dp)
7885 break;
7886 #endif /* _POSIX_C_SOURCE */
7887 #ifndef __CYGWIN__
7888 if(!dp->d_ino ||
7889 !strcmp(dp->d_name,".") ||
7890 !strcmp(dp->d_name,".."))
7891 continue;
7892 #else /* __CYGWIN__ */
7893 if(!strcmp(dp->d_name,".") ||
7894 !strcmp(dp->d_name,".."))
7895 continue;
7896 #endif /* !__CYGWIN__ */
7897 ajStrAssignS(&s,tpath);
7898 ajStrAppendC(&s,dp->d_name);
7899
7900 ajDebug("... testing '%S'\n",
7901 s);
7902
7903 if(ajFilenameExistsDir(s))
7904 {
7905 ajDebug("... rejected: directory '%S'\n",
7906 s);
7907 continue;
7908 }
7909
7910 ajDebug("... add to list '%S'\n",
7911 s);
7912
7913 t = ajStrNewS(s);
7914 ajListPushAppend(list,(void *)t);
7915
7916 }
7917
7918 closedir(indir);
7919
7920
7921 ajStrDel(&s);
7922 ajStrDel(&tpath);
7923
7924 return (ajuint) (ajListGetLength(list) - oldsize);
7925 }
7926
7927
7928
7929
7930 /* @func ajFilelistAddPathDir *************************************************
7931 **
7932 ** Scan through a directory returning all filenames and directory names
7933 ** except '.' and '..', including directories
7934 **
7935 ** @param [u] list [AjPList] List for matching entries
7936 ** @param [r] path [const AjPStr] Directory to scan
7937 **
7938 ** @return [ajint] number of entries in list
7939 **
7940 ** @release 6.0.0
7941 ** @@
7942 ******************************************************************************/
7943
ajFilelistAddPathDir(AjPList list,const AjPStr path)7944 ajint ajFilelistAddPathDir(AjPList list,
7945 const AjPStr path)
7946 {
7947 ajulong oldsize;
7948 DIR *indir;
7949 #if defined(AJ_IRIXLF)
7950 struct dirent64 *dp;
7951 #else /* !AJ_IRIXLF */
7952 struct dirent *dp;
7953 #endif /* AJ_IRIXLF */
7954 AjPStr s = NULL;
7955 AjPStr t = NULL;
7956 AjPStr tpath = NULL;
7957 #ifdef _POSIX_C_SOURCE
7958 char buf[sizeof(struct dirent)+MAXNAMLEN];
7959 #endif /* _POSIX_C_SOURCE */
7960
7961 oldsize = ajListGetLength(list);
7962
7963 tpath = ajStrNewS(path);
7964
7965 ajDebug("ajFilelistAddPath '%S' oldsize:%Lu\n",
7966 path, oldsize);
7967
7968 if(!ajDirnameFixExists(&tpath))
7969 {
7970 ajDebug("... not a directory '%S'\n", tpath);
7971 ajStrDel(&tpath);
7972
7973 return 0;
7974 }
7975
7976
7977 if(!(indir=opendir(ajStrGetPtr(tpath))))
7978 {
7979 ajDebug("... failed to open directory '%S'\n", tpath);
7980 ajStrDel(&tpath);
7981
7982 return 0;
7983 }
7984
7985
7986 s = ajStrNew();
7987
7988 while(
7989 #if defined(AJ_IRIXLF)
7990 #ifdef _POSIX_C_SOURCE
7991 !readdir64_r(indir,(struct dirent64 *)buf,&dp)
7992 #else /* !_POSIX_C_SOURCE */
7993 (dp=readdir64(indir))
7994 #endif /* _POSIX_C_SOURCE */
7995 #else /* !AJ_IRIXLF */
7996 #ifdef _POSIX_C_SOURCE
7997 !readdir_r(indir,(struct dirent *)buf,&dp)
7998 #else /* !_POSIX_C_SOURCE */
7999 (dp=readdir(indir))
8000 #endif /* _POSIX_C_SOURCE */
8001 #endif /* AJ_IRIXLF */
8002 )
8003 {
8004 #ifdef _POSIX_C_SOURCE
8005 if(!dp)
8006 break;
8007 #endif /* _POSIX_C_SOURCE */
8008 #ifndef __CYGWIN__
8009 if(!dp->d_ino ||
8010 !strcmp(dp->d_name,".") ||
8011 !strcmp(dp->d_name,".."))
8012 continue;
8013 #else /* __CYGWIN__ */
8014 if(!strcmp(dp->d_name,".") ||
8015 !strcmp(dp->d_name,".."))
8016 continue;
8017 #endif /* !__CYGWIN__ */
8018 ajStrAssignS(&s,tpath);
8019 ajStrAppendC(&s,dp->d_name);
8020
8021 ajDebug("... add to list '%S'\n",
8022 s);
8023
8024 t = ajStrNewS(s);
8025 ajListPushAppend(list,(void *)t);
8026
8027 }
8028 closedir(indir);
8029
8030
8031 ajStrDel(&s);
8032 ajStrDel(&tpath);
8033
8034 return (ajuint) (ajListGetLength(list) - oldsize);
8035 }
8036
8037
8038
8039
8040 /* @func ajFilelistAddPathWild ************************************************
8041 **
8042 ** Scan through a directory returning all filenames matching a
8043 ** wildcard filename
8044 **
8045 ** @param [w] list [AjPList] List for matching entries
8046 ** @param [r] path [const AjPStr] Directory to scan
8047 ** @param [r] wildname [const AjPStr] Filename to search for
8048 **
8049 ** @return [ajint] number of entries in list
8050 **
8051 ** @release 6.0.0
8052 ** @@
8053 ******************************************************************************/
8054
ajFilelistAddPathWild(AjPList list,const AjPStr path,const AjPStr wildname)8055 ajint ajFilelistAddPathWild(AjPList list,
8056 const AjPStr path,
8057 const AjPStr wildname)
8058 {
8059 ajulong oldsize;
8060 DIR *indir;
8061 #if defined(AJ_IRIXLF)
8062 struct dirent64 *dp;
8063 #else /* !AJ_IRIXLF */
8064 struct dirent *dp;
8065 #endif /* AJ_IRIXLF */
8066 AjPStr s = NULL;
8067 AjPStr t = NULL;
8068 AjPStr tpath = NULL;
8069 #ifdef _POSIX_C_SOURCE
8070 char buf[sizeof(struct dirent)+MAXNAMLEN];
8071 #endif /* _POSIX_C_SOURCE */
8072
8073 oldsize = ajListGetLength(list);
8074
8075 tpath = ajStrNew();
8076 ajStrAssignS(&tpath,path);
8077
8078
8079 if(!ajDirnameFixExists(&tpath))
8080 {
8081 ajStrDel(&tpath);
8082
8083 return 0;
8084 }
8085
8086
8087 if(!(indir=opendir(ajStrGetPtr(tpath))))
8088 {
8089 ajStrDel(&tpath);
8090
8091 return 0;
8092 }
8093
8094
8095 s = ajStrNew();
8096
8097 while(
8098 #if defined(AJ_IRIXLF)
8099 #ifdef _POSIX_C_SOURCE
8100 !readdir64_r(indir,(struct dirent64 *)buf,&dp)
8101 #else /* !_POSIX_C_SOURCE */
8102 (dp=readdir64(indir))
8103 #endif /* _POSIX_C_SOURCE */
8104 #else /* !AJ_IRIXLF */
8105 #ifdef _POSIX_C_SOURCE
8106 !readdir_r(indir,(struct dirent *)buf,&dp)
8107 #else /* !_POSIX_C_SOURCE */
8108 (dp=readdir(indir))
8109 #endif /* _POSIX_C_SOURCE */
8110 #endif /* AJ_IRIXLF */
8111 )
8112 {
8113 #ifdef _POSIX_C_SOURCE
8114 if(!dp)
8115 break;
8116 #endif /* _POSIX_C_SOURCE */
8117 #ifndef __CYGWIN__
8118 if(!dp->d_ino ||
8119 !strcmp(dp->d_name,".") ||
8120 !strcmp(dp->d_name,".."))
8121 continue;
8122 #else /* __CYGWIN__ */
8123 if(!strcmp(dp->d_name,".") ||
8124 !strcmp(dp->d_name,".."))
8125 continue;
8126 #endif /* !__CYGWIN__ */
8127 ajStrAssignS(&s,tpath);
8128 ajStrAppendC(&s,dp->d_name);
8129
8130 if(ajFilenameExistsDir(s))
8131 continue;
8132
8133 if(ajCharMatchWildS(dp->d_name,wildname))
8134 {
8135 t = ajStrNewS(s);
8136 ajListPushAppend(list,(void *)t);
8137 }
8138 }
8139 closedir(indir);
8140
8141
8142 ajStrDel(&s);
8143 ajStrDel(&tpath);
8144
8145 return (ajuint) (ajListGetLength(list) - oldsize);
8146 }
8147
8148
8149
8150
8151 /* @func ajFilelistAddPathWildDir *********************************************
8152 **
8153 ** Scan through a directory returning all filenames matching a
8154 ** wildcard filename, including directories
8155 **
8156 ** @param [w] list [AjPList] List for matching entries
8157 ** @param [r] path [const AjPStr] Directory to scan
8158 ** @param [r] wildname [const AjPStr] Filename to search for
8159 **
8160 ** @return [ajint] number of entries in list
8161 **
8162 ** @release 6.0.0
8163 ** @@
8164 ******************************************************************************/
8165
ajFilelistAddPathWildDir(AjPList list,const AjPStr path,const AjPStr wildname)8166 ajint ajFilelistAddPathWildDir(AjPList list,
8167 const AjPStr path,
8168 const AjPStr wildname)
8169 {
8170 ajulong oldsize;
8171 DIR *indir;
8172 #if defined(AJ_IRIXLF)
8173 struct dirent64 *dp;
8174 #else /* !AJ_IRIXLF */
8175 struct dirent *dp;
8176 #endif /* AJ_IRIXLF */
8177 AjPStr s = NULL;
8178 AjPStr t = NULL;
8179 AjPStr tpath = NULL;
8180 #ifdef _POSIX_C_SOURCE
8181 char buf[sizeof(struct dirent)+MAXNAMLEN];
8182 #endif /* _POSIX_C_SOURCE */
8183
8184 oldsize = ajListGetLength(list);
8185
8186 tpath = ajStrNew();
8187 ajStrAssignS(&tpath,path);
8188
8189
8190 if(!ajDirnameFixExists(&tpath))
8191 {
8192 ajStrDel(&tpath);
8193
8194 return 0;
8195 }
8196
8197
8198 if(!(indir=opendir(ajStrGetPtr(tpath))))
8199 {
8200 ajStrDel(&tpath);
8201
8202 return 0;
8203 }
8204
8205
8206 s = ajStrNew();
8207
8208 while(
8209 #if defined(AJ_IRIXLF)
8210 #ifdef _POSIX_C_SOURCE
8211 !readdir64_r(indir,(struct dirent64 *)buf,&dp)
8212 #else /* !_POSIX_C_SOURCE */
8213 (dp=readdir64(indir))
8214 #endif /* _POSIX_C_SOURCE */
8215 #else /* !AJ_IRIXLF */
8216 #ifdef _POSIX_C_SOURCE
8217 !readdir_r(indir,(struct dirent *)buf,&dp)
8218 #else /* !_POSIX_C_SOURCE */
8219 (dp=readdir(indir))
8220 #endif /* _POSIX_C_SOURCE */
8221 #endif /* AJ_IRIXLF */
8222 )
8223 {
8224 #ifdef _POSIX_C_SOURCE
8225 if(!dp)
8226 break;
8227 #endif /* _POSIX_C_SOURCE */
8228 #ifndef __CYGWIN__
8229 if(!dp->d_ino ||
8230 !strcmp(dp->d_name,".") ||
8231 !strcmp(dp->d_name,".."))
8232 continue;
8233 #else /* __CYGWIN__ */
8234 if(!strcmp(dp->d_name,".") ||
8235 !strcmp(dp->d_name,".."))
8236 continue;
8237 #endif /* !__CYGWIN__ */
8238 ajStrAssignS(&s,tpath);
8239 ajStrAppendC(&s,dp->d_name);
8240
8241 if(ajCharMatchWildS(dp->d_name,wildname))
8242 {
8243 t = ajStrNewS(s);
8244 ajListPushAppend(list,(void *)t);
8245 }
8246 }
8247
8248 closedir(indir);
8249
8250
8251 ajStrDel(&s);
8252 ajStrDel(&tpath);
8253
8254 return (ajuint) (ajListGetLength(list) - oldsize);
8255 }
8256
8257
8258
8259
8260 /* @funcstatic fileListRecurs ************************************************
8261 **
8262 ** Add a filename, expanded wildcard filenames and list file contents to
8263 ** a list
8264 **
8265 ** @param [r] srcfile [const AjPStr] filename, wild filename or list filename
8266 ** @param [u] list [AjPList] result filename list
8267 ** @param [u] recurs [ajint *] recursion level counter
8268 **
8269 ** @return [void]
8270 **
8271 ** @release 2.5.0
8272 ** @@
8273 ******************************************************************************/
8274
fileListRecurs(const AjPStr srcfile,AjPList list,ajint * recurs)8275 static void fileListRecurs(const AjPStr srcfile, AjPList list, ajint *recurs)
8276 {
8277 char c;
8278 AjPStr ptr = NULL;
8279 AjPStr dir = NULL;
8280 char *p;
8281 AjPList dlist;
8282 AjPFile inf;
8283 AjPStr line = NULL;
8284 AjPStr file = NULL;
8285
8286 ++(*recurs);
8287
8288 if(*recurs > FILERECURSLV)
8289 ajFatal("Filelist maximum recursion level reached");
8290
8291 ajStrAssignS(&file, srcfile);
8292 ajStrTrimWhite(&file);
8293 c = *ajStrGetPtr(file);
8294
8295 dir = ajStrNew();
8296 line = ajStrNew();
8297 dlist = ajListNew();
8298
8299
8300 if(ajStrIsWild(file))
8301 {
8302 if(!(p=strrchr(ajStrGetPtr(file),(int)SLASH_CHAR)))
8303 ajStrAssignC(&dir,CURRENT_DIR);
8304 else
8305 ajStrAssignSubC(&dir,ajStrGetPtr(file),0,p-ajStrGetPtr(file));
8306
8307 ajFilelistAddPathWild(dlist, dir, file);
8308
8309 while(ajListPop(dlist,(void **)&ptr))
8310 {
8311 if(ajStrPrefixC(ptr,CURRENT_DIR))
8312 ajStrCutStart(&ptr,2);
8313
8314 ajListPushAppend(list,(void *)ptr);
8315 }
8316 }
8317 else if(c=='@')
8318 {
8319 if((inf=ajFileNewInNameC(ajStrGetPtr(file)+1)))
8320 while(ajReadlineTrim(inf,&line))
8321 fileListRecurs(line,list,recurs);
8322 if(inf)
8323 ajFileClose(&inf);
8324 }
8325 else if(ajStrPrefixC(file,"list::"))
8326 {
8327 if((inf=ajFileNewInNameC(ajStrGetPtr(file)+6)))
8328 while(ajReadlineTrim(inf,&line))
8329 fileListRecurs(line,list,recurs);
8330 if(inf)
8331 ajFileClose(&inf);
8332 }
8333 else
8334 {
8335 ptr = ajStrNewC(ajStrGetPtr(file));
8336 ajListPushAppend(list,(void *)ptr);
8337 }
8338
8339
8340 ajListFree(&dlist);
8341 ajStrDel(&dir);
8342 ajStrDel(&line);
8343 ajStrDel(&file);
8344
8345 --(*recurs);
8346
8347 return;
8348 }
8349
8350
8351
8352
8353 /* @func ajFilelistAddPathWildRecursiveIgnore *********************************
8354 **
8355 ** Recursively scan through a directory
8356 **
8357 ** @param [u] list [AjPList] List for matching filenames
8358 ** @param [r] path [const AjPStr] Directory to scan
8359 ** @param [r] wildname [const AjPStr] Filename to search for (or NULL)
8360 ** @param [u] ignorelist [AjPList] List of directories to ignore
8361 **
8362 ** @return [ajint] number of new entries in list
8363 **
8364 ** @release 6.0.0
8365 ** @@
8366 ******************************************************************************/
8367
ajFilelistAddPathWildRecursiveIgnore(AjPList list,const AjPStr path,const AjPStr wildname,AjPList ignorelist)8368 ajint ajFilelistAddPathWildRecursiveIgnore(AjPList list,
8369 const AjPStr path,
8370 const AjPStr wildname,
8371 AjPList ignorelist)
8372 {
8373 ajulong oldsize;
8374 AjPList dirs = NULL;
8375 AjIList iter = NULL;
8376 DIR *indir;
8377 #if defined(AJ_IRIXLF)
8378 struct dirent64 *dp;
8379 #else /* !AJ_IRIXLF */
8380 struct dirent *dp;
8381 #endif /* AJ_IRIXLF */
8382 AjPStr s = NULL;
8383 AjPStr t = NULL;
8384 AjBool flag;
8385 AjPStr tpath = NULL;
8386 #ifdef _POSIX_C_SOURCE
8387 char buf[sizeof(struct dirent)+MAXNAMLEN];
8388 #endif /* _POSIX_C_SOURCE */
8389
8390 oldsize = ajListGetLength(list);
8391
8392 tpath = ajStrNew();
8393 ajStrAssignS(&tpath,path);
8394
8395 if(!ajDirnameFixExists(&tpath))
8396 {
8397 ajStrDel(&tpath);
8398
8399 return 0;
8400 }
8401
8402
8403 if(!(indir=opendir(ajStrGetPtr(tpath))))
8404 {
8405 ajStrDel(&tpath);
8406
8407 return 0;
8408 }
8409
8410
8411 s = ajStrNew();
8412 dirs = ajListNew();
8413
8414 while(
8415 #if defined(AJ_IRIXLF)
8416 #ifdef _POSIX_C_SOURCE
8417 !readdir64_r(indir,(struct dirent64 *)buf,&dp)
8418 #else /* !_POSIX_C_SOURCE */
8419 (dp=readdir64(indir))
8420 #endif /* _POSIX_C_SOURCE */
8421 #else /* !AJ_IRIXLF */
8422 #ifdef _POSIX_C_SOURCE
8423 !readdir_r(indir,(struct dirent *)buf,&dp)
8424 #else /* !_POSIX_C_SOURCE */
8425 (dp=readdir(indir))
8426 #endif /* _POSIX_C_SOURCE */
8427 #endif /* AJ_IRIXLF */
8428 )
8429 {
8430 #ifdef _POSIX_C_SOURCE
8431 if(!dp)
8432 break;
8433 #endif /* _POSIX_C_SOURCE */
8434 #ifndef __CYGWIN__
8435 if(!dp->d_ino ||
8436 !strcmp(dp->d_name,".") ||
8437 !strcmp(dp->d_name,".."))
8438 continue;
8439 #else /* __CYGWIN__ */
8440 if(!strcmp(dp->d_name,".") ||
8441 !strcmp(dp->d_name,".."))
8442 continue;
8443 #endif /* !__CYGWIN__ */
8444 ajStrAssignS(&s,tpath);
8445 /* ajStrAppendC(&s,SLASH_STRING);*/
8446 ajStrAppendC(&s,dp->d_name);
8447
8448 /* Its a directory */
8449 if(ajFilenameExistsDir(s))
8450 {
8451 /* Ignore selected directories */
8452 if(ajListGetLength(ignorelist))
8453 {
8454 flag = ajFalse;
8455 iter = ajListIterNewread(ignorelist);
8456
8457 while(!ajListIterDone(iter))
8458 {
8459 t = ajListIterGet(iter);
8460
8461 if(!strcmp(ajStrGetPtr(t),dp->d_name))
8462 {
8463 flag = ajTrue;
8464 break;
8465 }
8466 }
8467
8468 ajListIterDel(&iter);
8469
8470 if(flag)
8471 continue;
8472 }
8473
8474 if(!ajFilenameExistsRead(s) || !ajFilenameExistsExec(s))
8475 continue;
8476
8477 t = ajStrNewC(ajStrGetPtr(s));
8478 ajListPushAppend(dirs,(void *)t);
8479 }
8480 else if(ajFilenameExistsRead(s))
8481 {
8482 if(ajStrGetLen(wildname))
8483 if(ajCharMatchWildS(dp->d_name,wildname))
8484 {
8485 t = ajStrNewS(s);
8486 ajListPushAppend(list,(void *)t);
8487 }
8488
8489 /*ajDebug(" %s\n",dp->d_name);*/
8490 }
8491 }
8492
8493 closedir(indir);
8494
8495 while(ajListPop(dirs,(void **)&t))
8496 {
8497 ajFilelistAddPathWildRecursiveIgnore(list, t,wildname, ignorelist);
8498 ajStrDel(&t);
8499 }
8500
8501 ajStrDel(&s);
8502 ajStrDel(&tpath);
8503 ajListFree(&dirs);
8504
8505 return (ajuint) (ajListGetLength(list) - oldsize);
8506 }
8507
8508
8509
8510
8511 /* @datasection [none] File internal values ***********************************
8512 **
8513 ** Functions returning internal values and system parameters
8514 **
8515 ** @nam2rule File
8516 **
8517 ******************************************************************************/
8518
8519
8520
8521
8522 /* @section Internal values ***************************************************
8523 **
8524 ** Internal values and system parameters
8525 **
8526 ** @nam3rule Value Return a value
8527 ** @nam4rule Buffsize Internal buffer size default
8528 ** @nam4rule Cwd Current working directory
8529 ** @nam4rule Redirect Test whether a system file is redirected to
8530 ** a file object
8531 ** @nam5rule RedirectStderr Test redirection of standard error
8532 ** @nam5rule RedirectStdin Test redirection of standard input
8533 ** @nam5rule RedirectStdout Test redirection of standard output
8534 **
8535 ** @valrule *Cwd [const AjPStr] True on success
8536 ** @valrule *Buffsize [ajuint] Buffer size
8537 ** @valrule Redirect [AjBool] True if file is redirected.
8538 **
8539 ** @fcategory misc
8540 **
8541 ** @fdata [none]
8542 **
8543 ******************************************************************************/
8544
8545
8546
8547
8548 /* @func ajFileValueBuffsize **************************************************
8549 **
8550 ** Returns the default buffer size for a file
8551 **
8552 ** @return [ajuint] Buffer size default value
8553 **
8554 ** @release 6.0.0
8555 ******************************************************************************/
8556
ajFileValueBuffsize(void)8557 ajuint ajFileValueBuffsize(void)
8558 {
8559 return fileBuffSize;
8560 }
8561
8562
8563
8564
8565 /* @func ajFileValueCwd *******************************************************
8566 **
8567 ** Returns the current directory
8568 **
8569 ** @return [const AjPStr] Directory name.
8570 **
8571 ** @release 6.0.0
8572 ** @@
8573 ******************************************************************************/
8574
ajFileValueCwd(void)8575 const AjPStr ajFileValueCwd(void)
8576 {
8577 char cwd[PATH_MAX+1];
8578
8579 if(!getcwd(cwd,PATH_MAX))
8580 {
8581 ajStrAssignClear(&fileCwd);
8582
8583 return fileCwd;
8584 }
8585
8586
8587 ajStrAssignC(&fileCwd, cwd);
8588
8589 if(!ajStrSuffixC(fileCwd, SLASH_STRING))
8590 ajStrAppendC(&fileCwd, SLASH_STRING);
8591
8592 return fileCwd;
8593 }
8594
8595
8596
8597
8598 /* @func ajFileValueRedirectStderr ********************************************
8599 **
8600 ** Tests whether stderr is in use by an internal file
8601 **
8602 ** @return [AjBool] ajTrue if the file matches stderr.
8603 **
8604 ** @release 6.0.0
8605 ** @@
8606 ******************************************************************************/
8607
ajFileValueRedirectStderr(void)8608 AjBool ajFileValueRedirectStderr(void)
8609 {
8610 return fileUsedStderr;
8611 }
8612
8613
8614
8615
8616 /* @func ajFileValueRedirectStdin *********************************************
8617 **
8618 ** Tests whether stdin is in use by an internal file
8619 **
8620 ** @return [AjBool] ajTrue if the file matches stdin.
8621 **
8622 ** @release 6.0.0
8623 ** @@
8624 ******************************************************************************/
8625
ajFileValueRedirectStdin(void)8626 AjBool ajFileValueRedirectStdin(void)
8627 {
8628 return fileUsedStdin;
8629 }
8630
8631
8632
8633
8634 /* @func ajFileValueRedirectStdout ********************************************
8635 **
8636 ** Tests whether stdout is in use by an internal file
8637 **
8638 ** @return [AjBool] ajTrue if the file matches stdout.
8639 **
8640 ** @release 6.0.0
8641 ** @@
8642 ******************************************************************************/
8643
ajFileValueRedirectStdout(void)8644 AjBool ajFileValueRedirectStdout(void)
8645 {
8646 return fileUsedStdout;
8647 }
8648
8649
8650
8651
8652 /* @funcstatic filePrintname **************************************************
8653 **
8654 ** Create a printable version of a filename
8655 **
8656 ** @param [r] name [const AjPStr] File name
8657 ** @param [w] Pprintname [AjPStr*] Printable filename
8658 ** @return [void]
8659 **
8660 ** @release 6.4.0
8661 ******************************************************************************/
8662
filePrintname(const AjPStr name,AjPStr * Pprintname)8663 static void filePrintname(const AjPStr name, AjPStr* Pprintname)
8664 {
8665
8666 ajStrAssignS(Pprintname, name);
8667 #ifdef WIN32
8668 ajStrExchangeKK(Pprintname, '/', '\\');
8669 if(ajStrPrefixC(*Pprintname, ".\\"))
8670 ajStrCutStart(Pprintname, 2);
8671 #else /* !WIN32 */
8672 ajStrExchangeCC(Pprintname, "//", "/");
8673 #endif /* WIN32 */
8674
8675 return;
8676 }
8677
8678
8679
8680
8681 #ifdef AJ_COMPILE_DEPRECATED_BOOK
8682 #endif
8683
8684
8685
8686
8687 #ifdef AJ_COMPILE_DEPRECATED
8688 /* @obsolete ajDirOutNewSS
8689 ** @remove Use ajDiroutNewPathExt (prefix not relevant)
8690 */
ajDirOutNewSS(const AjPStr name,const AjPStr prefix,const AjPStr ext)8691 __deprecated AjPDir ajDirOutNewSS(const AjPStr name,
8692 const AjPStr prefix, const AjPStr ext)
8693 {
8694 (void) name;
8695 (void) prefix;
8696 (void) ext;
8697
8698 return NULL;
8699 }
8700
8701
8702
8703
8704 /* @obsolete ajDirNew
8705 ** @rename ajDirNewPath
8706 */
ajDirNew(const AjPStr name)8707 __deprecated AjPDir ajDirNew(const AjPStr name)
8708 {
8709 return ajDirNewPath(name);
8710 }
8711
8712
8713
8714
8715 /* @obsolete ajDirNewS
8716 ** @rename ajDirNewPathExt
8717 */
ajDirNewS(const AjPStr name,const AjPStr ext)8718 __deprecated AjPDir ajDirNewS(const AjPStr name, const AjPStr ext)
8719 {
8720 return ajDirNewPathExt(name, ext);
8721 }
8722
8723
8724
8725
8726 /* @obsolete ajDirNewSS
8727 ** @rename ajDirNewPathPreExt
8728 */
ajDirNewSS(const AjPStr name,const AjPStr prefix,const AjPStr ext)8729 __deprecated AjPDir ajDirNewSS(const AjPStr name,
8730 const AjPStr prefix, const AjPStr ext)
8731 {
8732 return ajDirNewPathPreExt(name,prefix,ext);
8733 }
8734
8735
8736
8737
8738 /* @obsolete ajDirExt
8739 ** @rename ajDirGetExt
8740 */
ajDirExt(const AjPDir thys)8741 __deprecated const AjPStr ajDirExt(const AjPDir thys)
8742 {
8743 return ajDirGetExt(thys);
8744 }
8745
8746
8747
8748
8749 /* @obsolete ajDirName
8750 ** @rename ajDirGetPath
8751 */
ajDirName(const AjPDir thys)8752 __deprecated const AjPStr ajDirName(const AjPDir thys)
8753 {
8754 return ajDirGetPath(thys);
8755 }
8756
8757
8758
8759
8760 /* @obsolete ajDirOutNew
8761 ** @remove Use ajDiroutNewPath
8762 */
ajDirOutNew(const AjPStr name)8763 __deprecated AjPDir ajDirOutNew(const AjPStr name)
8764 {
8765 (void)name;
8766 return NULL;
8767 }
8768
8769
8770
8771
8772 /* @obsolete ajDirOutNewS
8773 ** @remove Use ajDiroutNewPathExt
8774 */
ajDirOutNewS(const AjPStr name,const AjPStr ext)8775 __deprecated AjPDir ajDirOutNewS(const AjPStr name, const AjPStr ext)
8776 {
8777 (void)name;
8778 (void)ext;
8779
8780 return NULL;
8781 }
8782
8783
8784
8785
8786 /* @obsolete ajFileStat
8787 ** @remove Use ajFilenameExists ajFileNameExistsRead ajFilenameExistsWrite
8788 ** or ajFileNameExistsExec
8789 */
ajFileStat(const AjPStr fname,ajint mode)8790 __deprecated AjBool ajFileStat(const AjPStr fname, ajint mode)
8791 {
8792 #if defined(AJ_IRIXLF)
8793 struct stat64 buf;
8794 #else /* !AJ_IRIXLF */
8795 struct stat buf;
8796 #endif /* AJ_IRIXLF */
8797
8798 if(
8799 #if defined(AJ_IRIXLF)
8800 !stat64(ajStrGetPtr(fname), &buf)
8801 #else /* !AJ_IRIXLF */
8802 !stat(ajStrGetPtr(fname), &buf)
8803 #endif /* AJ_IRIXLF */
8804 )
8805 if((ajuint)buf.st_mode & mode)
8806 return ajTrue;
8807
8808 return ajFalse;
8809 }
8810
8811
8812
8813
8814 /* @obsolete ajFileNameValid
8815 ** @rename ajFilenameExistsRead
8816 */
ajFileNameValid(const AjPStr fname)8817 __deprecated AjBool ajFileNameValid (const AjPStr fname)
8818 {
8819 return ajFilenameExistsRead(fname);
8820 }
8821
8822
8823
8824
8825 /* @obsolete ajFileLength
8826 ** @rename ajFilenameGetSize
8827 */
ajFileLength(const AjPStr fname)8828 __deprecated ajlong ajFileLength(const AjPStr fname)
8829 {
8830 return ajFilenameGetSize(fname);
8831 }
8832
8833
8834
8835
8836 /* @obsolete ajFileHasDir
8837 ** @rename ajFilenameHasPath
8838 */
ajFileHasDir(const AjPStr name)8839 __deprecated AjBool ajFileHasDir(const AjPStr name)
8840 {
8841 return ajFilenameHasPath(name);
8842 }
8843
8844
8845
8846
8847 /* @obsolete ajFileTestSkip
8848 ** @remove Use ajFilenameTestExclude ajFilenameTestInclude and *Path
8849 */
ajFileTestSkip(const AjPStr fullname,const AjPStr exc,const AjPStr inc,AjBool keep,AjBool ignoredirectory)8850 __deprecated AjBool ajFileTestSkip(const AjPStr fullname,
8851 const AjPStr exc, const AjPStr inc,
8852 AjBool keep, AjBool ignoredirectory)
8853 {
8854 if(ignoredirectory)
8855 {
8856 if(keep)
8857 return ajFilenameTestInclude(fullname, exc, inc);
8858 else
8859 return ajFilenameTestExclude(fullname, exc, inc);
8860 }
8861
8862 if(keep)
8863 return ajFilenameTestIncludePath(fullname, exc, inc);
8864
8865 return ajFilenameTestExcludePath(fullname, exc, inc);
8866 }
8867
8868
8869
8870
8871 /* @obsolete ajFileNameExtC
8872 ** @rename ajFilenameReplaceExtC
8873 */
ajFileNameExtC(AjPStr * filename,const char * extension)8874 __deprecated AjBool ajFileNameExtC(AjPStr* filename, const char* extension)
8875 {
8876 return ajFilenameReplaceExtC(filename, extension);
8877 }
8878
8879
8880
8881
8882 /* @obsolete ajFileNameExt
8883 ** @rename ajFilenameReplaceExtS
8884 */
ajFileNameExt(AjPStr * filename,const AjPStr extension)8885 __deprecated AjBool ajFileNameExt(AjPStr* filename, const AjPStr extension)
8886 {
8887 return ajFilenameReplaceExtS(filename, extension);
8888 }
8889
8890
8891
8892
8893 /* @obsolete ajFileNameDirSetC
8894 ** @rename ajFilenameReplacePathC
8895 */
ajFileNameDirSetC(AjPStr * filename,const char * dir)8896 __deprecated AjBool ajFileNameDirSetC(AjPStr* filename, const char* dir)
8897 {
8898 return ajFilenameReplacePathC(filename, dir);
8899 }
8900
8901
8902
8903
8904 /* @obsolete ajFileNameDirSet
8905 ** @rename ajFilenameReplacePathS
8906 */
ajFileNameDirSet(AjPStr * filename,const AjPStr dir)8907 __deprecated AjBool ajFileNameDirSet(AjPStr* filename, const AjPStr dir)
8908 {
8909 return ajFilenameReplacePathS(filename, dir);
8910 }
8911
8912
8913
8914
8915 /* @obsolete ajFileSetDir
8916 ** @rename ajFilenameReplacePathS
8917 */
ajFileSetDir(AjPStr * pname,const AjPStr dir)8918 __deprecated AjBool ajFileSetDir (AjPStr *pname, const AjPStr dir)
8919
8920 {
8921 return ajFilenameReplacePathS(pname, dir);
8922 }
8923
8924
8925
8926
8927 /* @obsolete ajFileNewF
8928 ** @rename ajFileNewFromCfile
8929 */
ajFileNewF(FILE * file)8930 __deprecated AjPFile ajFileNewF(FILE* file)
8931 {
8932 return ajFileNewFromCfile(file);
8933 }
8934
8935
8936
8937
8938 /* @obsolete ajFileTempName
8939 ** @remove Use ajFilenameSetTempname or ajFilenameSetTempnamePath
8940 */
ajFileTempName(const char * dir)8941 __deprecated const char* ajFileTempName(const char *dir)
8942 {
8943 AjPStr tmpstr = NULL;
8944
8945 (void) dir;
8946 ajFilenameSetTempname(&tmpstr);
8947
8948 return ajStrGetPtr(tmpstr);
8949 }
8950
8951
8952
8953
8954 /* @obsolete ajFileNameShorten
8955 ** @rename ajFilenameTrimAll
8956 */
ajFileNameShorten(AjPStr * fname)8957 __deprecated AjBool ajFileNameShorten(AjPStr* fname)
8958 {
8959 return ajFilenameTrimAll(fname);
8960 }
8961
8962
8963
8964
8965 /* @obsolete ajFileExtnTrim
8966 ** @rename ajFilenameTrimExt
8967 */
ajFileExtnTrim(AjPStr * name)8968 __deprecated AjBool ajFileExtnTrim(AjPStr* name)
8969 {
8970 return ajFilenameTrimExt(name);
8971 }
8972
8973
8974
8975
8976 /* @obsolete ajFileNew
8977 ** @remove Use a constructor that opens a real file
8978 */
8979
ajFileNew(void)8980 __deprecated AjPFile ajFileNew(void)
8981 {
8982 return fileNew();
8983 }
8984
8985
8986
8987
8988 /* @obsolete ajFileNewInC
8989 ** @rename ajFileNewInNameC
8990 */
8991
ajFileNewInC(const char * name)8992 __deprecated AjPFile ajFileNewInC(const char *name)
8993 {
8994 return ajFileNewInNameC(name);
8995 }
8996
8997
8998
8999
9000 /* @obsolete ajFileNewIn
9001 ** @rename ajFileNewInNameS
9002 */
ajFileNewIn(const AjPStr name)9003 __deprecated AjPFile ajFileNewIn(const AjPStr name)
9004 {
9005
9006 return ajFileNewInNameS(name);
9007 }
9008
9009
9010
9011
9012 /* @obsolete ajFileNewDC
9013 ** @remove Use ajFileNewInNamePathS
9014 */
ajFileNewDC(const AjPStr dir,const char * filename)9015 __deprecated AjPFile ajFileNewDC(const AjPStr dir, const char* filename)
9016 {
9017 ajStrAssignC(&fileNameStrTmp, filename);
9018 return ajFileNewInNamePathS(fileNameStrTmp, dir);
9019 }
9020
9021
9022
9023
9024 /* @obsolete ajFileNewDF
9025 ** @replace ajFileNewInNamePathS (1,2/2,1)
9026 */
ajFileNewDF(const AjPStr dir,const AjPStr filename)9027 __deprecated AjPFile ajFileNewDF(const AjPStr dir, const AjPStr filename)
9028 {
9029 return ajFileNewInNamePathS(filename, dir);
9030 }
9031
9032
9033
9034
9035 /* @obsolete ajFileNewInList
9036 ** @rename ajFileNewListinList
9037 */
9038
ajFileNewInList(AjPList list)9039 __deprecated AjPFile ajFileNewInList(AjPList list)
9040 {
9041 return ajFileNewListinList(list);
9042 }
9043
9044
9045
9046
9047 /* @obsolete ajFileNewDirF
9048 ** @rename ajFileNewListinDirPre
9049 */
ajFileNewDirF(const AjPDir dir,const AjPStr filename)9050 __deprecated AjPFile ajFileNewDirF(const AjPDir dir, const AjPStr filename)
9051 {
9052 return ajFileNewListinDirPre(dir,filename);
9053 }
9054
9055
9056
9057
9058 /* @obsolete ajFileNewDW
9059 ** @rename ajFileNewListinPathWild
9060 */
9061
ajFileNewDW(const AjPStr dir,const AjPStr wildfile)9062 __deprecated AjPFile ajFileNewDW(const AjPStr dir, const AjPStr wildfile)
9063 {
9064 return ajFileNewListinPathWild(dir, wildfile);
9065 }
9066
9067
9068
9069
9070 /* @obsolete ajFileNewDWE
9071 ** @rename ajFileNewListinPathWildExclude
9072 */
ajFileNewDWE(const AjPStr dir,const AjPStr wildfile,const AjPStr exclude)9073 __deprecated AjPFile ajFileNewDWE(const AjPStr dir, const AjPStr wildfile,
9074 const AjPStr exclude)
9075 {
9076 return ajFileNewListinPathWildExclude(dir, wildfile, exclude);
9077 }
9078
9079
9080
9081
9082 /* @obsolete ajFileNewOut
9083 ** @rename ajFileNewOutNameS
9084 */
ajFileNewOut(const AjPStr name)9085 __deprecated AjPFile ajFileNewOut(const AjPStr name)
9086 {
9087 return ajFileNewOutNameS(name);
9088 }
9089
9090
9091
9092
9093 /* @obsolete ajFileNewOutDir
9094 ** @replace ajFileNewOutNameDirS (1,2/2,1)
9095 */
ajFileNewOutDir(const AjPDirout dir,const AjPStr name)9096 __deprecated AjPFile ajFileNewOutDir(const AjPDirout dir, const AjPStr name)
9097 {
9098 return ajFileNewOutNameDirS(name, dir);
9099 }
9100
9101
9102
9103
9104 /* @obsolete ajFileNewOutD
9105 ** @replace ajFileNewOutNamePathS (1,2/2,1)
9106 */
ajFileNewOutD(const AjPStr dir,const AjPStr name)9107 __deprecated AjPFile ajFileNewOutD(const AjPStr dir, const AjPStr name)
9108 {
9109 return ajFileNewOutNamePathS(name, dir);
9110 }
9111
9112
9113
9114
9115 /* @obsolete ajFileNewApp
9116 ** @rename ajFileNewOutappendNameS
9117 */
ajFileNewApp(const AjPStr name)9118 __deprecated AjPFile ajFileNewApp(const AjPStr name)
9119 {
9120
9121 return ajFileNewOutappendNameS(name);
9122 }
9123
9124
9125
9126
9127 /* @obsolete ajFileReopen
9128 ** @rename ajFileReopenName
9129 */
ajFileReopen(AjPFile thys,const AjPStr name)9130 __deprecated FILE* ajFileReopen(AjPFile thys, const AjPStr name)
9131 {
9132 ajFileReopenName(thys, name);
9133
9134 return thys->fp;
9135 }
9136
9137
9138
9139
9140 /* @obsolete ajFileNext
9141 ** @rename ajFileReopenNext
9142 */
ajFileNext(AjPFile thys)9143 __deprecated AjBool ajFileNext(AjPFile thys)
9144 {
9145 return ajFileReopenNext(thys);
9146 }
9147
9148
9149
9150
9151 /* @obsolete ajFileTell
9152 ** @rename ajFileResetPos
9153 */
ajFileTell(AjPFile file)9154 __deprecated ajlong ajFileTell(AjPFile file)
9155 {
9156 return ajFileResetPos(file);
9157 }
9158
9159
9160
9161
9162 /* @obsolete ajFileUnbuffer
9163 ** @rename ajFileSetUnbuffer
9164 */
ajFileUnbuffer(AjPFile thys)9165 __deprecated void ajFileUnbuffer(AjPFile thys)
9166 {
9167 ajFileSetUnbuffer(thys);
9168
9169 return;
9170 }
9171
9172
9173
9174
9175 /* @obsolete ajFileFp
9176 ** @rename ajFileGetFileptr
9177 */
ajFileFp(const AjPFile thys)9178 __deprecated FILE* ajFileFp(const AjPFile thys)
9179 {
9180 return ajFileGetFileptr(thys);
9181 }
9182
9183
9184
9185
9186 /* @obsolete ajFileName
9187 ** @rename ajFileGetNameC
9188 */
ajFileName(const AjPFile file)9189 __deprecated const char* ajFileName(const AjPFile file)
9190 {
9191 return ajFileGetNameC(file);
9192 }
9193
9194
9195
9196
9197 /* @obsolete ajFileNameS
9198 ** @rename ajFileGetNameS
9199 */
ajFileNameS(const AjPFile file)9200 __deprecated const AjPStr ajFileNameS(const AjPFile file)
9201 {
9202 return ajFileGetNameS(file);
9203 }
9204
9205
9206
9207
9208 /* @obsolete ajFileGetName
9209 ** @rename ajFileGetNameS
9210 */
ajFileGetName(const AjPFile file)9211 __deprecated const AjPStr ajFileGetName(const AjPFile file)
9212 {
9213 return ajFileGetNameS(file);
9214 }
9215
9216
9217
9218
9219 /* @obsolete ajFileGetApp
9220 ** @rename ajFileIsAppend
9221 */
ajFileGetApp(const AjPFile thys)9222 __deprecated AjBool ajFileGetApp(const AjPFile thys)
9223 {
9224 return ajFileIsAppend(thys);
9225 }
9226
9227
9228
9229
9230 /* @obsolete ajFileEof
9231 ** @rename ajFileIsEof
9232 */
ajFileEof(const AjPFile thys)9233 __deprecated AjBool ajFileEof(const AjPFile thys)
9234 {
9235 return ajFileIsEof(thys);
9236 }
9237
9238
9239
9240
9241 /* @obsolete ajFileStderr
9242 ** @rename ajFileIsStderr
9243 */
ajFileStderr(const AjPFile file)9244 __deprecated AjBool ajFileStderr(const AjPFile file)
9245 {
9246 return ajFileIsStderr(file);
9247 }
9248
9249
9250
9251
9252 /* @obsolete ajFileStdin
9253 ** @rename ajFileIsStdin
9254 */
ajFileStdin(const AjPFile file)9255 __deprecated AjBool ajFileStdin(const AjPFile file)
9256 {
9257 return ajFileIsStdin(file);
9258 }
9259
9260
9261
9262
9263
9264 /* @obsolete ajFileStdout
9265 ** @rename ajFileIsStdout
9266 */
ajFileStdout(const AjPFile file)9267 __deprecated AjBool ajFileStdout(const AjPFile file)
9268 {
9269 return ajFileIsStdout(file);
9270 }
9271
9272
9273
9274
9275 /* @obsolete ajFileBuffNewF
9276 ** @rename ajFilebuffNewFromCfile
9277 */
ajFileBuffNewF(FILE * fp)9278 __deprecated AjPFilebuff ajFileBuffNewF(FILE* fp)
9279 {
9280 return ajFilebuffNewFromCfile(fp);
9281 }
9282
9283
9284
9285
9286 /* @obsolete ajFileBuffNewFile
9287 ** @rename ajFilebuffNewFromFile
9288 */
ajFileBuffNewFile(AjPFile file)9289 __deprecated AjPFilebuff ajFileBuffNewFile(AjPFile file)
9290 {
9291 return ajFilebuffNewFromFile(file);
9292 }
9293
9294
9295
9296
9297 /* @obsolete ajFileBuffNewS
9298 ** @rename ajFilebuffNewLine
9299 */
ajFileBuffNewS(const AjPStr data)9300 __deprecated AjPFilebuff ajFileBuffNewS(const AjPStr data)
9301 {
9302 return ajFilebuffNewLine(data);
9303 }
9304
9305
9306
9307
9308 /* @obsolete ajFileBuffNewList
9309 ** @rename ajFilebuffNewListinList
9310 */
9311
ajFileBuffNewList(AjPList list)9312 __deprecated AjPFilebuff ajFileBuffNewList(AjPList list)
9313 {
9314 return ajFilebuffNewListinList(list);
9315 }
9316
9317
9318
9319
9320 /* @obsolete ajFileBuffNewIn
9321 ** @rename ajFilebuffNewNameS
9322 */
ajFileBuffNewIn(const AjPStr name)9323 __deprecated AjPFilebuff ajFileBuffNewIn(const AjPStr name)
9324 {
9325 return ajFilebuffNewNameS(name);
9326 }
9327
9328
9329
9330
9331 /* @obsolete ajFileBuffNewDC
9332 ** @replace ajFileBuffNewNamePathC (1,2/2,1)
9333 */
ajFileBuffNewDC(const AjPStr dir,const char * filename)9334 __deprecated AjPFilebuff ajFileBuffNewDC(const AjPStr dir,
9335 const char* filename)
9336 {
9337 return ajFilebuffNewNamePathC(filename, dir);
9338 }
9339
9340
9341
9342
9343 /* @obsolete ajFileBuffNewDF
9344 ** @replace ajFilebuffNewNamePathS (1,2/2,1)
9345 */
ajFileBuffNewDF(const AjPStr dir,const AjPStr filename)9346 __deprecated AjPFilebuff ajFileBuffNewDF(const AjPStr dir,
9347 const AjPStr filename)
9348 {
9349 return ajFilebuffNewNamePathS(filename, dir);
9350 }
9351
9352
9353
9354
9355
9356 /* @obsolete ajFileBuffNew
9357 ** @rename ajFilebuffNewNofile
9358 */
ajFileBuffNew(void)9359 __deprecated AjPFilebuff ajFileBuffNew(void)
9360 {
9361 return ajFilebuffNewNofile();
9362 }
9363
9364
9365
9366
9367 /* @obsolete ajFileBuffNewDW
9368 ** @rename ajFilebuffNewPathWild
9369 */
9370
ajFileBuffNewDW(const AjPStr dir,const AjPStr wildfile)9371 __deprecated AjPFilebuff ajFileBuffNewDW(const AjPStr dir,
9372 const AjPStr wildfile)
9373 {
9374 return ajFilebuffNewPathWild(dir, wildfile);
9375 }
9376
9377
9378
9379
9380 /* @obsolete ajFileBuffNewDWE
9381 ** @rename ajFilebuffNewPathWildExclude
9382 */
9383
ajFileBuffNewDWE(const AjPStr dir,const AjPStr wildfile,const AjPStr exclude)9384 __deprecated AjPFilebuff ajFileBuffNewDWE(const AjPStr dir,
9385 const AjPStr wildfile,
9386 const AjPStr exclude)
9387 {
9388 return ajFilebuffNewPathWildExclude(dir, wildfile, exclude);
9389 }
9390
9391
9392
9393
9394 /* @obsolete ajFileBuffDel
9395 ** @rename ajFilebuffDel
9396 */
ajFileBuffDel(AjPFilebuff * Pbuff)9397 __deprecated void ajFileBuffDel(AjPFilebuff* Pbuff)
9398 {
9399 ajFilebuffDel(Pbuff);
9400 }
9401
9402
9403
9404
9405 /* @obsolete ajFileBuffSetFile
9406 ** @remove Use ajFilebuffReopenFile or ajFilebuffClear
9407 */
ajFileBuffSetFile(AjPFilebuff * pthys,AjPFile file,AjBool samefile)9408 __deprecated AjBool ajFileBuffSetFile(AjPFilebuff* pthys,
9409 AjPFile file, AjBool samefile)
9410 {
9411 if(samefile)
9412 ajFilebuffClear(*pthys, -1);
9413 else
9414 ajFilebuffReopenFile(pthys, file);
9415
9416 return ajTrue;
9417 }
9418
9419
9420
9421
9422 /* @obsolete ajFileBuffClear
9423 ** @rename ajFilebuffClear
9424 */
ajFileBuffClear(AjPFilebuff buff,ajint lines)9425 __deprecated void ajFileBuffClear(AjPFilebuff buff, ajint lines)
9426 {
9427 ajFilebuffClear(buff, lines);
9428 }
9429
9430
9431
9432
9433 /* @obsolete ajFileBuffClearStore
9434 ** @rename ajFilebuffClearStore
9435 */
ajFileBuffClearStore(AjPFilebuff buff,ajint lines,const AjPStr rdline,AjBool store,AjPStr * astr)9436 __deprecated void ajFileBuffClearStore(AjPFilebuff buff, ajint lines,
9437 const AjPStr rdline, AjBool store, AjPStr *astr)
9438 {
9439 ajFilebuffClearStore(buff, lines, rdline, store, astr);
9440
9441 return;
9442 }
9443
9444
9445
9446
9447 /* @obsolete ajFileBuffFix
9448 ** @rename ajFilebuffFix
9449 */
ajFileBuffFix(AjPFilebuff buff)9450 __deprecated void ajFileBuffFix(AjPFilebuff buff)
9451 {
9452 ajFilebuffFix(buff);
9453
9454 return;
9455 }
9456
9457
9458
9459
9460 /* @obsolete ajFileBuffReset
9461 ** @rename ajFilebuffReset
9462 */
ajFileBuffReset(AjPFilebuff buff)9463 __deprecated void ajFileBuffReset(AjPFilebuff buff)
9464 {
9465 ajFilebuffReset(buff);
9466
9467 return;
9468 }
9469
9470
9471
9472
9473 /* @obsolete ajFileBuffResetPos
9474 ** @rename ajFilebuffResetPos
9475 */
ajFileBuffResetPos(AjPFilebuff buff)9476 __deprecated void ajFileBuffResetPos(AjPFilebuff buff)
9477 {
9478 ajFilebuffResetPos(buff);
9479
9480 return;
9481 }
9482
9483
9484
9485
9486 /* @obsolete ajFileBuffResetStore
9487 ** @rename ajFilebuffResetStore
9488 */
ajFileBuffResetStore(AjPFilebuff buff,AjBool store,AjPStr * astr)9489 __deprecated void ajFileBuffResetStore(AjPFilebuff buff,
9490 AjBool store, AjPStr *astr)
9491 {
9492 ajFilebuffResetStore(buff, store, astr);
9493
9494 return;
9495 }
9496
9497
9498
9499
9500 /* @obsolete ajFileBuffBuff
9501 ** @rename ajFilebuffSetBuffered
9502 */
ajFileBuffBuff(AjPFilebuff buff)9503 __deprecated AjBool ajFileBuffBuff(AjPFilebuff buff)
9504 {
9505 return ajFilebuffSetBuffered(buff);
9506 }
9507
9508
9509
9510
9511 /* @obsolete ajFileBuffNobuff
9512 ** @rename ajFilebuffSetUnbuffered
9513 */
ajFileBuffNobuff(AjPFilebuff buff)9514 __deprecated AjBool ajFileBuffNobuff(AjPFilebuff buff)
9515 {
9516 return ajFilebuffSetUnbuffered(buff);
9517 }
9518
9519
9520
9521
9522 /* @obsolete ajFileBuffStripHtmlPre
9523 ** @rename ajFileBuffHtmlPre
9524 */
ajFileBuffStripHtmlPre(AjPFilebuff buff)9525 __deprecated AjBool ajFileBuffStripHtmlPre(AjPFilebuff buff)
9526 {
9527 return ajFilebuffHtmlPre(buff);
9528 }
9529
9530
9531
9532
9533 /* @obsolete ajFileBuffStripHtml
9534 ** @rename ajFilebuffHtmlStrip
9535 */
ajFileBuffStripHtml(AjPFilebuff buff)9536 __deprecated void ajFileBuffStripHtml(AjPFilebuff buff)
9537 {
9538 ajFilebuffHtmlStrip(buff);
9539
9540 return;
9541 }
9542
9543
9544
9545
9546 /* @obsolete ajFileBuffLoadC
9547 ** @rename ajFilebuffLoadC
9548 */
ajFileBuffLoadC(AjPFilebuff buff,const char * line)9549 __deprecated void ajFileBuffLoadC(AjPFilebuff buff, const char* line)
9550 {
9551 ajFilebuffLoadC(buff, line);
9552
9553 return;
9554 }
9555
9556
9557
9558
9559 /* @obsolete ajFileBuffLoadS
9560 ** @rename ajFilebuffLoadS
9561 */
ajFileBuffLoadS(AjPFilebuff buff,const AjPStr line)9562 __deprecated void ajFileBuffLoadS(AjPFilebuff buff, const AjPStr line)
9563 {
9564 ajFilebuffLoadS(buff, line);
9565
9566 return;
9567 }
9568
9569
9570
9571
9572 /* @obsolete ajFileBuffLoad
9573 ** @rename ajFilebuffLoadAll
9574 */
ajFileBuffLoad(AjPFilebuff buff)9575 __deprecated void ajFileBuffLoad(AjPFilebuff buff)
9576 {
9577 ajFilebuffLoadAll(buff);
9578 }
9579
9580
9581
9582
9583 /* @obsolete ajFileBuffFile
9584 ** @rename ajFilebuffGetFile
9585 */
ajFileBuffFile(const AjPFilebuff buff)9586 __deprecated AjPFile ajFileBuffFile(const AjPFilebuff buff)
9587 {
9588 return ajFilebuffGetFile(buff);
9589 }
9590
9591
9592
9593
9594 /* @obsolete ajFileBuffSize
9595 ** @rename ajFileValueBuffsize
9596 */
ajFileBuffSize(void)9597 __deprecated ajint ajFileBuffSize(void)
9598 {
9599 return ajFileValueBuffsize();
9600 }
9601
9602
9603
9604
9605 /* @obsolete ajFileBuffFp
9606 ** @rename ajFilebuffGetFileptr
9607 */
ajFileBuffFp(const AjPFilebuff buff)9608 __deprecated FILE* ajFileBuffFp(const AjPFilebuff buff)
9609 {
9610 return ajFilebuffGetFileptr(buff);
9611 }
9612
9613
9614
9615
9616 /* @obsolete ajFileBuffIsBuffered
9617 ** @rename ajFilebuffIsBuffered
9618 */
ajFileBuffIsBuffered(const AjPFilebuff buff)9619 __deprecated AjBool ajFileBuffIsBuffered(const AjPFilebuff buff)
9620 {
9621 return ajFilebuffIsBuffered(buff);
9622 }
9623
9624
9625
9626
9627 /* @obsolete ajFileBuffEmpty
9628 ** @rename ajFilebuffIsEmpty
9629 */
ajFileBuffEmpty(const AjPFilebuff buff)9630 __deprecated AjBool ajFileBuffEmpty(const AjPFilebuff buff)
9631 {
9632 return ajFilebuffIsEmpty(buff);
9633 }
9634
9635
9636
9637
9638 /* @obsolete ajFileBuffEnd
9639 ** @rename ajFilebuffIsEnded
9640 */
ajFileBuffEnd(const AjPFilebuff buff)9641 __deprecated AjBool ajFileBuffEnd(const AjPFilebuff buff)
9642 {
9643 return ajFilebuffIsEnded(buff);
9644 }
9645
9646
9647
9648
9649 /* @obsolete ajFileBuffEof
9650 ** @rename ajFilebuffIsEof
9651 */
ajFileBuffEof(const AjPFilebuff buff)9652 __deprecated AjBool ajFileBuffEof(const AjPFilebuff buff)
9653 {
9654 return ajFilebuffIsEof(buff);
9655 }
9656
9657
9658
9659
9660 /* @obsolete ajFileBuffTrace
9661 ** @rename ajFilebuffTrace
9662 */
ajFileBuffTrace(const AjPFilebuff buff)9663 __deprecated void ajFileBuffTrace(const AjPFilebuff buff)
9664 {
9665 ajFilebuffTrace(buff);
9666
9667 return;
9668 }
9669
9670
9671
9672
9673 /* @obsolete ajFileBuffTraceFull
9674 ** @rename ajFilebuffTraceFull
9675 */
ajFileBuffTraceFull(const AjPFilebuff buff,size_t nlines,size_t nfree)9676 __deprecated void ajFileBuffTraceFull(const AjPFilebuff buff, size_t nlines,
9677 size_t nfree)
9678 {
9679 ajFilebuffTraceFull(buff, nlines, nfree);
9680
9681 return;
9682 }
9683
9684
9685
9686
9687 /* @obsolete ajFileBuffPrint
9688 ** @rename ajFilebuffTraceTitle
9689 */
ajFileBuffPrint(const AjPFilebuff buff,const char * title)9690 __deprecated void ajFileBuffPrint(const AjPFilebuff buff, const char* title)
9691 {
9692 ajFilebuffTraceTitle(buff, title);
9693
9694 return;
9695 }
9696
9697
9698
9699
9700 /* @obsolete ajOutfileNew
9701 ** @rename ajOutfileNewNameS
9702 */
ajOutfileNew(const AjPStr name)9703 __deprecated AjPOutfile ajOutfileNew(const AjPStr name)
9704 {
9705 return ajOutfileNewNameS(name);
9706 }
9707
9708
9709
9710
9711 /* @obsolete ajOutfileDel
9712 ** @rename ajOutfileClose
9713 */
ajOutfileDel(AjPOutfile * pthis)9714 __deprecated void ajOutfileDel(AjPOutfile* pthis)
9715 {
9716 ajOutfileClose(pthis);
9717 return;
9718 }
9719
9720
9721
9722
9723 /* @obsolete ajOutfileFile
9724 ** @rename ajOutfileGetFile
9725 */
ajOutfileFile(const AjPOutfile thys)9726 __deprecated AjPFile ajOutfileFile (const AjPOutfile thys)
9727 {
9728 return thys->File;
9729 }
9730
9731
9732
9733
9734 /* @obsolete ajOutfileFp
9735 ** @rename ajOutfileGetFileptr
9736 */
ajOutfileFp(const AjPOutfile thys)9737 __deprecated FILE* ajOutfileFp (const AjPOutfile thys)
9738 {
9739 return ajOutfileGetFileptr(thys);
9740 }
9741
9742
9743
9744
9745 /* @obsolete ajOutfileFormat
9746 ** @rename ajOutfileGetFormat
9747 */
ajOutfileFormat(const AjPOutfile thys)9748 __deprecated AjPStr ajOutfileFormat (const AjPOutfile thys)
9749 {
9750 return thys->Formatstr;
9751 }
9752
9753
9754
9755
9756 /* @obsolete ajFileNameTrim
9757 ** @rename ajFilenameTrimPath
9758 */
ajFileNameTrim(AjPStr * fname)9759 __deprecated AjBool ajFileNameTrim(AjPStr* fname)
9760 {
9761 char *p;
9762
9763 if((p = strrchr(ajStrGetPtr(*fname),(ajint)SLASH_CHAR)))
9764 {
9765 ajStrAssignC(&fileTmpStr,p+1);
9766 ajStrAssignS(fname,fileTmpStr);
9767 }
9768
9769 return ajTrue;
9770 }
9771
9772
9773
9774
9775 /* @obsolete ajFileDirTrim
9776 ** @rename ajFilenameTrimPath
9777 */
ajFileDirTrim(AjPStr * name)9778 __deprecated AjBool ajFileDirTrim(AjPStr* name)
9779 {
9780 return ajFilenameTrimPath(name);
9781 }
9782
9783
9784
9785
9786 /* @obsolete ajFileDirExtnTrim
9787 ** @rename ajFilenameTrimPathExt
9788 */
ajFileDirExtnTrim(AjPStr * name)9789 __deprecated AjBool ajFileDirExtnTrim(AjPStr* name)
9790 {
9791 return ajFilenameTrimPathExt(name);
9792 }
9793
9794
9795
9796
9797 /* @obsolete ajFileDirPath
9798 ** @rename ajDirnameFillPath
9799 */
ajFileDirPath(AjPStr * dir)9800 __deprecated AjBool ajFileDirPath(AjPStr* dir)
9801 {
9802 return ajDirnameFillPath(dir);
9803 }
9804
9805
9806
9807
9808 /* @obsolete ajFileDirFix
9809 ** @rename ajDirnameFix
9810 */
ajFileDirFix(AjPStr * dir)9811 __deprecated void ajFileDirFix(AjPStr* dir)
9812 {
9813 ajDirnameFix(dir);
9814
9815 return;
9816 }
9817
9818
9819
9820
9821 /* @obsolete ajFileDir
9822 ** @rename ajDirnameFixExists
9823 */
ajFileDir(AjPStr * dir)9824 __deprecated AjBool ajFileDir(AjPStr* dir)
9825 {
9826 return ajDirnameFixExists(dir);
9827 }
9828
9829
9830
9831
9832 /* @obsolete ajFileDirUp
9833 ** @rename ajDirnameUp
9834 */
ajFileDirUp(AjPStr * dir)9835 __deprecated AjBool ajFileDirUp(AjPStr* dir)
9836 {
9837 return ajDirnameUp(dir);
9838 }
9839
9840
9841
9842
9843 /* @obsolete ajFileScan
9844 ** @remove Use ajFilelistAddPathWild and others
9845 */
ajFileScan(const AjPStr path,const AjPStr filename,AjPList * result,AjBool show,AjBool dolist,AjPList * list,AjPList rlist,AjBool recurs,AjPFile outf)9846 __deprecated ajint ajFileScan(const AjPStr path,
9847 const AjPStr filename, AjPList *result,
9848 AjBool show, AjBool dolist, AjPList *list,
9849 AjPList rlist, AjBool recurs, AjPFile outf)
9850 {
9851 (void)dolist;
9852 (void)list;
9853
9854 if(show)
9855 {
9856 ajDirnamePrintRecursiveIgnore(path, rlist, outf);
9857
9858 return 0;
9859 }
9860
9861 if(recurs)
9862 return ajFilelistAddPathWildRecursiveIgnore(*result,
9863 path, filename, rlist);
9864
9865 return ajFilelistAddPathWild(*result, path, filename);
9866 }
9867
9868
9869
9870
9871 /* @obsolete ajDirScan
9872 ** @remove Use ajFilelistAddPathWildDir
9873 */
ajDirScan(const AjPStr path,const AjPStr filename,AjPList * result)9874 __deprecated ajint ajDirScan(const AjPStr path,
9875 const AjPStr filename, AjPList *result)
9876 {
9877 return ajFilelistAddPathWildDir(*result, path, filename);
9878 }
9879
9880
9881
9882
9883 /* @obsolete ajFileGetwd
9884 ** @remove Use ajFileValueCwd
9885 */
ajFileGetwd(AjPStr * dir)9886 __deprecated AjBool ajFileGetwd(AjPStr* dir)
9887 {
9888 ajStrAssignS(dir, ajFileValueCwd());
9889
9890 return ajTrue;
9891 }
9892
9893 #endif
9894