root/trunk/phobos/std/openrj.d

Revision 1519, 26.8 kB (checked in by Masahiro Nakagawa, 5 years ago)

opApply's delegate needs to be 'scope' for avoiding heap allocation

  • Property svn:eol-style set to native
Line 
1 // Written in the D programming language
2
3 /* /////////////////////////////////////////////////////////////////////////////
4  * File:    std/openrj.d
5  *
6  * Purpose: Open-RJ/D mapping for the D standard library
7  *
8  * Created: 11th June 2004
9  * Updated: 10th March 2005
10  *
11  * Home:    http://openrj.org/
12  *
13  * Copyright 2004-2005 by Matthew Wilson and Synesis Software
14  * Written by Matthew Wilson
15  *
16  * This software is provided 'as-is', without any express or implied
17  * warranty. In no event will the authors be held liable for any damages
18  * arising from the use of this software.
19  *
20  * Permission is granted to anyone to use this software for any purpose,
21  * including commercial applications, and to alter it and redistribute it
22  * freely, in both source and binary form, subject to the following
23  * restrictions:
24  *
25  * -  The origin of this software must not be misrepresented; you must not
26  *    claim that you wrote the original software. If you use this software
27  *    in a product, an acknowledgment in the product documentation would be
28  *    appreciated but is not required.
29  * -  Altered source versions must be plainly marked as such, and must not
30  *    be misrepresented as being the original software.
31  * -  This notice may not be removed or altered from any source
32  *    distribution.
33  *
34  * //////////////////////////////////////////////////////////////////////////
35  * Altered by Walter Bright.
36  */
37
38
39 /**
40  * Open-RJ mapping for the D standard library.
41  *
42  * Authors:
43  *  Matthew Wilson
44  * References:
45  *  $(LINK2 http://www.$(OPENRJ).org/, Open-RJ)
46  * Macros:
47  *  WIKI=Phobos/StdOpenrj
48  *  OPENRJ=openrj
49  */
50
51 /* /////////////////////////////////////////////////////////////////////////////
52  * Module
53  */
54
55 module std.openrj;
56
57 /* /////////////////////////////////////////////////////////////////////////////
58  * Imports
59  */
60
61 private import std.ctype;
62 version(MainTest)
63 {
64     private import std.file;
65     private import std.perf;
66 } // version(MainTest)
67 private import std.string;
68
69 /* /////////////////////////////////////////////////////////////////////////////
70  * Version information
71  */
72
73 // This'll be moved out to somewhere common soon
74
75 private struct Version
76 {
77     string  name;
78     string  description;
79     uint    major;
80     uint    minor;
81     uint    revision;
82     uint    edit;
83     ulong   buildTime;
84 }
85
86 public static Version   VERSION =
87 {
88         "std.openrj"
89     ,   "Record-JAR database reader"
90     ,   1
91     ,   0
92     ,   7
93     ,   7
94     ,   0
95 };
96
97 /* /////////////////////////////////////////////////////////////////////////////
98  * Structs
99  */
100
101 // This'll be moved out to somewhere common soon
102
103 private struct EnumString
104 {
105     int     value;
106     string  str;
107 };
108
109 private template enum_to_string(T)
110 {
111     string enum_to_string(const EnumString[] strings, T t)
112     {
113         // 'Optimised' search.
114         //
115         // Since many enums start at 0 and are contiguously ordered, it's quite
116         // likely that the value will equal the index. If it does, we can just
117         // return the string from that index.
118         int index   =   cast(int)(t);
119
120         if( index >= 0 &&
121             index < strings.length &&
122             strings[index].value == index)
123         {
124             return strings[index].str.idup;
125         }
126
127         // Otherwise, just do a linear search
128         foreach(s; strings)
129         {
130             if(cast(int)(t) == s.value)
131             {
132                 return s.str.idup;
133             }
134         }
135
136         return "<unknown>";
137     }
138 }
139
140 /* /////////////////////////////////////////////////////////////////////////////
141  * Enumerations
142  */
143
144 /** Flags that moderate the creation of Databases */
145 public enum ORJ_FLAG
146 {
147     ORDER_FIELDS                    =   0x0001,  /// Arranges the fields in alphabetical order
148     ELIDE_BLANK_RECORDS             =   0x0002,  /// Causes blank records to be ignored
149 }
150
151 /**
152  *
153  */
154 public string toString(ORJ_FLAG f)
155 {
156     static const EnumString    strings[] =
157     [
158             {   ORJ_FLAG.ORDER_FIELDS,           "Arranges the fields in alphabetical order" }
159         ,   {   ORJ_FLAG.ELIDE_BLANK_RECORDS,    "Causes blank records to be ignored"        }
160     ];
161
162     return enum_to_string!(ORJ_FLAG)(strings, f);
163 }
164
165 /** General error codes */
166 public enum ORJRC
167 {
168     SUCCESS                      =   0,          /// Operation was successful
169     CANNOT_OPEN_JAR_FILE,                        /// The given file does not exist, or cannot be accessed
170     NO_RECORDS,                                  /// The database file contained no records
171     OUT_OF_MEMORY,                               /// The API suffered memory exhaustion
172     BAD_FILE_READ,                               /// A read operation failed
173     PARSE_ERROR,                                 /// Parsing of the database file failed due to a syntax error
174     INVALID_INDEX,                               /// An invalid index was specified
175     UNEXPECTED,                                  /// An unexpected condition was encountered
176     INVALID_CONTENT,                             /// The database file contained invalid content
177 }
178
179 /**
180  *
181  */
182 public string toString(ORJRC f)
183 {
184     static const EnumString    strings[] =
185     [
186             {   ORJRC.SUCCESS,              "Operation was successful"                                      }
187         ,   {   ORJRC.CANNOT_OPEN_JAR_FILE, "The given file does not exist, or cannot be accessed"          }
188         ,   {   ORJRC.NO_RECORDS,           "The database file contained no records"                        }
189         ,   {   ORJRC.OUT_OF_MEMORY,        "The API suffered memory exhaustion"                            }
190         ,   {   ORJRC.BAD_FILE_READ,        "A read operation failed"                                       }
191         ,   {   ORJRC.PARSE_ERROR,          "Parsing of the database file failed due to a syntax error"     }
192         ,   {   ORJRC.INVALID_INDEX,        "An invalid index was specified"                                }
193         ,   {   ORJRC.UNEXPECTED,           "An unexpected condition was encountered"                       }   
194         ,   {   ORJRC.INVALID_CONTENT,      "The database file contained invalid content"                   }       
195     ];
196
197     return enum_to_string!(ORJRC)(strings, f);
198 }
199
200 /** Parsing error codes */
201 public enum ORJ_PARSE_ERROR
202 {
203     SUCCESS                         =   0,       /// Parsing was successful
204     RECORD_SEPARATOR_IN_CONTINUATION,            /// A record separator was encountered during a content line continuation
205     UNFINISHED_LINE,                             /// The last line in the database was not terminated by a line-feed
206     UNFINISHED_FIELD,                            /// The last field in the database file was not terminated by a record separator
207     UNFINISHED_RECORD,                           /// The last record in the database file was not terminated by a record separator
208 }
209
210 /**
211  *
212  */
213 public string toString(ORJ_PARSE_ERROR f)
214 {
215     static const EnumString    strings[] =
216     [
217             {   ORJ_PARSE_ERROR.SUCCESS,                            "Parsing was successful"                                                        }
218         ,   {   ORJ_PARSE_ERROR.RECORD_SEPARATOR_IN_CONTINUATION,   "A record separator was encountered during a content line continuation"         }
219         ,   {   ORJ_PARSE_ERROR.UNFINISHED_LINE,                    "The last line in the database was not terminated by a line-feed"               }
220         ,   {   ORJ_PARSE_ERROR.UNFINISHED_FIELD,                   "The last field in the database file was not terminated by a record separator"  }
221         ,   {   ORJ_PARSE_ERROR.UNFINISHED_RECORD,                  "The last record in the database file was not terminated by a record separator" }
222     ];
223
224     return enum_to_string!(ORJ_PARSE_ERROR)(strings, f);
225 }
226
227 /* /////////////////////////////////////////////////////////////////////////////
228  * Classes
229  */
230
231 /**
232  *
233  */
234 class OpenRJException
235     : public Exception
236 {
237 /* \name Construction */
238
239 protected:
240     this(string message)
241     {
242         super(message);
243     }
244
245 }
246
247 /**
248  *
249  */
250 class DatabaseException
251     : public OpenRJException
252 {
253 /* \name Construction */
254 private:
255     this(string details, ORJRC rc)
256     {
257 //printf("DatabaseException(0: %.*s, %.*s)\n", details, std.openrj.toString(rc));
258
259         string  message    =   std.string.format(   "Database creation failed; error: %s, %s"
260                                                 ,   cast(int)rc
261                                                 ,   std.openrj.toString(rc));
262
263         m_rc        =   rc;
264         m_pe        =   ORJ_PARSE_ERROR.SUCCESS;
265         m_lineNum   =   -1;
266
267         super(message);
268     }
269
270     this(ORJRC rc, int lineNum)
271     {
272 //printf("DatabaseException(1: %.*s, %d)\n", std.openrj.toString(rc), lineNum);
273
274         string  message    =   std.string.format(   "Database creation failed, at line %s; error: %s, %s"
275                                                 ,   lineNum
276                                                 ,   cast(int)rc
277                                                 ,   std.openrj.toString(rc));
278
279         m_rc        =   rc;
280         m_pe        =   ORJ_PARSE_ERROR.SUCCESS;
281         m_lineNum   =   lineNum;
282
283         super(message);
284     }
285
286     this(ORJ_PARSE_ERROR pe, int lineNum)
287     {
288 //printf("DatabaseException(2: %.*s, %d)\n", std.openrj.toString(pe), lineNum);
289
290         string  message    =   std.string.format(   "Parsing error in database, at line %s; parse error: %s, %s"
291                                                 ,   lineNum
292                                                 ,   cast(int)pe
293                                                 ,   std.openrj.toString(pe));
294
295         m_rc        =   ORJRC.PARSE_ERROR;
296         m_pe        =   pe;
297         m_lineNum   =   lineNum;
298
299         super(message);
300     }
301
302     this(string details, ORJ_PARSE_ERROR pe, int lineNum)
303     {
304 //printf("DatabaseException(3: %.*s, %.*s, %d)\n", details, std.openrj.toString(rc), lineNum);
305
306         string  message    =   std.string.format(   "Parsing error in database, at line %s; parse error: %s, %s; %s"
307                                                 ,   lineNum
308                                                 ,   cast(int)pe
309                                                 ,   std.openrj.toString(pe)
310                                                 ,   details);
311
312         m_rc        =   ORJRC.PARSE_ERROR;
313         m_pe        =   pe;
314         m_lineNum   =   lineNum;
315
316         super(message);
317     }
318
319 /* \name Attributes */
320 public:
321
322     /**
323      *
324      */
325     ORJRC rc()
326     {
327         return m_rc;
328     }
329
330     /**
331      *
332      */
333     ORJ_PARSE_ERROR parseError()
334     {
335         return m_pe;
336     }
337
338     /**
339      *
340      */
341     int lineNum()
342     {
343         return m_lineNum;
344     }
345
346 // Members
347 private:
348     int             m_lineNum;
349     ORJRC           m_rc;
350     ORJ_PARSE_ERROR m_pe;
351 }
352
353 /**
354  *
355  */
356 class InvalidKeyException
357     : public OpenRJException
358 {
359 /* \name Construction */
360 private:
361     this(string message)
362     {
363         super(message);
364     }
365 }
366
367 /**
368  *
369  */
370 class InvalidTypeException
371     : public OpenRJException
372 {
373 /* \name Construction */
374 private:
375     this(string message)
376     {
377         super(message);
378     }
379 }
380
381 /* /////////////////////////////////////////////////////////////////////////////
382  * Classes
383  */
384
385 /// Represents a field in the database
386 class Field
387 {
388 /* \name Construction */
389
390 private:
391     this(string name, string value/* , Record record */)
392     in
393     {
394         assert(null !is name);
395         assert(null !is value);
396     }
397     body
398     {
399         m_name      =   name;
400         m_value     =   value;
401         /* m_record =   record; */
402     }
403
404
405 /* \name Attributes */
406
407 public:
408
409     /**
410      *
411      */
412     final string  name()
413     {
414         return m_name;
415     }
416
417     /**
418      *
419      */
420     final string  value()
421     {
422         return m_value;
423     }
424
425     /**
426      *
427      */
428     Record record()
429     {
430         return m_record;
431     }
432
433
434 /* \name Comparison */
435
436 /+
437 public:
438     int opCmp(Object rhs)
439     {
440         Field   f   =   cast(Field)(rhs);
441
442         if(null is f)
443         {
444             throw new InvalidTypeException("Attempt to compare a Field with an instance of another type");
445         }
446
447         return opCmp(f);
448     }
449 public:
450     int opCmp(Field rhs)
451     {
452         int res;
453
454         if(this is rhs)
455         {
456             res = 0;
457         }
458         else
459         {
460             res = std.string.cmp(m_name, rhs.m_name);
461
462             if(0 == res)
463             {
464                 res = std.string.cmp(m_value, rhs.m_value);
465             }
466         }
467
468         return res;
469     }
470 +/
471
472
473 // Members
474 private:
475     string  m_name;
476     string  m_value;
477     Record  m_record;
478 }
479
480 /// Represents a record in the database, consisting of a set of fields
481 class Record
482 {
483 /* \name Types */
484
485 public:
486     alias object.size_t     size_type;
487     alias object.size_t     index_type;
488     alias object.ptrdiff_t  difference_type;
489
490
491 /* \name Construction */
492
493 private:
494     this(Field[] fields, uint flags, Database database)
495     {
496         m_fields = fields.dup;
497
498         if(flags & ORJ_FLAG.ORDER_FIELDS)
499         {
500             m_fields = m_fields.sort;
501         }
502
503         foreach(Field field; m_fields)
504         {
505             if(!(field.name in m_values))
506             {
507                 m_values[field.name] = field;
508             }
509         }
510
511         m_database = database;
512     }
513
514
515 /* \name Attributes */
516
517 public:
518
519     /**
520      *
521      */
522     uint numFields()
523     {
524         return m_fields.length;
525     }
526
527     /**
528      *
529      */
530     @property uint length()
531     {
532         return numFields();
533     }
534
535     /**
536      *
537      */
538     Field[] fields()
539     {
540         return m_fields.dup;
541     }
542
543     /**
544      *
545      */
546     Field opIndex(index_type index)
547     in
548     {
549         assert(index < m_fields.length);
550     }
551     body
552     {
553         return m_fields[index];
554     }
555
556     /**
557      *
558      */
559     string opIndex(string fieldName)
560     {
561         return getField(fieldName).value;
562     }
563
564     /**
565      *
566      */
567     Field   getField(string fieldName)
568     in
569     {
570         assert(null !is fieldName);
571     }
572     body
573     {
574         Field   field   =   findField(fieldName);
575
576         if(null is field)
577         {
578             throw new InvalidKeyException("field not found");
579         }
580
581         return field;
582     }
583
584     /**
585      *
586      */
587     Field   findField(string fieldName)
588     in
589     {
590         assert(null !is fieldName);
591     }
592     body
593     {
594         Field   *pfield =   (fieldName in m_values);
595
596         return (null is pfield) ? null : *pfield;
597     }
598
599     /**
600      *
601      */
602     int hasField(string fieldName)
603     {
604         return null !is findField(fieldName);
605     }
606
607     /**
608      *
609      */
610     Database database()
611     {
612         return m_database;
613     }
614
615
616 /* \name Enumeration */
617
618 public:
619
620     /**
621      *
622      */
623     int opApply(scope int delegate(ref Field field) dg)
624     {
625         int result  =   0;
626
627         foreach (ref field; m_fields)
628         {
629             result = dg(field);
630
631             if(0 != result)
632             {
633                 break;
634             }
635         }
636
637         return result;
638     }
639
640     /**
641      *
642      */
643     int opApply(scope int delegate(in string name, in string value) dg)
644     {
645         int result  =   0;
646
647         foreach(Field field; m_fields)
648         {
649             result = dg(field.name(), field.value());
650
651             if(0 != result)
652             {
653                 break;
654             }
655         }
656
657         return result;
658     }
659
660
661 // Members
662 private:
663     Field[]         m_fields;
664     Field[string]   m_values;
665     Database        m_database;
666 }
667
668
669 /**
670  *
671  */
672 class Database
673 {
674 /* \name Types */
675
676 public:
677     alias object.size_t     size_type;
678     alias object.size_t     index_type;
679     alias object.ptrdiff_t  difference_type;
680
681
682 /* \name Construction */
683
684 private:
685     void init_(string[] lines, uint flags)
686     {
687         // Enumerate
688         int         bContinuing =   false;
689         Field[]     fields;
690         string      nextLine;
691         int         lineNum     =   1;
692         int         nextLineNum =   1;
693
694         foreach(string ln; lines)
695         {
696             // Always strip trailing space
697         auto line = stripr(ln);
698
699             // Check that we don't start a continued line with a record separator
700             if( bContinuing &&
701                 line.length > 1 &&
702                 "%%" == line[0 .. 2])
703             {
704                 throw new DatabaseException(ORJ_PARSE_ERROR.RECORD_SEPARATOR_IN_CONTINUATION, lineNum);
705             }
706
707             // Always strip leading whitespace
708             line = stripl(line);
709
710             int bContinuationLine;
711
712             if( line.length > 0 &&
713                 '\\' == line[line.length - 1])
714             {
715                 bContinuationLine   =   true;
716                 bContinuing         =   true;
717                 line                =   line[0 .. line.length - 1];
718             }
719
720             // Always add on to the previous line
721             nextLine = nextLine ~ line;
722
723             line = null;
724
725             if(!bContinuationLine)
726             {
727                 if(0 == nextLine.length)
728                 {
729                     // Just ignore these lines
730                 }
731                 else if(1 == nextLine.length)
732                 {
733                     throw new DatabaseException(ORJ_PARSE_ERROR.UNFINISHED_FIELD, lineNum);
734                 }
735                 else
736                 {
737                     if("%%" == nextLine[0 .. 2])
738                     {
739                         // Comment line - terminate the record
740 //                      printf("-- record --\n");
741
742                         if( 0 != fields.length ||
743                             0 == (ORJ_FLAG.ELIDE_BLANK_RECORDS & flags))
744                         {
745                             Record  record  =   new Record(fields, flags, this);
746
747                             foreach(Field field; fields)
748                             {
749                                 field.m_record = record;
750                             }
751
752                             m_records   ~=  record;
753                             fields      =   null;
754                         }
755                     }
756                     else
757                     {
758                         int colon   =   find(nextLine, ':');
759
760                         if(-1 == colon)
761                         {
762                             throw new DatabaseException(ORJ_PARSE_ERROR.UNFINISHED_FIELD, lineNum);
763                         }
764
765 //                      printf("%.*s(%d): %.*s (%d)\n", file, nextLineNum, nextLine, colon);
766
767                         string  name    =   nextLine[0 .. colon];
768                         string  value   =   nextLine[colon + 1 .. nextLine.length];
769
770                         name    =   stripr(name);
771                         value   =   stripl(value);
772
773 //                      printf("%.*s(%d): %.*s=%.*s\n", file, nextLineNum, name, value);
774
775                         Field   field   =   new Field(name, value);
776
777                         fields      ~=  field;
778                         m_fields    ~=  field;
779                     }
780                 }
781
782                 nextLine    =   "";
783                 nextLineNum =   lineNum + 1;
784                 bContinuing =   false;
785             }
786
787 /+ // This is currently commented out as it seems unlikely to be sensible to
788    // order the Fields globally. The reasoning is that if the Fields are used
789    // globally then it's more likely that their ordering in the database source
790    // is meaningful. If someone really needs an all-Fields array ordered, they
791    // can do it manually.
792             if(flags & ORJ_FLAG.ORDER_FIELDS)
793             {
794                 m_fields = m_fields.sort;
795             }
796 +/
797
798             ++lineNum;
799         }
800         if(bContinuing)
801         {
802             throw new DatabaseException(ORJ_PARSE_ERROR.UNFINISHED_LINE, lineNum);
803         }
804         if(fields.length > 0)
805         {
806             throw new DatabaseException(ORJ_PARSE_ERROR.UNFINISHED_RECORD, lineNum);
807         }
808         if(0 == m_records.length)
809         {
810             throw new DatabaseException(ORJRC.NO_RECORDS, lineNum);
811         }
812
813         m_flags     =   flags;
814         m_numLines  =   lines.length;
815     }
816 public:
817
818     /**
819      *
820      */
821     this(string memory, uint flags)
822     {
823         string[]    lines = split(memory, "\n");
824
825         init_(lines, flags);
826     }
827
828     /**
829      *
830      */
831     this(string[] lines, uint flags)
832     {
833         init_(lines, flags);
834     }
835
836
837 /* \name Attributes */
838
839 public:
840
841     /**
842      *
843      */
844     size_type   numRecords()
845     {
846         return m_records.length;
847     }
848
849     /**
850      *
851      */
852     size_type   numFields()
853     {
854         return m_fields.length;
855     }
856
857     /**
858      *
859      */
860     size_type   numLines()
861     {
862         return m_numLines;
863     }
864
865
866 /* \name Attributes */
867
868 public:
869
870     /**
871      *
872      */
873     uint flags()
874     {
875         return m_flags;
876     }
877
878     /**
879      *
880      */
881     Record[] records()
882     {
883         return m_records.dup;
884     }
885
886     /**
887      *
888      */
889     Field[] fields()
890     {
891         return m_fields.dup;
892     }
893
894     /**
895      *
896      */
897     @property uint length()
898     {
899         return numRecords();
900     }
901
902     /**
903      *
904      */
905     Record  opIndex(index_type index)
906     in
907     {
908         assert(index < m_records.length);
909     }
910     body
911     {
912         return m_records[index];
913     }
914
915
916 /* \name Searching */
917
918 public:
919
920     /**
921      *
922      */
923     Record[]    getRecordsContainingField(string fieldName)
924     {
925         Record[]    records;
926
927         foreach(Record record; m_records)
928         {
929             if(null !is record.findField(fieldName))
930             {
931                 records ~= record;
932             }
933         }
934
935         return records;
936     }
937
938     /**
939      *
940      */
941     Record[]    getRecordsContainingField(string fieldName, string fieldValue)
942     {
943         Record[]    records;
944         uint        flags   =   flags;
945
946         foreach(Record record; m_records)
947         {
948             Field   field   =   record.findField(fieldName);
949
950             if(null !is field)
951             {
952                 // Since there can be more than one field with the same name in
953                 // the same record, we need to search all fields in this record
954                 if(ORJ_FLAG.ORDER_FIELDS == (flags & ORJ_FLAG.ORDER_FIELDS))
955                 {
956                     // We can do a sorted search
957                     foreach(Field field; record)
958                     {
959                         int res =   cmp(field.name, fieldName);
960
961                         if( 0 == res &&
962                             (   null is fieldValue ||
963                                 field.value == fieldValue))
964                         {
965                             records ~= record;
966
967                             break;
968                         }
969                         else if(res > 0)
970                         {
971                             break;
972                         }
973                     }
974                 }
975                 else
976                 {
977                     foreach(Field field; record)
978                     {
979                         if( field.name == fieldName &&
980                             (   null is fieldValue ||
981                                 field.value == fieldValue))
982                         {
983                             records ~= record;
984
985                             break;
986                         }
987                     }
988                 }
989             }
990         }
991
992         return records;
993     }
994
995
996 /* \name Enumeration */
997
998 public:
999
1000     /**
1001      *
1002      */
1003     int opApply(scope int delegate(ref Record record) dg)
1004     {
1005         int result  =   0;
1006
1007         foreach(ref Record record; m_records)
1008         {
1009             result = dg(record);
1010
1011             if(0 != result)
1012             {
1013                 break;
1014             }
1015         };
1016
1017         return result;
1018     }
1019
1020     /**
1021      *
1022      */
1023     int opApply(scope int delegate(ref Field field) dg)
1024     {
1025         int result  =   0;
1026
1027         foreach(ref Field field; m_fields)
1028         {
1029             result = dg(field);
1030
1031             if(0 != result)
1032             {
1033                 break;
1034             }
1035         };
1036
1037         return result;
1038     }
1039
1040
1041 // Members
1042 private:
1043     uint        m_flags;
1044     size_type   m_numLines;
1045     Record[]    m_records;
1046     Field[]     m_fields;
1047 }
1048
1049 /* ////////////////////////////////////////////////////////////////////////// */
1050
1051 version(MainTest)
1052 {
1053
1054     int main(string[] args)
1055     {
1056         int flags   =   0
1057                     |   ORJ_FLAG.ORDER_FIELDS
1058                     |   ORJ_FLAG.ELIDE_BLANK_RECORDS
1059                     |   0;
1060
1061         if(args.length < 2)
1062         {
1063             printf("Need to specify jar file\n");
1064         }
1065         else
1066         {
1067             PerformanceCounter  counter =   new PerformanceCounter();
1068
1069             try
1070             {
1071                 printf( "std.openrj test:\n\tmodule:      \t%.*s\n\tdescription: \t%.*s\n\tversion:     \t%d.%d.%d.%d\n"
1072                     ,   std.openrj.VERSION.name
1073                     ,   std.openrj.VERSION.description
1074                     ,   std.openrj.VERSION.major
1075                     ,   std.openrj.VERSION.minor
1076                     ,   std.openrj.VERSION.revision
1077                     ,   std.openrj.VERSION.edit);
1078
1079                 counter.start();
1080
1081                 string      file        =   args[1];
1082                 string      chars       =   cast(string)std.file.read(file);
1083                 Database    database    =   new Database(chars, flags);
1084 //                Database    database    =   new Database(split(chars, "\n"), flags);
1085
1086                 counter.stop();
1087
1088                 PerformanceCounter.interval_type    loadTime    =   counter.microseconds();
1089
1090                 counter.start();
1091
1092                 int i   =   0;
1093                 foreach(Record record; database.records)
1094                 {
1095                     foreach(Field field; record)
1096                     {
1097                         i += field.name.length + field.value.length;
1098                     }
1099                 }
1100
1101                 counter.stop();
1102
1103                 PerformanceCounter.interval_type    enumerateTime   =   counter.microseconds();
1104
1105                 printf("Open-RJ/D test: 100%%-D!!\n");
1106                 printf("Load time:       %ld\n", loadTime);
1107                 printf("Enumerate time:  %ld\n", enumerateTime);
1108
1109                 return 0;
1110
1111                 printf("Records (%u)\n", database.numRecords);
1112                 foreach(Record record; database)
1113                 {
1114                     printf("  Record\n");
1115                     foreach(Field field; record.fields)
1116                     {
1117                         printf("    Field: %.*s=%.*s\n", field.name, field.value);
1118                     }
1119                 }
1120
1121                 printf("Fields (%u)\n", database.numFields);
1122                 foreach(Field field; database)
1123                 {
1124                         printf("    Field: %.*s=%.*s\n", field.name, field.value);
1125                 }
1126
1127                 Record[]    records =   database.getRecordsContainingField("Name");
1128                 printf("Records containing 'Name' (%u)\n", records);
1129                 foreach(Record record; records)
1130                 {
1131                     printf("  Record\n");
1132                     foreach(Field field; record.fields)
1133                     {
1134                         printf("    Field: %.*s=%.*s\n", field.name, field.value);
1135                     }
1136                 }
1137             }
1138             catch(Exception x)
1139             {
1140                 printf("Exception: %.*s\n", x.toString());
1141             }
1142         }
1143
1144         return 0;
1145     }
1146
1147 } // version(MainTest)
1148
1149 /* ////////////////////////////////////////////////////////////////////////// */
Note: See TracBrowser for help on using the browser.