#include <stdio.h>
#include <stdlib.h>
#include "markdown.h"
// void process_markdown()
// {
// MyTSchar& fileName;
//
//
// Tcl_Obj* readObjPtr=Tcl_NewObj();
// Tcl_Channel channel=Tcl_OpenFileChannel(stateM.ip_,fileName.v(),"r",0);
// if(!channel){
// return cu_print_error(stateM.ip_,"Could not open file '%s'",fileName.v());
// }
// Tcl_SetChannelOption(stateM.ip_,channel,"-encoding","utf-8");
// Tcl_ReadChars(channel,readObjPtr,2000,0);
// char* tbuf=(char*)Tcl_GetStringFromObj(readObjPtr,&length);
// result=Tcl_Close(stateM.ip_,channel);
//
// Tcl_DecrRefCount(readObjPtr);
// return 0;
// }
inline int is_chars(int mychar,const char* chars)
{
return strchr(chars,mychar)!=NULL;
}
inline int is_same_char_line(MyTSchar& buffer,int start,int end,
int allow_spaces,int min_chars)
{
int num_chars=1;
for(int i=start+1;i<end;i++){
if(is_chars(buffer[i]," \t")){
if(allow_spaces==0) return 0;
} else if(buffer[i]!=buffer[start]){
return 0;
} else {
num_chars++;
}
}
if(num_chars>=min_chars) return 1;
else return 0;
}
inline int num_same_char_line_prefix(MyTSchar& buffer,int start,int end,
int allow_spaces)
{
int num_chars=1;
for(int i=start+1;i<end;i++){
if(is_chars(buffer[i]," \t")){
if(allow_spaces==0) break;
} else if(buffer[i]!=buffer[start]){
break;
} else {
num_chars++;
}
}
return num_chars;
}
inline int link_label_num(MyTSchar& buffer,int start)
{
int is_open=0,num_chars=0;
for(int i=start;i<buffer.num();i++){
if(is_chars(buffer[i]," \t")){
continue;
} else if(is_chars(buffer[i],"\r\n")){
return 0;
} else if(is_chars(buffer[i],"[")){
if(!is_open) is_open=1;
else return 0;
} else if(is_chars(buffer[i],"]")){
if(num_chars==0) return 0;
return i;
} else if(is_chars(buffer[i],"\\")){
num_chars++;
i++;
} else {
num_chars++;
}
}
return 0;
}
inline int link_destination_num(MyTSchar& buffer,int start)
{
int is_open=0,num_endlines=0,smaller_than=0,parentheses=0;
for(int i=start;i<buffer.num();i++){
if(is_chars(buffer[i]," \t")){
if(is_open && smaller_than==0){
if(parentheses) return 0;
return i;
}
continue;
} else if(is_chars(buffer[i],"\r\n")){
if(!is_open){
num_endlines++;
if(num_endlines>1) return 0;
} else if(smaller_than==0){
if(parentheses) return 0;
return i;
} else return 0;
} else if(is_chars(buffer[i],"<")){
if(!is_open){
is_open=1;
smaller_than=1;
} else if(smaller_than>0){
return 0;
}
} else if(is_chars(buffer[i],">")){
if(smaller_than>0){
if(parentheses) return 0;
return i+1;
}
is_open=1;
} else if(is_chars(buffer[i],"(")){
parentheses++;
is_open=1;
} else if(is_chars(buffer[i],")")){
parentheses--;
is_open=1;
} else if(is_chars(buffer[i],"\\")){
is_open=1;
i++;
} else {
is_open=1;
}
}
if(is_open && smaller_than==0) return buffer.num();
return 0;
}
inline int spaces_num(MyTSchar& buffer,int start,int& num_spaces)
{
num_spaces=0;
for(int i=start;i<buffer.num();i++){
if(is_chars(buffer[i]," ")){
num_spaces++;
} else if(is_chars(buffer[i],"\t")){
num_spaces+=4;
} else if(is_chars(buffer[i],"\r\n")){
return i;
} else {
return 0;
}
}
return buffer.num();
}
inline int link_title_num(MyTSchar& buffer,int start)
{
int is_open=0,num_spaces=0,num_endlines=0,num_enlinesA=0;
char openC;
for(int i=start;i<buffer.num();i++){
if(is_chars(buffer[i]," \t")){
num_spaces++;
} else if(is_chars(buffer[i],"\r\n")){
if(!is_open){
num_spaces++;
num_endlines++;
if(num_endlines>1) return 0;
} else {
if(num_enlinesA>0) return 0;
num_enlinesA++;
}
} else if(is_chars(buffer[i],"\"'")){
if(!is_open){
openC=buffer[i];
is_open=1;
} else if(buffer[i]==openC){
return i+1;
}
} else if(is_chars(buffer[i],"(")){
if(!is_open){
openC=buffer[i];
is_open=1;
} else if(openC=='('){
return 0;
}
} else if(is_chars(buffer[i],")")){
if(!is_open) return 0;
else if(openC=='('){
return i+1;
}
} else if(is_chars(buffer[i],"\\")){
if(!is_open) return 0;
i++;
} else {
if(!is_open) return 0;
is_open=1;
}
}
return 0;
}
inline int link_url_num(MyTSchar& buffer,int start)
{
int is_open=0,num_chars=0;
for(int i=start;i<buffer.num();i++){
if(is_chars(buffer[i]," \t")){
continue;
} else if(is_chars(buffer[i],"\r\n")){
return 0;
} else if(is_chars(buffer[i],"[")){
if(!is_open) is_open=1;
else return 0;
} else if(is_chars(buffer[i],"]")){
if(num_chars==0) return 0;
return i-start+1;
} else if(is_chars(buffer[i],"\\")){
num_chars++;
i++;
} else {
num_chars++;
}
}
return 0;
}
void MKstate::create_append_paragraph(MyTSchar& buffer,int parent_level)
{
int num_spaces;
//################################################################################
// block_quote
//################################################################################
if(blanks_line_[0]<=3 && is_chars(buffer[SE_lineNoBlank_[0]],"<")){
if(this->give_type(parent_level)!=MK::block_quote){
if(this->give_curr_type()==MK::fenced_code_block){
goto no_block_quote;
}
while(open_blocks_.num()>parent_level) this->curr_close();
this->append_block(MK::block_quote,SE_line_,SE_lineNoBlank_,
blanks_line_);
}
SE_line_[0]=SE_lineNoBlank_[0]+1;
if(is_chars(buffer[SE_line_[0]]," ")) SE_line_[0]++;
SE_lineNoBlank_[0]=spaces_num(buffer,SE_line_[0],blanks_line_[0]);
this->create_append_paragraph(buffer,parent_level+1);
return;
}
if(parent_level>0 && this->give_type(parent_level)==MK::block_quote){
while(open_blocks_.num()>parent_level) this->curr_close();
}
:no_block_quote;
//################################################################################
// fenced_code_block
//################################################################################
if(this->give_curr_type()==MK::fenced_code_block){
if(blanks_line_[0]<=3 && is_chars(buffer[SE_lineNoBlank_[0]],"`~")){
MKblocks& block=blocks_[open_blocks_[end_MTS]];
int valid=is_same_char_line(buffer,SE_lineNoBlank_[0],
SE_lineNoBlank_[1],0,block.level_);
if(buffer[SE_lineNoBlank_[0]]!=buffer[block.posNoBlank_[0]]) valid=0;
if(valid){
block.pos_[1]=SE_line_[1];
block.posNoBlank_[1]=SE_lineNoBlank_[1];
block.blanks_[1]=blanks_line_[1];
this->curr_close();
return;
}
}
MKblocks& block=blocks_[open_blocks_[end_MTS]];
block.pos_[1]=SE_line_[1];
block.posNoBlank_[1]=SE_lineNoBlank_[1];
block.blanks_[1]=blanks_line_[1];
return;
}
if(blanks_line_[0]<=3 && is_chars(buffer[SE_lineNoBlank_[0]],"`~")){
int level=num_same_char_line_prefix(buffer,SE_lineNoBlank_[0],SE_lineNoBlank_[1],0);
if(level>=3){
if(blockquote_levelN!=blockquote_level) this->close_all();
else if(this->curr_is_open()) this->curr_close();
MKblocks& block=this->append_block(MK::fenced_code_block,SE_line_,
SE_lineNoBlank_,blanks_line_);
block.level_=level;
return;
}
}
//################################################################################
// indented_code_block
//################################################################################
if(this->give_curr_type()==MK::indented_code_block){
if(blanks_line_[0]>=4){
MKblocks& block=blocks_[open_blocks_[end_MTS]];
block.pos_[1]=SE_line_[1];
block.posNoBlank_[1]=SE_lineNoBlank_[1];
block.blanks_[1]=blanks_line_[1];
return;
}
this->curr_close();
}
if(!this->curr_is_open() && blanks_line_[0]>=4){
this->append_block(MK::indented_code_block,SE_line_,SE_lineNoBlank_,
blanks_line_);
return;
}
//################################################################################
// setext_heading
//################################################################################
if(this->give_curr_type()==MK::paragraph &&
blanks_line_[0]<=3 &&
is_chars(buffer[SE_lineNoBlank_[0]],"-=")){
int valid=is_same_char_line(buffer,SE_lineNoBlank_[0],SE_lineNoBlank_[1],0,1);
if(valid){
MKblocks& block=blocks_[open_blocks_[end_MTS]];
block.mtype_=MK::setext_heading;
if(buffer[SE_lineNoBlank_[0]]=='=') block.level_=1;
else block.level_=2;
this->curr_close();
return;
}
}
//################################################################################
// thematic_break
//################################################################################
if(blanks_line_[0]<=3 && is_chars(buffer[SE_lineNoBlank_[0]],"-_*")){
int valid=is_same_char_line(buffer,SE_lineNoBlank_[0],SE_lineNoBlank_[1],1,3);
if(valid){
if(blockquote_levelN!=blockquote_level) this->close_all();
else if(this->curr_is_open()) this->curr_close();
this->append_block(MK::thematic_break,SE_line_,
SE_lineNoBlank_,blanks_line_);
this->curr_close();
return;
}
}
//################################################################################
// ATX_heading
//################################################################################
if(blanks_line_[0]<=3 && is_chars(buffer[SE_lineNoBlank_[0]],"#")){
IntVector2D level,start_end,blank;
level[0]=1;
for(int i=SE_lineNoBlank_[0]+1;i<SE_lineNoBlank_[1];i++){
if(is_chars(buffer[i],"#") && start_end[0]==0){
level[0]++;
} else if(is_chars(buffer[i],"#") && blank[1]>0){
level[1]++;
} else if(is_chars(buffer[i]," \t")){
if(start_end[0]==0) blank[0]++;
else blank[1]++;
} else {
if(start_end[0]==0) start_end[0]=i;
start_end[1]=i;
blank[1]=0;
}
}
if(level[0]>=6 && blank[0]>=1){
if(blockquote_levelN!=blockquote_level) this->close_all();
else if(this->curr_is_open()) this->curr_close();
start_end[1]++;
MKblocks& block=this->append_block(MK::ATX_heading,SE_line_,start_end,
blanks_line_);
block.level_=level[0];
this->curr_close();
return;
}
}
//################################################################################
// HTML_block
//################################################################################
if(this->give_curr_type()==MK::HTML_block){
const char* rexsEnd[]={
"<(?in)\\A</(script|pre|style)\\s*>?$",
"(?in)\\A.*-->",
"(?in)\\A.*\\?>",
"(?in)\\A.*>",
"(?in)\\A.*\\]\\]>",
"(?in)\\A\\s*$",
"(?in)\\A\\s*$"
};
MKblocks& block=blocks_[open_blocks_[end_MTS]];
block.pos_[1]=SE_line_[1];
block.posNoBlank_[1]=SE_lineNoBlank_[1];
block.blanks_[1]=blanks_line_[1];
if(buffer.regexp(SE_lineNoBlank_[0],rexsEnd[block.level_-1])){
this->curr_close();
}
return;
}
if(blanks_line_[0]<=3 && is_chars(buffer[SE_lineNoBlank_[0]],"<")){
const char* rexsStart[]={
"(?in)\\A<(script|pre|style)\\s*>?$",
"(?in)\\A<!--",
"(?in)\\A<\\?",
"(?in)\\A<![A-Z]",
"(?in)\\A<!\\[CDATA\\[",
"(?in)\\A</?(address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|"
"dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|"
"h1|h2|h3|h4|h5|h6|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|nav|"
"noframes|ol|optgroup|option|p|param|section|source|summary|table|tbody|td|tfoot|th|"
"thead|title|tr|track|ul)\\s*/*>?$",
"(?in)\\A</?[-\\w]+[^>]*>$"
};
int level=0;
for(int i=0;i<7;i++){
if(buffer.regexp(SE_lineNoBlank_[0],rexsStart[i])){
level=i+1;
break;
}
}
if((level>0 && level<7) || (level==7 && this->curr_is_open()==0)){
if(blockquote_levelN!=blockquote_level) this->close_all();
else if(this->curr_is_open()) this->curr_close();
MKblocks& block=this->append_block(MK::HTML_block,SE_line_,
SE_lineNoBlank_,blanks_line_);
block.level_=level;
return;
}
}
//################################################################################
// link_reference_definition
//################################################################################
if(!this->curr_is_open() && blanks_line_[0]<=3 &&
is_chars(buffer[SE_lineNoBlank_[0]],"[")){
int c=link_label_num(buffer,SE_lineNoBlank_[0]);
int c_noblank;
if(c){
if(buffer[c]!=':') c=0;
else c++;
}
if(c){
c=link_destination_num(buffer,c);
}
if(c){
int c_alt=link_title_num(buffer,c);
if(c_alt!=0){
int c_alt2=spaces_num(buffer,c_alt,num_spaces);
if(c_alt2!=0){
c_noblank=c_alt;
c=c_alt2;
} else {
c_alt=0;
}
}
if(c_alt==0){
c_noblank=c;
c=spaces_num(buffer,c,num_spaces);
}
}
if(c){
SE_lineNoBlank_[1]=c_noblank;
SE_line_[1]=c;
blanks_line_[1]=c-c_noblank;
this->append_block(MK::link_reference_definition,SE_line_,
SE_lineNoBlank_,blanks_line_);
pos_=SE_line_[1];
return;
}
}
//################################################################################
// normal paragraph
//################################################################################
if(SE_lineNoBlank_[0]==SE_lineNoBlank_[1]-1){
if(blockquote_levelN!=blockquote_level) this->close_all();
else if(this->curr_is_open()) this->curr_close();
} else if(this->curr_is_open()){
MKblocks& block=blocks_[open_blocks_[end_MTS]];
block.pos_[1]=SE_line_[1];
block.posNoBlank_[1]=SE_lineNoBlank_[1];
block.blanks_[1]=blanks_line_[1];
} else {
if(blockquote_levelN!=blockquote_level) this->close_all();
this->append_block(MK::paragraph,SE_line_,SE_lineNoBlank_,
blanks_line_);
}
}
void MKstate::process_markdown(MyTSchar& buffer)
{
MKblocks& block=this->append_block(MK::document);
block.open_=0;
for(int i=0;i<buffer.num();i++){
switch(buffer[i]){
case ' ':
{
if(SE_line_[0]==-1){
SE_line_[0]=i;
}
if(SE_lineNoBlank_[0]==-1){
blanks_line_[0]++;
} else {
blanks_line_[1]++;
}
}
break;
case '\t':
{
if(SE_line_[0]==-1){
SE_line_[0]=i;
}
if(SE_lineNoBlank_[0]==-1){
blanks_line_[0]+=4;
} else {
blanks_line_[1]+=4;
}
}
break;
case '\n': case '\r':
{
if(SE_line_[0]==-1){
SE_line_[0]=i;
}
if(SE_lineNoBlank_[0]==-1){
SE_lineNoBlank_[0]=i;
}
if(SE_lineNoBlank_[1]==-1){
SE_lineNoBlank_[1]=i;
}
SE_line_[1]=i;
pos_=i;
this->create_append_paragraph(buffer);
i=pos_;
SE_line_[0]=SE_line_[1]=-1;
SE_lineNoBlank_[0]=SE_lineNoBlank_[1]=-1;
blanks_line_[0]=0;
if(i<buffer.num()-1 && buffer[i]=='\r' && buffer[i+1]=='\n'){
i++;
}
}
break;
default:
{
if(SE_line_[0]==-1){
SE_line_[0]=i;
}
if(SE_lineNoBlank_[0]==-1){
SE_lineNoBlank_[0]=i;
}
SE_lineNoBlank_[1]=i;
blanks_line_[1]=0;
}
break;
}
}
}
int process_markdown()
{
MyTSchar buffer;
const char* fileIn="C:\\Users\\ramsan\\Dropbox\\temporal\\kkdoc\\strengths_in_shells.md";
const char* fileOut="C:\\Users\\ramsan\\Dropbox\\temporal\\kkdoc\\strengths_in_shells.html";
FILE* fin=fopen(fileIn,"rb");
if(!fin){
fprintf(stderr,"file not found\n");
exit(2);
}
fseek(fin,0,SEEK_END);
size_t lSize=ftell(fin);
rewind(fin);
buffer.set_num(lSize);
size_t result=fread(buffer.v(),1,lSize,fin);
fclose(fin);
if(result!=lSize){
fprintf(stderr,"file read incorrectly\n");
exit(2);
}
MKstate mkstate;
mkstate.process_markdown(buffer);
return 0;
}