1/******************************************************************************
2 *   Copyright (C) 2008-2009, 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) {
60    Package *listPkg;
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    listPkg=new Package();
70    if(listPkg==NULL) {
71        fprintf(stderr, "icupkg: not enough memory\n");
72        exit(U_MEMORY_ALLOCATION_ERROR);
73    }
74
75    listNameEnd=strchr(listname, 0);
76    if(isListTextFile(listname)) {
77        // read the list file
78        char line[1024];
79        char *end;
80        const char *start;
81
82        file=fopen(listname, "r");
83        if(file==NULL) {
84            fprintf(stderr, "icupkg: unable to open list file \"%s\"\n", listname);
85            delete listPkg;
86            exit(U_FILE_ACCESS_ERROR);
87        }
88
89        while(fgets(line, sizeof(line), file)) {
90            // remove comments
91            end=strchr(line, '#');
92            if(end!=NULL) {
93                *end=0;
94            } else {
95                // remove trailing CR LF
96                end=strchr(line, 0);
97                while(line<end && (*(end-1)=='\r' || *(end-1)=='\n')) {
98                    *--end=0;
99                }
100            }
101
102            // check first non-whitespace character and
103            // skip empty lines and
104            // skip lines starting with reserved characters
105            start=u_skipWhitespace(line);
106            if(*start==0 || NULL!=strchr(U_PKG_RESERVED_CHARS, *start)) {
107                continue;
108            }
109
110            // take whitespace-separated items from the line
111            for(;;) {
112                // find whitespace after the item or the end of the line
113                for(end=(char *)start; *end!=0 && *end!=' ' && *end!='\t'; ++end) {}
114                if(*end==0) {
115                    // this item is the last one on the line
116                    end=NULL;
117                } else {
118                    // the item is terminated by whitespace, terminate it with NUL
119                    *end=0;
120                }
121                if(readContents) {
122                    listPkg->addFile(filesPath, start);
123                } else {
124                    listPkg->addItem(start);
125                }
126
127                // find the start of the next item or exit the loop
128                if(end==NULL || *(start=u_skipWhitespace(end+1))==0) {
129                    break;
130                }
131            }
132        }
133        fclose(file);
134    } else if((listNameEnd-listname)>4 && 0==memcmp(listNameEnd-4, ".dat", 4)) {
135        // read the ICU .dat package
136        listPkg->readPackage(listname);
137    } else {
138        // list the single file itself
139        if(readContents) {
140            listPkg->addFile(filesPath, listname);
141        } else {
142            listPkg->addItem(listname);
143        }
144    }
145
146    return listPkg;
147}
148
149U_CAPI int U_EXPORT2
150writePackageDatFile(const char *outFilename, const char *outComment, const char *sourcePath, const char *addList, Package *pkg, char outType) {
151    Package *addListPkg = NULL;
152    UBool pkgDelete = FALSE;
153
154    if (pkg == NULL) {
155        pkg = new Package;
156        if(pkg == NULL) {
157            fprintf(stderr, "icupkg: not enough memory\n");
158            return U_MEMORY_ALLOCATION_ERROR;
159        }
160
161        addListPkg = readList(sourcePath, addList, TRUE);
162        if(addListPkg != NULL) {
163            pkg->addItems(*addListPkg);
164        } else {
165            return U_ILLEGAL_ARGUMENT_ERROR;
166        }
167
168        pkgDelete = TRUE;
169    }
170
171    pkg->writePackage(outFilename, outType, outComment);
172
173    if (pkgDelete) {
174        delete pkg;
175        delete addListPkg;
176    }
177
178    return 0;
179}
180
181