/* Counter.C * * LameTeX needs to keep track of a number of counters, just like LaTeX does, * for things like tables, footnotes, chapters and sections, and enumerations. * Since all counters need to be handled in much the same way, the Counter * derived class under the Parameters class has been defined. * * Copyright 1992 Jonathan Monsarrat. Permission given to freely distribute, * edit and use as long as this copyright statement remains intact. * */ #include "Operator.h" #include "Global.h" #include "Counter.h" #include "Document.h" #include "Font.h" #include #include Counter::Counter() { for(int x=0; x < LastType; x++) counters[x] = 0; } Counter::Counter(Counter *base) { for(int x=0; x < LastType; x++) counters[x] = base->counters[x]; } Param *Counter::copy() { return new Counter(this); } int Counter::set(int subtype, float print_number, char *) { char number[10]; char message[20]; char output[20]; if(subtype >= Part && subtype <= Subparagraph) { Token openbrace; if(!openbrace.match("{")) Global::files->fatal_error("Expecting '{' after section statement"); if(print_number) { counters[subtype]++; switch(subtype) { case Part: counters[Chapter]=0; case Chapter: counters[Section]=0; case Section: counters[Subsection]=0; case Subsection: counters[Subsubsection]=0; case Subsubsection: counters[Paragraph]=0; case Paragraph: counters[Subparagraph]=0; case Subparagraph: default: break; } } else counters[subtype] = -1; } float fontsize = Global::stack->get(Environment::PFont, Font::Size, ""); switch(subtype) { case Part: Global::files->outfile << endl; if(print_number) { Operator::plaintext("Part"); upcase_roman(counters[Part], number); Operator::plaintext(number); } Operator::do_vspace(0, 0, 200.0, ""); break; case Chapter: Global::files->outfile << endl; if(Global::files->plain_text_output) Operator::do_vspace(0, 0, 13.0, ""); else Operator::do_vspace(0, 0, 112.5 + (fontsize-18.0) * 0.85, ""); if(print_number) { Operator::plaintext("Chapter"); arabic(counters[Chapter], number); Operator::plaintext(number); if(Global::files->plain_text_output) Operator::do_vspace(0, 0, 13.0, ""); else Operator::do_vspace(0, 0, 50.0 + (fontsize-22.0) * 0.85, ""); } Stack::set(Environment::PFont, Font::Huge, 0.0, ""); break; case Section: Global::files->outfile << endl; if(Global::files->plain_text_output) Operator::do_vspace(0, 0, 8.0, ""); else Operator::do_vspace(0, 0, 20.7 + (fontsize-13.0) * 3.4, ""); if(print_number) { sprintf(number,"%d.%d",counters[Chapter],counters[Section]); Operator::plaintext(number); Global::files->outfile << endl; Global::files->outfile << 15.0 + (fontsize-13.0) * 1.1 << " HSpace" << endl; } break; case Subsection: Global::files->outfile << endl; Operator::do_vspace(0, 0, 4.5 + (fontsize-11.0) * 3.4, ""); if(print_number) { sprintf(number,"%d.%d.%d",counters[Chapter],counters[Section], counters[Subsection]); Operator::plaintext(number); Global::files->outfile << endl; Global::files->outfile << 15.0 + (fontsize-11.0) * 1.1 << " HSpace" << endl; } break; case Subsubsection: case Paragraph: case Subparagraph: break; case Page: break; case Equation: break; case Figure: break; case Table: break; case Footnote: break; case Mpfootnote: break; case Description: counters[Item] = Description; // Mark Description most recent counters[Description]=0; break; case Itemize: counters[Item] = Itemize; // Mark Itemize most recent break; case Enum: if(++counters[Enum] > 4) Global::files->fatal_error( "Can't have more than four nested enumerates"); counters[Item] = Enum; // Mark Enumerate most recent switch(counters[Enum]) { case 1: counters[Enumi]=0; break; case 2: counters[Enumii]=0; break; case 3: counters[Enumiii]=0; break; case 4: counters[Enumiv]=0; break; } break; case Enumi: break; case Enumii: break; case Enumiii: break; case Enumiv: break; case Item: switch(counters[Item]) { case Description: description(); break; case Itemize: Stack::set(Environment::PDocument, Document::NewLine, 0.0, ""); Global::files->force_start_page(); Global::files->outfile << endl; Global::files->outfile << "BULLET" << endl; break; case Enum: Stack::set(Environment::PDocument, Document::NewLine, 0.0, ""); Global::files->force_start_page(); Global::files->outfile << endl; switch(counters[Enum]) { case 1: arabic(++counters[Enumi], message); strcat(message, "."); break; case 2: message[0]='('; downcase_alpha(++counters[Enumii], &message[1]); strcat(message, ")"); break; case 3: downcase_roman(++counters[Enumiii], message); strcat(message, "."); break; case 4: upcase_alpha(++counters[Enumiv], message); strcat(message, "."); break; } Global::files->force_start_page(); Operator::registrar(message, output); Global::files->outfile << " " << output << " ENUMERATE" << endl; break; default: break; } break; default: break; } return TRUE; } /* Handles the \item command in a description. If the item is the 0th * item, then make an indentation. */ void Counter::description() { Stack::relative_set(Environment::PLength, Length::Parameter, -22.5, "\\oddsidemargin"); Stack::relative_set(Environment::PLength, Length::Parameter, 22.5, "\\textwidth"); Stack::set(Environment::PDocument, Document::NewLine, 0.0, ""); Global::files->force_start_page(); Global::files->outfile << endl; Token openbrace; if(!openbrace.match("[")) Global::files->fatal_error("Expecting '[' after \\item"); Stack::set(Environment::PFont, Font::Bold, 0.0, ""); for(Token description; !description.match("]"); description=Token()) description.handle(); Global::files->outfile << endl << "13.0 HSpace" << endl; Stack::set(Environment::PFont, Font::Roman, 0.0, ""); Stack::relative_set(Environment::PLength, Length::Parameter, 22.5, "\\oddsidemargin"); Stack::relative_set(Environment::PLength, Length::Parameter, -22.5, "\\textwidth"); } float Counter::get(int subtype, char *) { return counters[subtype]; } void Counter::postscript_set(int subtype) { switch(subtype) { default: break; } } void Counter::revert(Param *from) { int count; for(int subtype=0; subtype < LastType; subtype++) if((count = (int)from->get(subtype,"revert")) != counters[subtype]) { if(count > 0) counters[subtype] = count; switch(subtype) { case Part: Stack::set(Environment::PDocument, Document::NewLine, 0.0, ""); case Chapter: if(Global::files->plain_text_output) Operator::do_vspace(0, 0, 13.0, ""); else Operator::do_vspace(0, 0, 52, ""); break; case Section: if(Global::files->plain_text_output) Operator::do_vspace(0, 0, 8.0, ""); else Operator::do_vspace(0, 0, 22.4, ""); break; case Subsection: if(Global::files->plain_text_output) Operator::do_vspace(0, 0, 8.0, ""); else Operator::do_vspace(0, 0, 18.0, ""); break; case Subsubsection: case Paragraph: case Subparagraph: Stack::set(Environment::PDocument, Document::NewLine, 0.0, ""); break; case Page: break; case Equation: break; case Figure: break; case Table: break; case Footnote: break; case Mpfootnote: break; case Enum: counters[Enum]--; break; case Enumi: break; case Enumii: break; case Enumiii: break; case Enumiv: break; case Itemize: break; } } } void Counter::downcase_roman(int count, char *number) { switch(count/100) { case 1: strcpy(number,"c"); break; case 2: strcpy(number,"cc"); break; case 3: strcpy(number,"ccc"); break; case 4: strcpy(number,"cd"); break; case 5: strcpy(number,"d"); break; case 0: default: strcpy(number,""); break; } switch(count%100/10) { case 0: break; case 1: strcat(number,"x"); break; case 2: strcat(number,"xx"); break; case 3: strcat(number,"xxx"); break; case 4: strcat(number,"xl"); break; case 5: strcat(number,"l"); break; case 6: strcat(number,"lx"); break; case 7: strcat(number,"lxx"); break; case 8: strcat(number,"lxxx"); break; case 9: strcat(number,"xc"); break; } switch(count%10) { case 0: break; case 1: strcat(number,"i"); break; case 2: strcat(number,"ii"); break; case 3: strcat(number,"iii"); break; case 4: strcat(number,"iv"); break; case 5: strcat(number,"v"); break; case 6: strcat(number,"vi"); break; case 7: strcat(number,"vii"); break; case 8: strcat(number,"viii"); break; case 9: strcat(number,"ix"); break; } }; void Counter::upcase_roman(int count, char *number) { switch(count/100) { case 1: strcpy(number,"C"); break; case 2: strcpy(number,"CC"); break; case 3: strcpy(number,"CCC"); break; case 4: strcpy(number,"CD"); break; case 5: strcpy(number,"D"); break; case 0: default: strcpy(number,""); break; } switch(count%100/10) { case 0: break; case 1: strcat(number,"X"); break; case 2: strcat(number,"XX"); break; case 3: strcat(number,"XXX"); break; case 4: strcat(number,"XL"); break; case 5: strcat(number,"L"); break; case 6: strcat(number,"LX"); break; case 7: strcat(number,"LXX"); break; case 8: strcat(number,"LXXX"); break; case 9: strcat(number,"XC"); break; } switch(count%10) { case 0: break; case 1: strcat(number,"I"); break; case 2: strcat(number,"II"); break; case 3: strcat(number,"III"); break; case 4: strcat(number,"IV"); break; case 5: strcat(number,"V"); break; case 6: strcat(number,"VI"); break; case 7: strcat(number,"VII"); break; case 8: strcat(number,"VIII"); break; case 9: strcat(number,"IX"); break; } }; void Counter::arabic(int count, char *number) { sprintf(number,"%d",count); }; void Counter::downcase_alpha(int count, char *number) { if(count >= 26) { sprintf(number,"%c%c",('a'+count/26-1),('a'+count%26-1)); } sprintf(number,"%c",('a'+count%26-1)); }; void Counter::upcase_alpha(int count, char *number) { if(count >= 26) { sprintf(number,"%c%c",('A'+count/26-1),('A'+count%26-1)); } sprintf(number,"%c",('A'+count%26-1)); };