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