4 * Copyright (c) 2009-2012 project bchan
6 * This software is provided 'as-is', without any express or implied
7 * warranty. In no event will the authors be held liable for any damages
8 * arising from the use of this software.
10 * Permission is granted to anyone to use this software for any purpose,
11 * including commercial applications, and to alter it and redistribute it
12 * freely, subject to the following restrictions:
14 * 1. The origin of this software must not be misrepresented; you must not
15 * claim that you wrote the original software. If you use this software
16 * in a product, an acknowledgment in the product documentation would be
17 * appreciated but is not required.
19 * 2. Altered source versions must be plainly marked as such, and must not be
20 * misrepresented as being the original software.
22 * 3. This notice may not be removed or altered from any source
34 #include "bbsmenuparser.h"
35 #include <parse/tokenchecker.h>
37 #ifdef BCHANL_CONFIG_DEBUG
38 # define DP(arg) printf arg
39 # define DP_ER(msg, err) printf("%s (%d/%x)\n", msg, err>>16, err)
42 # define DP_ER(msg, err) /**/
45 LOCAL tokenchecker_valuetuple_t nList_element[] = {
49 LOCAL B eToken_element[] = ">=";
51 struct bbsmnparser_t_ {
65 tokenchecker_t tokenchecker;
66 bbsmnparser_item_t *itembuffer;
69 EXPORT bbsmnparser_item_t* bbsmnparser_item_new()
71 bbsmnparser_item_t *item;
73 item = malloc(sizeof(bbsmnparser_item_t));
77 item->category = NULL;
78 item->category_len = NULL;
79 item->url = malloc(sizeof(UB)*1);
88 LOCAL VOID bbsmnparser_item_clear(bbsmnparser_item_t *item)
90 if (item->category != NULL) {
93 if (item->url != NULL) {
96 if (item->title != NULL) {
99 item->url = malloc(sizeof(UB)*1);
104 item->category = NULL;
105 item->category_len = 0;
108 EXPORT VOID bbsmnparser_item_delete(bbsmnparser_item_t *item)
110 if (item->category != NULL) {
111 free(item->category);
113 if (item->url != NULL) {
116 if (item->title != NULL) {
122 LOCAL W bbsmnparser_convert_str(bbsmnparser_t *parser, const UB *src, W slen, UW attr, TC **dest, W *dlen)
127 err = tf_strtotcs(parser->ctx, src, slen, attr, &ch, &dest_len);
129 DP_ER("tf_strtotcs error", err);
137 *dest = realloc(*dest, sizeof(TC)*(*dlen + 1));
138 (*dest)[*dlen - 1] = ch;
139 (*dest)[*dlen] = TNULL;
146 err = tf_strtotcs(parser->ctx, NULL, slen, attr, &ch, &dest_len);
148 DP_ER("tf_strtotcs error:", err);
156 *dest = realloc(*dest, sizeof(TC)*(*dlen + 1));
157 (*dest)[*dlen - 1] = ch;
158 (*dest)[*dlen] = TNULL;
168 LOCAL W bbsmnparser_parsechar(bbsmnparser_t *parser, UB ch, bbsmnparser_item_t *item)
171 W *len, ret, err, val;
173 switch (parser->state) {
174 case STATE_READBOARDTITLE:
175 str = &(item->title);
176 len = &(item->title_len);
178 case STATE_READCATEGORY:
179 str = &(item->category);
180 len = &(item->category_len);
188 switch (parser->state) {
189 case STATE_SEARCHTAG:
191 parser->state = STATE_ELEMENTCHECK;
194 case STATE_ELEMENTCHECK:
195 ret = tokenchecker_inputchar(&(parser->tokenchecker), ch, &val);
196 if (ret == TOKENCHECKER_RESULT_CONTINUE) {
199 tokenchecker_clear(&(parser->tokenchecker));
200 if (ret == TOKENCHECKER_RESULT_DETERMINE) {
203 parser->state = STATE_READBOARDURL;
205 } else if (val == 2) {
207 parser->state = STATE_READCATEGORY;
211 parser->state = STATE_SEARCHTAG;
213 case STATE_READBOARDURL:
215 parser->state = STATE_READBOARDURL_2;
219 parser->state = STATE_READBOARDTITLE;
223 item->url = realloc(item->url, item->url_len + 1);
224 strncat(item->url, &ch, 1);
226 case STATE_READBOARDURL_2:
228 parser->state = STATE_READBOARDTITLE;
232 case STATE_READBOARDTITLE:
234 parser->state = STATE_ELEMENTCHECK;
235 err = bbsmnparser_convert_str(parser, NULL, 0, TF_ATTR_SUPPRESS_FUSEN, str, len);
241 err = bbsmnparser_convert_str(parser, &ch, 1, TF_ATTR_CONT|TF_ATTR_SUPPRESS_FUSEN, str, len);
246 case STATE_READCATEGORY:
248 parser->state = STATE_ELEMENTCHECK;
249 err = bbsmnparser_convert_str(parser, NULL, 0, TF_ATTR_SUPPRESS_FUSEN, str, len);
255 err = bbsmnparser_convert_str(parser, &ch, 1, TF_ATTR_CONT|TF_ATTR_SUPPRESS_FUSEN, str, len);
265 EXPORT VOID bbsmnparser_item_gethostboard(bbsmnparser_item_t *item, UB **host, W *host_len, UB **board, W *board_len)
268 UB *host0 = NULL, *board0 = NULL;
269 W host_len0 = 0, board_len0 = 0;
271 host0 = item->url + 7;
272 for (i=7; i < item->url_len; i++) {
273 if (item->url[i] == '/') {
280 board0 = item->url + i;
281 for (; i < item->url_len; i++) {
282 if (item->url[i] == '/') {
289 *host_len = host_len0;
291 *board_len = board_len0;
294 EXPORT Bool bbsmnparser_item_checkboradurl(bbsmnparser_item_t *item)
298 W host_len = 0, board_len = 0;
301 if (item->category != NULL) {
304 if (item->url == NULL) {
309 if (item->url_len < 7) {
310 /* this is not "http://". too short. */
313 cmp = strncmp(item->url, "http://", 7);
315 /* this is not "http://" */
319 host = item->url + 7;
320 for (i=7; i < item->url_len; i++) {
321 if (item->url[i] == '/') {
329 cmp = strncmp(host + host_len - 8, ".2ch.net", 8);
335 board = item->url + i;
336 for (; i < item->url_len; i++) {
337 if (item->url[i] == '/') {
342 if (board_len <= 0) {
346 if ((i+1) != item->url_len) {
353 EXPORT W bbsmnparser_getnextitem(bbsmnparser_t *parser, bbsmnparser_item_t **item)
355 bbsmncache_datareadcontext_t *context;
358 W len_cache, i, err = 0;
362 context = bbsmncache_startdataread(parser->cache, parser->i);
363 if (context == NULL) {
364 return -1; /* TODO */
368 cont = bbsmncache_datareadcontext_nextdata(context, &bin_cache, &len_cache);
373 for (i = 0; i < len_cache; i++) {
374 err = bbsmnparser_parsechar(parser, bin_cache[i], parser->itembuffer);
390 *item = parser->itembuffer;
391 parser->itembuffer = bbsmnparser_item_new();
396 bbsmncache_enddataread(parser->cache, context);
401 EXPORT VOID bbsmnparser_clear(bbsmnparser_t *parser)
406 err = tf_strtotcs(parser->ctx, NULL, 0, TF_ATTR_START, &ch, &len);
408 DP_ER("tf_strtotcs (clear)", err);
412 parser->isLSTN = False;
413 parser->state = STATE_SEARCHTAG;
415 bbsmnparser_item_clear(parser->itembuffer);
418 EXPORT bbsmnparser_item_t* bbsmnparser_newcategoryitem(bbsmnparser_t *parser, TC *category, W category_len)
420 bbsmnparser_item_t *item;
422 item = bbsmnparser_item_new();
426 item->category = malloc(sizeof(TC)*(category_len+1));
427 if (item->category == NULL) {
428 bbsmnparser_item_delete(item);
431 memcpy(item->category, category, sizeof(TC)*category_len);
432 item->category[category_len] = TNULL;
433 item->category_len = category_len;
438 EXPORT bbsmnparser_item_t* bbsmnparser_newboarditem(bbsmnparser_t *parser, TC *title, W title_len, UB *url, W url_len)
440 bbsmnparser_item_t *item;
442 item = bbsmnparser_item_new();
448 item->url = malloc(sizeof(UB)*(url_len+1));
449 if (item->url == NULL) {
450 bbsmnparser_item_delete(item);
453 memcpy(item->url, url, sizeof(UB)*url_len);
454 item->url[url_len] = '\0';
455 item->url_len = url_len;
457 item->title = malloc(sizeof(TC)*(title_len+1));
458 if (item->title == NULL) {
459 bbsmnparser_item_delete(item);
462 memcpy(item->title, title, sizeof(TC)*title_len);
463 item->title[title_len] = TNULL;
464 item->title_len = title_len;
469 EXPORT bbsmnparser_t* bbsmnparser_new(bbsmncache_t *cache)
471 bbsmnparser_t *parser;
474 parser = malloc(sizeof(bbsmnparser_t));
475 if (parser == NULL) {
478 parser->cache = cache;
480 tf_open_ctx(&parser->ctx);
481 ctx_id = tf_to_id(TF_ID_PROFSET_CONVERTFROM, "Shift_JIS");
483 tf_close_ctx(parser->ctx);
487 err = tf_set_profile(parser->ctx, ctx_id);
489 tf_close_ctx(parser->ctx);
495 parser->isLSTN = False;
496 parser->state = STATE_SEARCHTAG;
498 parser->itembuffer = bbsmnparser_item_new();
499 if (parser->itembuffer == NULL) {
500 tf_close_ctx(parser->ctx);
505 tokenchecker_initialize(&(parser->tokenchecker), nList_element, 2, eToken_element);
510 EXPORT VOID bbsmnparser_delete(bbsmnparser_t *parser)
512 bbsmnparser_item_delete(parser->itembuffer);
513 tf_close_ctx(parser->ctx);