void Interpose(OBJECT z, int typ, OBJECT x, OBJECT y) { OBJECT encl; New(encl, typ); FposCopy(fpos(encl), fpos(y)); ReplaceNode(encl, z); Link(encl, z); back(encl, COLM) = back(x, COLM); fwd(encl, COLM) = fwd(x, COLM); back(encl, ROWM) = back(y, ROWM); fwd(encl, ROWM) = fwd(y, ROWM); underline(encl) = underline(z); } /* end Interpose */
static OBJECT InterposeWideOrHigh(OBJECT y, int dim) { OBJECT res; New(res, dim == COLM ? WIDE : HIGH); FposCopy(fpos(res), fpos(y)); back(res, dim) = back(y, dim); fwd(res, dim) = fwd(y, dim); back(res, 1-dim) = back(y, 1-dim); fwd(res, 1-dim) = fwd(y, 1-dim); SetConstraint(constraint(res), MAX_FULL_LENGTH, size(res, dim), MAX_FULL_LENGTH); ReplaceNode(res, y); Link(res, y); return res; } /* end InterposeWideOrHigh */
void PDF_PrintGraphicObject(OBJECT x) { OBJECT y, link; debug3(DPF, D, "PDF_PrintGraphicObject(%s %s %s)", EchoFilePos(&fpos(x)), Image(type(x)), EchoObject(x)); switch( type(x) ) { case WORD: case QWORD: PDFPage_WriteGraphic(out_fp, string(x)); break; case ACAT: for( link = Down(x); link != x; link = NextDown(link) ) { Child(y, link); if( type(y) == GAP_OBJ ) { if( vspace(y) > 0 ) PDFPage_Write(out_fp, "\n"); else if( hspace(y) > 0 ) PDFPage_Write(out_fp, " "); } else if( is_word(type(y)) || type(y) == ACAT ) PDF_PrintGraphicObject(y); else if( type(y) == WIDE || is_index(type(y)) ) { /* ignore: @Wide, indexes are sometimes inserted by Manifest */ } else { Error(50, 2, "error in left parameter of %s", WARN, &fpos(x), KW_GRAPHIC); debug1(DPF, D, " type(y) = %s, y =", Image(type(y))); ifdebug(DPF, D, DebugObject(y)); } } break; default: Error(50, 3, "error in left parameter of %s", WARN, &fpos(x), KW_GRAPHIC); debug1(DPF, D, " type(x) = %s, x =", Image(type(x))); ifdebug(DPF, D, DebugObject(x)); break; } debug0(DPF, D, "PDF_PrintGraphicObject returning"); } /* end PDF_PrintGraphicObject */
UnicodeString &MeasureFormat::formatMeasurePerUnit( const Measure &measure, const MeasureUnit &perUnit, UnicodeString &appendTo, FieldPosition &pos, UErrorCode &status) const { if (U_FAILURE(status)) { return appendTo; } bool isResolved = false; MeasureUnit resolvedUnit = MeasureUnit::resolveUnitPerUnit(measure.getUnit(), perUnit, &isResolved); if (isResolved) { Measure newMeasure(measure.getNumber(), new MeasureUnit(resolvedUnit), status); return formatMeasure( newMeasure, **numberFormat, appendTo, pos, status); } FieldPosition fpos(pos.getField()); UnicodeString result; int32_t offset = withPerUnitAndAppend( formatMeasure( measure, **numberFormat, result, fpos, status), perUnit, appendTo, status); if (U_FAILURE(status)) { return appendTo; } if (fpos.getBeginIndex() != 0 || fpos.getEndIndex() != 0) { pos.setBeginIndex(fpos.getBeginIndex() + offset); pos.setEndIndex(fpos.getEndIndex() + offset); } return appendTo; }
UnicodeString & DigitFormatter::formatExponent( const VisibleDigits &digits, const DigitFormatterIntOptions &options, int32_t signField, int32_t intField, FieldPositionHandler &handler, UnicodeString &appendTo) const { UBool neg = digits.isNegative(); if (neg || options.fAlwaysShowSign) { appendField( signField, neg ? fNegativeSign : fPositiveSign, handler, appendTo); } int32_t begin = appendTo.length(); DigitGrouping grouping; DigitFormatterOptions expOptions; FieldPosition fpos(FieldPosition::DONT_CARE); FieldPositionOnlyHandler noHandler(fpos); format( digits, grouping, expOptions, noHandler, appendTo); handler.addAttribute(intField, begin, appendTo.length()); return appendTo; }
UnicodeString& DateFormat::format(UDate date, UnicodeString& appendTo) const { // Note that any error information is just lost. That's okay // for this convenience method. FieldPosition fpos(0); return format(date, appendTo, fpos); }
void PDF_PrintGraphicInclude(OBJECT x, FULL_LENGTH colmark, FULL_LENGTH rowmark) { OBJECT y; debug0(DPF, D, "PDF_PrintGraphicInclude(x)"); Child(y, Down(x)); Error(50, 4, "cannot include EPS file in PDF output; EPS file %s ignored", WARN, &fpos(x), string(y)); debug0(DPF, D, "PDF_PrintGraphicInclude returning."); } /* end PDF_PrintGraphicInclude */
static OBJECT ReadMacro(OBJECT *token, OBJECT curr_encl, OBJECT encl) { OBJECT t, res; /* find macro name and insert into symbol table */ SuppressScope(); Dispose(*token); t = LexGetToken(); if( !is_word(type(t)) ) { Error(5, 24, "%s ignored (name is missing)", WARN, &fpos(t), KW_MACRO); debug1(ANY, D, "offending type is %s", Image(type(t))); UnSuppressScope(); *token = t; return nilobj; } res = InsertSym(string(t), MACRO, &fpos(t), 0, FALSE,TRUE,0,curr_encl,nilobj); if( curr_encl != encl ) visible(res) = TRUE; UnSuppressScope(); /* find alternative names for this symbol */ Dispose(t); t = LexGetToken(); while( is_word(type(t)) ) { InsertAlternativeName(string(t), res, &fpos(t)); Dispose(t); t = LexGetToken(); } /* find opening left brace */ if( type(t) != LBR ) { Error(5, 25, "%s ignored (opening %s is missing)", WARN, &fpos(t), KW_MACRO, KW_LBR); *token = t; return nilobj; } /* read macro body */ ReadTokenList(t, res); Dispose(t); /* clean up (kill final RBR, dispose macro name) and exit */ t = pred(sym_body(res), PARENT); sym_body(res) = Delete(t, PARENT); Dispose(t); recursive(res) = FALSE; *token = nilobj; return res; } /* end ReadMacro */
void PushScope(OBJECT x, BOOLEAN npars, BOOLEAN vis) { debug3(DST, DD, "[ PushScope(%s, %s, %s)", SymName(x), bool(npars), bool(vis)); assert( suppress_scope == FALSE, "PushScope: suppress_scope!" ); if( scope_top >= MAX_STACK ) { #if DEBUG_ON int i; for( i = 0; i < scope_top; i++ ) Error(29, 1, " scope[%2d] = %s", WARN, &fpos(x), i, SymName(scope[i])); #endif Error(29, 2, "scope depth limit exceeded", INTERN, &fpos(x)); } scope[scope_top] = x; npars_only[scope_top] = npars; vis_only[scope_top] = vis; body_ok[scope_top] = FALSE; scope_top++; } /* end PushScope */
UnicodeString PluralFormat::format(double number, UErrorCode& status) const { if (U_FAILURE(status)) { return UnicodeString(); } FieldPosition fpos(0); UnicodeString result; return format(number, result, fpos, status); }
OBJECT ChildSym(OBJECT s, unsigned typ) { OBJECT link, y; for( link = Down(s); link != s; link = NextDown(link) ) { Child(y, link); if( type(y) == typ && enclosing(y) == s ) return y; } Error(29, 10, "symbol %s has missing %s", FATAL, &fpos(s), SymName(s), Image(typ)); return nilobj; } /* end ChildSym */
void ReadDatabaseDef(unsigned typ, OBJECT encl) { OBJECT symbs, t, fname; New(symbs, ACAT); t = LexGetToken(); while( type(t)==CLOSURE || (type(t)==WORD && string(t)[0]==CH_SYMSTART) ) { if( type(t) == CLOSURE ) { Link(symbs, t); } else { Error(5, 7, "unknown or misspelt symbol %s", WARN, &fpos(t), string(t)); Dispose(t); } t = LexGetToken(); } if( type(t) != LBR ) { Error(5, 8, "symbol name or %s expected here (%s declaration)", WARN, &fpos(t), KW_LBR, KW_DATABASE); Dispose(t); return; } if( Down(symbs) == symbs ) { Error(5, 9, "symbol names missing in %s declaration", WARN, &fpos(t), KW_DATABASE); } fname = Parse(&t, encl, FALSE, FALSE); fname = ReplaceWithTidy(fname, ACAT_TIDY); if( !is_word(type(fname)) ) { Error(5, 10, "name of %s file expected here", WARN, &fpos(fname), KW_DATABASE); DisposeObject(fname); return; } if( StringEndsWith(string(fname), DATA_SUFFIX) ) { Error(5, 47, "%s suffix should be omitted in %s clause", WARN, &fpos(fname), DATA_SUFFIX, KW_DATABASE); DisposeObject(fname); return; } if( Down(symbs) != symbs ) (void) DbLoad(fname, typ == DATABASE ? DATABASE_PATH : SYSDATABASE_PATH, TRUE, symbs, InMemoryDbIndexes); } /* end ReadDatabaseDef */
OBJECT ChildSymWithCode(OBJECT s, unsigned char code) { OBJECT link, y; for( link = Down(actual(s)); link != actual(s); link = NextDown(link) ) { Child(y, link); if( type(y) == NPAR && enclosing(y) == actual(s) && npar_code(y) == code ) return y; } Error(29, 11, "symbol %s has erroneous code %c (database out of date?)", FATAL, &fpos(s), SymName(actual(s)), (char) code); return nilobj; } /* end ChildSym */
static OBJECT InterposeScale(OBJECT y, int scale_factor, int dim) { OBJECT res; New(res, SCALE); FposCopy(fpos(res), fpos(y)); if( dim == COLM ) { bc(constraint(res)) = scale_factor; fc(constraint(res)) = 1 * SF; } else { bc(constraint(res)) = 1 * SF; fc(constraint(res)) = scale_factor; } back(res, dim) = (back(y, dim) * scale_factor) / SF; fwd(res, dim) = (fwd(y, dim) * scale_factor) / SF; back(res, 1-dim) = back(y, 1-dim); fwd(res, 1-dim) = fwd(y, 1-dim); ReplaceNode(res, y); Link(res, y); return res; } /* end InterposeScale */
void ReadIncGRepeatedDef(unsigned typ, OBJECT encl) { OBJECT t, fname; t = LexGetToken(); if( type(t) != LBR ) { Error(5, 5, "left brace expected here in %s declaration", WARN, &fpos(t), KW_INCG_REPEATED); Dispose(t); return; } fname = Parse(&t, encl, FALSE, FALSE); fname = ReplaceWithTidy(fname, ACAT_TIDY); if( !is_word(type(fname)) ) { Error(5, 6, "name of %s file expected here", WARN, &fpos(fname), KW_INCG_REPEATED); DisposeObject(fname); return; } debug0(DFS, D, " calling PS_IncGRepeated from ReadPrependDef"); incg_type(fname) = (typ == INCG_REPEATED ? INCGRAPHIC : SINCGRAPHIC); PS_IncGRepeated(fname); } /* end ReadPrependDef */
void InsertAlternativeName(FULL_CHAR *str, OBJECT s, FILE_POS *xfpos) { register int sum, rlen; register unsigned char *x; int len; OBJECT entry, link, plink, p, q; debug3(DST, DD, "InsertAlternativeName(%s, %s, %s)", str, SymName(s), EchoFilePos(xfpos)); len = StringLength(str); hash(str, len, sum); ifdebug(DST, D, sym_spread[sum]++; sym_count++); entry = (OBJECT) &symtab[sum]; for( plink = Down(entry); plink != entry; plink = NextDown(plink) ) { Child(p, plink); if( length(p) == len && StringEqual(str, string(p)) ) { for( link = Down(p); link != p; link = NextDown(link) ) { Child(q, link); if( enclosing(s) == enclosing(q) ) { Error(29, 12, "symbol name %s previously defined at%s", WARN, &fpos(s), str, EchoFilePos(&fpos(q)) ); break; } } goto wrapup; } } /* need a new OBJECT as well as s */ NewWord(p, WORD, len, xfpos); length(p) = len; StringCopy(string(p), str); Link(entry, p); wrapup: Link(p, s); /* not for copies if( enclosing(s) != nilobj ) Link(enclosing(s), s); */ debug0(DST, DD, "InsertAlternativeName returning."); } /* end InsertAlternativeName */
void PDF_SaveGraphicState(OBJECT x) { debug0(DPF, D, "PDF_SaveGraphicState()"); PDFPage_Push(out_fp); gs_stack_top++; if( gs_stack_top >= MAX_GS ) Error(50, 1, "rotations, graphics etc. too deeply nested (max is %d)", FATAL, &fpos(x), MAX_GS); gs_stack[gs_stack_top].gs_font = currentfont; gs_stack[gs_stack_top].gs_colour = currentcolour; gs_stack[gs_stack_top].gs_cpexists = cpexists; gs_stack[gs_stack_top].gs_currenty = currenty; gs_stack[gs_stack_top].gs_xheight2 = currentxheight2; debug0(DPF, D, "PDF_SaveGraphicState returning."); } /* end PDF_SaveGraphicState */
UnicodeString &MeasureFormat::formatMeasuresSlowTrack( const Measure *measures, int32_t measureCount, UnicodeString& appendTo, FieldPosition& pos, UErrorCode& status) const { if (U_FAILURE(status)) { return appendTo; } FieldPosition dontCare(FieldPosition::DONT_CARE); FieldPosition fpos(pos.getField()); UnicodeString *results = new UnicodeString[measureCount]; int32_t fieldPositionFoundIndex = -1; for (int32_t i = 0; i < measureCount; ++i) { const NumberFormat *nf = cache->getIntegerFormat(); if (i == measureCount - 1) { nf = numberFormat->get(); } if (fieldPositionFoundIndex == -1) { formatMeasure(measures[i], *nf, results[i], fpos, status); if (U_FAILURE(status)) { delete [] results; return appendTo; } if (fpos.getBeginIndex() != 0 || fpos.getEndIndex() != 0) { fieldPositionFoundIndex = i; } } else { formatMeasure(measures[i], *nf, results[i], dontCare, status); } } int32_t offset; listFormatter->format( results, measureCount, appendTo, fieldPositionFoundIndex, offset, status); if (U_FAILURE(status)) { delete [] results; return appendTo; } if (offset != -1) { pos.setBeginIndex(fpos.getBeginIndex() + offset); pos.setEndIndex(fpos.getEndIndex() + offset); } delete [] results; return appendTo; }
FULL_CHAR *FullSymName(OBJECT x, FULL_CHAR *str) { OBJECT stack[20]; int i; static FULL_CHAR buff[MAX_BUFF], *sname; if( x == nilobj ) return AsciiToFull("<nilobj>"); assert( enclosing(x) != nilobj, "FullSymName: enclosing(x) == nilobj!" ); for( i = 0; enclosing(x) != nilobj && i < 20; i++ ) { stack[i] = x; x = enclosing(x); } StringCopy(buff, STR_EMPTY); for( i--; i > 0; i-- ) { sname = SymName(stack[i]); if( StringLength(sname)+StringLength(str)+StringLength(buff) >= MAX_BUFF ) Error(29, 8, "full name of symbol is too long", FATAL, &fpos(x)); StringCat(buff, sname); StringCat(buff, str); } sname = SymName(stack[0]); if( StringLength(sname) + StringLength(buff) >= MAX_BUFF ) Error(29, 9, "full name of symbol is too long", FATAL, &fpos(x)); StringCat(buff, sname); return buff; } /* end FullSymName */
void ReadPrependDef(unsigned typ, OBJECT encl) { OBJECT t, fname; FILE_NUM fnum; t = LexGetToken(); if( type(t) != LBR ) { Error(5, 5, "left brace expected here in %s declaration", WARN, &fpos(t), KW_PREPEND); Dispose(t); return; } fname = Parse(&t, encl, FALSE, FALSE); fname = ReplaceWithTidy(fname, ACAT_TIDY); if( !is_word(type(fname)) ) { Error(5, 6, "name of %s file expected here", WARN, &fpos(fname),KW_PREPEND); DisposeObject(fname); return; } debug0(DFS, D, " calling DefineFile from ReadPrependDef"); fnum = FileNum(string(fname), STR_EMPTY); if( fnum == NO_FILE || FileType(fnum) != PREPEND_FILE ) DefineFile(string(fname), STR_EMPTY, &fpos(fname), PREPEND_FILE, typ == PREPEND ? INCLUDE_PATH : SYSINCLUDE_PATH); } /* end ReadPrependDef */
static void ReadLangDef(OBJECT encl) { OBJECT t, names, inside; New(names, ACAT); t = LexGetToken(); while( is_word(type(t)) ) { Link(names, t); t = LexGetToken(); } if( type(t) != LBR ) { Error(5, 4, "expected opening %s of langdef here", WARN, &fpos(t), KW_LBR); Dispose(t); return; } inside = Parse(&t, encl, FALSE, FALSE); inside = ReplaceWithTidy(inside, ACAT_TIDY); LanguageDefine(names, inside); return; } /* end ReadLangDef */
OBJECT ParameterCheck(OBJECT x, OBJECT env) { OBJECT link, y, res, prnt_env, par, prnt; debug2(DCE, DD, "ParameterCheck(%s, %s)", EchoObject(x), EchoObject(env)); assert( type(x) == CLOSURE, "ParameterCheck given non-CLOSURE!"); /* case x is a parameter */ prnt = SearchEnv(env, enclosing(actual(x))); if( prnt == nilobj ) { debug0(DCE, DD, "ParameterCheck returning nilobj (prnt fail)"); return nilobj; } prnt_env = GetEnv(prnt); for( link = Down(prnt); link != prnt; link = NextDown(link) ) { Child(par, link); if( type(par) == PAR && actual(par) == actual(x) ) { assert( Down(par) != par, "ParameterCheck: Down(par)!"); Child(y, Down(par)); res = is_word(type(y)) ? CopyObject(y, no_fpos) : nilobj; debug1(DCE, DD, " ParameterCheck returning %s", EchoObject(res)); return res; } } /* case x is a default parameter */ y = sym_body(actual(x)); if( y == nilobj ) { res = nilobj; } else if( is_word(type(y)) ) { res = CopyObject(y, &fpos(y)); } else if( type(y) == CLOSURE && is_par(type(actual(y))) ) { res = ParameterCheck(y, prnt_env); } else { res = nilobj; } debug1(DCE, DD, "ParameterCheck returning %s", EchoObject(res)); return res; } /* end ParameterCheck */
OBJECT InsertSym(FULL_CHAR *str, unsigned char xtype, FILE_POS *xfpos, unsigned char xprecedence, BOOLEAN xindefinite, BOOLEAN xrecursive, unsigned xpredefined, OBJECT xenclosing, OBJECT xbody) { register int sum, rlen; register unsigned char *x; OBJECT p, q, s, tmp, link, entry, plink; int len; debug3(DST, DD, "InsertSym( %s, %s, in %s )", Image(xtype), str, SymName(xenclosing)); if( !LexLegalName(str) ) Error(29, 3, "invalid symbol name %s", WARN, xfpos, str); New(s, xtype); FposCopy(fpos(s), *xfpos); has_body(s) = FALSE; filter(s) = nilobj; use_invocation(s) = nilobj; imports(s) = nilobj; imports_encl(s) = FALSE; right_assoc(s) = TRUE; precedence(s) = xprecedence; indefinite(s) = xindefinite; recursive(s) = xrecursive; predefined(s) = xpredefined; enclosing(s) = xenclosing; sym_body(s) = xbody; base_uses(s) = nilobj; uses(s) = nilobj; marker(s) = nilobj; cross_sym(s) = nilobj; is_extern_target(s) = FALSE; uses_extern_target(s)= FALSE; visible(s) = FALSE; uses_galley(s) = FALSE; horiz_galley(s) = ROWM; has_compulsory(s) = 0; is_compulsory(s) = FALSE; uses_count(s) = 0; dirty(s) = FALSE; if( enclosing(s) != nilobj && type(enclosing(s)) == NPAR ) dirty(s) = dirty(enclosing(s)) = TRUE; has_par(s) = FALSE; has_lpar(s) = FALSE; has_rpar(s) = FALSE; if( is_par(type(s)) ) has_par(enclosing(s)) = TRUE; if( type(s) == LPAR ) has_lpar(enclosing(s)) = TRUE; if( type(s) == RPAR ) has_rpar(enclosing(s)) = TRUE; /* assign a code letter between a and z to any NPAR symbol */ if( type(s) == NPAR ) { if( LastDown(enclosing(s)) != enclosing(s) ) { Child(tmp, LastDown(enclosing(s))); if( type(tmp) == NPAR ) { if( npar_code(tmp) == 'z' || npar_code(tmp) == ' ' ) npar_code(s) = ' '; else npar_code(s) = npar_code(tmp)+1; } else npar_code(s) = 'a'; } else npar_code(s) = 'a'; } has_target(s) = FALSE; force_target(s) = FALSE; if( !StringEqual(str, KW_TARGET) ) is_target(s) = FALSE; else { is_target(s) = has_target(enclosing(s)) = TRUE; /* if @Target is found after @Key, take note of external target */ if( has_key(enclosing(s)) && xbody != nilobj && is_cross(type(xbody)) ) { if( LastDown(xbody) != Down(xbody) ) { OBJECT sym; Child(sym, Down(xbody)); if( type(sym) == CLOSURE ) { is_extern_target(actual(sym)) = TRUE; uses_extern_target(actual(sym)) = TRUE; } } } } has_tag(s) = is_tag(s) = FALSE; has_key(s) = is_key(s) = FALSE; has_optimize(s) = is_optimize(s) = FALSE; has_merge(s) = is_merge(s) = FALSE; has_enclose(s) = is_enclose(s) = FALSE; if( enclosing(s) != nilobj && type(enclosing(s)) == LOCAL ) { if( StringEqual(str, KW_TAG) ) is_tag(s) = has_tag(enclosing(s)) = dirty(enclosing(s)) = TRUE; if( StringEqual(str, KW_OPTIMIZE) ) is_optimize(s) = has_optimize(enclosing(s)) = TRUE; if( StringEqual(str, KW_KEY) ) { is_key(s) = has_key(enclosing(s)) = dirty(enclosing(s)) = TRUE; /* if @Key is found after @Target, take note of external target */ for( link=Down(enclosing(s)); link!=enclosing(s); link=NextDown(link) ) { Child(p, link); if( is_target(p) && sym_body(p)!=nilobj && is_cross(type(sym_body(p))) ) { OBJECT sym; Child(sym, Down(sym_body(p))); if( type(sym) == CLOSURE ) { is_extern_target(actual(sym)) = TRUE; uses_extern_target(actual(sym)) = TRUE; } } } } if( StringEqual(str, KW_MERGE) ) is_merge(s) = has_merge(enclosing(s)) = TRUE; if( StringEqual(str, KW_ENCLOSE) ) is_enclose(s) = has_enclose(enclosing(s)) = TRUE; } if( StringEqual(str, KW_FILTER) ) { if( type(s) != LOCAL || enclosing(s) == StartSym ) Error(29, 4, "%s must be a local definition", WARN, &fpos(s), str); else if( !has_rpar(enclosing(s)) ) Error(29, 14, "%s must lie within a symbol with a right parameter", WARN, &fpos(s), KW_FILTER); else { filter(enclosing(s)) = s; precedence(enclosing(s)) = FILTER_PREC; } } if( type(s) == RPAR && has_body(enclosing(s)) && (is_tag(s) || is_key(s) || is_optimize(s)) ) Error(29, 5, "a body parameter may not be named %s", WARN, &fpos(s), str); if( type(s) == RPAR && has_target(enclosing(s)) && (is_tag(s) || is_key(s) || is_optimize(s)) ) Error(29, 6, "the right parameter of a galley may not be called %s", WARN, &fpos(s), str); len = StringLength(str); hash(str, len, sum); ifdebug(DST, D, sym_spread[sum]++; sym_count++); entry = (OBJECT) &symtab[sum]; for( plink = Down(entry); plink != entry; plink = NextDown(plink) ) { Child(p, plink); if( length(p) == len && StringEqual(str, string(p)) ) { for( link = Down(p); link != p; link = NextDown(link) ) { Child(q, link); if( enclosing(s) == enclosing(q) ) { Error(29, 7, "symbol %s previously defined at%s", WARN, &fpos(s), str, EchoFilePos(&fpos(q)) ); if( AltErrorFormat ) { Error(29, 13, "symbol %s previously defined here", WARN, &fpos(q), str); } break; } } goto wrapup; } } /* need a new OBJECT as well as s */ NewWord(p, WORD, len, xfpos); length(p) = len; StringCopy(string(p), str); Link(entry, p); wrapup: Link(p, s); if( enclosing(s) != nilobj ) Link(enclosing(s), s); debug2(DST, DD, "InsertSym Link(%s, %s) and returning.", SymName(enclosing(s)), SymName(s)); return s; } /* end InsertSym */
UnicodeString &QuantityFormatter::format( const Formattable& quantity, const NumberFormat &fmt, const PluralRules &rules, UnicodeString &appendTo, FieldPosition &pos, UErrorCode &status) const { if (U_FAILURE(status)) { return appendTo; } UnicodeString count; const DecimalFormat *decFmt = dynamic_cast<const DecimalFormat *>(&fmt); if (decFmt != NULL) { FixedDecimal fd = decFmt->getFixedDecimal(quantity, status); if (U_FAILURE(status)) { return appendTo; } count = rules.select(fd); } else { if (quantity.getType() == Formattable::kDouble) { count = rules.select(quantity.getDouble()); } else if (quantity.getType() == Formattable::kLong) { count = rules.select(quantity.getLong()); } else if (quantity.getType() == Formattable::kInt64) { count = rules.select((double) quantity.getInt64()); } else { status = U_ILLEGAL_ARGUMENT_ERROR; return appendTo; } } CharString buffer; buffer.appendInvariantChars(count, status); if (U_FAILURE(status)) { return appendTo; } int32_t pluralIndex = getPluralIndex(buffer.data()); if (pluralIndex == -1) { pluralIndex = 0; } const SimplePatternFormatter *pattern = formatters[pluralIndex]; if (pattern == NULL) { pattern = formatters[0]; } if (pattern == NULL) { status = U_INVALID_STATE_ERROR; return appendTo; } UnicodeString formattedNumber; FieldPosition fpos(pos.getField()); fmt.format(quantity, formattedNumber, fpos, status); const UnicodeString *params[1] = {&formattedNumber}; int32_t offsets[1]; pattern->format(params, LENGTHOF(params), appendTo, offsets, LENGTHOF(offsets), status); if (offsets[0] != -1) { if (fpos.getBeginIndex() != 0 || fpos.getEndIndex() != 0) { pos.setBeginIndex(fpos.getBeginIndex() + offsets[0]); pos.setEndIndex(fpos.getEndIndex() + offsets[0]); } } return appendTo; }
UnicodeString PluralFormat::format(int32_t number, UErrorCode& status) const { FieldPosition fpos(0); UnicodeString result; return format(number, result, fpos, status); }
UnicodeString PluralFormat::format(double number, UErrorCode& status) const { FieldPosition fpos(0); UnicodeString result; return format(Formattable(number), number, result, fpos, status); }
int AttachGalley(OBJECT hd, OBJECT *inners, OBJECT *suspend_pt) { OBJECT hd_index; /* the index of hd in the enclosing galley */ OBJECT hd_inners; /* inner galleys of hd, if unsized */ OBJECT dest; /* the target @Galley hd empties into */ OBJECT dest_index; /* the index of dest */ OBJECT target; /* the target indefinite containing dest */ OBJECT target_index; /* the index of target */ OBJECT target_galley; /* the body of target, made into a galley */ OBJECT tg_inners; /* inner galleys of target_galley */ BOOLEAN need_precedes = FALSE;/* true if destination lies before galley */ OBJECT recs; /* list of recursive definite objects */ OBJECT link, y = nilobj; /* for scanning through the components of hd */ CONSTRAINT c; /* temporary variable holding a constraint */ OBJECT env, n1, tmp, zlink, z, sym; /* placeholders and temporaries */ BOOLEAN was_sized; /* true if sized(hd) initially */ int dim; /* the galley direction */ FULL_LENGTH perp_back, perp_fwd; OBJECT why, junk; debug2(DGA, D, "[ AttachGalley(Galley %s into %s)", SymName(actual(hd)), SymName(whereto(hd))); ifdebug(DGA, DD, DebugGalley(hd, nilobj, 4)); assert( Up(hd) != hd, "AttachGalley: no index!" ); Parent(hd_index, Up(hd)); assert( type(hd_index) == UNATTACHED, "AttachGalley: not UNATTACHED!" ); hd_inners = tg_inners = nilobj; was_sized = sized(hd); dim = gall_dir(hd); for(;;) { /*************************************************************************/ /* */ /* Search for a destination for hd. If hd is unsized, search for */ /* inner galleys preceding it first of all, then for receptive objects */ /* following it, possibly in inner galleys. If no luck, exit. */ /* If hd is sized, search only for receptive objects in the current */ /* galley below the current spot, and fail if cannot find any. */ /* */ /*************************************************************************/ sym = whereto(hd); if( sized(hd) ) { /* sized galley case: search on from current spot */ target_index = SearchGalley(Up(hd_index), sym, TRUE, FALSE, TRUE, TRUE); if( target_index == nilobj ) { /* search failed to find any new target, so kill the galley */ for( link = Down(hd); link != hd; link = NextDown(link) ) { Child(y, link); if( type(y) == SPLIT ) Child(y, DownDim(y, dim)); if( is_definite(type(y)) ) break; } if( link != hd ) Error(19, 1, "galley %s deleted from here (no target)", WARN, &fpos(y), SymName(actual(hd))); if( hd_inners != nilobj ) DisposeObject(hd_inners), hd_inners=nilobj; if( tg_inners != nilobj ) DisposeObject(tg_inners), tg_inners=nilobj; KillGalley(hd, FALSE); *inners = nilobj; debug0(DGA, D, "] AttachGalley returning ATTACH_KILLED"); return ATTACH_KILLED; } else if( actual(actual(target_index)) == InputSym ) { /* search found input object, so suspend on that */ DeleteNode(hd_index); Link(target_index, hd); *inners = nilobj; debug0(DGA, D, "] AttachGalley returning ATTACH_INPUT"); return ATTACH_INPUT; } } else /* unsized galley, either backwards or normal */ { if( foll_or_prec(hd) == GALL_PREC ) { target_index= SearchGalley(Up(hd_index), sym, FALSE, TRUE,TRUE,FALSE); need_precedes = FALSE; } else { target_index = SearchGalley(Up(hd_index), sym, FALSE,TRUE,FALSE,FALSE); need_precedes = (target_index != nilobj); if( target_index == nilobj ) target_index = SearchGalley(Up(hd_index), sym, TRUE,TRUE,TRUE,FALSE); } /* if no luck, exit without error */ if( target_index == nilobj ) { *inners = nilobj; debug0(DGA, D, "] AttachGalley returning ATTACH_NOTARGET"); return ATTACH_NOTARGET; } } assert( type(target_index) == RECEPTIVE, "AttachGalley: target_index!" ); target = actual(target_index); assert( type(target) == CLOSURE, "AttachGalley: target!" ); /* set target_galley to the expanded value of target */ debug1(DYY, D, "[ EnterErrorBlock(FALSE) (expanding target %s)", SymName(actual(target))); EnterErrorBlock(FALSE); New(target_galley, HEAD); force_gall(target_galley) = FALSE; enclose_obj(target_galley) = limiter(target_galley) = nilobj; ClearHeaders(target_galley); opt_components(target_galley) = opt_constraints(target_galley) = nilobj; gall_dir(target_galley) = external_hor(target) ? COLM : ROWM; FposCopy(fpos(target_galley), fpos(target)); actual(target_galley) = actual(target); whereto(target_galley) = ready_galls(target_galley) = nilobj; foll_or_prec(target_galley) = GALL_FOLL; must_expand(target_galley) = FALSE; sized(target_galley) = FALSE; /* get perpendicular constraint (none if horizontal galley) */ if( dim == ROWM ) { Constrained(target, &c, 1-dim, &junk); if( !constrained(c) ) Error(19, 2, "receptive symbol %s has unconstrained width", FATAL, &fpos(target), SymName(actual(target))); debug2(DSC, DD, "Constrained( %s, 1-dim ) = %s", EchoObject(target), EchoConstraint(&c)); if( !FitsConstraint(0, 0, c) ) { debug0(DGA, D, " reject: target_galley horizontal constraint is -1"); y = nilobj; goto REJECT; } } else /* actually unused */ SetConstraint(c, MAX_FULL_LENGTH, MAX_FULL_LENGTH, MAX_FULL_LENGTH); debug1(DGA, DDD, " expanding %s", EchoObject(target)); tmp = CopyObject(target, no_fpos); Link(target_galley, tmp); env = DetachEnv(tmp); debug4(DGM, D, " external_ver(%s) = %s, external_hor(%s) = %s", SymName(actual(target)), bool(external_ver(target)), SymName(actual(target)), bool(external_hor(target))); SizeGalley(target_galley, env, external_ver(target) || external_hor(target), threaded(target), non_blocking(target_index), trigger_externs(target_index), &save_style(target), &c, whereto(hd), &dest_index, &recs, &tg_inners, enclose_obj(hd) != nilobj ? CopyObject(enclose_obj(hd), no_fpos):nilobj); debug1(DGA, DD, " SizeGalley tg_inners: %s", DebugInnersNames(tg_inners)); if( recs != nilobj ) ExpandRecursives(recs); dest = actual(dest_index); if( underline(dest) == UNDER_UNDEF ) underline(dest) = UNDER_OFF; /* verify that hd satisfies any horizontal constraint on dest */ if( dim == ROWM ) { debug1(DGA, DDD, " checking hor fit of hd in %s",SymName(actual(dest))); Constrained(dest, &c, 1-dim, &junk); debug3(DSC, DD, "Constrained( %s, %s ) = %s", EchoObject(dest), dimen(1-dim), EchoConstraint(&c)); assert( constrained(c), "AttachGalley: dest unconstrained!" ); if( !FitsConstraint(0, 0, c) ) { debug0(DGA, D, " reject: hd horizontal constraint is -1"); y = nilobj; goto REJECT; } } /* manifest and size the galley if not done yet */ if( !sized(hd) ) { debug2(DYY, D, "[ EnterErrorBlock(TRUE) (sizing galley %s into %s)", SymName(actual(hd)), SymName(whereto(hd))); EnterErrorBlock(TRUE); n1 = nilobj; Child(y, Down(hd)); env = DetachEnv(y); /*** threaded() only defined in ROWM case SizeGalley(hd, env, TRUE, threaded(dest), non_blocking(target_index), TRUE, &save_style(dest), &c, nilobj, &n1, &recs, &hd_inners); *** */ SizeGalley(hd, env, TRUE, dim == ROWM ? threaded(dest) : FALSE, non_blocking(target_index), TRUE, &save_style(dest), &c, nilobj, &n1, &recs, &hd_inners, nilobj); debug1(DGA,DD," SizeGalley hd_inners: %s", DebugInnersNames(hd_inners)); if( recs != nilobj ) ExpandRecursives(recs); if( need_precedes ) /* need an ordering constraint */ { OBJECT index1, index2; New(index1, PRECEDES); New(index2, FOLLOWS); blocked(index2) = FALSE; tmp = MakeWord(WORD, STR_EMPTY, no_fpos); Link(index1, tmp); Link(index2, tmp); Link(Up(hd_index), index1); Link(Down(hd), index2); debug0(DGA, D, " inserting PRECEDES and FOLLOWS"); } LeaveErrorBlock(TRUE); debug0(DYY, D, "] LeaveErrorBlock(TRUE) (finished sizing galley)"); } if( dim == ROWM ) { if( !FitsConstraint(back(hd, 1-dim), fwd(hd, 1-dim), c) ) { debug3(DGA, D, " reject: hd %s,%s does not fit target_galley %s", EchoLength(back(hd, 1-dim)), EchoLength(fwd(hd, 1-dim)), EchoConstraint(&c)); Error(19, 3, "too little horizontal space for galley %s at %s", WARN, &fpos(hd), SymName(actual(hd)), SymName(actual(dest))); goto REJECT; } } /* check status of first component of hd */ debug0(DGA, DDD, " now ready to attach; hd ="); ifdebug(DGA, DDD, DebugObject(hd)); for( link = Down(hd); link != hd; link = NextDown(link) ) { Child(y, link); debug1(DGA, DDD, " examining %s", EchoIndex(y)); if( type(y) == SPLIT ) Child(y, DownDim(y, dim)); switch( type(y) ) { case EXPAND_IND: case SCALE_IND: case COVER_IND: case GALL_PREC: case GALL_FOLL: case GALL_FOLL_OR_PREC: case GALL_TARG: case CROSS_PREC: case CROSS_FOLL: case CROSS_FOLL_OR_PREC: case CROSS_TARG: case PAGE_LABEL_IND: break; case PRECEDES: case UNATTACHED: if( was_sized ) { /* SizeGalley was not called, so hd_inners was not set by it */ if( hd_inners == nilobj ) New(hd_inners, ACAT); Link(hd_inners, y); } break; case RECEPTIVE: goto SUSPEND; case RECEIVING: goto SUSPEND; case FOLLOWS: Child(tmp, Down(y)); if( Up(tmp) == LastUp(tmp) ) { link = pred(link, CHILD); debug0(DGA, DD, " disposing FOLLOWS"); DisposeChild(NextDown(link)); break; } Parent(tmp, Up(tmp)); assert(type(tmp) == PRECEDES, "Attach: PRECEDES!"); switch( CheckComponentOrder(tmp, target_index) ) { case CLEAR: DeleteNode(tmp); link = pred(link, CHILD); DisposeChild(NextDown(link)); break; case PROMOTE: break; case BLOCK: debug0(DGA, DD, "CheckContraint: BLOCK"); goto SUSPEND; case CLOSE: debug0(DGA, D, " reject: CheckContraint"); goto REJECT; } break; case GAP_OBJ: underline(y) = underline(dest); if( !join(gap(y)) ) seen_nojoin(hd) = TRUE; break; case BEGIN_HEADER: case END_HEADER: case SET_HEADER: case CLEAR_HEADER: /* do nothing until actually promoted out of here */ underline(y) = underline(dest); break; case CLOSURE: case CROSS: case FORCE_CROSS: case NULL_CLOS: case PAGE_LABEL: underline(y) = underline(dest); break; case WORD: case QWORD: case ONE_COL: case ONE_ROW: case WIDE: case HIGH: case HSHIFT: case VSHIFT: case HMIRROR: case VMIRROR: case HSCALE: case VSCALE: case HCOVER: case VCOVER: case HCONTRACT: case VCONTRACT: case HLIMITED: case VLIMITED: case HEXPAND: case VEXPAND: case START_HVSPAN: case START_HSPAN: case START_VSPAN: case HSPAN: case VSPAN: case ROTATE: case BACKGROUND: case SCALE: case KERN_SHRINK: case INCGRAPHIC: case SINCGRAPHIC: case PLAIN_GRAPHIC: case GRAPHIC: case LINK_SOURCE: case LINK_DEST: case LINK_DEST_NULL: case LINK_URL: case ACAT: case HCAT: case VCAT: case ROW_THR: case COL_THR: underline(y) = underline(dest); if( dim == ROWM ) { /* make sure y is not joined to a target below (vertical only) */ for( zlink = NextDown(link); zlink != hd; zlink = NextDown(zlink) ) { Child(z, zlink); switch( type(z) ) { case RECEPTIVE: if( non_blocking(z) ) { zlink = PrevDown(zlink); DeleteNode(z); } else { y = z; goto SUSPEND; } break; case RECEIVING: if( non_blocking(z) ) { zlink = PrevDown(zlink); while( Down(z) != z ) { Child(tmp, Down(y)); if( opt_components(tmp) != nilobj ) { DisposeObject(opt_components(tmp)); opt_components(tmp) = nilobj; debug3(DOG, D, "AttachGalley(%s) de-optimizing %s %s", SymName(actual(hd)), SymName(actual(tmp)), "(join)"); } DetachGalley(tmp); KillGalley(tmp, FALSE); } DeleteNode(z); } else { y = z; goto SUSPEND; } break; case GAP_OBJ: if( !join(gap(z)) ) zlink = PrevDown(hd); break; default: break; } } /* if HCAT, try vertical hyphenation (vertical galleys only) */ if( type(y) == HCAT ) VerticalHyphenate(y); } /* check availability of parallel space for the first component */ why = nilobj; Constrained(dest, &c, dim, &why); debug3(DGF, DD, " dest parallel Constrained(%s, %s) = %s", EchoObject(dest), dimen(dim), EchoConstraint(&c)); if( !FitsConstraint(back(y, dim), fwd(y, dim), c) ) { BOOLEAN scaled; /* if forcing galley doesn't fit, try scaling first component */ scaled = FALSE; if( force_gall(hd) && size(y, dim) > 0 ) { int scale_factor; scale_factor = ScaleToConstraint(back(y,dim), fwd(y,dim), &c); if( scale_factor > 0.5 * SF ) { char num1[20], num2[20]; sprintf(num1, "%.1fc", (float) size(y, dim) / CM); sprintf(num2, "%.1fc", (float) bfc(c) / CM); if( dim == ROWM ) Error(19, 4, "%s object too high for %s space; %s inserted", WARN, &fpos(y), num1, num2, KW_SCALE); else Error(19, 5, "%s object too wide for %s space; %s inserted", WARN, &fpos(y), num1, num2, KW_SCALE); y = InterposeScale(y, scale_factor, dim); scaled = TRUE; } } /* otherwise we must reject, and warn the user */ if( !scaled ) { char num1[20], num2[20]; debug3(DGA, D, " reject: vsize %s,%s in %s; y=", EchoLength(back(y, dim)), EchoLength(fwd(y, dim)), EchoConstraint(&c)); ifdebug(DGA, D, DebugObject(y)); if( size(y, dim) > 0 ) { sprintf(num1, "%.1fc", (float) size(y, dim) / CM); sprintf(num2, "%.1fc", (float) bfc(c) / CM); if( dim == ROWM ) Error(19, 12, "%s object too high for %s space; will try elsewhere", WARN, &fpos(y), num1, num2); else Error(19, 13, "%s object too wide for %s space; will try elsewhere", WARN, &fpos(y), num1, num2); } goto REJECT; } } /* check availability of perpendicular space for first component */ if( dim == ROWM ) { perp_back = back(hd, 1-dim); perp_fwd = fwd(hd, 1-dim); } else { perp_back = back(y, 1-dim); perp_fwd = fwd(y, 1-dim); } Constrained(dest, &c, 1-dim, &junk); debug3(DGF, DD, " dest perpendicular Constrained(%s, %s) = %s", EchoObject(dest), dimen(1-dim), EchoConstraint(&c)); if( !FitsConstraint(perp_back, perp_fwd, c) ) { BOOLEAN scaled; /* if forcing galley doesn't fit, try scaling first component */ scaled = FALSE; if( force_gall(hd) && perp_back + perp_fwd > 0 ) { int scale_factor; scale_factor = ScaleToConstraint(perp_back, perp_fwd, &c); if( scale_factor > 0.5 * SF ) { char num1[20], num2[20]; sprintf(num1, "%.1fc", (float) (perp_back + perp_fwd) / CM); sprintf(num2, "%.1fc", (float) bfc(c) / CM); if( 1-dim == ROWM ) Error(19, 6, "%s object too high for %s space; %s inserted", WARN, &fpos(y), num1, num2, KW_SCALE); else Error(19, 7, "%s object too wide for %s space; %s inserted", WARN, &fpos(y), num1, num2, KW_SCALE); y = InterposeScale(y, scale_factor, 1-dim); scaled = TRUE; } } /* otherwise we must reject, and warn the user */ if( !scaled ) { debug3(DGA, D, " reject: vsize %s,%s in %s; y=", EchoLength(perp_back), EchoLength(perp_fwd), EchoConstraint(&c)); ifdebug(DGA, D, DebugObject(y)); goto REJECT; } } /* dest seems OK, so perform its size adjustments */ debug0(DSA, D, "calling AdjustSize from AttachGalley (a)"); AdjustSize(dest, back(y, dim), fwd(y, dim), dim); debug0(DSA, D, "calling AdjustSize from AttachGalley (b)"); AdjustSize(dest, perp_back, perp_fwd, 1-dim); /* now check parallel space for target_galley in target */ Constrained(target, &c, dim, &why); debug3(DGF, DD, " target parallel Constrained(%s, %s) = %s", EchoObject(target), dimen(dim), EchoConstraint(&c)); Child(z, LastDown(target_galley)); /* works in all cases? */ assert( !is_index(type(z)), "AttachGalley: is_index(z)!" ); assert( back(z, dim)>=0 && fwd(z, dim)>=0, "AttachGalley: z size!" ); if( !FitsConstraint(back(z, dim), fwd(z, dim), c) ) { BOOLEAN scaled; debug2(DGA, D, " why = %d %s", (int) why, EchoObject(why)); debug2(DGA, D, " limiter = %d %s", (int) limiter(hd), EchoObject(limiter(hd))); /* if forcing galley doesn't fit, try scaling z */ scaled = FALSE; if( force_gall(hd) && size(z, dim) > 0 && limiter(hd) != why ) { int scale_factor; scale_factor = ScaleToConstraint(back(z,dim), fwd(z,dim), &c); if( scale_factor > 0.5 * SF ) { char num1[20], num2[20]; sprintf(num1, "%.1fc", (float) size(z, dim) / CM); sprintf(num2, "%.1fc", (float) bfc(c) / CM); if( dim == ROWM ) Error(19, 8, "%s object too high for %s space; %s inserted", WARN, &fpos(y), num1, num2, KW_SCALE); else Error(19, 9, "%s object too wide for %s space; %s inserted", WARN, &fpos(y), num1, num2, KW_SCALE); z = InterposeWideOrHigh(z, dim); z = InterposeScale(z, scale_factor, dim); scaled = TRUE; } } if( !scaled ) { char num1[20], num2[20]; limiter(hd) = why; debug3(DGA, D, " set limiter(%s) = %d %s", SymName(actual(hd)), (int) limiter(hd), EchoObject(limiter(hd))); debug3(DGA, D, " reject: size was %s,%s in %s; y =", EchoLength(back(z, dim)), EchoLength(fwd(z, dim)), EchoConstraint(&c)); ifdebug(DGA, D, DebugObject(y)); if( size(z, dim) > 0 ) { sprintf(num1, "%.1fc", (float) size(z, dim) / CM); sprintf(num2, "%.1fc", (float) bfc(c) / CM); if( dim == ROWM ) Error(19, 14, "%s object too high for %s space; will try elsewhere", WARN, &fpos(y), num1, num2); else Error(19, 15, "%s object too wide for %s space; will try elsewhere", WARN, &fpos(y), num1, num2); } goto REJECT; } } limiter(hd) = why; debug3(DGA, D, " set limiter(%s) = %d %s", SymName(actual(hd)), (int) limiter(hd), EchoObject(limiter(hd))); /* now check perpendicular space for target_galley in target */ Constrained(target, &c, 1-dim, &junk); debug3(DGF, DD, " target perpendicular Constrained(%s, %s) = %s", EchoObject(target), dimen(1-dim), EchoConstraint(&c)); Child(z, LastDown(target_galley)); /* works in all cases? */ assert( !is_index(type(z)), "AttachGalley: is_index(z)!" ); assert( back(z, 1-dim)>=0 && fwd(z, 1-dim)>=0, "AttachGalley: z size (perpendicular)!" ); if( !FitsConstraint(back(z, 1-dim), fwd(z, 1-dim), c) ) { BOOLEAN scaled; /* if forcing galley doesn't fit, try scaling z */ scaled = FALSE; if( force_gall(hd) && size(z, 1-dim) > 0 ) { int scale_factor; scale_factor = ScaleToConstraint(back(z,1-dim), fwd(z,1-dim), &c); if( scale_factor > 0.5 * SF ) { char num1[20], num2[20]; sprintf(num1, "%.1fc", (float) size(z, 1-dim) / CM); sprintf(num2, "%.1fc", (float) bfc(c) / CM); if( 1-dim == ROWM ) Error(19, 10, "%s object too high for %s space; %s inserted", WARN, &fpos(y), num1, num2, KW_SCALE); else Error(19, 11, "%s object too wide for %s space; %s inserted", WARN, &fpos(y), num1, num2, KW_SCALE); z = InterposeWideOrHigh(z, 1-dim); z = InterposeScale(z, scale_factor, 1-dim); scaled = TRUE; } } if( !scaled ) { debug3(DGA, D, " reject: size was %s,%s in %s; y =", EchoLength(back(z, 1-dim)), EchoLength(fwd(z, 1-dim)), EchoConstraint(&c)); ifdebug(DGA, D, DebugObject(y)); goto REJECT; } } /* target seems OK, so adjust sizes and accept */ if( external_hor(target) ) { /* don't adjust any sizes, none to adjust */ debug0(DSA, D, "not calling AdjustSize from AttachGalley (c)"); } else if( external_ver(target) ) { /* adjust perp size only, to galley size */ debug0(DSA, D, "calling AdjustSize from AttachGalley (d)"); AdjustSize(target, back(target_galley, 1-dim), fwd(target_galley, 1-dim), 1-dim); } else { /* adjust both directions, using z (last component) */ Child(z, LastDown(target_galley)); debug0(DSA, D, "AttachGalley AdjustSize using z ="); ifdebug(DSA, D, DebugObject(z)); debug0(DSA, D, "calling AdjustSize from AttachGalley (e)"); AdjustSize(target, back(z, dim), fwd(z, dim), dim); debug0(DSA, D, "calling AdjustSize from AttachGalley (f)"); AdjustSize(target, back(z, 1-dim), fwd(z, 1-dim), 1-dim); } goto ACCEPT; default: assert1(FALSE, "AttachGalley:", Image(type(y))); break; } /* end switch */ } /* end for */ /* null galley: promote whole galley without expanding the target */ debug0(DGA, D, " null galley"); if( tg_inners != nilobj ) DisposeObject(tg_inners), tg_inners = nilobj; DisposeObject(target_galley); LeaveErrorBlock(FALSE); debug0(DYY, D, "] LeaveErrorBlock(FALSE) (null galley)"); /* kill off any null objects within the galley, then transfer it */ /* don't use Promote() since it does extra unwanted things here */ for( link = Down(hd); link != hd; link = NextDown(link) ) { Child(y, link); switch( type(y) ) { case GAP_OBJ: case CLOSURE: case CROSS: case FORCE_CROSS: case NULL_CLOS: case PAGE_LABEL: link = PrevDown(link); debug1(DGA, D, " null galley, disposing %s", Image(type(y))); DisposeChild(NextDown(link)); break; default: break; } } TransferLinks(NextDown(hd), hd, Up(target_index)); /* attach hd temporarily to target_index */ MoveLink(Up(hd), target_index, PARENT); assert( type(hd_index) == UNATTACHED, "AttachGalley: type(hd_index)!" ); DeleteNode(hd_index); /* return; only hd_inners needs to be flushed now */ *inners = hd_inners; debug0(DGA, D, "] AttachGalley returning ATTACH_NULL"); return ATTACH_NULL; REJECT: /* reject first component */ /* debug1(DGA, D, " reject %s", EchoObject(y)); */ debug0(DGA, D, " reject first component"); LeaveErrorBlock(TRUE); debug0(DYY, D, "] LeaveErrorBlock(TRUE) (REJECT)"); if( tg_inners != nilobj ) DisposeObject(tg_inners), tg_inners = nilobj; DisposeObject(target_galley); if( foll_or_prec(hd) == GALL_PREC && !sized(hd) ) { /* move to just before the failed target */ MoveLink(Up(hd_index), Up(target_index), PARENT); } else { /* move to just after the failed target */ MoveLink(Up(hd_index), NextDown(Up(target_index)), PARENT); } continue; SUSPEND: /* suspend at first component */ debug1(DGA, D, " suspend %s", EchoIndex(y)); blocked(y) = TRUE; LeaveErrorBlock(FALSE); debug0(DYY, D, "] LeaveErrorBlock(FALSE) (SUSPEND)"); if( tg_inners != nilobj ) DisposeObject(tg_inners), tg_inners = nilobj; DisposeObject(target_galley); MoveLink(Up(hd_index), Up(target_index), PARENT); if( was_sized ) { /* nothing new to flush if suspending and already sized */ if( hd_inners != nilobj ) DisposeObject(hd_inners), hd_inners=nilobj; *inners = nilobj; } else { /* flush newly discovered inners if not sized before */ *inners = hd_inners; } debug0(DGA, D, "] AttachGalley returning ATTACH_SUSPEND"); *suspend_pt = y; return ATTACH_SUSPEND; ACCEPT: /* accept first component; now committed to the attach */ debug3(DGA, D, " accept %s %s %s", Image(type(y)), EchoObject(y), EchoFilePos(&fpos(y))); LeaveErrorBlock(TRUE); debug0(DYY, D, "] LeaveErrorBlock(TRUE) (ACCEPT)"); /* attach hd to dest */ MoveLink(Up(hd), dest_index, PARENT); assert( type(hd_index) == UNATTACHED, "AttachGalley: type(hd_index)!" ); DeleteNode(hd_index); /* move first component of hd into dest */ /* nb Interpose must be done after all AdjustSize calls */ if( dim == ROWM && !external_ver(dest) ) Interpose(dest, VCAT, hd, y); else if( dim == COLM && !external_hor(dest) ) { Interpose(dest, ACAT, y, y); Parent(junk, Up(dest)); assert( type(junk) == ACAT, "AttachGalley: type(junk) != ACAT!" ); StyleCopy(save_style(junk), save_style(dest)); adjust_cat(junk) = padjust(save_style(junk)); } debug1(DGS, D, "calling Promote(hd, %s) from AttachGalley/ACCEPT", link == hd ? "hd" : "NextDown(link)"); Promote(hd, link == hd ? hd : NextDown(link), dest_index, TRUE); /* move target_galley into target */ /* nb Interpose must be done after all AdjustSize calls */ if( !(external_ver(target) || external_hor(target)) ) { Child(z, LastDown(target_galley)); Interpose(target, VCAT, z, z); } debug0(DGS, D, "calling Promote(target_galley) from AttachGalley/ACCEPT"); Promote(target_galley, target_galley, target_index, TRUE); DeleteNode(target_galley); assert(Down(target_index)==target_index, "AttachGalley: target_ind"); if( blocked(target_index) ) blocked(dest_index) = TRUE; DeleteNode(target_index); /* return; both tg_inners and hd_inners need to be flushed now; */ /* if was_sized, hd_inners contains the inners of the first component; */ /* otherwise it contains the inners of all components, from SizeGalley */ if( tg_inners == nilobj ) *inners = hd_inners; else if( hd_inners == nilobj ) *inners = tg_inners; else { TransferLinks(Down(hd_inners), hd_inners, tg_inners); DeleteNode(hd_inners); *inners = tg_inners; } debug0(DGA, D, "] AttachGalley returning ATTACH_ACCEPT"); ifdebug(DGA, D, if( dim == COLM && !external_hor(dest) ) { OBJECT z; Parent(z, Up(dest)); debug2(DGA, D, " COLM dest_encl on exit = %s %s", Image(type(z)), EchoObject(z)); } ) return ATTACH_ACCEPT; } /* end for */
void TestChoiceFormat::TestComplexExample( void ) { UErrorCode status = U_ZERO_ERROR; const double filelimits[] = {-1, 0,1,2}; const UnicodeString filepart[] = {"are corrupted files", "are no files","is one file","are {2} files"}; ChoiceFormat* fileform = new ChoiceFormat( filelimits, filepart, 4); if (!fileform) { it_errln("*** test_complex_example fileform"); return; } Format* filenumform = NumberFormat::createInstance( status ); if (!filenumform) { dataerrln((UnicodeString)"*** test_complex_example filenumform - " + u_errorName(status)); delete fileform; return; } if (!chkstatus( status, "*** test_simple_example filenumform" )) { delete fileform; delete filenumform; return; } //const Format* testFormats[] = { fileform, NULL, filenumform }; //pattform->setFormats( testFormats, 3 ); MessageFormat* pattform = new MessageFormat("There {0} on {1}", status ); if (!pattform) { it_errln("*** test_complex_example pattform"); delete fileform; delete filenumform; return; } if (!chkstatus( status, "*** test_complex_example pattform" )) { delete fileform; delete filenumform; delete pattform; return; } pattform->setFormat( 0, *fileform ); pattform->setFormat( 2, *filenumform ); Formattable testArgs[] = {(int32_t)0, "Disk_A", (int32_t)0}; UnicodeString str; UnicodeString res1, res2; pattform->toPattern( res1 ); it_logln("MessageFormat toPattern: " + res1); fileform->toPattern( res1 ); it_logln("ChoiceFormat toPattern: " + res1); if (res1 == "-1#are corrupted files|0#are no files|1#is one file|2#are {2} files") { it_logln("toPattern tested!"); }else{ it_errln("*** ChoiceFormat to Pattern result!"); } FieldPosition fpos(FieldPosition::DONT_CARE); UnicodeString checkstr[] = { "There are corrupted files on Disk_A", "There are no files on Disk_A", "There is one file on Disk_A", "There are 2 files on Disk_A", "There are 3 files on Disk_A" }; // if (status != U_ZERO_ERROR) return; // TODO: analyze why we have such a bad bail out here! if (U_FAILURE(status)) { delete fileform; delete filenumform; delete pattform; return; } int32_t i; int32_t start = -1; for (i = start; i < 4; ++i) { str = ""; status = U_ZERO_ERROR; testArgs[0] = Formattable((int32_t)i); testArgs[2] = testArgs[0]; res2 = pattform->format(testArgs, 3, str, fpos, status ); if (!chkstatus( status, "*** test_complex_example format" )) { delete fileform; delete filenumform; delete pattform; return; } it_logln(i + UnicodeString(" -> ") + res2); if (res2 != checkstr[i - start]) { it_errln("*** test_complex_example res string"); it_errln(UnicodeString("*** ") + i + UnicodeString(" -> '") + res2 + UnicodeString("' unlike '") + checkstr[i] + UnicodeString("' ! ")); } } it_logln(); it_logln("------ additional testing in complex test ------"); it_logln(); // #if 0 // ICU 4.8 deprecates and disables the ChoiceFormat getters. int32_t retCount; const double* retLimits = fileform->getLimits( retCount ); if ((retCount == 4) && (retLimits) && (retLimits[0] == -1.0) && (retLimits[1] == 0.0) && (retLimits[2] == 1.0) && (retLimits[3] == 2.0)) { it_logln("getLimits tested!"); }else{ it_errln("*** getLimits unexpected result!"); } const UnicodeString* retFormats = fileform->getFormats( retCount ); if ((retCount == 4) && (retFormats) && (retFormats[0] == "are corrupted files") && (retFormats[1] == "are no files") && (retFormats[2] == "is one file") && (retFormats[3] == "are {2} files")) { it_logln("getFormats tested!"); }else{ it_errln("*** getFormats unexpected result!"); } #endif UnicodeString checkstr2[] = { "There is no folder on Disk_A", "There is one folder on Disk_A", "There are many folders on Disk_A", "There are many folders on Disk_A" }; fileform->applyPattern("0#is no folder|1#is one folder|2#are many folders", status ); if (status == U_ZERO_ERROR) it_logln("status applyPattern OK!"); if (!chkstatus( status, "*** test_complex_example pattform" )) { delete fileform; delete filenumform; delete pattform; return; } pattform->setFormat( 0, *fileform ); fpos = 0; for (i = 0; i < 4; ++i) { str = ""; status = U_ZERO_ERROR; testArgs[0] = Formattable((int32_t)i); testArgs[2] = testArgs[0]; res2 = pattform->format(testArgs, 3, str, fpos, status ); if (!chkstatus( status, "*** test_complex_example format 2" )) { delete fileform; delete filenumform; delete pattform; return; } it_logln(UnicodeString() + i + UnicodeString(" -> ") + res2); if (res2 != checkstr2[i]) { it_errln("*** test_complex_example res string"); it_errln(UnicodeString("*** ") + i + UnicodeString(" -> '") + res2 + UnicodeString("' unlike '") + checkstr2[i] + UnicodeString("' ! ")); } } const double limits_A[] = {1,2,3,4,5,6,7}; const UnicodeString monthNames_A[] = {"Sun","Mon","Tue","Wed","Thur","Fri","Sat"}; ChoiceFormat* form_A = new ChoiceFormat(limits_A, monthNames_A, 7); ChoiceFormat* form_A2 = new ChoiceFormat(limits_A, monthNames_A, 7); const double limits_B[] = {1,2,3,4,5,6,7}; const UnicodeString monthNames_B[] = {"Sun","Mon","Tue","Wed","Thur","Fri","Sat_BBB"}; ChoiceFormat* form_B = new ChoiceFormat(limits_B, monthNames_B, 7); if (!form_A || !form_B || !form_A2) { it_errln("*** test-choiceFormat not allocatable!"); }else{ if (*form_A == *form_A2) { it_logln("operator== tested."); }else{ it_errln("*** operator=="); } if (*form_A != *form_B) { it_logln("operator!= tested."); }else{ it_errln("*** operator!="); } ChoiceFormat* form_A3 = (ChoiceFormat*) form_A->clone(); if (!form_A3) { it_errln("*** ChoiceFormat->clone is nil."); }else{ if ((*form_A3 == *form_A) && (*form_A3 != *form_B)) { it_logln("method clone tested."); }else{ it_errln("*** ChoiceFormat clone or operator==, or operator!= ."); } } ChoiceFormat form_Assigned( *form_A ); UBool ok = (form_Assigned == *form_A) && (form_Assigned != *form_B); form_Assigned = *form_B; ok = ok && (form_Assigned != *form_A) && (form_Assigned == *form_B); if (ok) { it_logln("copy constructor and operator= tested."); }else{ it_errln("*** copy constructor or operator= or operator == or operator != ."); } delete form_A3; } delete form_A; delete form_A2; delete form_B; const char* testPattern = "0#none|1#one|2#many"; ChoiceFormat form_pat( testPattern, status ); if (!chkstatus( status, "*** ChoiceFormat contructor( newPattern, status)" )) { delete fileform; delete filenumform; delete pattform; return; } form_pat.toPattern( res1 ); if (res1 == "0#none|1#one|2#many") { it_logln("ChoiceFormat contructor( newPattern, status) tested"); }else{ it_errln("*** ChoiceFormat contructor( newPattern, status) or toPattern result!"); } double d_a2[] = { 3.0, 4.0 }; UnicodeString s_a2[] = { "third", "forth" }; form_pat.setChoices( d_a2, s_a2, 2 ); form_pat.toPattern( res1 ); it_logln(UnicodeString("ChoiceFormat adoptChoices toPattern: ") + res1); if (res1 == "3#third|4#forth") { it_logln("ChoiceFormat adoptChoices tested"); }else{ it_errln("*** ChoiceFormat adoptChoices result!"); } str = ""; fpos = 0; status = U_ZERO_ERROR; double arg_double = 3.0; res1 = form_pat.format( arg_double, str, fpos ); it_logln(UnicodeString("ChoiceFormat format:") + res1); if (res1 != "third") it_errln("*** ChoiceFormat format (double, ...) result!"); str = ""; fpos = 0; status = U_ZERO_ERROR; int64_t arg_64 = 3; res1 = form_pat.format( arg_64, str, fpos ); it_logln(UnicodeString("ChoiceFormat format:") + res1); if (res1 != "third") it_errln("*** ChoiceFormat format (int64_t, ...) result!"); str = ""; fpos = 0; status = U_ZERO_ERROR; int32_t arg_long = 3; res1 = form_pat.format( arg_long, str, fpos ); it_logln(UnicodeString("ChoiceFormat format:") + res1); if (res1 != "third") it_errln("*** ChoiceFormat format (int32_t, ...) result!"); Formattable ft( (int32_t)3 ); str = ""; fpos = 0; status = U_ZERO_ERROR; res1 = form_pat.format( ft, str, fpos, status ); if (!chkstatus( status, "*** test_complex_example format (int32_t, ...)" )) { delete fileform; delete filenumform; delete pattform; return; } it_logln(UnicodeString("ChoiceFormat format:") + res1); if (res1 != "third") it_errln("*** ChoiceFormat format (Formattable, ...) result!"); Formattable fta[] = { (int32_t)3 }; str = ""; fpos = 0; status = U_ZERO_ERROR; res1 = form_pat.format( fta, 1, str, fpos, status ); if (!chkstatus( status, "*** test_complex_example format (int32_t, ...)" )) { delete fileform; delete filenumform; delete pattform; return; } it_logln(UnicodeString("ChoiceFormat format:") + res1); if (res1 != "third") it_errln("*** ChoiceFormat format (Formattable[], cnt, ...) result!"); ParsePosition parse_pos = 0; Formattable result; UnicodeString parsetext("third"); form_pat.parse( parsetext, result, parse_pos ); double rd = (result.getType() == Formattable::kLong) ? result.getLong() : result.getDouble(); if (rd == 3.0) { it_logln("parse( ..., ParsePos ) tested."); }else{ it_errln("*** ChoiceFormat parse( ..., ParsePos )!"); } form_pat.parse( parsetext, result, status ); rd = (result.getType() == Formattable::kLong) ? result.getLong() : result.getDouble(); if (rd == 3.0) { it_logln("parse( ..., UErrorCode ) tested."); }else{ it_errln("*** ChoiceFormat parse( ..., UErrorCode )!"); } /* UClassID classID = ChoiceFormat::getStaticClassID(); if (classID == form_pat.getDynamicClassID()) { it_out << "getStaticClassID and getDynamicClassID tested." << endl; }else{ it_errln("*** getStaticClassID and getDynamicClassID!"); } */ it_logln(); delete fileform; delete filenumform; delete pattform; }
void TestChoiceFormat::TestSimpleExample( void ) { double limits[] = {1,2,3,4,5,6,7}; UnicodeString monthNames[] = {"Sun","Mon","Tue","Wed","Thur","Fri","Sat"}; ChoiceFormat* form = new ChoiceFormat(limits, monthNames, 7); ParsePosition parse_pos; // TODO Fix this ParsePosition stuff... UnicodeString str; UnicodeString res1, res2; UErrorCode status; FieldPosition fpos(FieldPosition::DONT_CARE); Formattable f; int32_t ix; //for (double i = 0.0; i <= 8.0; ++i) { for (ix = 0; ix <= 8; ++ix) { double i = ix; //nos status = U_ZERO_ERROR; fpos = 0; str = ""; res1 = form->format(i, str, fpos, status ); if (!chkstatus( status, "*** test_simple_example format" )) { delete form; return; } //form->parse(res1, f, parse_pos); res2 = " ??? "; it_logln(UnicodeString("") + ix + UnicodeString(" -> ") + res1 + UnicodeString(" -> ") + res2); } //Testing ==operator const double filelimits[] = {0,1,2}; const UnicodeString filepart[] = {"are no files","is one file","are {2} files"}; ChoiceFormat* formnew=new ChoiceFormat(filelimits, filepart, 3); ChoiceFormat* formequal=new ChoiceFormat(limits, monthNames, 7); if(*formnew == *form){ errln("ERROR: ==operator failed\n"); } if(!(*form == *formequal)){ errln("ERROR: ==operator failed\n"); } delete formequal; delete formnew; //Testing getLimits() int32_t count=0; const double *gotLimits=form->getLimits(count); #if 1 // ICU 4.8 deprecates and disables the ChoiceFormat getters. if(count != 0 || gotLimits != NULL) { errln("getLimits() returns something, should be disabled"); } const UnicodeString *gotFormats=form->getFormats(count); if(count != 0 || gotFormats != NULL) { errln("getFormats() returns something, should be disabled"); } const UBool *gotClosures=form->getClosures(count); if(count != 0 || gotClosures != NULL) { errln("getClosures() returns something, should be disabled"); } #else if(count != 7){ errln("getLimits didn't update the count correctly\n"); } for(ix=0; ix<count; ix++){ if(gotLimits[ix] != limits[ix]){ errln((UnicodeString)"getLimits didn't get the limits correctly. Expected " + limits[ix] + " Got " + gotLimits[ix]); } } //Testing getFormats() count=0; const UnicodeString *gotFormats=form->getFormats(count); if(count != 7){ errln("getFormats didn't update the count correctly\n"); } for(ix=0; ix<count; ix++){ if(gotFormats[ix] != monthNames[ix]){ errln((UnicodeString)"getFormats didn't get the Formats correctly. Expected " + monthNames[ix] + " Got " + gotFormats[ix]); } } #endif delete form; }
int startup(int argc, char *argv[]) { int i, len; FULL_CHAR *arg; OBJECT t, y, res, s; /* current token, parser output */ BOOLEAN stdin_seen; /* TRUE when stdin file seen */ int source_file_count; /* number of source files in command */ FULL_CHAR *cross_db; /* name of cross reference database */ FULL_CHAR *outfile; /* name of output file */ FULL_CHAR *lib; /* name of library directory */ FILE *out_fp; long MemCheckLong; FULL_CHAR oname[MAX_BUFF], oval[MAX_BUFF], buff[MAX_BUFF], *p; int bp; OBJECT z; BOOLEAN seen_wordcount; #if LOCALE_ON char catname[MAX_BUFF], *loc; #endif /* find the name of the library directory, from envt or else from -D */ lib = AsciiToFull(getenv("LOUTLIB")); if( lib == (FULL_CHAR *) NULL ) lib = AsciiToFull(LIB_DIR); /* set locale if that's what we are doing */ #if LOCALE_ON loc = setlocale(LC_MESSAGES, ""); if( loc == (char *) NULL ) { Error(1, 6, "unable to initialize locale", WARN, no_fpos); loc = "C"; } sprintf(catname, "%s/%s/%s/LC_MESSAGES/errors.%s", lib, LOCALE_DIR, loc, loc); MsgCat = catopen(catname, 0); #endif /* initialise various modules, add current directory to search paths */ TotalWordCount = 0; seen_wordcount = FALSE; BackEnd = PS_BackEnd; PlainCharWidth = PLAIN_WIDTH; PlainCharHeight = PLAIN_HEIGHT; PlainFormFeed = FALSE; InitializeAll = FALSE; UseCollate = COLLATE; AllowCrossDb = TRUE; InMemoryDbIndexes = TRUE; Encapsulated = FALSE; SafeExecution = SAFE_DFT ? TRUE : FALSE; Kern = TRUE; MemInit(); InitSym(); LexInit(); InitFiles(); AddToPath(SOURCE_PATH, MakeWord(WORD, STR_EMPTY, no_fpos)); AddToPath(DATABASE_PATH, MakeWord(WORD, STR_EMPTY, no_fpos)); AddToPath(INCLUDE_PATH, MakeWord(WORD, STR_EMPTY, no_fpos)); /* read command line */ stdin_seen = FALSE; AltErrorFormat = FALSE; cross_db = CROSS_DB; outfile = STR_STDOUT; source_file_count = 0; New(CommandOptions, ACAT); for( i = 1; i < argc; i++ ) { if( *argv[i] == CH_HYPHEN ) switch( *(argv[i]+1) ) { case CH_FLAG_OUTFILE: /* read name of output file */ if( (outfile = GetArg(argv, argc, &i)) == NULL ) Error(1, 7, "usage: -o <filename>", FATAL, no_fpos); if( StringEndsWith(outfile, SOURCE_SUFFIX) ) Error(1, 28, "-o: output file name %s ends with %s", FATAL, no_fpos, outfile, SOURCE_SUFFIX); break; case CH_FLAG_SUPPRESS: /* suppress references to OldCrossDb and NewCrossDb */ AllowCrossDb = FALSE; break; case CH_FLAG_MEMCR: /* don't use in-memory database indexes */ InMemoryDbIndexes = FALSE; break; case CH_FLAG_NOKERN: /* suppress kerning */ Kern = FALSE; break; case CH_FLAG_NOCOLLATE: /* suppress local collation */ UseCollate = FALSE; break; case CH_FLAG_COLLATE: /* invoke local collation */ UseCollate = TRUE; break; case CH_FLAG_CROSS: /* read name of cross reference database */ if( (cross_db = GetArg(argv, argc, &i)) == NULL ) Error(1, 8, "usage: -c <filename>", FATAL, no_fpos); break; case CH_FLAG_ERRFILE: /* read log file name */ if( (arg = GetArg(argv, argc, &i)) == NULL ) Error(1, 9, "usage: -e <filename>", FATAL, no_fpos); ErrorInit(arg); break; case CH_FLAG_ALTERR: /* alternative error message format */ AltErrorFormat = TRUE; break; case CH_FLAG_EPSFIRST: /* -EPS produces encapsulated PostScript output */ if( !StringEqual(AsciiToFull(argv[i]+1), STR_EPS) ) Error(1, 10, "usage: -EPS", FATAL, no_fpos); Encapsulated = TRUE; break; case CH_FLAG_DIRPATH: /* add directory to database and sysdatabase paths */ if( (arg = GetArg(argv, argc, &i)) == NULL ) Error(1, 11, "usage: -D <directoryname>", FATAL, no_fpos); AddToPath(DATABASE_PATH, MakeWord(WORD, arg, no_fpos)); AddToPath(SYSDATABASE_PATH, MakeWord(WORD, arg, no_fpos)); break; case CH_FLAG_ENCPATH: /* add directory to character mapping path */ if( (arg = GetArg(argv, argc, &i)) == NULL ) Error(1, 12, "usage: -C <directoryname>", FATAL, no_fpos); AddToPath(MAPPING_PATH, MakeWord(WORD, arg, no_fpos)); break; case CH_FLAG_FNTPATH: /* add directory to font path */ if( (arg = GetArg(argv, argc, &i)) == NULL ) Error(1, 13, "usage: -F <directoryname>", FATAL, no_fpos); AddToPath(FONT_PATH, MakeWord(WORD, arg, no_fpos)); break; case CH_FLAG_HYPPATH: /* add directory to hyph path */ if( (arg = GetArg(argv, argc, &i)) == NULL ) Error(1, 14, "usage: -H <directoryname>", FATAL, no_fpos); AddToPath(HYPH_PATH, MakeWord(WORD, arg, no_fpos)); break; case CH_FLAG_INCPATH: /* add directory to include and sysinclude paths */ if( (arg = GetArg(argv, argc, &i)) == NULL ) Error(1, 15, "usage: -I <directoryname>", FATAL, no_fpos); AddToPath(INCLUDE_PATH, MakeWord(WORD, arg, no_fpos)); AddToPath(SYSINCLUDE_PATH, MakeWord(WORD, arg, no_fpos)); break; case CH_FLAG_INCLUDE: /* read sysinclude file and strip any .lt suffix */ if( (arg = GetArg(argv, argc, &i)) == NULL ) Error(1, 16, "usage: -i <filename>", FATAL, no_fpos); len = StringLength(arg) - StringLength(SOURCE_SUFFIX); if( len >= 0 && StringEqual(&arg[len], SOURCE_SUFFIX) ) StringCopy(&arg[len], STR_EMPTY); debug0(DFS, D, " calling DefineFile from main (1)"); DefineFile(arg, STR_EMPTY, no_fpos, SOURCE_FILE, SYSINCLUDE_PATH); break; case CH_FLAG_HYPHEN: /* declare hyphenation file */ if( FirstFile(HYPH_FILE) != NO_FILE ) Error(1, 17, "two -h options illegal", FATAL, no_fpos); if( (arg = GetArg(argv, argc, &i)) == NULL ) Error(1, 18, "usage: -h <filename>", FATAL, no_fpos); debug0(DFS, D, " calling DefineFile from main (2)"); DefineFile(arg, STR_EMPTY, no_fpos, HYPH_FILE, INCLUDE_PATH); DefineFile(arg, HYPH_SUFFIX, no_fpos, HYPH_PACKED_FILE, INCLUDE_PATH); break; case CH_FLAG_VERSION: fprintf(stderr, "%s\n", LOUT_VERSION); fprintf(stderr, "%-28s %s\n", "Basser Lout written by:", "Jeffrey H. Kingston ([email protected])"); fprintf(stderr, "%-28s %s\n", "Free source available from:", "ftp://ftp.cs.usyd.edu.au/jeff/lout"); fprintf(stderr, "%-28s %s %s\n", "This executable compiled:", __TIME__, __DATE__); fprintf(stderr, "%-28s %s%s%s\n", "System include directory:", lib, STR_DIR, INCL_DIR); fprintf(stderr, "%-28s %s%s%s\n", "System database directory:", lib, STR_DIR, DATA_DIR); fprintf(stderr, "Database index files created afresh automatically:%s\n", USE_STAT ? " yes" : " no"); fprintf(stderr, "Safe execution (disabling system()) is default:%s\n", SAFE_DFT ? " yes" : " no"); fprintf(stderr, "strcoll() used for sorting by default:%s\n", COLLATE ? " yes" : " no"); fprintf(stderr, "PDF compression on:%s\n", PDF_COMPRESSION ? " yes" : " no"); fprintf(stderr, "Debugging (-d, -dd, -ddd flags) available:%s\n", DEBUG_ON ? " yes" : " no"); fprintf(stderr, "\n"); fprintf(stderr, "Basser Lout comes with ABSOLUTELY NO WARRANTY.\n"); fprintf(stderr, "This is free software, and you are welcome to\n"); fprintf(stderr, "redistribute it under certain conditions. For\n"); fprintf(stderr, "details on both points, consult the GNU General\n"); fprintf(stderr, "Public License (distributed with this software).\n"); exit(0); break; case CH_FLAG_WORDS: seen_wordcount = TRUE; break; case CH_FLAG_PDF: BackEnd = PDF_BackEnd; break; case CH_FLAG_FFPLAIN: if( StringEqual(AsciiToFull(argv[i]+1), STR_PDF) ) { BackEnd = PDF_BackEnd; break; } PlainFormFeed = TRUE; /* NB NO BREAK */ case CH_FLAG_PLAIN: BackEnd = Plain_BackEnd; if( *(argv[i]+2) != '\0' ) { float len1, len2; FULL_CHAR units1, units2; if( sscanf(argv[i]+2, "%f%c%f%c",&len1,&units1,&len2,&units2) != 4 ) { Error(1, 19, "usage: lout -%c<length><length>", FATAL, no_fpos, *(argv[i]+1)); } switch( units1 ) { case CH_UNIT_CM: PlainCharWidth = len1 * CM; break; case CH_UNIT_IN: PlainCharWidth = len1 * IN; break; case CH_UNIT_PT: PlainCharWidth = len1 * PT; break; case CH_UNIT_EM: PlainCharWidth = len1 * EM; break; default: Error(1, 20, "lout -%c: units must be c, i, p, or m", FATAL, no_fpos, *(argv[i]+1)); break; } switch( units2 ) { case CH_UNIT_CM: PlainCharHeight = len2 * CM; break; case CH_UNIT_IN: PlainCharHeight = len2 * IN; break; case CH_UNIT_PT: PlainCharHeight = len2 * PT; break; case CH_UNIT_EM: PlainCharHeight = len2 * EM; break; default: Error(1, 21, "lout -%c: units must be c, i, p, or m", FATAL, no_fpos, *(argv[i]+1)); break; } } break; case CH_FLAG_INITALL: InitializeAll = TRUE; AllowCrossDb = FALSE; break; case CH_FLAG_USAGE: PrintUsage(stderr); exit(0); break; case CH_FLAG_DEBUG: debug_init(AsciiToFull(argv[i])); break; case CH_FLAG_MEMCHECK: sscanf(argv[i], "-m%ld", &MemCheckLong); MemCheck = (POINTER) MemCheckLong; fprintf(stderr, "checking memory location %ld\n", (long) MemCheck); break; case '\0': /* read stdin as file name */ if( stdin_seen ) Error(1, 23, "standard input specified twice", FATAL, no_fpos); stdin_seen = TRUE; debug0(DFS, D, " calling DefineFile from main (3)"); DefineFile(STR_STDIN, STR_EMPTY, no_fpos, SOURCE_FILE, SOURCE_PATH); break; case CH_FLAG_OPTION: /* read command-line document option */ if( sscanf(argv[i]+2, "%[^{ ] { %[^}] }", oname, oval) != 2 || StringLength(oname) == 0 || StringLength(oval) == 0 ) Error(1, 24, "error in command-line option %s", FATAL, no_fpos, argv[i]+2); y = MakeWord(WORD, oname, no_fpos); Link(CommandOptions, y); New(y, ACAT); Link(CommandOptions, y); bp = 0; for( p = oval; *p != '\0'; p++ ) switch( *p ) { case ' ': case '\t': case '\n': case '{': case '}': if( bp > 0 ) { buff[bp++] = '\0'; if( Down(y) != y ) { OBJECT g; New(g, GAP_OBJ); hspace(g) = 1; vspace(g) = 0; FposCopy(fpos(g), *no_fpos); Link(y, g); } z = MakeWord(WORD, buff, no_fpos); Link(y, z); bp = 0; } break; default: buff[bp++] = *p; break; } if( bp > 0 ) { buff[bp++] = '\0'; z = MakeWord(WORD, buff, no_fpos); Link(y, z); } if( Down(y) == y ) Error(1, 25, "error in command-line option %s", FATAL, no_fpos, argv[i]+2); break; case CH_FLAG_SAFE: /* ensure safe execution by disabling system calls */ SafeExecution = TRUE; break; case CH_FLAG_UNSAFE: /* allow unsafe execution */ SafeExecution = FALSE; break; default: PrintUsage(stderr); Error(1, 26, "unknown command line flag %s", FATAL, no_fpos, argv[i]); break; } else { /* argument is source file, strip any .lout suffix and define it */ arg = AsciiToFull(argv[i]); len = StringLength(arg) - StringLength(SOURCE_SUFFIX); if( len >= 0 && StringEqual(&arg[len], SOURCE_SUFFIX) ) StringCopy(&arg[len], STR_EMPTY); debug0(DFS, D, " calling DefineFile from main (4)"); DefineFile(AsciiToFull(argv[i]), STR_EMPTY, no_fpos, SOURCE_FILE, SOURCE_PATH); source_file_count++; } } /* for */ if( UseCollate ) { if (!setlocale (LC_COLLATE, "")) Error(1, 30, "unable to initialize collation", WARN, no_fpos); } /* start timing if required */ ifdebug(DPP, D, ProfileOn("main")); /* open output file, or stdout if none specified, and initialize printer */ if( StringEqual(outfile, STR_STDOUT) ) { #if OS_DOS /* For DOS/Win32 we need to set binary mode on stdout to prevent PDF compressed streams and xrefs from being corrupted - Uwe 12/98 */ if( BackEnd->code != PLAINTEXT && _setmode(_fileno(stdout), _O_BINARY) == -1 ) Error(1, 31, "cannot set binary mode on stdout", FATAL, no_fpos); #endif out_fp = stdout; } else { out_fp = StringFOpen(outfile, BackEnd->code == PLAINTEXT ? WRITE_TEXT : WRITE_BINARY); if( out_fp == null ) Error(1, 27, "cannot open output file %s", FATAL, no_fpos, outfile); } /* initialize miscellaneous modules */ ColourInit(); LanguageInit(); BackEnd->PrintInitialize(out_fp); /* append default directories to file search paths */ AddToPath(FONT_PATH, MakeWordThree(lib, STR_DIR, AsciiToFull(FONT_DIR))); AddToPath(HYPH_PATH, MakeWordThree(lib, STR_DIR, AsciiToFull(HYPH_DIR))); AddToPath(MAPPING_PATH, MakeWordThree(lib, STR_DIR, AsciiToFull(MAPS_DIR))); AddToPath(SYSDATABASE_PATH,MakeWordThree(lib,STR_DIR, AsciiToFull(DATA_DIR))); AddToPath(DATABASE_PATH, MakeWordThree(lib, STR_DIR, AsciiToFull(DATA_DIR))); AddToPath(SYSINCLUDE_PATH,MakeWordThree(lib, STR_DIR, AsciiToFull(INCL_DIR))); AddToPath(INCLUDE_PATH, MakeWordThree(lib, STR_DIR, AsciiToFull(INCL_DIR))); /* use stdin if no source files were mentioned */ if( source_file_count == 0 ) { debug0(DFS, D, " calling DefineFile from main (5)"); DefineFile(STR_STDIN, STR_EMPTY, no_fpos, SOURCE_FILE, SOURCE_PATH); } /* load predefined symbols into symbol table */ StartSym = nilobj; /* Not a mistake */ StartSym = load(KW_START, 0, FALSE, FALSE, TRUE, NO_PREC ); GalleySym = load(KW_GALLEY, 0, FALSE, FALSE, TRUE, NO_PREC ); ForceGalleySym= load(KW_FORCE_GALLEY, 0, FALSE, FALSE, TRUE, NO_PREC ); InputSym = load(KW_INPUT, 0, FALSE, FALSE, TRUE, NO_PREC ); PrintSym = load(KW_PRINT, 0, FALSE, FALSE, TRUE, NO_PREC ); FilterInSym = load(KW_FILTERIN, 0, FALSE, FALSE, FALSE, NO_PREC ); FilterOutSym = load(KW_FILTEROUT, 0, FALSE, FALSE, FALSE, NO_PREC ); FilterErrSym = load(KW_FILTERERR, 0, FALSE, FALSE, FALSE, NO_PREC ); OptGallSym = load(KW_OPTGALL, 0, FALSE, TRUE, FALSE, DEFAULT_PREC); VerbatimSym = load(KW_VERBATIM,VERBATIM,FALSE, TRUE, FALSE, DEFAULT_PREC); RawVerbatimSym= load(KW_RAWVERBATIM,RAW_VERBATIM,FALSE,TRUE,FALSE,DEFAULT_PREC); load(KW_BEGIN, BEGIN, FALSE, FALSE, FALSE, BEGIN_PREC ); load(KW_END, END, FALSE, FALSE, FALSE, END_PREC ); load(KW_ENV, ENV, FALSE, FALSE, FALSE, NO_PREC ); load(KW_ENVA, ENVA, FALSE, FALSE, FALSE, NO_PREC ); load(KW_ENVB, ENVB, FALSE, FALSE, FALSE, NO_PREC ); load(KW_ENVC, ENVC, FALSE, FALSE, FALSE, NO_PREC ); load(KW_ENVD, ENVD, FALSE, FALSE, FALSE, NO_PREC ); load(KW_CENV, CENV, FALSE, FALSE, FALSE, NO_PREC ); load(KW_CLOS, CLOS, FALSE, FALSE, FALSE, NO_PREC ); load(KW_LVIS, LVIS, FALSE, FALSE, FALSE, NO_PREC ); load(KW_LUSE, LUSE, FALSE, FALSE, FALSE, NO_PREC ); load(KW_LEO, LEO, FALSE, FALSE, FALSE, NO_PREC ); load(KW_LBR, LBR, FALSE, FALSE, FALSE, LBR_PREC ); load(KW_RBR, RBR, FALSE, FALSE, FALSE, RBR_PREC ); load(KW_INCLUDE, INCLUDE, FALSE, FALSE, FALSE, NO_PREC ); load(KW_SYSINCLUDE, SYS_INCLUDE, FALSE, FALSE, FALSE, NO_PREC ); load(KW_PREPEND, PREPEND, FALSE, FALSE, FALSE, NO_PREC ); load(KW_SYSPREPEND, SYS_PREPEND, FALSE, FALSE, FALSE, NO_PREC ); load(KW_DATABASE, DATABASE, FALSE, FALSE, FALSE, NO_PREC ); load(KW_SYSDATABASE, SYS_DATABASE, FALSE, FALSE, FALSE, NO_PREC ); load(KW_USE, USE, FALSE, FALSE, FALSE, NO_PREC ); load(KW_NOT_REVEALED, NOT_REVEALED, FALSE, FALSE, FALSE, NO_PREC ); load(KW_CASE, CASE, TRUE, TRUE, FALSE, DEFAULT_PREC); load(KW_YIELD, YIELD, TRUE, TRUE, FALSE, DEFAULT_PREC); load(KW_BACKEND, BACKEND, FALSE, FALSE, FALSE, DEFAULT_PREC); load(KW_XCHAR, XCHAR, FALSE, TRUE, FALSE, DEFAULT_PREC); load(KW_FONT, FONT, TRUE, TRUE, FALSE, DEFAULT_PREC); load(KW_SPACE, SPACE, TRUE, TRUE, FALSE, DEFAULT_PREC); load(KW_YUNIT, YUNIT, TRUE, TRUE, FALSE, DEFAULT_PREC); load(KW_ZUNIT, ZUNIT, TRUE, TRUE, FALSE, DEFAULT_PREC); load(KW_BREAK, BREAK, TRUE, TRUE, FALSE, DEFAULT_PREC); load(KW_UNDERLINE, UNDERLINE, FALSE, TRUE, FALSE, DEFAULT_PREC); load(KW_COLOUR, COLOUR, TRUE, TRUE, FALSE, DEFAULT_PREC); load(KW_COLOR, COLOUR, TRUE, TRUE, FALSE, DEFAULT_PREC); load(KW_OUTLINE, OUTLINE, FALSE, TRUE, FALSE, DEFAULT_PREC); load(KW_LANGUAGE, LANGUAGE, TRUE, TRUE, FALSE, DEFAULT_PREC); load(KW_CURR_LANG, CURR_LANG, FALSE, FALSE, FALSE, DEFAULT_PREC); load(KW_CURR_FAMILY, CURR_FAMILY, FALSE, FALSE, FALSE, DEFAULT_PREC); load(KW_CURR_FACE, CURR_FACE, FALSE, FALSE, FALSE, DEFAULT_PREC); load(KW_CURR_YUNIT, CURR_YUNIT, FALSE, FALSE, FALSE, DEFAULT_PREC); load(KW_CURR_ZUNIT, CURR_ZUNIT, FALSE, FALSE, FALSE, DEFAULT_PREC); load(KW_COMMON, COMMON, TRUE, TRUE, FALSE, DEFAULT_PREC); load(KW_RUMP, RUMP, TRUE, TRUE, FALSE, DEFAULT_PREC); load(KW_MELD, MELD, TRUE, TRUE, FALSE, DEFAULT_PREC); load(KW_INSERT, INSERT, TRUE, TRUE, FALSE, DEFAULT_PREC); load(KW_ONE_OF, ONE_OF, FALSE, TRUE, FALSE, DEFAULT_PREC); load(KW_NEXT, NEXT, FALSE, TRUE, FALSE, DEFAULT_PREC); load(KW_PLUS, PLUS, TRUE, TRUE, FALSE, DEFAULT_PREC); load(KW_MINUS, MINUS, TRUE, TRUE, FALSE, DEFAULT_PREC); load(KW_OPEN, OPEN, TRUE, TRUE, FALSE, DEFAULT_PREC); load(KW_TAGGED, TAGGED, TRUE, TRUE, FALSE, DEFAULT_PREC); load(KW_WIDE, WIDE, TRUE, TRUE, FALSE, DEFAULT_PREC); load(KW_HIGH, HIGH, TRUE, TRUE, FALSE, DEFAULT_PREC); load(KW_HSHIFT, HSHIFT, TRUE, TRUE, FALSE, DEFAULT_PREC); load(KW_VSHIFT, VSHIFT, TRUE, TRUE, FALSE, DEFAULT_PREC); load(KW_BEGIN_HEADER, BEGIN_HEADER, TRUE, TRUE, FALSE, DEFAULT_PREC); load(KW_END_HEADER, END_HEADER, FALSE, FALSE, FALSE, DEFAULT_PREC); load(KW_SET_HEADER, SET_HEADER, TRUE, TRUE, FALSE, DEFAULT_PREC); load(KW_CLEAR_HEADER, CLEAR_HEADER, FALSE, FALSE, FALSE, DEFAULT_PREC); load(KW_ONE_COL, ONE_COL, FALSE, TRUE, FALSE, DEFAULT_PREC); load(KW_ONE_ROW, ONE_ROW, FALSE, TRUE, FALSE, DEFAULT_PREC); load(KW_HSCALE, HSCALE, FALSE, TRUE, FALSE, DEFAULT_PREC); load(KW_VSCALE, VSCALE, FALSE, TRUE, FALSE, DEFAULT_PREC); load(KW_HCOVER, HCOVER, FALSE, TRUE, FALSE, DEFAULT_PREC); load(KW_VCOVER, VCOVER, FALSE, TRUE, FALSE, DEFAULT_PREC); load(KW_KERN_SHRINK, KERN_SHRINK, TRUE, TRUE, FALSE, DEFAULT_PREC); load(KW_SCALE, SCALE, TRUE, TRUE, FALSE, DEFAULT_PREC); load(KW_HCONTRACT, HCONTRACT, FALSE, TRUE, FALSE, DEFAULT_PREC); load(KW_VCONTRACT, VCONTRACT, FALSE, TRUE, FALSE, DEFAULT_PREC); load(KW_HLIMITED, HLIMITED, FALSE, TRUE, FALSE, DEFAULT_PREC); load(KW_VLIMITED, VLIMITED, FALSE, TRUE, FALSE, DEFAULT_PREC); load(KW_HEXPAND, HEXPAND, FALSE, TRUE, FALSE, DEFAULT_PREC); load(KW_VEXPAND, VEXPAND, FALSE, TRUE, FALSE, DEFAULT_PREC); load(KW_STARTHVSPAN, START_HVSPAN, FALSE, TRUE, FALSE, DEFAULT_PREC); load(KW_STARTHSPAN, START_HSPAN, FALSE, TRUE, FALSE, DEFAULT_PREC); load(KW_STARTVSPAN, START_VSPAN, FALSE, TRUE, FALSE, DEFAULT_PREC); load(KW_HSPAN, HSPAN, FALSE, FALSE, FALSE, DEFAULT_PREC); load(KW_VSPAN, VSPAN, FALSE, FALSE, FALSE, DEFAULT_PREC); load(KW_PADJUST, PADJUST, FALSE, TRUE, FALSE, DEFAULT_PREC); load(KW_HADJUST, HADJUST, FALSE, TRUE, FALSE, DEFAULT_PREC); load(KW_VADJUST, VADJUST, FALSE, TRUE, FALSE, DEFAULT_PREC); load(KW_ROTATE, ROTATE, TRUE, TRUE, FALSE, DEFAULT_PREC); load(KW_BACKGROUND, BACKGROUND, TRUE, TRUE, FALSE, DEFAULT_PREC); load(KW_INCGRAPHIC, INCGRAPHIC, FALSE, TRUE, FALSE, DEFAULT_PREC); load(KW_SINCGRAPHIC, SINCGRAPHIC, FALSE, TRUE, FALSE, DEFAULT_PREC); load(KW_PLAINGRAPHIC, PLAIN_GRAPHIC, TRUE, TRUE, FALSE, DEFAULT_PREC); load(KW_GRAPHIC, GRAPHIC, TRUE, TRUE, FALSE, DEFAULT_PREC); load(KW_LINK_SOURCE, LINK_SOURCE, TRUE, TRUE, FALSE, DEFAULT_PREC); load(KW_LINK_DEST, LINK_DEST, TRUE, TRUE, FALSE, DEFAULT_PREC); load(KW_CROSS, CROSS, TRUE, TRUE, FALSE, CROSSOP_PREC); load(KW_FORCE_CROSS, FORCE_CROSS, TRUE, TRUE, FALSE, CROSSOP_PREC); load(KW_NULL, NULL_CLOS, FALSE, FALSE, TRUE, NO_PREC ); load(KW_PAGE_LABEL, PAGE_LABEL, FALSE, TRUE, TRUE, DEFAULT_PREC); #define setcat(s, mk, jn) has_mark(s)=mk, has_join(s)=jn s=load(KW_VCAT_NN, VCAT, TRUE, TRUE, FALSE, VCAT_PREC); setcat(s,FALSE,FALSE); s=load(KW_VCAT_MN, VCAT, TRUE, TRUE, FALSE, VCAT_PREC); setcat(s,TRUE, FALSE); s=load(KW_VCAT_NJ, VCAT, TRUE, TRUE, FALSE, VCAT_PREC); setcat(s,FALSE,TRUE); s=load(KW_VCAT_MJ, VCAT, TRUE, TRUE, FALSE, VCAT_PREC); setcat(s,TRUE, TRUE); s=load(KW_HCAT_NN, HCAT, TRUE, TRUE, FALSE, HCAT_PREC); setcat(s,FALSE,FALSE); s=load(KW_HCAT_MN, HCAT, TRUE, TRUE, FALSE, HCAT_PREC); setcat(s,TRUE, FALSE); s=load(KW_HCAT_NJ, HCAT, TRUE, TRUE, FALSE, HCAT_PREC); setcat(s,FALSE,TRUE); s=load(KW_HCAT_MJ, HCAT, TRUE, TRUE, FALSE, HCAT_PREC); setcat(s,TRUE, TRUE); s=load(KW_ACAT_NJ, ACAT, TRUE, TRUE, FALSE, ACAT_PREC); setcat(s,FALSE,TRUE); s=load(KW_ACAT_MJ, ACAT, TRUE, TRUE, FALSE, ACAT_PREC); setcat(s,TRUE, TRUE); /* intialize fonts and load @FontDef symbol */ FontInit(); /* intialize current time and load @Moment symbol */ InitTime(); /* initialize filter module */ FilterInit(); /* initialize enviroment table module */ EnvInit(); /* initialise scope chain to <StartSym> */ PushScope(StartSym, FALSE, FALSE); /* initialise lexical analyser */ LexPush(FirstFile(SOURCE_FILE), 0, SOURCE_FILE, 1, FALSE); /* process input files */ InitParser(cross_db); t = NewToken(BEGIN, no_fpos, 0, 0, BEGIN_PREC, StartSym); res = Parse(&t, StartSym, TRUE, TRUE); debug0(DGT, D, "calling TransferEnd(res) from main()"); DisposeObject(CommandOptions); TransferEnd(res); TransferClose(); /* close various modules */ BackEnd->PrintAfterLastPage(); BackEnd->LinkCheck(); CrossClose(); CloseFiles(); /* remove any leftover filter temporary files */ FilterScavenge(TRUE); /* print word count, if required */ if( seen_wordcount ) Error(1, 29, "total of all words printed: %d", WARN,no_fpos,TotalWordCount); /* check for unbalanced error blocks */ CheckErrorBlocks(); /* wrapup */ ifdebug(DST, DD, CheckSymSpread() ); ifdebug(ANY, D, DeleteEverySym() ); debug0(DMA, D, "at end of run:"); ifdebug(DMA, D, DebugMemory() ); ifdebug(DPP, D, ProfileOff("main")); ifdebug(DPP, D, ProfilePrint()); ifdebug(DET, D, EnvDebug()); #if LOCALE_ON catclose(MsgCat); #endif exit(0); return 0; } /* end main */