roswell.roswell/src/html.c
2016-04-16 04:25:36 +09:00

286 lines
6.8 KiB
C

/* -*- tab-width : 2 -*- */
#include "opt.h"
struct tag {
int type; /* 0 for not tag
1 for open tag
2 for close tag*/
char* name;
struct Cons* attr;
};
struct Cons* attralloc(void) {
struct opts* ret=alloc(sizeof(struct opts));
ret->name=NULL;
ret->value=NULL;
return toPointer(cons(ret,(LVal)NULL));
}
void attrsfree(struct Cons* a) {
struct Cons* next;
for(;a;) {
struct opts* p=(struct opts*)firstp((LVal)a);
s((char*)p->name),s((char*)p->value);
next=(struct Cons*)a->next;
dealloc(a);
a=next;
}
}
LVal parse_attr(char* str) {
int i,j;
char *name,*val;
struct Cons tmp,*ret=&tmp,*cur=ret;
struct opts* p;
tmp.next=(LVal)NULL;
for(i=0;str[i]!='\0';++i) {
name=NULL,val=NULL;
/*skip space*/
int pos=position_char_not(" \t\r\n",&str[i]);
if(pos!=-1) {
i+=pos;
}else continue;
/*attr name */
pos=position_char("\"'>/= \t\r\n",&str[i]);
if(pos!=-1)
name=subseq(&str[i],0,pos),i+=pos;
/*skip space*/
pos=position_char_not(" \t\r\n",&str[i]);
if(pos!=-1)
i+=pos;
if(!(name && str[i]=='='))
continue;
cur->next=(LVal)attralloc();;
p=(struct opts*)firstp((LVal)cur->next);
p->name=name;
/*skip space*/
pos=position_char_not(" \t\r\n",&str[++i]);
if(pos!=-1) {
i+=pos;
switch(str[i]) {
case '\'':
j=position_char("'",&str[i+1]);
if(j!=-1) {
val=subseq(&str[i+1],0,j);
i+=j+1;
}
break;
case '"':
for(j=1;str[i+j]!='"';++j)
if(str[i+j]=='\\')
++j;
val=subseq(&str[i],1,j);
i+=j;
break;
default:
pos=position_char(" \t\r\n",&str[i]);
val=subseq(&str[i],0,pos);
break;
}
p->value=val;
}
cur=(struct Cons *)cur->next;
}
return (LVal)ret->next;
}
LVal tagalloc(void) {
struct tag* t=alloc(sizeof(struct tag));
t->type=0;
t->name=NULL;
t->attr=NULL;
return (LVal)toPointer(cons(t,(LVal)NULL));
}
void tagfree(LVal l) {
struct tag* t=firstp(l);
s(t->name);
attrsfree(t->attr);
dealloc(t);
dealloc((void*)l);
}
void tagsfree(LVal tags) {
struct Cons* t=(struct Cons*)tags;
struct Cons* next;
for(;t;t=next) {
next=(struct Cons*)t->next;
tagfree((LVal)t);
}
}
LVal delete_not_open_tags(LVal t) {
LVal tag=t;
LVal ret=tag;
LVal next;
for(;((struct Cons*)tag)->next!=(LVal)NULL&&((struct tag*)firstp(tag))->type!=1;tag=next) { /* find first*/
next=Next(tag);
tagfree(tag);
}
while(Next(tag)) {
if(((struct tag*)firstp(Next(tag)))->type!=1) {
next=Next(Next(tag));
tagfree(Next(tag));
((struct Cons*)tag)->next=next;
}else
tag=Next(tag);
}
return ret;
}
LVal delete_not_tags(char* tags,LVal tag) {
LVal ret;
LVal next;
for(;Next((LVal)tag)!=(LVal)NULL&&((struct tag*)firstp(tag))->name&&strcmp(((struct tag*)firstp(tag))->name,tags)!=0;tag=Next(tag)); /* find first*/
ret=tag;
while(Next(tag)) {
if(((struct tag*)firstp(Next((LVal)tag)))->name&&
strcmp(((struct tag*)firstp(Next((LVal)tag)))->name,tags)!=0) {
next=Next(Next(tag));
tagfree(Next(tag));
((struct Cons*)tag)->next=next;
}else
tag=Next(tag);
}
return (LVal)ret;
}
LVal filter_href(LVal t) {
LVal tags=t;
LVal ret=(LVal)NULL;
for(;tags!=(LVal)NULL;tags=Next(tags)) {
char* href=NULL;
LVal a=(LVal)((struct tag*)firstp(tags))->attr;
for(;a;a=Next(a)) {
struct opts* v=(struct opts*)firstp(a);
if(strcmp(v->name,"href")==0) {
href=q(v->value);
break;
}
}
if(href)
ret=(LVal)toPointer(conss(href,ret));
}
return ret;
}
LVal parse_tags(FILE* fp,LVal before,int mode) {
LVal current=tagalloc();
char str[2]={'\0','\0'};
int c,i=0;
char* buf=q("");
switch(mode) {
case 0: /* wait for '<' */
((struct tag*)firstp(current))->type=0;
while((c=fgetc(fp))!=EOF) {
if(c=='<') {
if(strlen(buf)==0) {
tagfree(current);
s(buf);
return parse_tags(fp,before,1);
}else {
((struct Cons*)current)->next=parse_tags(fp,current,1);
s(buf);
return current;
}
}else
str[0]=c,buf=s_cat2(buf,q(str));
}
break;
case 1: /* wait for '>' */
((struct tag*)firstp(current))->type=0;
while((c=fgetc(fp))!=EOF) {
if(i==0) {
if(c=='/')
((struct tag*)firstp(current))->type=2;
else {
((struct tag*)firstp(current))->type=1;
str[0]=c;
buf=s_cat2(buf,q(str));
}
++i;
continue;
}
if(c=='>') {
char *buf2;
if(((struct tag*)firstp(current))->type==2) {
int pos=position_char(" \t\r\n",buf);
if(pos!=-1) {
buf2=subseq(buf,0,pos);
s(buf);
buf=buf2;
((struct tag*)firstp(current))->name=q(buf);
}else {
((struct tag*)firstp(current))->name=buf;
buf=q("");
}
}else if(((struct tag*)firstp(current))->type==1) {
int pos=position_char(" \t\r\n",buf);
if(pos!=-1) {
((struct tag*)firstp(current))->name=subseq(buf,0,pos);
buf2=subseq(buf,pos,0);
((struct tag*)firstp(current))->attr=(struct Cons*)parse_attr(buf2);
s(buf);
buf=buf2;
}else {
((struct tag*)firstp(current))->name=buf;
buf=q("");
}
}
if(strcmp(((struct tag*)firstp(current))->name,"script")==0) {
((struct Cons*)current)->next=parse_tags(fp,current,2);
}else{
((struct Cons*)current)->next=parse_tags(fp,current,0);
}
s(buf);
return current;
}else {
str[0]=c;
buf=s_cat2(buf,q(str));
}
++i;
}
break;
case 2: /* wait for '</' */
((struct tag*)firstp(current))->type=0;
while((c=fgetc(fp))!=EOF) {
if(c=='<') {
if((c=fgetc(fp))!=EOF && c=='/') {
ungetc('/',fp);
if(strlen(buf)==0) {
tagfree(current);
s(buf);
return parse_tags(fp,current,1);
}else {
((struct Cons*)current)->next=parse_tags(fp,current,1);
s(buf);
return current;
}
}
ungetc('/',fp);
}else {
str[0]=c;
buf=s_cat2(buf,q(str));
}
}
break;
}
s(buf);
return current;
}
LVal atag_list(char* filename) {
FILE* fp;
LVal ret=(LVal)NULL;
cond_printf(1,"open %s\n",filename);
fp=fopen(filename,"r");
if(fp!=NULL) {
LVal tags=parse_tags(fp,(LVal)NULL,0);
tags=delete_not_tags("a",delete_not_open_tags(tags));
ret=nreverse(filter_href(tags));
tagsfree(tags);
fclose (fp);
}
return ret;
}