1 /******************************************************************************
2  *   Copyright (C) 2008-2014, International Business Machines
3  *   Corporation and others.  All Rights Reserved.
4  *******************************************************************************
5  */
6 #include "unicode/utypes.h"
7 #include "unicode/putil.h"
8 #include "cstring.h"
9 #include "toolutil.h"
10 #include "uoptions.h"
11 #include "uparse.h"
12 #include "package.h"
13 #include "pkg_icu.h"
14 
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 
19 // read a file list -------------------------------------------------------- ***
20 
21 U_NAMESPACE_USE
22 
23 static const struct {
24     const char *suffix;
25     int32_t length;
26 } listFileSuffixes[]={
27     { ".txt", 4 },
28     { ".lst", 4 },
29     { ".tmp", 4 }
30 };
31 
32 /* check for multiple text file suffixes to see if this list name is a text file name */
33 static UBool
isListTextFile(const char * listname)34 isListTextFile(const char *listname) {
35     const char *listNameEnd=strchr(listname, 0);
36     const char *suffix;
37     int32_t i, length;
38     for(i=0; i<UPRV_LENGTHOF(listFileSuffixes); ++i) {
39         suffix=listFileSuffixes[i].suffix;
40         length=listFileSuffixes[i].length;
41         if((listNameEnd-listname)>length && 0==memcmp(listNameEnd-length, suffix, length)) {
42             return TRUE;
43         }
44     }
45     return FALSE;
46 }
47 
48 /*
49  * Read a file list.
50  * If the listname ends with ".txt", then read the list file
51  * (in the system/ invariant charset).
52  * If the listname ends with ".dat", then read the ICU .dat package file.
53  * Otherwise, read the file itself as a single-item list.
54  */
55 U_CAPI Package * U_EXPORT2
readList(const char * filesPath,const char * listname,UBool readContents,Package * listPkgIn)56 readList(const char *filesPath, const char *listname, UBool readContents, Package *listPkgIn) {
57     Package *listPkg = listPkgIn;
58     FILE *file;
59     const char *listNameEnd;
60 
61     if(listname==NULL || listname[0]==0) {
62         fprintf(stderr, "missing list file\n");
63         return NULL;
64     }
65 
66     if (listPkg == NULL) {
67         listPkg=new Package();
68         if(listPkg==NULL) {
69             fprintf(stderr, "icupkg: not enough memory\n");
70             exit(U_MEMORY_ALLOCATION_ERROR);
71         }
72     }
73 
74     listNameEnd=strchr(listname, 0);
75     if(isListTextFile(listname)) {
76         // read the list file
77         char line[1024];
78         char *end;
79         const char *start;
80 
81         file=fopen(listname, "r");
82         if(file==NULL) {
83             fprintf(stderr, "icupkg: unable to open list file \"%s\"\n", listname);
84             delete listPkg;
85             exit(U_FILE_ACCESS_ERROR);
86         }
87 
88         while(fgets(line, sizeof(line), file)) {
89             // remove comments
90             end=strchr(line, '#');
91             if(end!=NULL) {
92                 *end=0;
93             } else {
94                 // remove trailing CR LF
95                 end=strchr(line, 0);
96                 while(line<end && (*(end-1)=='\r' || *(end-1)=='\n')) {
97                     *--end=0;
98                 }
99             }
100 
101             // check first non-whitespace character and
102             // skip empty lines and
103             // skip lines starting with reserved characters
104             start=u_skipWhitespace(line);
105             if(*start==0 || NULL!=strchr(U_PKG_RESERVED_CHARS, *start)) {
106                 continue;
107             }
108 
109             // take whitespace-separated items from the line
110             for(;;) {
111                 // find whitespace after the item or the end of the line
112                 for(end=(char *)start; *end!=0 && *end!=' ' && *end!='\t'; ++end) {}
113                 if(*end==0) {
114                     // this item is the last one on the line
115                     end=NULL;
116                 } else {
117                     // the item is terminated by whitespace, terminate it with NUL
118                     *end=0;
119                 }
120                 if(readContents) {
121                     listPkg->addFile(filesPath, start);
122                 } else {
123                     listPkg->addItem(start);
124                 }
125 
126                 // find the start of the next item or exit the loop
127                 if(end==NULL || *(start=u_skipWhitespace(end+1))==0) {
128                     break;
129                 }
130             }
131         }
132         fclose(file);
133     } else if((listNameEnd-listname)>4 && 0==memcmp(listNameEnd-4, ".dat", 4)) {
134         // read the ICU .dat package
135         // Accept a .dat file whose name differs from the ToC prefixes.
136         listPkg->setAutoPrefix();
137         listPkg->readPackage(listname);
138     } else {
139         // list the single file itself
140         if(readContents) {
141             listPkg->addFile(filesPath, listname);
142         } else {
143             listPkg->addItem(listname);
144         }
145     }
146 
147     return listPkg;
148 }
149 
150 U_CAPI int U_EXPORT2
writePackageDatFile(const char * outFilename,const char * outComment,const char * sourcePath,const char * addList,Package * pkg,char outType)151 writePackageDatFile(const char *outFilename, const char *outComment, const char *sourcePath, const char *addList, Package *pkg, char outType) {
152     Package *addListPkg = NULL;
153     UBool pkgDelete = FALSE;
154 
155     if (pkg == NULL) {
156         pkg = new Package;
157         if(pkg == NULL) {
158             fprintf(stderr, "icupkg: not enough memory\n");
159             return U_MEMORY_ALLOCATION_ERROR;
160         }
161 
162         addListPkg = readList(sourcePath, addList, TRUE, NULL);
163         if(addListPkg != NULL) {
164             pkg->addItems(*addListPkg);
165         } else {
166             return U_ILLEGAL_ARGUMENT_ERROR;
167         }
168 
169         pkgDelete = TRUE;
170     }
171 
172     pkg->writePackage(outFilename, outType, outComment);
173 
174     if (pkgDelete) {
175         delete pkg;
176         delete addListPkg;
177     }
178 
179     return 0;
180 }
181 
182