static int l_csys_bodies(lua_State *L) { CustomSystem *cs = l_csys_check(L, 1); CustomSystemBody **primary_ptr = l_csb_check_ptr(L, 2); int primary_type = (*primary_ptr)->type; luaL_checktype(L, 3, LUA_TTABLE); if ((primary_type < SystemBody::TYPE_STAR_MIN || primary_type > SystemBody::TYPE_STAR_MAX) && primary_type != SystemBody::TYPE_GRAVPOINT) return luaL_error(L, "first body does not have a valid star type"); if (primary_type != cs->primaryType[0] && primary_type != SystemBody::TYPE_GRAVPOINT) return luaL_error(L, "first body type does not match the system's primary star type"); lua_pushvalue(L, 3); _add_children_to_sbody(L, *primary_ptr); lua_pop(L, 1); cs->sBody = *primary_ptr; *primary_ptr = 0; if (cs->sBody) { unsigned star_count = count_stars(cs->sBody); if (star_count != cs->numStars) return luaL_error(L, "expected %u star(s) in system %s, but found %u (did you forget star types in CustomSystem:new?)", cs->numStars, cs->name.c_str(), star_count); // XXX Someday, we should check the other star types as well, but we do not use them anyway now. } lua_settop(L, 1); return 1; }
static unsigned count_stars(CustomSystemBody* csb) { if (!csb) return 0; unsigned count = 0; if (csb->type >= SystemBody::TYPE_STAR_MIN && csb->type <= SystemBody::TYPE_STAR_MAX) ++count; for (CustomSystemBody* child : csb->children) count += count_stars(child); return count; }
/* ** Output Wiki text while inserting the proper HTML control codes. ** The following formatting conventions are implemented: ** ** * Characters with special meaning to HTML are escaped. ** ** * Blank lines results in a paragraph break. ** ** * Paragraphs where the first line is indented by two or more ** spaces are shown verbatim. None of the following rules apply ** to verbatim text. ** ** * Lines beginning with "*: " begin a bullet in a bullet list. ** ** * Lines beginning with "1: " begin an item in an enumerated list. ** ** * Paragraphs beginning with "_: " are indented. ** ** * Multiple colons can be used in *:, 1:, and _: for multiple ** levels of indentation. ** ** * Text within _..._ is italic and text in *...* is bold. ** Text with in **...** or ***...*** bold with a larger font. ** ** * Wiki pages names (Words in initial caps) are enclosed in an ** appropriate hyperlink. ** ** * Words that begin with "http:", "https:", "ftp:", or "mailto:" ** are enclosed in an appropriate hyperlink. ** ** * Text of the form "#NNN" where NNN is a valid ticket number ** is converted into a hyperlink to the corresponding ticket. ** ** * Text of the form "[NNN]" where NNN is a valid check-in number ** becomes a hyperlink to the checkin. ** ** * {quote: XYZ} renders XYZ with all special meanings for XYZ escaped. ** ** * {link: URL TEXT} renders TEXT with a link to URL. URL can be ** relative. ** ** * {linebreak} renders a linebreak. ** ** * {image: URL ALT} renders an in-line image from URL. URL can be ** relative or it can be the name of an attachment to zPageId. ** {leftimage: URL ALT} and {rightimage: URL ALT} create wrap-around ** images at the left or right margin. ** ** * {clear} skips down the page far enough to clear any wrap-around ** images. ** ** * Text between <html>...</html> is interpreted as HTML. A restricted ** subset of tags are supported - things like forms and javascript are ** intentionally excluded. The initial <html> must occur at the ** beginning of a paragraph. */ void output_wiki( const char *zText, /* The text to be formatted */ const char *zLinkSuffix, /* Suffix added to hyperlinks to Wiki */ const char *zPageId /* Name of current page */ ){ int i, j, k; int aList[20]; /* See adjust_list_nesting for details */ int inPRE = 0; int inB = 0; int inI = 0; int v; int wordStart = 1; /* At the start of a word */ int lineStart = 1; /* At the start of a line */ int paraStart = 1; /* At the start of a paragraph */ const char *zEndB; /* Text used to end a run of bold */ char **azAttach; /* Attachments to zPageId */ static int once = 1; static int nTicket, nCommit; if( once ){ nTicket = atoi(db_short_query("SELECT max(tn) FROM ticket")); nCommit = atoi(db_short_query("SELECT max(cn) FROM chng")); once = 0; } i = 0; aList[0] = 0; azAttach = 0; zEndB = ""; while( zText[i] ){ char *z; int n; Markup sMarkup; int c = zText[i]; /* Text between <html>...</html> is interpreted as HTML. */ if( c=='<' && (n = is_html(&zText[i]))>0 ){ put_htmlized_text(&zText, i); zText += 6; output_restricted_html(zText, n-13); zText += n - 6; i = 0; continue; } /* Markup may consist of special strings contained in curly braces. ** Examples: "{linebreak}" or "{quote: *:}" */ if( c=='{' && is_markup(&zText[i], &sMarkup) ){ /* ** Markup of the form "{linebreak}" forces a line break. */ if( sMarkup.lenType==9 && strncmp(sMarkup.zType,"linebreak",9)==0 ){ put_htmlized_text(&zText, i); zText += sMarkup.lenTotal; i = 0; cgi_printf("<br>\n"); wordStart = lineStart = paraStart = 0; continue; } /* ** Markup of the form "{clear}" moves down past any left or right ** aligned images. */ if( sMarkup.lenType==5 && strncmp(sMarkup.zType,"clear",5)==0 ){ put_htmlized_text(&zText, i); zText += sMarkup.lenTotal; i = 0; cgi_printf("<br clear=\"both\">\n"); wordStart = lineStart = paraStart = 0; continue; } /* ** Markup of the form "{quote: ABC}" writes out the text ABC exactly ** as it appears. This can be used to escape special meanings ** associated with ABC. */ if( sMarkup.lenType==5 && strncmp(sMarkup.zType,"quote",5)==0 ){ int n; put_htmlized_text(&zText, i); if( sMarkup.zKey==sMarkup.zArgs ){ n = sMarkup.lenKey; }else{ n = &sMarkup.zArgs[sMarkup.lenArgs] - sMarkup.zKey; } put_htmlized_text(&sMarkup.zKey, n); zText += sMarkup.lenTotal; i = 0; wordStart = lineStart = paraStart = 0; continue; } /* ** Markup of the form "{link: TO TEXT}" creates a hyperlink to TO. ** The hyperlink appears on the screen as TEXT. TO can be a any URL, ** including a relative URL such as "chngview?cn=123". */ if( sMarkup.lenType==4 && strncmp(sMarkup.zType,"link",4)==0 ){ put_htmlized_text(&zText, i); cgi_printf("<a href=\"%.*s\">", sMarkup.lenKey, sMarkup.zKey); put_htmlized_text(&sMarkup.zArgs, sMarkup.lenArgs); cgi_printf("</a>"); zText += sMarkup.lenTotal; i = 0; wordStart = lineStart = paraStart = 0; continue; } /* ** Markup of the form "{image: URL ALT}" creates an in-line image to ** URL with ALT as the alternate text. URL can be relative (for example ** the URL of an attachment. ** ** If the URL is the name of an attachment, then automatically ** convert it to the correct URL for that attachment. */ if( (sMarkup.lenType==5 && strncmp(sMarkup.zType,"image",5)==0) || (sMarkup.lenType==9 && strncmp(sMarkup.zType,"leftimage",9)==0) || (sMarkup.lenType==10 && strncmp(sMarkup.zType,"rightimage",10)==0) ){ char *zUrl = 0; const char *zAlign; char *zAlt = htmlize(sMarkup.zArgs, sMarkup.lenArgs); if( azAttach==0 && zPageId!=0 ){ azAttach = (char **) db_query("SELECT fname, atn FROM attachment " "WHERE tn='%q'", zPageId); } if( azAttach ){ int ix; for(ix=0; azAttach[ix]; ix+=2){ if( strncmp(azAttach[ix],sMarkup.zKey,sMarkup.lenKey)==0 ){ free(zUrl); zUrl = mprintf("attach_get/%s/%h", azAttach[ix+1], azAttach[ix]); break; } } } if( zUrl==0 ){ zUrl = htmlize(sMarkup.zKey, sMarkup.lenKey); } put_htmlized_text(&zText, i); switch( sMarkup.zType[0] ){ case 'l': case 'L': zAlign = " align=\"left\""; break; case 'r': case 'R': zAlign = " align=\"right\""; break; default: zAlign = ""; break; } cgi_printf("<img src=\"%s\" alt=\"%s\"%s>", zUrl, zAlt, zAlign); free(zUrl); free(zAlt); zText += sMarkup.lenTotal; i = 0; wordStart = lineStart = paraStart = 0; continue; } } if( paraStart ){ put_htmlized_text(&zText, i); /* Blank lines at the beginning of a paragraph are ignored. */ if( isspace(c) && (j = is_blank_line(&zText[i]))>0 ){ zText += j; continue; } /* If the first line of a paragraph begins with a tab or with two ** or more spaces, then that paragraph is printed verbatim. */ if( c=='\t' || (c==' ' && (zText[i+1]==' ' || zText[i+1]=='\t')) ){ if( !inPRE ){ if( inB ){ cgi_printf(zEndB); inB=0; } if( inI ){ cgi_printf("</i>"); inI=0; } adjust_list_nesting(aList, 0); cgi_printf("<pre>\n"); inPRE = 1; } } } /* end if( paraStart ) */ if( lineStart ){ /* Blank lines in the middle of text cause a paragraph break */ if( isspace(c) && (j = is_blank_line(&zText[i]))>0 ){ put_htmlized_text(&zText, i); zText += j; if( inB ){ cgi_printf(zEndB); inB=0; } if( inI ){ cgi_printf("</i>"); inI=0; } if( inPRE ){ cgi_printf("</pre>\n"); inPRE = 0; } is_list_elem(zText, &k); if( abs(k)<aList[0] ) adjust_list_nesting(aList, k); if( zText[0]!=0 ){ cgi_printf("\n<p>"); } wordStart = lineStart = paraStart = 1; i = 0; continue; } } /* end if( lineStart ) */ if( lineStart && !inPRE ){ /* If we are not in verbatim text and a line begins with "*:", then ** generate a bullet. Or if the line begins with "NNN:" where NNN ** is a number, generate an enumeration item. */ if( (j = is_list_elem(&zText[i], &k))>0 ){ put_htmlized_text(&zText, i); adjust_list_nesting(aList, k); if( zText[0]!='_' ) cgi_printf("<li>"); zText += j; i = 0; wordStart = 1; lineStart = paraStart = 0; continue; } /* Four or more "-" characters on at the beginning of a line that ** contains no other text results in a horizontal rule. */ if( (c=='-' || c=='=') && (j = is_horizontal_rule(&zText[i]))>0 ){ put_htmlized_text(&zText, i); adjust_list_nesting(aList, 0); cgi_printf("<hr>\n"); zText += j; if( *zText ) zText++; i = 0; lineStart = wordStart = 1; paraStart = 1; continue; } } /* end if( lineStart && !inPre ) */ if( wordStart && !inPRE ){ /* A wiki name at the beginning of a word which is not in verbatim ** text generates a hyperlink to that wiki page. ** ** Special case: If the name is in CamelCase but ends with a "_", then ** suppress the "_" and do not generate the hyperlink. This allows ** CamelCase words that are not wiki page names to appear in text. */ if( g.okRdWiki && isupper(c) && (j = is_wiki_name(&zText[i]))>0 ){ put_htmlized_text(&zText, i); cgi_printf("<a href=\"wiki?p=%.*s%s\">%.*s</a>", j, zText, zLinkSuffix, j, zText); zText += j; i = 0; wordStart = lineStart = paraStart = 0; continue; } /* A "_" at the beginning of a word puts us into an italic font. */ if( c=='_' && !inB && !inI && font_terminator(&zText[i+1],c,1) ){ put_htmlized_text(&zText, i); i = 0; zText++; cgi_printf("<i>"); inI = 1; continue; } /* A "*" at the beginning of a word puts us into a bold font. */ if( c=='*' && !inB && !inI && (j = count_stars(&zText[i]))>=1 && j<=3 && font_terminator(&zText[i+j],c,j) ){ const char *zBeginB = ""; put_htmlized_text(&zText, i); i = 0; zText += j; switch( j ){ case 1: zBeginB = "<b>"; zEndB = "</b>"; break; case 2: zBeginB = "<big><b>"; zEndB = "</b></big>"; break; case 3: zBeginB = "<big><big><b>"; zEndB = "</b></big></big>"; break; } cgi_printf(zBeginB); inB = j; continue; } /* Words that begin with "http:" or "https:" or "ftp:" or "mailto:" ** become hyperlinks. */ if( (c=='h' || c=='f' || c=='m') && (j=is_url(&zText[i]))>0 ){ put_htmlized_text(&zText, i); z = htmlize(zText, j); if( is_image(z, strlen(z)) ){ cgi_printf("<img src=\"%s\" alt=\"%s\">", z, z); }else{ cgi_printf("<a href=\"%s\">%s</a>", z, z); } free(z); zText += j; i = 0; wordStart = lineStart = paraStart = 0; continue; } /* If the user has read permission on tickets and a word is of the ** form "#NNN" where NNN is a sequence of digits, then generate a ** hyperlink to ticket number NNN. */ if( c=='#' && g.okRead && (j = ndigit(&zText[i+1]))>0 && is_eow(&zText[i+1+j],0) && (v = atoi(&zText[i+1]))>0 && v<=nTicket ){ put_htmlized_text(&zText, i); cgi_printf("<a href=\"tktview?tn=%d\">#%d</a>", v, v); zText += j; if( *zText ) zText++; i = 0; wordStart = lineStart = paraStart = 0; continue; } /* If the user has checkout permissions and a word is of the form ** "[NNN]" where NNN is a checkin number, then generate a hyperlink ** to check-in NNN. */ if( c=='[' && g.okCheckout && (j = ndigit(&zText[i+1]))>0 && is_eow(&zText[i+j+2],0) && (v = atoi(&zText[i+1]))>0 && v<=nCommit && zText[i+j+1]==']' ){ put_htmlized_text(&zText, i); cgi_printf("<a href=\"chngview?cn=%d\">[%d]</a>", v, v); zText += j+1; if( *zText ) zText++; i = 0; wordStart = lineStart = paraStart = 0; continue; } } /* end if( wordStart && !inPre ) */ /* A "*" or a "_" at the end of a word takes us out of bold or ** italic mode. */ if( inB && c=='*' && !isspace(zText[i-1]) && zText[i-1]!='*' && (j = count_stars(&zText[i]))==inB && is_eow(&zText[i+j],0) ){ inB = 0; put_htmlized_text(&zText, i); i = 0; zText += j; cgi_printf(zEndB); continue; } if( inI && c=='_' && !isspace(zText[i-1]) && is_eow(&zText[i+1],0) ){ put_htmlized_text(&zText, i); i = 0; zText++; inI = 0; cgi_printf("</i>"); continue; } if( wordStart ){ wordStart = isspace(c) || c=='(' || c=='"'; }else{ wordStart = isspace(c); } lineStart = c=='\n'; paraStart = 0; i++; } if( zText[0] ) cgi_printf("%h", zText); if( inB ) cgi_printf("%s\n",zEndB); if( inI ) cgi_printf("</i>\n"); adjust_list_nesting(aList, 0); if( inPRE ) cgi_printf("</pre>\n"); }