- Added new dir for the library
[textus:php-language-detection.git] / textcat / handlers.c
1 /*
2    +----------------------------------------------------------------------+
3    | Copyright (c) 2010 The PHP Group                                     |
4    +----------------------------------------------------------------------+
5    | This source file is subject to version 3.01 of the PHP license,      |
6    | that is bundled with this package in the file LICENSE, and is        |
7    | available through the world-wide-web at the following url:           |
8    | http://www.php.net/license/3_01.txt                                  |
9    | If you did not receive a copy of the PHP license and are unable to   |
10    | obtain it through the world-wide-web, please send a note to          |
11    | license@php.net so we can mail you a copy immediately.               |
12    +----------------------------------------------------------------------+
13    | Author:  C├ęsar Rodas <crodas@member.fsf.org>                         |
14    +----------------------------------------------------------------------+
15  */
16 #include "textcat.h"
17 #include "textcat_internal.h"
18 #include <dirent.h>
19
20
21 #ifndef DIR_NAME
22     #define DIR_NAME "./knowledge/"
23 #endif
24
25 #define FILE_BUFFER 1024
26
27 Bool knowledge_save(void * memory, const uchar * id, NGrams * result, void * param)
28 {
29     uchar * fname, * content;
30     long i, ret, offset;
31     int fd;
32
33     fname = mempool_malloc(memory, strlen(id) + strlen(DIR_NAME) + 2);
34     sprintf(fname, "%s/%s", DIR_NAME, id);
35     mkdir(DIR_NAME, 0777);
36
37     fd = open(fname, O_CREAT | O_TRUNC | O_WRONLY, 0644);
38     if (fd == -1) {
39         return TC_FALSE;
40     }
41     content = mempool_malloc(memory, FILE_BUFFER); 
42     if (content == NULL) {
43         return TC_FALSE;
44     }
45
46     /* sort by freq */
47     textcat_ngram_sort_by_freq(result);
48
49     for(i=0,offset=0; i < result->size; i++) {
50         if (offset + result->ngram[i].size >= FILE_BUFFER - 1) {
51             ret    = write(fd, content, offset);
52             offset = 0;
53         }
54         strncpy(content+offset, result->ngram[i].str, result->ngram[i].size);
55         offset += result->ngram[i].size+1;
56         *(content+ offset-1) = '\n';
57     }
58     ret = write(fd, content, offset);
59     close(fd);
60     return TC_TRUE;
61 }
62
63 Bool knowledge_list(void * memory, uchar *** list, int * size, void * param) 
64 {
65     DIR * fd;
66     struct dirent * info;
67     int len, i;
68
69     fd = opendir(DIR_NAME);
70     if (fd == NULL) {
71         return TC_FALSE;
72     }
73     len = -2; /* . and .. aren't files */
74     i   = 0;
75     while (readdir(fd))  len++;
76     rewinddir(fd);
77     *list = mempool_malloc(memory, len * sizeof(char *));
78     if (*list == NULL) {
79         return TC_FALSE;
80     }
81     while (info = readdir(fd)) {
82         if (strcmp(info->d_name, ".") == 0 || strcmp(info->d_name, "..") == 0) {
83             continue;
84         }
85         *(*list+i) = mempool_strdup(memory, info->d_name);
86         if (*(*list+i) == NULL) {
87             return TC_FALSE;
88         }
89         i++;
90     }
91     *size = len;
92     closedir(fd);
93     return TC_TRUE;
94 }
95
96 Bool knowledge_load(void * memory, const uchar * id, NGrams * result, int max, void * param)
97 {
98     int fd;
99     int bytes, offset, ncount, i,e;
100     uchar * fname,  * content;
101
102     fname = mempool_malloc(memory, strlen(id) + strlen(DIR_NAME) + 2);
103     sprintf(fname, "%s/%s", DIR_NAME, id);
104
105     fd = open(fname, O_RDONLY);
106     if (fd == -1) {
107         return TC_FALSE;
108     }
109     
110     content = mempool_malloc(memory, FILE_BUFFER);
111     ncount  = 0;
112     offset  = 0;
113     do {
114         bytes = read(fd, content + offset, FILE_BUFFER - offset) + offset;
115         for (i=0; offset < bytes; offset++) {
116             if (*(content+offset) == '\n') {
117                 result->ngram[ncount].str       = mempool_strndup(memory, content+i, offset-i);
118                 result->ngram[ncount].size      = offset-i;
119                 result->ngram[ncount].position  = ncount;
120                 i = offset+1;
121                 ncount++;
122                 if (ncount >= max) {
123                     break;
124                 }
125             }
126         }
127         if (ncount >= max) {
128             break;
129         }
130         if (offset > i) {
131             offset -= i;
132             for (e=0; i < bytes; i++,e++) {
133                 *(content+e) = *(content+i);
134             }
135             *(content+e) = '\0';
136         } else {
137             offset = 0;
138         }
139     } while (bytes > 0);
140     result->size = ncount;
141     close(fd);
142     return TC_TRUE;
143 }
144
145 long knowledge_dist(NGrams *a, NGrams *b, void * param)
146 {
147     int ai, bi, diff;
148     long dist;
149     int max, match;
150     dist = 0;
151     max  = a->size > b->size ? a->size : b->size;
152     max++;
153     match = 0;
154
155     for (ai=0,bi=0; ai < a->size && bi < b->size; ) {
156          diff = strcmp(a->ngram[ai].str, b->ngram[bi].str);
157          if (diff < 0) {
158              ai++;
159          } else if (diff > 0) {
160              dist += max;
161              bi++;
162          } else {
163              dist += abs(a->ngram[ai].position - b->ngram[bi].position);
164              match++;
165              bi++;
166              ai++;
167          }
168     }
169     dist += max * (b->size - bi);
170     return (long)dist/max;
171 }
172
173 /* Default Parsing text callback {{{ */
174 Bool textcat_default_text_parser(TextCat *tc, const uchar * text, size_t length, int * (*set_ngram)(TextCat *, const uchar *, size_t), void * param)
175 {
176     size_t i,e,x, valid;
177     uchar *ntext;
178     /* create a copy of the text in order to do a best-effort
179      * to clean it, setting everything to lower-case, removing
180      * non-alpha and whitespaces.
181      */
182     ntext = mempool_malloc(tc->temp,length+1);
183     for (i=0, e=0; i < length; i++) {
184         if (isalpha(text[i])) {
185             ntext[e++] = tolower(text[i]);
186         } else {
187             while (++i < length && !isalpha(text[i]));
188             ntext[e++] = ' ';
189             i--;
190         }
191     }
192     ntext[e++] = '\0';
193     length     = e - 1;
194     /* extract the ngrams, and pass-it to the library (with the callback) */
195     for (e=0; e < length; e++) {
196         for (i=tc->min_ngram_len; i <= tc->max_ngram_len; i++) {
197             if (e+i > length) {
198                 break;
199             }
200
201
202             /* allow spaces only at the beging and end (in order to reduce n-grams quantities) {{{ */
203             valid = 1;
204             for (x=1; x < i-1; x++) {
205                 if (isblank(*(ntext+e+x))) {
206                     valid = 0;
207                     break;
208                 }
209             }
210             if (valid==0) {
211                 continue;
212             }
213             /* }}} */
214
215             if (set_ngram(tc, ntext+e, i) == TC_FALSE) {
216                 return TC_FALSE;
217             }
218         }
219     }
220     return TC_TRUE;
221 }
222 /* }}} */
223
224 /*
225  * Local variables:
226  * tab-width: 4
227  * c-basic-offset: 4
228  * End:
229  * vim600: sw=4 ts=4 fdm=marker
230  * vim<600: sw=4 ts=4
231  */