Application_1.m


max21 Unternehmensgruppe
#import "Aprica.h"
#ifdef GNU_RUNTIME
#import <objc/objc-api.h>
#else
#import <objc/objc-class.h>
#endif
//	Aprica2
//	copyright Pirmin Braun 1997-2007 - pirmin@pirmin.de
//	all Rights reserved;
#ifndef GNUSTEP
#import <Python26/Python.h>
@implementation Application (Python)
- (void)py_initialize;
{
    Py_Initialize();
}
- (void)py_finalize;
{
    Py_Finalize();
}
- (int)pyRun_simpleString:(NSString *)s;
{
    return PyRun_SimpleString([s lossyCString]);
}
@end
#endif
@implementation Application (Admin)
- (void)createTransFor:(NSString *)ps;
{
    NSString *s,*sql,*result;
    PBEO *eo;
    s = [ps stringWithoutLeadingWhiteSpace];
    s = [s stringWithoutTrailingWhiteSpace]; // Bug in MySQL:Trailing white space geht beim speichern verloren
    if(!FILLED(s))return;
    sql = [NSSWF @"select text0 from translationsm where text0 = BINARY '%@'",[s mysqlEscapedString]];
    result = singleValueSQL(sql);
    if(!FILLED(result)){
        eo = NEW_EO(@"translationsm");
        [eo tvfk(s,@"text0")];
        [eo tvfk(@"J",@"collect_trans")];
        INSRT(eo);
    }else{
        sql = [NSSWF @"update translationsm set collect_trans = 'J' where text0 = BINARY '%@'",[s mysqlEscapedString]];
        SQL(sql);
    }
}
- (void)convertWithEnumerator:(NSDirectoryEnumerator *)e extension:(NSString *)extension path:(NSString *)path;
{
    NSString *file,*content;
    NSAutoreleasePool *pool = nil;
    while ((file = [e nextObject])) {
        pool = [[NSAutoreleasePool alloc]init];
        if ([[file pathExtension] iE:extension] && ![file rangeOfString:@".svn"].length){
            NSString *fn = [NSSWF @"%@%@/%@",MANDANTPATH,path,[file stringWithForwardSlashes]];
            content = [NSSWCOF fn];
            if(![content WTF:fn])LOG(([NSSWF @"FAILED:%@",fn]));
        }
        [pool release];
    }
}
- (void)convertToUTF8;
{
// alle Texte, die von Hand editiert sein koennen, in UTF8 ohne BOM konvertieren
     NSDirectoryEnumerator *e;
     e = [[NSFileManager defaultManager]enumeratorAtPath:[NSSWF @"%@/Scripts",MANDANTPATH]];
     [self convertWithEnumerator:e extension:@"script" path:@"/Scripts"];
     e = [[NSFileManager defaultManager]enumeratorAtPath:[NSSWF @"%@/Resources/Hilfe",MANDANTPATH]];
     [self convertWithEnumerator:e extension:@"txt" path:@"/Resources/Hilfe"];
     e = [[NSFileManager defaultManager]enumeratorAtPath:[NSSWF @"%@/Templates",MANDANTPATH]];
     [self convertWithEnumerator:e extension:@"htmlwod" path:@"/Templates"];
     e = [[NSFileManager defaultManager]enumeratorAtPath:[NSSWF @"%@/Druck",MANDANTPATH]];
     [self convertWithEnumerator:e extension:@"cpdf" path:@"/Druck"];
}
- (void)instantiateAllModules;
{
    NSArray *a = [[_APP availableBundles]sortedArrayUsingKeyOrderArray:[NSArray soaFrom:@"name"]];
    int i,j;
// alle bundles instantiieren und rendern; fuellt damit transDict
#warning todo: Register durchsteppen und damit portlets aktivieren
    for(i=0,j=[a count];i<j;i++){
        PBWOBundle *b = [a oai:i];
        PBWOEditor *pbe;
        NSAutoreleasePool *pool;
        WOResponse *resp;
        pool = [[NSAutoreleasePool alloc]init];
        resp = [[[WOResponse alloc]init]autorelease];
        NS_DURING;
        pbe = MODUL([b name]);
        LOGS([b name]);
        [pbe _template]; //erzwingt laden von htmlwod
        [[currentComponent context]setCurrentComponent:pbe];
        [pbe performInitialSearch];
        [pbe appendToResponse:resp inContext:[currentComponent context]];
        [pbe saveLif];
        NS_HANDLER;
        LOGS_Ex(([NSSWF @"ging schief:%@",[b name]]));
        NS_ENDHANDLER;
        [pool release];
    }
    [[currentComponent context]setCurrentComponent:currentComponent];
}
- (void)stripCRInDir:(NSString *)dir suffix:(NSString *)suffix;
{
    NSArray *a = [myFM directoryDeepContentsAtPath:[NSSWF @"%@/%@",MANDANTPATH,dir] suffixes:[NSArray arrayWithObject:suffix] skips:[NSArray arrayWithObject:@".svn"] fullName:YES];
    int i,j;
    for(i=0,j=[a count];i<j;i++){
        NSString *fn = [NSSWF @"%@/%@/%@",MANDANTPATH,dir,[[a oai:i]stringWithForwardSlashes]];
        NSAutoreleasePool *pool;
        pool = [[NSAutoreleasePool alloc] init];
        [[[NSSWCOF fn] stringWithout0xD] WTF:fn];
        [pool release];
    }
}
- (void)stripCR;
{
// CR machen immer wieder Probleme in .idm  .lif  .script .cpdf beim Mergen und bei svn; daher weg damit
    [self stripCRInDir:@"LayoutsUsers" suffix:@"lif"];
    [self stripCRInDir:@"Scripts" suffix:@"script"];
    [self stripCRInDir:@"Druck" suffix:@"cpdf"];
    [self stripCRInDir:@"Templates" suffix:@"htmlwod"];
    [self stripCRInDir:@"Resources/Hilfe" suffix:@"txt"];
}
- (void)logObsoleteLifs;
{
    NSArray *a = [myFM directoryContentsAtPath:[NSSWF @"%@/%@",MANDANTPATH,@"LayoutsUsers/Administrator"] suffixes:[NSArray arrayWithObject:@".lif"] skips:[NSArray arrayWithObject:@".svn"] fullName:NO];
    int i,j;
    for(i=0,j=[a count];i<j;i++){
	NSString *s = [a oai:i];
        if(![_APP bundleWithName:s])LOG(s);
    }
}
- (NSString *)processFileLogiTrans:(NSString *)s;
{
    NSArray *a = [s componentsSeparatedByString:@"\n"];
    int i,j;
    LMA;
    for(i=0,j=[a count];i<j;i++){
        NSString *line = [a oai:i];
        NSRange myRange;
        myRange = [line rangeOfString:@"logi \""];
        if(myRange.length){
            NSMutableString *ms = [NSMutableString stringWithString:line];
            [ms replaceCharactersInRange:myRange withString:@"logi <trans>\""];
            [lma addObject:ms];
            continue;
        }
        myRange = [line rangeOfString:@"logi '"];
        if(myRange.length){
            NSMutableString *ms = [NSMutableString stringWithString:line];
            [ms replaceCharactersInRange:myRange withString:@"logi <trans>'"];
            [lma addObject:ms];
            continue;
        }
        [lma addObject:line];
    }
    return [lma componentsJoinedByString:@"\n"];
}
- (void)logiTransWithEnumerator:(NSDirectoryEnumerator *)e extension:(NSString *)extension path:(NSString *)path;
{
    NSString *file,*content;
    NSAutoreleasePool *pool = nil;
    while ((file = [e nextObject])) {
        pool = [[NSAutoreleasePool alloc]init];
        if ([[file pathExtension] iE:extension] && ![file rangeOfString:@".svn"].length){
            NSString *fn = [NSSWF @"%@/%@",path,[file stringWithForwardSlashes]];
            content = [NSSWCOF fn];
            content = [self processFileLogiTrans:content];
            if(![content WTF:fn])LOG(([NSSWF @"FAILED:%@",fn]));
        }
        [pool release];
    }
}
- (void)logiTrans;
{
// logi " zu logi <trans>"
// logi ' zu logi <trans>'
    NSDirectoryEnumerator *e;
    NSString *path;
    path = [NSSWF @"%@/Scripts",MANDANTPATH];
    e = [[NSFileManager defaultManager]enumeratorAtPath:path];
    [self logiTransWithEnumerator:e extension:@"script" path:path];
    path = [NSSWF @"%@/Druck",MANDANTPATH];
    e = [[NSFileManager defaultManager]enumeratorAtPath:path];
    [self logiTransWithEnumerator:e extension:@"cpdf" path:path];
}
- (void)processCollectTrans:(NSString *)s;
{
    NSRange r,r1;
    NSString *s1;
    s = [s stringWithout0xD];
    r = [s rangeOfString:@"<trans>"];
    while(r.length){
        s = [s substringFromIndex:r.location + r.length];
        if([s hasSecurePrefix:@"\""]){
            s = [s substringFromIndex:1];
            r = [s rangeOfString:@"\n"];
        }else{
            if([s hasSecurePrefix:@"'"]){
                s = [s substringFromIndex:1];
            }else{
                if([s hasSecurePrefix:@"$"]){ // keine Scriptvariablen
                    r = [s rangeOfString:@"<trans>"];
                    continue;
                }
            }
            r = [s rangeOfString:@","];
            r1 = [s rangeOfString:@"\n"];
            if(r1.length && r.length){
                if(r1.location < r.location)r = r1;
            }else{
                if(!r.length)r=r1;
            }
        }
        if(!r.length)r.location=[s length]-1;
        s1 = [s substringToIndex:r.location];
        if(![lookup ofk:s1]){
            [lookup setObject:@"x" forKey:s1];
            LOG(([NSSWF @">>>>>>>>>>>> %@",s1]));
            [self createTransFor:s1];
        }
        s = [s substringFromIndex:r.location  + r.length];
        r = [s rangeOfString:@"<trans>"];
    }
}
- (void)collectTransWithEnumerator:(NSDirectoryEnumerator *)e extension:(NSString *)extension path:(NSString *)path;
{
    NSString *file,*content;
    NSAutoreleasePool *pool = nil;
    while ((file = [e nextObject])) {
        pool = [[NSAutoreleasePool alloc]init];
        if ([[file pathExtension] iE:extension] && ![file rangeOfString:@".svn"].length){
            NSString *fn = [NSSWF @"%@/%@",path,[file stringWithForwardSlashes]];
            content = [NSSWCOF fn];
            LOG(fn);
            [self processCollectTrans:content];
        }
        [pool release];
    }
}
- (void)processCollectHTMLTrans:(NSString *)s;
{
    NSRange r;
    s = [s stringWithout0xD];
    r = [s rangeOfString:@"<|"];
    while(r.length){
        s = [s substringFromIndex:r.location + r.length];
        r = [s rangeOfString:@"|>"];
        if(r.length){
            NSString *s1 = [s substringToIndex:r.location];
            if(![lookup ofk:s1]){
                [lookup setObject:@"x" forKey:s1];
                LOG(([NSSWF @">>>>>>>>>>>> %@",s1]));
                [self createTransFor:s1];
            }
            s = [s substringFromIndex:r.location  + r.length];
        }
        r = [s rangeOfString:@"<|"];
    }
}
- (void)collectHTMLTransWithEnumerator:(NSDirectoryEnumerator *)e extension:(NSString *)extension path:(NSString *)path;
{
    NSString *file,*content;
    NSAutoreleasePool *pool = nil;
    while ((file = [e nextObject])) {
        pool = [[NSAutoreleasePool alloc]init];
        if ([[file pathExtension] iE:extension] && ![file rangeOfString:@".svn"].length){
            NSString *fn = [NSSWF @"%@/%@",path,[file stringWithForwardSlashes]];
            content = [NSSWCOF fn];
            LOG(fn);
            [self processCollectHTMLTrans:content];
        }
        [pool release];
    }
}
- (void)processCollectObjCTrans:(NSString *)s;
{
    NSRange r;
    r = [s rangeOfString:@"TRANSLATION(@\""];
    while(r.length){
        s = [s substringFromIndex:r.location + r.length];
        r = [s rangeOfString:@"\")"];
        if(r.length){
            NSString *s1 = [s substringToIndex:r.location];
            if(![lookup ofk:s1]){
                [lookup setObject:@"x" forKey:s1];
                LOG(([NSSWF @">>>>>>>>>>>> %@",s1]));
                [self createTransFor:s1];
            }
            s = [s substringFromIndex:r.location  + r.length];
        }
        r = [s rangeOfString:@"TRANSLATION(@\""];
    }
}
- (void)collectObjCTransWithEnumerator:(NSDirectoryEnumerator *)e extension:(NSString *)extension path:(NSString *)path;
{
    NSString *file,*content;
    NSAutoreleasePool *pool = nil;
    while ((file = [e nextObject])) {
        pool = [[NSAutoreleasePool alloc]init];
        if ([[file pathExtension] iE:extension] && ![file rangeOfString:@".svn"].length){
            NSString *fn = [NSSWF @"%@/%@",path,[file stringWithForwardSlashes]];
            content = [NSSWCOF fn];
            LOG(fn);
            [self processCollectObjCTrans:content];
        }
        [pool release];
    }
}
- (void)processCollectLIFTrans:(NSString *)s;
{
// a|200|Detail-Ansicht	betrag_brutto
    NSArray *a = [s componentsSeparatedByString:@"\n"];
    int i,j;
    for(i=0,j=[a count];i<j;i++){
        NSArray *a2 = [[[[a oai:i] componentsSeparatedByString:@"\t"] firstObject]componentsSeparatedByString:@"|"];
        NSString *s1;
        if([a2 count]==3){
            s1 = [a2 oai:2];
            if([lookup ofk:s1])continue;
            [lookup setObject:@"x" forKey:s1];
            LOG(([NSSWF @">>>>>>>>>>>> %@",s1]));
            [self createTransFor:s1];
        }
    }
}
- (void)collectLIFTransWithEnumerator:(NSDirectoryEnumerator *)e extension:(NSString *)extension path:(NSString *)path;
{
    NSString *file,*content;
    NSAutoreleasePool *pool = nil;
    while ((file = [e nextObject])) {
        pool = [[NSAutoreleasePool alloc]init];
        if ([[file pathExtension] iE:extension] && ![file rangeOfString:@".svn"].length){
            NSString *fn = [NSSWF @"%@/%@",path,[file stringWithForwardSlashes]];
            content = [NSSWCOF fn];
            LOG(fn);
            [self processCollectLIFTrans:content];
        }
        [pool release];
    }
}
- (void)collectTrans;
{
// alle <trans> strings sammeln: <trans>"... bis zeilenende; <trans>'... bis comma oder Zeilenende;  <trans>... bis comma oder Zeilenende;
    NSDirectoryEnumerator *e;
    NSString *path;
    [lookup removeAllObjects];
    SQL(@"update translationsm set collect_trans = 'N'");
    LOG(@".......<trans>");
    path = [NSSWF @"%@/Scripts",MANDANTPATH];
    e = [[NSFileManager defaultManager]enumeratorAtPath:path];
    [self collectTransWithEnumerator:e extension:@"script" path:path];
    path = [NSSWF @"%@/Druck",MANDANTPATH];
    e = [[NSFileManager defaultManager]enumeratorAtPath:path];
    [self collectTransWithEnumerator:e extension:@"cpdf" path:path];
// <| ... |> aus htmlwod
    LOG(@".......<| ... |>");
    path = [NSSWF @"%@/Templates",MANDANTPATH];
    e = [[NSFileManager defaultManager]enumeratorAtPath:path];
    [self collectHTMLTransWithEnumerator:e extension:@"htmlwod" path:path];
// TRANSLATION(@"...")  aus .m
    LOG(@".......TRANSLATION()");
    path = [NSSWF @"%@/Local/Projects/Aprica2",[_APP nextRoot]];
    e = [[NSFileManager defaultManager]enumeratorAtPath:path];
    [self collectObjCTransWithEnumerator:e extension:@"m" path:path];
// Registernamen aus LIF
    LOG(@".......LIF");
    path = [NSSWF @"%@/LayoutsUsers",MANDANTPATH];
    e = [[NSFileManager defaultManager]enumeratorAtPath:path];
    [self collectLIFTransWithEnumerator:e extension:@"lif" path:path];
// Modul Unterbereiche werden sowieso nach dem Einloggen uebersetzt
}
@end
@implementation Application (Scripting)
- (NSArray *)scriptNames;
{
    return scriptNames;
}
- (NSString *)currentScriptName;
{
    NSString *s = [scriptNames lastObject];
    if(!FILLED(s))return @"_no_scipt";
    return s;
}
- (NSString *)hasRestString;
{
    return (restString != nil?@"J":@"N");
}
- (NSMutableDictionary *)scriptDict;
{
    return scriptDict;
}
- (NSMutableDictionary *)matchingEndif;
{
    return matchingEndif;
}
- (NSMutableDictionary *)matchingEndwhile;
{
    return matchingEndwhile;
}
- (NSMutableDictionary *)matchingEndsub;
{
    return matchingEndsub;
}
- (NSMutableDictionary *)matchingWhile;
{
    return matchingWhile;
}
- (NSMutableDictionary *)matchingEndfor;
{
    return matchingEndfor;
}
- (NSMutableDictionary *)matchingForeach;
{
    return matchingForeach;
}
- (NSMutableDictionary *)subNamed;
{
    return subNamed;
}
- (NSMutableDictionary *)parmDict;
{
    return parmDict;
}
/***********************************************************************/
// pdf-Druck , Script
- (NSString *)exprValue:(NSString *)s datasource:ds varDict:(NSMutableDictionary *)varDict localVarDict:(NSMutableDictionary *)localVarDict;
{
    // wert von datasource holen; bei prefix %
    // modifiers am ende
    // keypath in s bereits ohne %
    NSString *v;
    BOOL bez = NO,provideEO=NO;
    v = s;
    if(!FILLED(s))return s;
    if([s iE:@"datasource"])return ds; // sonderfall
    if([s hasSecureSuffix:@".*bez"]){ //bezeichnung
        bez = YES;
        s = [s substringToIndex:[s length] - 5];
    }
    if([s hasSecureSuffix:@".*eo"]){ //EO; wenn letztes keyPath-Element eine Relation ist, das ziel-eo statt dem foreignkey liefern
        provideEO = YES;
        s = [s substringToIndex:[s length] - 4];
    }
    if([s hasSecurePrefix:@"*."]){ // obsolet
        s = [s substringFromIndex:2];
    }
    if([s hasSecurePrefix:@"datasource."]){ // obsolet
        s = [s substringFromIndex:11];
    }
    v = [self kpValueFrom:ds forKp:s bez:bez provideEO:provideEO varDict:varDict localVarDict:localVarDict];
    return v;
}
- (NSString *)exprValue:(NSString *)s varDict:(NSMutableDictionary *)varDict localVarDict:(NSMutableDictionary *)localVarDict;
{
    // wert von varDict holen; bei prefix $
    // modifiers am ende
    // keypath in s bereits ohne $
    NSString *v;
    BOOL bez = NO,provideEO=NO;
    NSMutableDictionary *d2use;
    if([s hasSecurePrefix:@"l_"] && localVarDict){ //kennzeichen f. lokale Variable in Subroutine
        d2use = localVarDict;
    }else{
        d2use = varDict;
    }
    v = s; // Vorbelegen; v wird am ende zurueckgegeben
    if(!FILLED(s))return s;
    if([s hasSecureSuffix:@".*bez"]){ //bezeichnung
        bez = YES;
        s = [s substringToIndex:[s length] - 5];
    }
    if([s hasSecureSuffix:@".*eo"]){ //EO; wenn letztes keyPath-Element eine Relation ist, das ziel-eo statt dem foreignkey liefern
        provideEO = YES;
        s = [s substringToIndex:[s length] - 4];
    }
    v = [self kpValueFrom:d2use forKp:s bez:bez provideEO:provideEO varDict:varDict localVarDict:localVarDict];
    return v;
}
- (NSString *)kpValueFrom:(id)o forKp:(NSString *)keypath bez:(BOOL)bez provideEO:(BOOL)provideEO varDict:(NSMutableDictionary *)varDict localVarDict:(NSMutableDictionary *)localVarDict;
{
    // keypath aufloesen
    NSArray *kps;
    id co;
    int i,j;
    PBDDTable *t;
    PBDDAttribute *pba=nil;
    NSString *kp,*kpv=nil;
    if(!o || !FILLED(keypath))return EON;
//    if([keypath iE:@"ma.lastObject"])LOGS(([NSSWF @"o:%@ class:%@ keypath:%@",[o description],[[o class]description],keypath]));
    kps = [keypath componentsSeparatedByString:@"."];
    j = [kps count];
    co = o;
    for(i=0;i<j;i++){
        NSRange kpr;
        kp = [kps oai:i];
        pba = nil;
// kp kann auch embedded Variablen mit $... haben; kann auch komplett eine variable sein, mit $ am anfang
// z.B. bla$fasel$x$y oder $$fasel
        kpr = [kp rangeOfString:@"$"];
        if(kpr.length){
            NSArray *kpvars = [kp componentsSeparatedByString:@"$"];
            LMAN(kpvarsval);
            int i1=0,j1;
            if(kpr.location){ //prefix ohne $
                [kpvarsval addObject:[kpvars firstObject]];
                i1=1; 
            }
            for(j1=[kpvars count];i1<j1;i1++){
                NSString *kpvar = [kpvars oai:i1];
                if([kpvar hasSecurePrefix:@"l_"] && localVarDict){ //kennzeichen f. lokale Variable in Subroutine
                    kpvar = [localVarDict ofk:kpvar];
                }else{
                    kpvar = [varDict ofk:kpvar];
                }
                if(FILLED(kpvar))[kpvarsval addObject:kpvar];
            }
            kp = [kpvarsval componentsJoinedByString:EON];
        }
        if([co isKindOfClass:[PBEO class]]){
            NSString *effTn=nil;
            kpv = [co vfk:kp]; //Wert aus dem EO
            if(!FILLED(kpv))return EON; //geht nicht weiter
            pba = [[co myTable] plainAttrNamed:kp]; //wg. bez-behandlung unten vor dem break
            if(i==(j-1) && !provideEO)break; //letztes Element nicht aufloesen, sondern foreignkey liefern, wenn nicht explizit EO gewuenscht;
            if(pba){
                if((t = [pba relationTable])){ //relation verfolgen
                    effTn = [t dbName];
                }
                if(effTn){
                    co = getEOPkValue(effTn,kpv);
                    if(!co)return nil; //damit es keine exception gibt; ein NSString wuerde unknown key exception geben
                }else{ //normales attribut, geht mit nsstring weiter
                    co = kpv;
                }
            }else{
                co = kpv; //z.B. values oder descri
            }
        }else{
            kpv = nil;
            if(!([co isKindOfClass:[NSArray class]] || [co isKindOfClass:[NSString class]])){
// mit Arrays und Strings udn Dictionaries geht's nicht so richtig
                NS_DURING;
                kpv = [co vfk:kp];
//tut bei Dictionaries nicht so richtig; z.B. allValues, allKeys, description etc.
// mit vfk kann man auch an BOOL Werte herangehen; liefert eine NSShortNumber 0 oder 1
                if([kpv isKindOfClass:[NSNumber class]])kpv = [kpv description]; // wir wollen einen NSString
                NS_HANDLER;
                kpv = nil;
                NS_ENDHANDLER;
            }
            if(!kpv){
                kpv = [self scriptValueForTarget:co andMethod:kp];
           }
            co = kpv;
        }
//        LOGS(([NSSWF @"kpv:%@",kpv]));
    }
    
    //Nachbehandlung: *bez oder *eo
        if(pba){
            if([co isKindOfClass:[PBEO class]] && provideEO)return co;
            if(bez)return [pba bezeichnungForValue:kpv];
        }
        return kpv;
}
- (void)determineOperands:(NSArray *)a1 datasource:(PBWOEditor *)datasource varDict:(NSMutableDictionary *)varDict localVarDict:(NSMutableDictionary *)localVarDict into:(NSMutableArray *)ops;
{
    // jeder Operand kann ein zusammengesetzter ausdruck sein
    // <money>(($a + %b) / 16) - %*.bla
    // operanden sind duch kommata getrennt und enthalten expressions, die wiederum mit operatoren verknuepft sein koennen
    // der parser bricht die operanden an spaces auf, ermittelt die werte der expressions, 
    // fuehrt die operationen aus und formatiert am ende noch
    // expressions koennen einen Modifier am ende drangehaengt haben
    // der erste Operand, der mit doubleQuote beginnt, geht bis zum Ende der Zeile
    int opc,j=[a1 count];
    PBDate *pbd;
    
    //"   -> woertlich, $, % etc. ignorieren; gilt bis Rest der Zeile; funktioniert nur richtig, wenn am letzten Parameter spezifiziert
    //formatting options auswerten
    //<date>  -> guiDate machen
    //<week>  -> Kalenderwoche
    //<yw>  -> Jahr/Kalenderwoche
    //<year>  -> Jahr 4-stellig
    //<yy>  -> Jahr 2-stellig
    //<wdayn>  -> Wochenname kurz
    //<int>  -> integer
    //<floor>  -> floor()
    //<intnd>  -> integer no decimalpoint
    //<money>  -> 2 NK
    //<f1>  -> 1 NK
    //<f3>  -> 3 NK
    //<f1nd>  -> 1 NK no decimalpoint
    //<f2nd>  -> 2 NK no decimalpoint
    //<f3nd>  -> 3 NK no decimalpoint
    //<lit> oder '  literally bis Komma
    //"             literally bis Ende der Zeile
    //<uc>   uppercase
    //<lc>   lowercase
    //<trans> Uebersetzen mit lang_script
    //<trim..> abschneiden
//<str..> rechtsbuendig money laenge ... mit space padded
//<strs...> rechtsbuendig string laenge ... mit space padded
//<stl...> linksbuendig string laenge ... mit space padded
    //<round2> -> auf 2 NK runden
    for(opc=0;opc<j;opc++){
        BOOL collectFlags = YES;
        BOOL guidate=NO,guiint=NO,guiintnd=NO,guimoney=NO,guif1=NO,guif3=NO,week=NO,weekYear=NO,year=NO;
        BOOL yy=NO,month=NO,wdayn=NO,lit=NO,rnd2=NO,ucFlag=NO,lcFlag=NO,dblQuote=NO;
        BOOL trans=NO;
        BOOL rnd1=NO;
        BOOL f1nd=NO,f2nd=NO,f3nd=NO;
        BOOL flr=NO,cl=NO;
        int trim=0,str=0,strs=0,stl=0;
        NSString *s=[a1 oai:opc],*rv=@"";
        if(!FILLED(s)){ [ops addObject:@""]; continue;}
        if([s iE:@"%"]){ [ops addObject:@"%"]; continue;}
        if([s iE:@"%%"]){ [ops addObject:@"%"]; continue;}
        if([s iE:@"%datasource"]){ [ops addObject:datasource]; continue;}
        if([s iE:@"\\r\\n"] || [s iE:@"\"\\r\\n"]){ [ops addObject:@"\r\n"]; continue;} // cr + newline
        if([s iE:@"\\n"] || [s iE:@"\"\\n"]) { [ops addObject:@"\n"]; continue;}// newline
        if([s iE:@"\\t"] || [s iE:@"\"\\t"]){ [ops addObject:@"\t"]; continue;}// tab
        
    //Formatierungsoptionen vorangestellt fuer ganzen Ausdruck; Reihenfolge egal;
        while(collectFlags){
            if([s hasSecurePrefix:@"\""]){
                s = [s substringFromIndex:1];
                dblQuote = YES;
                break;
            }
            if([s hasSecurePrefix:@"<lit>"] && !lit){ //literally
                lit=YES;
                s = [s substringFromIndex:5];
                continue;
            }
            if([s hasSecurePrefix:@"'"] && !lit){ //literally
                lit=YES;
                s = [s substringFromIndex:1];
                continue;
            }
            if([s hasSecurePrefix:@"<trans>"]){ //translate standard
                trans=YES;
                s = [s substringFromIndex:7];
                continue;
            }
            if([s hasSecurePrefix:@"<trim"]){
                NSString *trims;
                s = [s substringFromIndex:5];
                trims = [s substringToIndex:3]; //z.B. 20>
                trim=[trims intValue];
                s = [s substringFromIndex:3];
                continue;
            }
            if([s hasSecurePrefix:@"<strs"]){ // rechtsb. string
                s = [s substringFromIndex:5];
                strs=[[s substringToIndex:3] intValue];
                s = [s substringFromIndex:3];
                continue;
            }
            if([s hasSecurePrefix:@"<str"]){ // rechtsb. money
                s = [s substringFromIndex:4];
                str=[[s substringToIndex:3] intValue];
                s = [s substringFromIndex:3];
                continue;
            }
            if([s hasSecurePrefix:@"<stl"]){  // linksb. string
                s = [s substringFromIndex:4];
                stl=[[s substringToIndex:3] intValue];
                s = [s substringFromIndex:3];
                continue;
            }
            if([s hasSecurePrefix:@"<date>"]){
                guidate=YES;
                s = [s substringFromIndex:6];
                continue;
            }
            if([s hasSecurePrefix:@"<week>"]){
                week=YES;
                s = [s substringFromIndex:6];
                continue;
            }
            if([s hasSecurePrefix:@"<month>"]){
                month=YES;
                s = [s substringFromIndex:7];
                continue;
            }
            if([s hasSecurePrefix:@"<yw>"]){
                weekYear=YES;
                s = [s substringFromIndex:4];
                continue;
            }
            if([s hasSecurePrefix:@"<year>"]){
                year=YES;
                s = [s substringFromIndex:6];
                continue;
            }
            if([s hasSecurePrefix:@"<yy>"]){
                yy=YES;
                s = [s substringFromIndex:4];
                continue;
            }
            if([s hasSecurePrefix:@"<wdayn>"]){
                wdayn=YES;
                s = [s substringFromIndex:7];
                continue;
            }
            if([s hasSecurePrefix:@"<int>"]){
                guiint=YES;
                s = [s substringFromIndex:5];
                continue;
            }
            if([s hasSecurePrefix:@"<round2>"]){
                rnd2=YES;
                s = [s secureSubstringFromIndex:8];
                continue;
            }
            if([s hasSecurePrefix:@"<round1>"]){
                rnd1=YES;
                s = [s secureSubstringFromIndex:8];
                continue;
            }
            if([s hasSecurePrefix:@"<intnd>"]){
                guiintnd=YES;
                s = [s substringFromIndex:7];
                continue;
            }
            if([s hasSecurePrefix:@"<money>"]){
                guimoney=YES;
                s = [s substringFromIndex:7];
                continue;
            }
            if([s hasSecurePrefix:@"<f1>"]){
                guif1=YES;
                s = [s substringFromIndex:4];
                continue;
            }
            if([s hasSecurePrefix:@"<f3>"]){
                guif3=YES;
                s = [s substringFromIndex:4];
                continue;
            }
            if([s hasSecurePrefix:@"<f1nd>"]){
                f1nd=YES;
                s = [s substringFromIndex:6];
                continue;
            }
            if([s hasSecurePrefix:@"<f2nd>"]){
                f2nd=YES;
                s = [s substringFromIndex:6];
                continue;
            }
            if([s hasSecurePrefix:@"<f3nd>"]){
                f3nd=YES;
                s = [s substringFromIndex:6];
                continue;
            }
            if([s hasSecurePrefix:@"<floor>"]){
                flr=YES;
                s = [s substringFromIndex:7];
                continue;
            }
            if([s hasSecurePrefix:@"<ceil>"]){
                cl=YES;
                s = [s substringFromIndex:7];
                continue;
            }
            if([s hasSecurePrefix:@"<uc>"]){
                ucFlag=YES;
                s = [s substringFromIndex:4];
                continue;
            }
            if([s hasSecurePrefix:@"<lc>"]){
                lcFlag=YES;
                s = [s substringFromIndex:4];
                continue;
            }
            collectFlags = NO;
        }
        if(dblQuote){
            // wenn dblQuote, s und alle folgeoperanden zusammencatten und die Formatierung auf alle anwenden;
            rv = [[a1 arrayFromIndex:opc + 1]componentsJoinedByString:@","];
            if(FILLED(rv)){
                rv = [NSSWF @"%@,%@",s,rv];
            }else{
                rv = s;
            }
        }else{
            // Werte der einzelnen Ausdruecke beschaffen, Klammern, rechnen; rekursiv
            if(lit){ //nicht parsen, sondern als woertlichen string interpretieren
                rv = s;
            }else{
                // wenn es der letzte Operand ist, trailing spaces und comments abschneiden
                if(opc==(j-1))s = [s stringWithoutTrailingWSC];
                rv = (NSString *)[[PBExpression expressionFromString:s] valueForDatasource:datasource varDict:varDict localVarDict:localVarDict];
            }
        }
        if(!rv){
            [ops addObject:@""];
            continue;
        }
        
    // und formatieren
        if(guidate){
            rv = [rv guiDate];
        }
        if(week){
            rv = NSS([[PBDate dateWithDBString:rv] weekOfYear]);
        }
        if(month){
            rv = [[rv normalizedDate]nd_month];
        }
        if(weekYear){
            pbd = [PBDate dateWithDBString:rv];
            rv = [NSSWF @"%04i/%02i",[pbd yearForWeek],[pbd weekOfYear]];
        }
        if(year){
            rv = [[rv normalizedDate]nd_year];
        }
        if(yy){
            rv = [[[rv normalizedDate]nd_year]secureSubstringFromIndex:2];
        }
        if(wdayn){
            rv = [[rv normalizedDate]nd_weekdayName];
        }
        if(guiint){
            rv = NSS((int)round0([rv doubleValue]));
        }
        if(guiintnd){
            rv = NSS([rv intValue]);
        }
        if(rnd2){
            rv = [NSString dbFromDouble:[rv doubleValue]];
        }
        if(rnd1){
            rv = [NSString dbFromDouble:[rv doubleValue] nak:1];
        }
        if(guimoney){
            rv = [NSString dottedGuiFromDouble:[rv doubleValue] nak:2];
        }
        if(guif1){
            rv = [NSString dottedGuiFromDouble:[rv doubleValue] nak:1];
        }
        if(guif3){
            rv = [NSString dottedGuiFromDouble:[rv doubleValue] nak:3];
        }
        if(f1nd){
            rv = [[NSSWF @"%0.1f",round1([rv doubleValue])]comma];
        }
        if(f2nd){
            rv = [[NSSWF @"%0.2f",round2([rv doubleValue])]comma];
        }
        if(f3nd){
            rv = [[NSSWF @"%0.3f",round3([rv doubleValue])]comma];
        }
        if(flr){
            rv = [[NSSWF @"%0.0f",floor([rv doubleValue])]comma];
        }
        if(cl){
            rv = [[NSSWF @"%0.0f",ceil([rv doubleValue])]comma];
        }
        if(ucFlag){
            rv = [rv uppercaseString];
        }
        if(lcFlag){
            rv = [rv lowercaseString];
        }
        if(trans){
            rv = [_SESSION transScriptFor:rv];
        }
        
    	// evt. noch kuerzen
        if(trim && [rv length]>trim)rv = [rv substringToIndex:trim];
        if(stl)rv = [rv stl:stl]; // linksb. string
        if(str)rv = [rv str:str]; // rechtsb. money
        if(strs)rv = [rv strs:strs];  // rechtsb. string
        [ops addObject:rv];
        if(dblQuote)break;
    }
}
- (NSString *)valueFromExpression:(NSString *)s datasource:(PBWOEditor *)datasource varDict:(NSMutableDictionary *)varDict localVarDict:(NSMutableDictionary *)localVarDict;
{
// loest eine einzelne Expression auf; verwendet dabei die entsprechende exprValue:... Methode
    NSString *s1;
    
    // feststellen, woher der wert geholt werden soll: $ = eigene Var., % = datasource; sonst woertlich
    if([s length] < 2)return s; // z.B. "%"
    if([s hasPrefix:@"$"]){
        s = [s substringFromIndex:1];
        if([s hasSecurePrefix:@"$"]){ // $$... varieblenname steht in einer variablen
            s = [s substringFromIndex:1];
            s = [self exprValue:s varDict:varDict localVarDict:localVarDict];
        }
        s1 = [self exprValue:s varDict:varDict localVarDict:localVarDict];
    }else{
        if([s hasPrefix:@"%"] && ![s hasPrefix:@"%@"]){ // wg. spf %@ am Anfang moeglich
            s = [s substringFromIndex:1];
            s1 = [self exprValue:s datasource:datasource varDict:varDict localVarDict:localVarDict];
        }else{
            return [s replace:@"<comma>" with:@","]; //woertlich; <comma> durch , ersetzen
        }
    }
    if(!s1)return EON; // damit leere NSMutableStrings und NSMutableData nicht zu NSString werden
    return s1;
}
- (void)determineTargetObject:(NSObject **)targetObject andKey:(NSString **)targetKey forKeyPath:(NSString *)keyPath datasource:(PBWOEditor *)datasource intern:(BOOL)intern varDict:(NSMutableDictionary *)varDict localVarDict:(NSMutableDictionary *)localVarDict;
{
// fuer Wertzuweisungen: %bla.fasel.x.y,=,z ergibt [[[[datasource vfk:@"bla"]vfk@"fasel"]vfk:@"x"] takeValue:z forKey:@"y"]
// fuehrendes % oder $ schon weg; information steckt in intern-Flag
    NSObject *co; //currentObject
    NSArray *kps;
    NSString *kp,*kpv; //keypart, keypart value
    LMA;
    int i,j;
    *targetObject = nil;
    *targetKey = nil;
    if(!keyPath)return;
    kps = [keyPath componentsSeparatedByString:@"."];
    
//erstmal variable keynamen aufloesen
    j = [kps count];
    for(i=0;i<j;i++){
        NSRange kpr;
        kp = [kps oai:i];
// kp kann auch embedded Variablen mit $... haben; kann auch komplett eine variable sein, mit $ am anfang
// z.B. bla$fasel$x$y oder $$fasel
        kpr = [kp rangeOfString:@"$"];
        if(kpr.length){
            NSArray *kpvars = [kp componentsSeparatedByString:@"$"];
            LMAN(kpvarsval);
            int i1=0,j1;
            if(kpr.location){ // prefix ohne $
                [kpvarsval addObject:[kpvars firstObject]];
                i1=1;
            }
            for(j1=[kpvars count];i1<j1;i1++){
                NSString *kpvar = [kpvars oai:i1];
                if([kpvar hasSecurePrefix:@"l_"] && localVarDict){ // kennzeichen f. lokale Variable in Subroutine
                    kpvar = [localVarDict ofk:kpvar];
                }else{
                    kpvar = [varDict ofk:kpvar];
                }
                if(FILLED(kpvar))[kpvarsval addObject:kpvar];
            }
            kp = [kpvarsval componentsJoinedByString:EON];
        }
        if(!kp)kp=EON;
        [lma addObject:kp];
    }
    if(intern){
	// geht auf varDict
        co = varDict;
        if([keyPath hasSecurePrefix:@"l_"]){
            if(localVarDict)co = localVarDict;
        }
    }else{
        co = datasource;
    }
    if([[lma firstObject]iE:@"*"]){
// %*.
// ist die Datasource mit gemeint; nur noch bei EOs; co bleibt die datasource
        [lma removeObjectAtIndex:0];
    }
    if([[lma firstObject]iE:@"datasource"]){
// %datasource.
// ist die Datasource mit gemeint; doppelt gemoppelt
        [lma removeObjectAtIndex:0];
    }
    while([lma count]>1){
        PBDDAttribute *pba=nil;
        kp = [lma firstObject];
        if([co isKindOfClass:[PBEO class]]){
            NSString *effTn=nil;
            kpv = [co vfk:kp];
            if(!FILLED(kpv)){
                LOGS(([NSSWF @"leerer Key %@ an %@ fuer %@",kp,[lma description],keyPath]));
                return; //geht nicht weiter
            }
            pba = [[(PBEO *)co myTable] plainAttrNamed:kp];
            if(pba){
                PBDDTable *t;
                if((t = [pba relationTable])){ //relation verfolgen
                    effTn = [t dbName];
                }
                if(effTn){
                    co = getEOPkValue(effTn,kpv);
                    if(!co)return; //damit es keine exception gibt; ein NSString wuerde unknown key exception geben
                }else{ //normales attribut, geht mit nsstring weiter
                    co = kpv;
                }
            }else{
                co = kpv; //z.B. values oder descri
            }
        }else{
            kpv = nil;
            if(!([co isKindOfClass:[NSArray class]] || [co isKindOfClass:[NSString class]])){
// mit Arrays und Strings udn Dictionaries geht's nicht so richtig
                NS_DURING;
                kpv = [co vfk:kp];
//tut bei Dictionaries nicht so richtig; z.B. allValues, allKeys, description etc.
// mit vfk kann man auch an BOOL Werte herangehen; liefert eine NSShortNumber 0 oder 1
                if([kpv isKindOfClass:[NSNumber class]])kpv = [kpv description]; // wir wollen einen NSString
                NS_HANDLER;
                kpv = nil;
                NS_ENDHANDLER;
            }
            if(!kpv){
                kpv = [self scriptValueForTarget:co andMethod:kp];
            }
            co = kpv;
        }
        [lma removeObjectAtIndex:0];
    }
    *targetObject = co;
    *targetKey = [lma firstObject];
}
- (NSString *)currentPDFPath;
{
    return [NSSWF @"%@/temp/%@_%@.pdf",RESOURCEPATH,[_SESSION sessionID],currentTempName];
}
- (PBPDFDoc *)preparePBPDF;
{
    PBPDFDoc *pdf;
    pageCount = 0;
    scale = 10;
    pages = 1000;
    pdf = [PBPDFDoc newPDF];
    [self setCurrentTempName:[self tempName]]; //currentTempName wird in naechster methode gebraucht
    return pdf;
}
- (NSArray *)pdfStatementsNamed:(NSString *)v datasource:(PBWOEditor *)datasource;
{
    NSArray *a;
    a = [[_APP scriptDict] ofk:v];
    if(!a){
        LOGS(([NSSWF @"Druckformular %@ nicht gefunden",v]));
        return nil;
    }
    return a;
}
- (void)ohnePreview;
{
//zuletzt gedrucktes PDF in spoolpath und nicht in Acrobat; nach finishPBPDF;
    NSString *spoolPath = [NSSWF @"%@/Spool/%@_%@.pdf",MANDANTPATH,[_SESSION sessionID],currentTempName];
    if(pageCount){
        [myFM createAllDirsAtPath:[spoolPath stringByDeletingLastPathComponent]];
        [myFM copyPath:[self currentPDFPath] toPath:spoolPath handler:nil];
        [self setUrlToOpenInNewBrowser:nil];
    }
}
- (void)finischPBPDF:(PBPDFDoc *)pdf;
{
    NSString *path = [self currentPDFPath];
    NSString *url;
    NSData *renderedPDF=nil;
// das pdf kann sich selbst rendern in sein File
    if(![pdf wasRendered]){
        renderedPDF = [pdf renderPDF];
        if(!renderedPDF){
            LOGI(TRANSLATION(@"Druck hat keine Seiten erzeugt"));
            return;
        }
    }
    [renderedPDF writeToFile:path atomically:YES];
    if([[configDict ofk:@"always_embedding"]iE:@"J"] || [pdf needsFontEmbedding]){
// durch pdftk und gs pipen
// pdftk a.pdf output c.pdf
// C:\seat1ERP\Local\bin\gs\gs8.53\bin\gswin32.exe -dBATCH  -dNOPAUSE -sDEVICE=pdfwrite -sOUTPUTFILE=g.pdf c.pdf
        NSString *pdftk = [[_APP configDict]ofk:@"pdftk"];
        NSString *gs = [[_APP configDict]ofk:@"gs"];
        NSString *sys;
        if(!FILLED(pdftk))pdftk = @"pdftk";
        if(!FILLED(gs))gs = @"gs";
        sys = [NSSWF @"%@ %@ output %@_c",pdftk,path,path];
        SYSTEM(sys);
        sys = [NSSWF @"%@ -q -dBATCH  -dNOPAUSE -sDEVICE=pdfwrite -sOUTPUTFILE=%@ %@_c",gs,path,path];
        SYSTEM(sys);
    }
    url = [NSSWF @"/Aprica2_%@/temp/%@_%@.pdf",mandant,[_SESSION sessionID],currentTempName];
    if(![_APP isBatch]){
        [self setUrlToOpenInNewBrowser:url];
    }
}
- (NSMutableDictionary *)druckPDFNamed:(NSString *)v datasource:(PBWOEditor *)datasource parmDict:(NSMutableDictionary *)p_parmDict;
{
    NSArray *a = nil;
    PBPDFDoc *pbpdf=nil;
    NSMutableDictionary *resultDict;
    NSString *currentPDFVorgang;
    PBEO *currentPDFEmpfaenger;
    a = [self pdfStatementsNamed:v datasource:datasource];
    if(!a)return nil;
    pbpdf = [self preparePBPDF];
    resultDict = [self executeScriptNamed:v statements:a datasource:datasource parmDict:p_parmDict pdf:pbpdf continueMode:NO];
    [self finischPBPDF:pbpdf];
// falls in resultdict currentPDFEmpfaenger, currentPDFVorgang vorhanden sind:document erzeugen u. zuordnen
// funktioniert nur, wenn nicht in einem PDF mehrere Dokumente fuer mehrere Empfaenger vorhanden sind
    currentPDFEmpfaenger = [resultDict ofk:@"currentPDFEmpfaenger"];
    currentPDFVorgang = [resultDict ofk:@"currentPDFVorgang"];
    if(FILLED(currentPDFVorgang)){
// falls es kein document mit dieser document_id gibt, eines erzeugen wie wenn pdf upgeloaded worden waere
        [parmDict setObject:currentPDFVorgang forKey:@"p_vorgang"];
        [parmDict setObject:[self currentPDFPath] forKey:@"p_path"];
        if(FILLED(currentPDFEmpfaenger)){
            [parmDict setObject:currentPDFEmpfaenger forKey:@"p_empfaenger"];
        }else{
            [parmDict removeObjectForKey:@"p_empfaenger"];
        }
        [parmDict setObject:resultDict forKey:@"p_resultDict"];
        [_APP executeScriptNamed:@"archivePDF" datasource:(PBWOEditor *)self parmDict:parmDict];
    }
    return resultDict;
}
- (int)pages;
{
    return pages;
}
- (int)subNamed:(NSString *)s in:(NSArray *)a name:(NSString *)v;
{
    int i,j;
    NSString *s2,*s1;
    s1 = [NSSWF @"%@%@",v,s];
    if((s2=[[self subNamed] ofk:s1])){
        return [s2 intValue];
    }
    for(i=0,j=[a count];i<j;i++){
        s2 = [a oai:i];
        if([s2 hasSecurePrefix:@"sub "]){
            if([s iE:[s2 substringFromIndex:4]]){
                [[self subNamed] setSecureObject:NSS(i) forKey:s1]; //in Cache merken
                return i;
            }
        }
    }
    LOGS(([NSSWF @"sub named %@ not found",s]));
    return j;
}
- (int)matchingEndifFrom:(int)i in:(NSArray *)a name:(NSString *)v;
{
    return [self matchingEndifFrom:i orElse:NO in:a name:v];
}
- (int)matchingEndifOrElseFrom:(int)i in:(NSArray *)a name:(NSString *)v;
{
    return [self matchingEndifFrom:i orElse:YES in:a name:v];
}
- (int)matchingEndifFrom:(int)i orElse:(BOOL)yn in:(NSArray *)a name:(NSString *)v;
{
    int nest = 0;
    int j = [a count];
    NSString *s,*s1;
    s1 = [NSSWF @"%@%i",v,i];
    if((s=[[self matchingEndif] ofk:s1])){
        return [s intValue];
    }
    i++;
    for(;i<j;i++){
        s = [a oai:i];
        if(yn && [s hasSecurePrefix:@"else"] && !nest){
            [[self matchingEndif] setSecureObject:NSS(i) forKey:s1]; //in Cache merken
            return i;
        }
        if([s hasSecurePrefix:@"endif"]){
            if(!nest){
                [[self matchingEndif] setSecureObject:NSS(i) forKey:s1]; //in Cache merken
                return i;
            }
            nest--;
            if(nest < 0){
                LOGS(([NSSWF @"nesting Error endif from %i in %@",i,v]));
                return j;
            }
            continue;
        }
        if([s hasSecurePrefix:@"if "]){
            nest++;
            continue;
        }
    }
    LOGS(([NSSWF @"nesting Error endif not found from %i in %@",i,v]));
    return j;
}
- (int)matchingEndwhileFrom:(int)i in:(NSArray *)a  name:(NSString *)v;
{
    int nest = 0;
    int j = [a count];
    NSString *s,*s1;
    s1 = [NSSWF @"%@%i",v,i];
    if((s=[[self matchingEndwhile] ofk:s1])){
        return [s intValue];
    }
    i++;
    for(;i<j;i++){
        s = [a oai:i];
        if([s hasSecurePrefix:@"endwhile"]){
            if(!nest){
                [[self matchingEndwhile] setSecureObject:NSS(i) forKey:s1]; //in Cache merken
                return i;
            }
            nest--;
            if(nest < 0){
                LOGS(([NSSWF @"nesting Error endwhile from %i in %@ \nstatments:%@",i,v,[a componentsJoinedByString:@"\n"]]));
                return j;
            }
            continue;
        }
        if([s hasSecurePrefix:@"while "]){
            nest++;
            continue;
        }
    }
    LOGS(([NSSWF @"nesting Error endwhile not found from %i in %@ \nstatments:%@",i,v,[a componentsJoinedByString:@"\n"]]));
    return j;
}
- (int)matchingEndsubFrom:(int)i in:(NSArray *)a  name:(NSString *)v;
{
    int j = [a count];
    NSString *s,*s1;
    s1 = [NSSWF @"%@%i",v,i];
    if((s=[[self matchingEndsub] ofk:s1])){
        return [s intValue];
    }
    i++;
    for(;i<j;i++){
        s = [a oai:i];
        if([s hasSecurePrefix:@"endsub"]){
            [[self matchingEndsub] setSecureObject:NSS(i) forKey:s1]; //in Cache merken
            return i;
        }
    }
    LOGS(([NSSWF @"endsub not found from %i in %@ \nstatments:%@",i,v,[a componentsJoinedByString:@"\n"]]));
    return j;
}
- (int)matchingWhileFrom:(int)i in:(NSArray *)a name:(NSString *)v;
{
    int nest = 0;
    int j = [a count];
    NSString *s,*s1;
    s1 = [NSSWF @"%@%i",v,i];
    if((s=[[self matchingWhile] ofk:s1])){
        return [s intValue];
    }
    i--;
    for(;i>=0;i--){
        s = [a oai:i];
        if([s hasSecurePrefix:@"while "]){
            if(!nest){
                [[self matchingWhile] setSecureObject:NSS(i) forKey:s1]; //in Cache merken
                return i;
            }
            nest--;
            if(nest < 0){
                LOGS(([NSSWF @"nesting Error while from %i in %@ \nstatments:%@",i,v,[a componentsJoinedByString:@"\n"]]));
                return j;
            }
            continue;
        }
        if([s hasSecurePrefix:@"endwhile"]){
            nest++;
            continue;
        }
    }
    LOGS(([NSSWF @"nesting Error while not found from %i in %@ \nstatments:%@",i,v,[a componentsJoinedByString:@"\n"]]));
    return j;
}
- (int)matchingEndforFrom:(int)i in:(NSArray *)a  name:(NSString *)v;
{
    int nest = 0;
    int j = [a count];
    NSString *s,*s1;
    s1 = [NSSWF @"%@%i",v,i];
    if((s=[[self matchingEndfor] ofk:s1])){
        return [s intValue];
    }
    i++;
    for(;i<j;i++){
        s = [a oai:i];
        if([s hasSecurePrefix:@"endfor"]){
            if(!nest){
                [[self matchingEndfor] setSecureObject:NSS(i) forKey:s1]; //in Cache merken
                return i;
            }
            nest--;
            if(nest < 0){
                LOGS(([NSSWF @"nesting Error endfor from %i in %@ \nstatments:%@",i,v,[a componentsJoinedByString:@"\n"]]));
                return j;
            }
            continue;
        }
        if([s hasSecurePrefix:@"foreach "]){
            nest++;
            continue;
        }
    }
    LOGS(([NSSWF @"nesting Error endfor not found from %i in %@ \nstatments:%@",i,v,[a componentsJoinedByString:@"\n"]]));
    return j;
}
- (int)matchingForeachFrom:(int)i in:(NSArray *)a name:(NSString *)v;
{
    int nest = 0;
    int j = [a count];
    NSString *s,*s1;
    s1 = [NSSWF @"%@%i",v,i];
    if((s=[[self matchingForeach] ofk:s1])){
        return [s intValue];
    }
    i--;
    for(;i>=0;i--){
        s = [a oai:i];
        if([s hasSecurePrefix:@"foreach "]){
            if(!nest){
                [[self matchingForeach] setSecureObject:NSS(i) forKey:s1]; //in Cache merken
                return i;
            }
            nest--;
            if(nest < 0){
                LOGS(([NSSWF @"nesting Error foreach from %i in %@ \nstatments:%@",i,v,[a componentsJoinedByString:@"\n"]]));
                return j;
            }
            continue;
        }
        if([s hasSecurePrefix:@"endfor"]){
            nest++;
            continue;
        }
    }
    LOGS(([NSSWF @"nesting Error foreach not found from %i in %@ \nstatments:%@",i,v,[a componentsJoinedByString:@"\n"]]));
    return j;
}
- (NSDictionary *)splitScriptIntoSubScripts:(NSArray *)a defaultScriptName:(NSString *)defaultScriptName;
{
    NSString *scriptBaseName=nil;
    LMD;
    int i,j;
    NSMutableArray *lma=nil;
    if([defaultScriptName rangeOfString:@"/"].length){
        scriptBaseName = [[defaultScriptName stringByDeletingLastPathComponent]stringWithForwardSlashes];
    }
    for(i=0,j=[a count];i<j;i++){
        NSString *s = [a oai:i];
        if([s hasSecurePrefix:@"subScript:"]){
            NSString *ssn = [s substringFromIndex:[@"subScript:" length]];
            if(scriptBaseName)ssn=[NSSWF @"%@/%@",scriptBaseName,ssn];
            lma = [NSMutableArray arrayWithCapacity:100];
            [lmd setObject:lma forKey:ssn];
        }else{
            if(lma)[lma addObject:s]; //subscriptarray in place
        }
    }
    return lmd;
}
- (NSMutableDictionary *)loadScriptFilesIntoDict:(NSMutableDictionary *)dict dirName:(NSString *)dirName suffix:(NSString *)suffix;
{
//alle scipt files in dir; rekursiv;
//dirName ist Script oder  Druck
// returned ein Dictionary mit den geladenen Scripts, um changedScripts analysieren zu koennen
    int	i,j;
    NSString *s,*baseDir;
    NSArray *filesToLoad;
    NSArray *a1;
    LMD;
// suffix ist schon mit .
    nestinglevel = 0;
    [infiniteDetection removeAllObjects];
    [gma  removeAllObjects];
    [logs  removeAllObjects];
    NS_DURING;
    baseDir = [NSSWF @"%@/%@",MANDANTPATH,dirName];
    filesToLoad = [myFM directoryDeepContentsAtPath:baseDir suffixes:[NSArray arrayWithObject:suffix] skips:nil fullName:YES newer:lastReload];
    for(i=0,j=[filesToLoad count];i<j;i++){
        s = [[filesToLoad oai:i]stringWithForwardSlashes];
        if([s rangeOfString:@".svn"].length)continue; //keine svn Files laden
        if(lastReload){
            [scriptFileNames addObjectUniq:s];
        }else{
            [scriptFileNames addObject:s];
        }
        if([[s lastPathComponent]hasSecurePrefix:@"_"])continue; // ein Import
        if((a1 = [self loadScriptFileNamed:s dirName:dirName suffix:suffix])){
            NSString *scriptName = [[s stringByDeletingPathExtension]stringWithForwardSlashes];
            if([suffix iE:@".script"]){
                NSDictionary *d = [self splitScriptIntoSubScripts:a1 defaultScriptName:scriptName]; 
//mehrere Scripts in einem File
//z.B.:
//subScript:didInsert
//....
                if([d count]){
                    [dict addEntriesFromDictionary:d];
                    [lmd  addEntriesFromDictionary:d];
                    continue;
                }
            }
            if([dict ofk:scriptName] && !lastReload){
                LOG(([NSSWF @"#### doppelter Name Script und Druck: %@",scriptName]));
            }
            [dict setSecureObject:a1 forKey:scriptName];
            [lmd setSecureObject:a1 forKey:scriptName];
        }else{
            LOGS(([NSSWF @"could not load file %@",s]));
        }
    }
    if([[configDict ofk:@"logscriptnames"]iE:@"J"])[[logs componentsJoinedByString:@"\n"]writeToFile:[NSSWF @"%@/all_%@.txt",TEMPDIR,suffix]];
    NS_HANDLER;
    LOGS_Ex(@"laden fehlgeschlagen");
    NS_ENDHANDLER;
    return lmd;
}
- (void)loadScriptFiles;
{
    int i,j;
    NSString *fn,*path,*file;
    LOG(@"loading ScriptFiles for searching");
// nach reloadScripts; .script u. .cpdf komplett reinladen, um sie durchsuchen zu koennen; gleiche reihenfolge wie scriptFileNames;
    [scriptFiles removeAllObjects];
    for(i=0,j=[scriptFileNames count];i<j;i++){
        fn = [scriptFileNames oai:i];
        if([fn hasSecureSuffix:@".cpdf"]){
            path = [NSSWF @"%@/Druck/%@",MANDANTPATH,fn];
        }else{
            path = [NSSWF @"%@/Scripts/%@",MANDANTPATH,fn];
        }
        file = [NSSWCOF path];
        if(!file)file=@"";
        [scriptFiles addObject:file];
    }
}
- (void)loadTemplateFiles;
{
    int i,j;
    NSString *fn,*path,*file;
    LOG(@"loading TemplateFiles for searching");
// Templates komplett reinladen, um sie durchsuchen zu koennen; gleiche reihenfolge wie templateFileNames;
    [templateFiles removeAllObjects];
    for(i=0,j=[templateFileNames count];i<j;i++){
        fn = [templateFileNames oai:i];
        path = [NSSWF @"%@/Templates/%@",MANDANTPATH,fn];
        file = [NSSWCOF path];
        if(!file)file=@"";
        [templateFiles addObject:file];
    }
}
- (NSArray *)findInFiles:(NSString *)s;
{
    LMA;
    int i,j;
    NSString *fn,*file;
    if(![scriptFiles count])[self loadScriptFiles];
    for(i=0,j=[scriptFiles count];i<j;i++){
        fn = [scriptFileNames oai:i];
        file = [scriptFiles oai:i];
        if([file rangeOfString:s].length)[lma addObject:fn];
    }
    return lma;
}
- (NSArray *)findInTemplates:(NSString *)s;
{
    LMA;
    int i,j;
    NSString *fn,*file;
    if(![templateFiles count])[self loadTemplateFiles];
    for(i=0,j=[templateFiles count];i<j;i++){
        fn = [templateFileNames oai:i];
        file = [templateFiles oai:i];
        if([file rangeOfString:s].length)[lma addObject:fn];
    }
    return lma;
}
- (NSArray *)loadScriptFileNamed:(NSString *)dn dirName:(NSString *)dirName suffix:(NSString *)suffix;
{
    NSString	*pathf;
    NSString	*s;
    LMA;
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
    NSString *baseDir = [NSSWF @"%@/%@",MANDANTPATH,dirName];
    if([infiniteDetection ofk:dn]){
        LOGS(([NSSWF @"endlosschleife %@ %@",dn,dirName]));
        [pool release];
        return nil; //endlos-Schleife
    }
    [infiniteDetection setSecureObject:EON forKey:dn];
    [gma addObject:dn];
    [logs addObject:[gma componentsJoinedByString:@"->"]];
    pathf = [NSSWF@"%@/%@",baseDir,dn];
    s = [NSSWCOF pathf];
    if(!s){
        LOGS(([NSSWF @"file %@ nicht gefunden",pathf]));
        [infiniteDetection removeObjectForKey:dn];
        [gma secureRemoveLastObject];
        [pool release];
        return nil;
    }
    [lma addObjectsFromArray:[self statementsForScript:s dirName:dirName suffix:suffix]];
    [infiniteDetection removeObjectForKey:dn];
    [gma secureRemoveLastObject];
    [pool release];
    return lma;
}
- (NSArray *)statementsForScript:(NSString *)script dirName:(NSString *)dirName suffix:(NSString *)suffix;
{
    // kommentare rausfiltern, imports aufloesen
    // uebersprungene Zeilen mit leerem Statement drinlassen, um Source-Linenumbers zu behalten
    LMA;
    NSArray *a = [script componentsSeparatedByString:@"\n"];
    int i,j = [a count];
    BOOL inComment = NO;
    for(i=0;i<j;i++){
        NSString *s = [a oai:i];
        // drinlassen wg. Textverarbeitung if(!FILLED(s))continue; //Leerzeilen
        s = [s stringWithoutWindowsShit];
        s = [s stringWithoutLeadingWhiteSpace];
        //            if([s hasPrefix:@"#"])continue;		sind jetzt Preprocessor Anweisungen;
        if([s hasPrefix:COMMENT]){ [lma addObject:@""]; continue;}	//
        if([s hasPrefix:ENDCOMMENT]){
            inComment = NO;
            [lma addObject:@""]; continue;
        }
        if([s hasPrefix:STARTCOMMENT]){
            if([s hasSecureSuffix:ENDCOMMENT]){
                [lma addObject:@""]; continue;
            }
            inComment = YES;
            [lma addObject:@""]; continue;
        }
        if(inComment){ [lma addObject:@""]; continue;}
        if([s hasSecurePrefix:@"erklaerung"]){ [lma addObject:@""]; continue;}
        if([s hasSecurePrefix:@"label "]){ [lma addObject:@""]; continue;}
        if([s length]>6 &&  [s hasPrefix:@"import"]){
            NSString *s1;
            NSArray *a1;
            NSString *pathf;
            a1 = [s componentsSeparatedByString:@" "];
            if([a1 count]<2)continue;
            s1 = [a1 lastObject]; //name der zu importierenden Datei; $mandant im Filename wird durch mandantennr ersetzt
            s1 = [s1 replace:@"$mandant" with:[_APP mandant]];
// wo sucht man imports?
// 1. im Mandanten-Directory
            pathf = [NSSWF @"%@/%@/%@%@",MANDANTPATH,dirName,s1,suffix];
            if([myFM fileExistsAtPath:pathf]){
//im Mandantendirectory suchen
                if((a1 = [self loadScriptFileNamed:[s1 stringByAppendingString:suffix] dirName:dirName suffix:suffix])){
                    [lma addObjectsFromArray:a1];
                    continue;
                }
            }
            LOGS(([NSSWF @"import %@ nicht gefunden! %@",s1,pathf]));
            continue;
        }
        [lma addObject:s];
    }
    return lma;
}
- (void)clearCacheForScriptNamed:(NSString *)scriptName;
{
// f. Temp-Script
    NSString *s = [@"Script_" stringByAppendingString:scriptName];
    [matchingEndif removeAllEntriesWithPrefix:s];
    [matchingEndwhile removeAllEntriesWithPrefix:s];
    [matchingEndsub removeAllEntriesWithPrefix:s];
    [matchingWhile removeAllEntriesWithPrefix:s];
    [subNamed removeAllEntriesWithPrefix:s];
    [matchingEndfor removeAllEntriesWithPrefix:s];
    [matchingForeach removeAllEntriesWithPrefix:s];
}
- (void)reloadChangedScripts;
{
    NSDictionary *d;
    LOG(@"reloading changed Scripts");
    [scriptFiles removeAllObjects];
    [scriptErrors removeAllObjects];
    [matchingEndif removeAllObjects];
    [matchingEndwhile removeAllObjects];
    [matchingEndsub removeAllObjects];
    [matchingWhile removeAllObjects];
    [subNamed removeAllObjects];
    [matchingEndfor removeAllObjects];
    [matchingForeach removeAllObjects];
    d = [self loadScriptFilesIntoDict:scriptDict dirName:@"Druck" suffix:@".cpdf"];
    [self analyzeScriptsIn:d into:scriptDictAnalyzed];
    d = [self loadScriptFilesIntoDict:scriptDict dirName:@"Scripts" suffix:@".script"];
    [self analyzeScriptsIn:d into:scriptDictAnalyzed];
    [self setLastReload:[NSDate date]];
    [scriptFileNames sortUsingSelector:@selector(compareCaseInsensitive:)];
}
- (void)reloadScripts;
{
    NSArray *a = [scriptDict ofk:@"scripting/bu_reload_scripts"];
    [a retain];
    LOG(@"reloading all Scripts");
    [self setLastReload:nil];
    [scriptDict removeAllObjects];
    [scriptDictAnalyzed removeAllObjects];
    [scriptFileNames removeAllObjects];
    [scriptFiles removeAllObjects];
    [scriptErrors removeAllObjects];
    [matchingEndif removeAllObjects];
    [matchingEndwhile removeAllObjects];
    [matchingEndsub removeAllObjects];
    [matchingWhile removeAllObjects];
    [subNamed removeAllObjects];
    [matchingEndfor removeAllObjects];
    [matchingForeach removeAllObjects];
    [self loadScriptFilesIntoDict:scriptDict dirName:@"Druck" suffix:@".cpdf"];
    [self loadScriptFilesIntoDict:scriptDict dirName:@"Scripts" suffix:@".script"];
    [self loadScriptsForAttributes];
    [self analyzeScriptsIn:scriptDict into:scriptDictAnalyzed];
    [self setLastReload:[NSDate date]];
    [scriptFileNames sortUsingSelector:@selector(compareCaseInsensitive:)];
}
- (void)loadScriptsForAttributes;
{
    /*
     aufgerufen nachdem die Scripts aus den Files geladen sind
     alle plainAttributes durchgehen:
     bei Buttons: wenn Expression leer: tablename/attributename ist Scriptname; setzen;
     wenn Expression eine Zeile: .cpdf isDruck=YES; sonst ist die Zeile der Scriptname; scriptName setzen;
     wenn mehrere Zeilen: script unter tablename-attributname ins scriptDict, scriptName setzen;
     bei TVCSELOBJ:
     wenn Expression eine Zeile: wenn .script hintendran, scriptName setzen;
     sonst PBExpression setzen
     wenn mehrere Zeilen: script unter tablename-attributname ins scriptDict, scriptName setzen;
     im EO bei valueForKey: wenn nicht im values-Dict.: PBExpression? scriptName? script mit datasource=EO aufrufen
     bei Buttons: isDruck? script mit richtiger Methode (druck oder script) mit datasource=PBWOEditor aufrufen
     */
    NSArray *a = [myDD plainAttributes];
    int i,j;
    NSString *expression;
    for(i=0,j=[a count];i<j;i++){
        PBDDAttribute *pbat = [a oai:i];
        expression = [pbat expression];
        if(!FILLED(expression) && ![pbat isButton])continue; // schnelle vorab-pruefung
        if([pbat isButton]){
            if(FILLED(expression)){
                if([expression rangeOfString:@"\n"].length){
                    // mehrzeilig; ganzes script liegt in expression
                    [pbat setScriptName:[NSSWF @"%@-%@",[[pbat myTable] dbName],[pbat dbName]]];
                    if(![scriptDict ofk:[pbat scriptName]]){
                        // bei Buttons aus mehrfach verwendeten abstract tables kann es sein, dass script bereits vorliegt
                        // imports aufloesen, Kommentare raus
                        [scriptDict setObject:[self statementsForScript:expression dirName:@"Scripts" suffix:@".script"] forKey:[pbat scriptName]];
                    }
                }else{
                    // einzeilig: nur der Scriptname liegt in expression
                    if([expression hasSecureSuffix:@".cpdf"]){
                        [pbat setIsDruck:YES];
                        [pbat setScriptName:[expression stringWithoutSuffix:@".cpdf"]];
                    }else if([expression hasSecureSuffix:@".script"]){
                        [pbat setScriptName:[expression stringWithoutSuffix:@".script"]];
                    }else{
                        //ohne suffix -> script annehmen
                        [pbat setScriptName:expression];
                    }
                }
            }else{
                // wenn Expression leer: dbName ist Name des scripts im Hauptmodul-Directory, welches so heisst wie die Tabelle
                [pbat setScriptName:[NSSWF @"%@/%@",[[pbat myTable] dbName],[pbat dbName]]];
            }
            // pruefen, ob Script da ist;
            if(![scriptDict ofk:[pbat scriptName]])LOG(([NSSWF @"*** script missing: %@",[pbat scriptName]]));
            continue;
        }
        if([pbat targetTyp] == ATTVCSELOBJ){
            // ist es nur 1 Zeile, dann als expression interpretieren
            // bei mehreren Zeilen als Script ausfuehren; $_rv ist ergebnis
            if(![expression rangeOfString:@"\n"].length){
                if([expression hasSecurePrefix:@"SQL:"])continue;
                if([expression hasSecureSuffix:@".script"]){
                    [pbat setScriptName:[expression stringWithoutSuffix:@".script"]];
                }else{
                    [pbat setPbexpression:[PBExpression expressionFromString:expression]];
                }
            }else{
                // mehrzeilig; ganzes script liegt in expression
                // Script ins Scriptdict, dann muss es nicht jedesmal geparsed werden
                [pbat setScriptName:[NSSWF @"%@-%@",[[pbat myTable] dbName],[pbat dbName]]];
                if(![scriptDict ofk:[pbat scriptName]]){
                    // bei Attributen aus mehrfach verwendeten abstract tables kann es sein, dass script bereits vorliegt
                    // imports aufloesen, Kommentare raus
                    [scriptDict setObject:[self statementsForScript:expression dirName:@"Scripts" suffix:@".script"] forKey:[pbat scriptName]];
                }
            }
        }
    }
}
- (NSMutableDictionary *)executeScriptNamed:(NSString *)s1 datasource:(PBWOEditor *)datasource parmDict:(NSMutableDictionary *)p_parmDict;
{
// das Script mit Name s1 ausfuehren, das bereits geladen ist
    NSArray *a2;
    a2 = [scriptDict ofk:s1];
    if(!a2){
        // bei Events ist es eher normal, dass das script nicht da ist
        return p_parmDict;
    }
    [scriptStatistic setObject:NSS([[scriptStatistic ofk:s1]intValue] + 1) forKey:s1];
    return [self executeScriptNamed:s1 statements:a2 datasource:(PBWOEditor *)datasource parmDict:p_parmDict pdf:nil continueMode:NO];
}
- (void)provideEnvironmentInVardict:(NSMutableDictionary *)varDict;
{
    NSCalendarDate *date = [NSCalendarDate date];
    [varDict setSecureObject:MANDANTPATH forKey:@"_MANDANTPATH"];
    if(CURRENTUSER)[varDict setSecureObject:CURRENTUSER forKey:@"_user"];
    [varDict setSecureObject:myFM forKey:@"_myFM"];
    [varDict setSecureObject:[date descriptionWithCalendarFormat:@"%Y%m%d000000"] forKey:@"_today"];
}
- (NSMutableDictionary *)executeScriptNamed:(NSString *)v script:(NSString *)s1 datasource:(PBWOEditor *)datasource parmDict:(NSMutableDictionary *)p_parmDict;
{
//das Script namens v ausfuehren, dessen source in s1 enthalten ist;
//greift nicht auf bereits geladene scripts in scriptDict zurueck
//imports werden aufgeloest
//name muss eindeutig sein wg. matchingEndif etc.
    NSArray *a;
    if(!FILLED(s1))return p_parmDict;
    if(!FILLED(v))return p_parmDict;
    a = [self statementsForScript:s1 dirName:@"Scripts" suffix:@".script"]; // imports aufloesen, Kommentare raus
    return [self executeScriptNamed:v statements:a datasource:(PBWOEditor *)datasource parmDict:p_parmDict pdf:nil continueMode:NO];
}
- (NSMutableDictionary *)continueScript;
{
    [_SESSION setDialogMode:NO]; // die einzige Stelle, wo dialogMode zurueckgesetzt wird; solange dialogMode YES ist, wird kein anderes Script ausgefuehrt;
    if(![_SESSION cs_v])return nil; // kein script zum fortsetzen
    return [self executeScriptNamed:[_SESSION cs_v] statements:[_SESSION cs_a] datasource:(PBWOEditor *)[_SESSION cs_datasource] parmDict:[_SESSION cs_p_parmDict] pdf:nil continueMode:YES];
    if(![_SESSION dialogMode]){ // wenn nicht erneut in DialogMode, das zeug freigeben
        [_SESSION setCs_v:nil];
        [_SESSION setCs_a:nil];
        [_SESSION setCs_datasource:nil];
        [_SESSION setCs_p_parmDict:nil];
        [_SESSION setCs_stack:nil];
        [_SESSION setCs_varDictStack:nil];
        [_SESSION setCs_varDict:nil];
        [_SESSION setCs_localVarDict:nil];
        [_SESSION setCs_foreachStack:nil];
    }
}
- (NSMutableDictionary *)executeScriptNamed:(NSString *)v statements:(NSArray *)a datasource:(PBWOEditor *)datasource  parmDict:(NSMutableDictionary *)p_parmDict pdf:(PBPDFDoc *)pdf continueMode:(BOOL)continueMode;
{
// ein fertig vorbereitetes script ausfuehren; einzelne Zeilen sind in statements
// imports sind aufgeloest, kommentare raus gefiltert
    NSString *s;
    NSString *op = @"NOOP";
    NSArray *a1;
    LMAN(ops);
    NSString *op1=nil,*op2=nil,*op3=nil,*op4=nil;
    NSString *opx;
    NSRange r;
    LMAN(stack); 		// returnstack des program counter
    LMAN(varDictStack); 	// localVardict
    LMAN(foreachStack);		// enthaelt Foreach-Objekte
    NSMutableDictionary *varDict = [NSMutableDictionary dictionaryWithCapacity:100],*localVarDict=nil;
    BOOL debug = NO; 		//wenn YES, einzelne Statements loggen
    NSAutoreleasePool *localPool = nil;
    int i,j,stc=0,ii,jj;	// i ist der program counter
    NSString *scriptTyp = (pdf?@"PDF_":@"Script_");
    NSString *lookupName = [NSSWF @"%@%@",scriptTyp,v]; // verhinderung namespace collision mit pdf; v ist der name des scripts;
    
// PDF-Variablen
    NSString *lastFont;
    NSString *dash;
    float lastSize = 11.0;
    float lineWidth = 1.0;
    float lastEndpos = 0.0; //von Textstrings
    float lastYpos = 0.0; //von Textstrings
    float ulx1 = 0.0;
    int fromTop = 842;
    int alignment;
    BOOL underlinePending = NO;
    NSString *dfn=nil;
    NSString *pn;
    NSString *fn_ext;
    NSString *path;
    if([_SESSION dialogMode])return varDict; // keine weiteren Scripts nachdem Ja/Nein geklickt wurde
    if(pdf){
        lastFont = [@"Helvetica" retain];
        dash = [@"[ ] 0" retain];
        pn = [[v componentsSeparatedByString:@"/"]componentsJoinedByString:@"_"];
        fn_ext = [NSSWF @"%@_%@.pdf",[_SESSION sessionID],currentTempName];
        path = [self currentPDFPath];
        [self setCurrentPDFName:v];
        xOffset = 0;
        yOffset = 0;
        [self setRestString:nil];
        [varDict setObject:[NSSWF @"/Aprica2_%@/temp/%@_%@.pdf",mandant,[_SESSION sessionID],currentTempName]forKey:@"_url"];
        [varDict setObject:fn_ext forKey:@"_fn_ext"];
        [varDict setObject:currentTempName forKey:@"_ts"];
        [varDict setObject:pn forKey:@"_name"];
        [varDict setObject:path forKey:@"_path"];
        [varDict setObject:[path stringWithBackSlashes] forKey:@"_path_back_slash"];
        [varDict setObject:lastFont forKey:@"_lastFont"];
        [varDict setObject:@"11" forKey:@"_lastSize"];
	// dBase style printing
        [varDict setObject:@"0" forKey:@"?line"];
        [varDict setObject:@"10" forKey:@"?size"];
        [varDict setObject:@"100" forKey:@"?leftMargin"];
        [varDict setObject:@"120" forKey:@"?topMargin"];
        [varDict setObject:@"40" forKey:@"?cr"];
        [varDict setObject:@"Courier" forKey:@"?font"];
    }
    if(continueMode){ // Script wieder fortsetzen;
        stack = [_SESSION cs_stack];
        varDictStack = [_SESSION cs_varDictStack];
        varDict = [_SESSION cs_varDict];
        localVarDict = [_SESSION cs_localVarDict];
        foreachStack  = [_SESSION cs_foreachStack];
        debug = [_SESSION cs_debug];
        i = [_SESSION cs_i];
        j = [_SESSION cs_j];
    // LOGS(([NSSWF @"i=%i j=%i",i,j]));
        stc = 0;
        [varDict setObject:[_SESSION _rv] forKey:@"_rv"];
    }else{
        [_SESSION inc_scriptStackDepth];
        if([[[_APP configDict]ofk:@"logscriptnames"]iE:@"J"] && ![v rangeOfString:@"-"].length){
            LOG(([NSSWF @"%@> start %@ %@",[@"---------------------" secureSubstringToIndex:[_SESSION scriptStackDepth]],scriptTyp,v]));
        }else{
            if([_APP logActions] && ([_SESSION scriptStackDepth]==1)){
                LOG(([NSSWF @"-> start Script %@",v]));
            }
        }
        [scriptNames addObject:v];
        [self provideEnvironmentInVardict:varDict];
        [varDict addEntriesFromDictionary:p_parmDict];
        i=0;
        j=[a count];
    }
    NS_DURING;
    for(;i<j;i++){
        if(!(stc%3000)){
            [localPool release];
            localPool = [[NSAutoreleasePool alloc]init];
        }
        stc++;
        s = [a oai:i];
        if(!FILLED(s))continue;
// kommentare sind hier schon rausgefiltert
        if(debug){
            LOGS(([NSSWF @"--- %@",s]));
        }
        if([s hasSecurePrefix:@"#"])continue; // preprocessor, script validator
        if([s hasSecurePrefix:@"debug"]){
            debug=YES;
            continue;
        }
        if([s hasSecurePrefix:@"nodebug"] || [s hasSecurePrefix:@"enddebug"]){
            debug=NO;
            continue;
        }
        if([s hasSecurePrefix:@"endif"]){
            continue;
        }
// Wertzuweisungen
        if([s hasPrefix:@"$"] || [s hasPrefix:@"%"]){ //Variable setzen $ bla,=,1; % extern, $ intern
            NSString *varName,*val1,*s1;
            BOOL intern = [s hasPrefix:@"$"];
            double varVal=0;
            NSObject *targetObject; // f. [targetObject takeValue: forKey:targetKey]
            NSString *targetKey;
            NSObject *oldObject;
            s1 = [s substringFromIndex:1];
            a1 = [s1 componentsSeparatedByString:@","];
            if([a1 count]<3)goto BADSTATEMENT;
            varName = [a1 oai:0];
            [self determineTargetObject:&targetObject andKey:&targetKey forKeyPath:varName datasource:datasource intern:intern varDict:varDict localVarDict:localVarDict];
            if(!targetObject){
                LOGS(([NSSWF @"targetObject nicht erhalten von: %@",varName]));
                goto BADSTATEMENT;
            }
            if(!targetKey){
                LOGS(([NSSWF @"targetKey nicht erhalten von: %@",varName]));
                goto BADSTATEMENT;
            }
            oldObject = [targetObject vfk:targetKey]; // fuer a,au,+,-,/,*,d+,d-
            op = [[a1 oai:1]lowercaseString]; // der operand
            
//der erste Operand, der mit doubleQuote beginnt, geht bis zum Ende der Zeile
            [ops removeAllObjects];
            [self determineOperands:[a1 arrayFromIndex:2] datasource:datasource varDict:varDict localVarDict:localVarDict into:ops];
            op1 = op2 = op3 = op4 = 0;
            op1 = [ops firstObject];
            if([ops count]>1)op2 = [ops oai:1];
            if([ops count]>2)op3 = [ops oai:2];
            if([ops count]>3)op4 = [ops oai:3];
            if([op iE:@"spf"]){ //sprintf
                NSString *fs = op1; //formatString;
                LMA;
                for(ii=1,jj=[ops count];ii<jj;ii++){
                    s1 = [ops oai:ii];
                    if(debug){
                        LOGS(([NSSWF @"Parm %i: %@",ii,s1]));
                    }
                    if([s1 isKindOfClass:[NSArray class]]){
                        [lma addObjectsFromArray:(NSArray *)s1];
                    }else{
                        [lma addObject:s1];
                    }
                }
                s1 = [NSString stringWithFormat:fs andParmStrings:lma];
            }else if([op iE:@"="]){ // string u. numerisch gleichermassen
                s1 = [ops firstObject];
            }else if([op iE:@"ml"]){ // multi line string ab naechster Zeile bis \end
                LMAN(mla);
                i++;
                while(i<[a count]){
                    s1 = [a oai:i];
                    if([s1 iE:@"\\end"]){
                        break;
                    }
                    [mla addObject:s1];
                    i++;
                }
                s1 = (NSString *)mla;
            }else if([op iE:@"=:"] || [op iE:@":="]){ // zuweisung formatiert nach EO (der linke operand muss ein EO feld sein)
                s1 = [ops firstObject];
                s1 = [[[(PBEO *)targetObject myTable] plainAttrNamed: targetKey] formatStringValue:s1];
            }else if([op iE:@"a"]){ //append string(s), add Objects
                s1 =(NSString *)oldObject;
                if(!s1)s1 = EON;
                for(ii=0,jj=[ops count];ii<jj;ii++){
                    NSString *s2 = [ops oai:ii];
                    if(debug){
                        LOGS(([NSSWF @"Parm %i: %@",ii,s2]));
                    }
                    if([s1 isKindOfClass:[NSMutableString class]]){
                        [(NSMutableString *)s1 appendString:[s2 description]];
                        continue;
                    }
                    if([s1 isKindOfClass:[NSString class]]){
                        s1 = [s1 stringByAppendingString:[s2 description]];
                        continue;
                    }
                    if([s1 isKindOfClass:[NSMutableArray class]]){
                        if([s2 isKindOfClass:[NSArray class]]){
                            [(NSMutableArray *)s1 addObjectsFromArray:(NSArray *)s2];
                        }else{
                            [(NSMutableArray *)s1 addObject:s2];
                        }
                        continue;
                    }
                    if([s1 isKindOfClass:[NSMutableSet class]]){
                        [(NSMutableSet *)s1 addObject:s2];
                        continue;
                    }
                    if([s1 isKindOfClass:[NSMutableData class]]){
                        if([s2 isKindOfClass:[NSData class]]){
                            [(NSMutableData *)s1 appendData:(NSData *)s2];
                        }else if([s2 isKindOfClass:[NSString class]]){
                            [(NSMutableData *)s1 appendData:(NSData *)[s2 dataUsingEncoding:NSUTF8StringEncoding]];
                        }else{
                            LOGS(([NSSWF @"%@ cannot be appended to a MutableData",[s2 description]]));
                        }
                        continue;
                    }
                    if([s1 isKindOfClass:[NSMutableDictionary class]]){
                        if([s2 isKindOfClass:[NSDictionary class]]){
                            [(NSMutableDictionary *)s1 addEntriesFromDictionary:(NSDictionary *)s2];
                        }
                        continue;
                    }
                }
            }else if([op iE:@"au"]){ //addUniq; nur fuer Arrays
                s1 =(NSString *)oldObject;
                if(![s1 isKindOfClass:[NSMutableArray class]]){
                    LOGS(@"not a NSMutableArray");
                    goto BADSTATEMENT;
                }
                for(ii=0,jj=[ops count];ii<jj;ii++){
                    NSString *s2 = [ops oai:ii];
                    if(debug){
                        LOGS(([NSSWF @"Parm %i: %@",ii,s2]));
                    }
                    if(!s2)continue;
                    if([s2 isKindOfClass:[NSArray class]]){
                        [(NSMutableArray *)s1 addObjectsUniq:(NSArray *)s2];
                    }else{
                        [(NSMutableArray *)s1 addObjectUniq:s2];
                    }
                }
            }else if([op iE:@"ah"]){ //append hex; einzelne Bytes
                unsigned char c;
                s1 =(NSString *)oldObject;
                if(![s1 isKindOfClass:[NSMutableData class]]){
                    LOGS(@"not a NSMutableData");
                    goto BADSTATEMENT;
                }
                for(ii=0,jj=[ops count];ii<jj;ii++){
                    NSString *s2 = [ops oai:ii];
                    if(debug){
                        LOGS(([NSSWF @"Parm %i: %@",ii,s2]));
                    }
                    if(!s2)continue;
                    if(![s2 isKindOfClass:[NSString class]])continue;
                    if([s2 length]!=2)continue;
                    c = [s2 hexValue];
                    [(NSMutableData *)s1 appendBytes:&c length:1];
                }
            }else if([op iE:@"find"]){
// find,string,suchstring,{start,option}	suchstring in string ab Position start suchen;
// liefert position innerhalb string oder -1 falls nicht
// gefunden;
// option:  ci = case insensitive
                int find_start = [op3 intValue];
                if(!FILLED(op1) || !FILLED(op2) || [op2 length] > [op1 length] || (find_start > ([op1 length] - [op2 length]))){
                    s1 =@"-1";
                }else if([op1 iE:op2]){
                    s1 =@"0";
                }else{
                    unsigned mask = 0;
                    NSRange r;
                    if([op4 iE:@"ci"])mask = NSCaseInsensitiveSearch;
                    if(find_start){
                        NSRange searchRange = {find_start,[op1 length]-find_start};
                        r = [op1 rangeOfString:op2 options:mask range:searchRange];
                    }else{
                        r = [op1 rangeOfString:op2 options:mask];
                    }
                    if(!r.length){
                        s1 =@"-1";
                    }else{
                        s1 = NSS(r.location);
                    }
                }
            }else if([op iE:@"ss"]){ //ss substring string,von,laenge
                if([a1 count] != 5)goto BADSTATEMENT;
                s1 = [op1 secureSubstringFromIndex:[op2 intValue]];
                if(![[op3 lowercaseString] iE:@"e"]){
                    s1 = [s1 secureSubstringToIndex:[op3 intValue]];
                }
            }else if([op iE:@"geteopkvalue"]){ //eo fetchen
                if([a1 count] != 4)goto BADSTATEMENT;
                if(FILLED(op1) && FILLED(op2)){
                    s1 = (NSString *)getEOPkValue(op1,op2); //ist ein eo eigentlich
                }else{
                    s1 = nil; //damit es keine exception gibt, wenn pkValue nicht gefuellt
                }
            }else if([op iE:@"geteoq"]){ //getEOQ,entityName,Qualifier
                if([a1 count] != 4)goto BADSTATEMENT;
                if(op2 && ![op2 isKindOfClass:[PBSQLQualifier class]])goto BADSTATEMENT;
                s1 = (NSString *)getEOQ(op1,(PBSQLQualifier *)op2);
            }else if([op iE:@"geteoqf"]){ //getEOQf,entityName,Qualifierformat
                if([a1 count] != 4)goto BADSTATEMENT;
                s1 = (NSString *)getEOQf(op1,op2);
            }else if([op iE:@"geteosq"]){ //getEOsQ,entityName,Qualifier
                if([a1 count] != 4)goto BADSTATEMENT;
                if(op2 && ![op2 isKindOfClass:[PBSQLQualifier class]])goto BADSTATEMENT;
                s1 = (NSString *)getEOsQ(op1,(PBSQLQualifier *)op2);
            }else if([op iE:@"geteosqf"]){ //getEOsQf,entityName,Qualifierformat
                if([a1 count] != 4)goto BADSTATEMENT;
                s1 = (NSString *)getEOsQf(op1,op2);
            }else if([op iE:@"geteosqsoa"]){ //getEOsQSoa,entityName,Qualifier,soa; optionaler limit-Count
                if([a1 count] < 5)goto BADSTATEMENT;
                if(FILLED(op2) && ![op2 isKindOfClass:[PBSQLQualifier class]])goto BADSTATEMENT;
                if(op3 && ![op3 isKindOfClass:[NSArray class]])goto BADSTATEMENT;
                if(!FILLED(op2))op2=nil;
                s1 = (NSString *)[_APP getEOs:op1 qualifier:(PBSQLQualifier *)op2 offset:0 count:[op4 intValue] soa:(NSArray *)op3];
            }else if([op iE:@"soafrom"]){ //$name,soaFrom,op1,...	macht sortorder Array in $name; op1... sind die feldnamen mit angehaengtem :a bzw. :d
                LMA;
                for(ii=0,jj=[ops count];ii<jj;ii++){
                    s1 = [ops oai:ii];
                    if(debug){
                        LOGS(([NSSWF @"soa-Key %i: %@",ii,s1]));
                    }
                    [lma addObject:s1];
                }
                s1 = (NSString *)[NSArray soaADFrom:[lma componentsJoinedByString:@","]];
            }else if([op iE:@"newfile"]){ // liefert Filehandle
                [@"" WTF:op1];
                if(![myFM fileExistsAtPath:op1]){
                    LOG(([NSSWF @"konnte File %@ nicht anlegen",op1]));
                    goto BADSTATEMENT;
                }
                s1 = (NSString *)[NSFileHandle fileHandleForUpdatingAtPath:op1];
                [(NSFileHandle *)s1 seekToEndOfFile];
            }else if([op iE:@"neweo"]){ //
                s1 = (NSString *)NEW_EO(op1);
            }else if([op iE:@"newstring"]){ //
                int capacity=[op1 intValue];
                if(capacity <10)capacity=10;
                if(capacity > 1000)capacity=1000;
                s1 = (NSString *)[NSMutableString stringWithCapacity:capacity];
                [(NSMutableString *)s1 setString:@""];
            }else if([op iE:@"newdata"]){ //
                int capacity=[op1 intValue];
                if(capacity <1000)capacity=1000;
                if(capacity > 1000000)capacity=1000000;
                s1 = (NSString *)[NSMutableData dataWithCapacity:capacity];
            }else if([op iE:@"newarraye"]){ // Array aus elementen
                s1 = [NSMutableArray arrayWithCapacity:10];
                for(ii=0,jj=[ops count];ii<jj;ii++){
                    NSString *s2 = [ops oai:ii];
                    if(debug){
                        LOGS(([NSSWF @"Parm %i: %@",ii,s2]));
                    }
                    if([s2 isKindOfClass:[NSArray class]]){
                        [(NSMutableArray *)s1 addObjectsFromArray:(NSArray *)s2];
                    }else{
                        [(NSMutableArray *)s1 addObject:s2];
                    }
                }
            }else if([op iE:@"cat"]){ // string aus elementen mit " " vercattet
                s1 = [NSMutableArray arrayWithCapacity:10];
                for(ii=0,jj=[ops count];ii<jj;ii++){
                    NSString *s2 = [ops oai:ii];
                    if(debug){
                        LOGS(([NSSWF @"Parm %i: %@",ii,s2]));
                    }
                    if([s2 isKindOfClass:[NSArray class]]){
                        [(NSMutableArray *)s1 addObjectsFromArray:(NSArray *)s2];
                    }else{
                        [(NSMutableArray *)s1 addObject:s2];
                    }
                }
                s1 = [(NSArray *)s1 componentsJoinedByString:@" "];
            }else if([op iE:@"newarray"]){ //
                int capacity=[op1 intValue];
                if(capacity <10)capacity=10;
                if(capacity > 1000)capacity=1000;
                s1 = (NSString *)[NSMutableArray arrayWithCapacity:capacity];
            }else if([op iE:@"class"]){ // class pointer
                s1 = (NSString *)NSClassFromString(op1);
            }else if([op iE:@"newdict"]){ //
                int capacity=[op1 intValue];
                if(capacity <10)capacity=10;
                if(capacity > 1000)capacity=1000;
                s1 = (NSString *)[NSMutableDictionary dictionaryWithCapacity:capacity];
            }else if([op iE:@"newset"]){ //
                int capacity=[op1 intValue];
                if(capacity <10)capacity=10;
                if(capacity > 1000)capacity=1000;
                s1 = (NSString *)[NSMutableSet setWithCapacity:capacity];
            }else if([op iE:@"count"]){ //
                if([op1 isKindOfClass:[NSString class]]){
                    s1 = NSS([op1 length]);
                }else if([op1 respondsToSelector:@selector(count)]){
                    s1 = NSS([(NSArray *)op1 count]);
                }else{
                    s1 = @"0";
                }
            }else if([op iE:@"oai"]){ //$v,oai,$array,$index
                if([a1 count]!=4){
                    goto BADSTATEMENT;
                }else{
                    int index;
                    if(![op1 respondsToSelector:@selector(objectAtIndex:)]){
                        goto BADSTATEMENT;
                    }
                    if([op2 respondsToSelector:@selector(intValue)]){
                        index = [op2 intValue];
                    }else{
                        goto BADSTATEMENT;
                    }
                    if(index < [(NSArray *)op1 count]){
                        s1 = [(NSArray *)op1 oai:index];
                    }else{
                        s1 = nil;
                    }
                }
            }else if([op iE:@"ofk"]){ //$v,ofk,$dict,$key
                if([a1 count]!=4){
                    goto BADSTATEMENT;
                }else{
                    if(![op1 respondsToSelector:@selector(objectForKey:)]){
                        goto BADSTATEMENT;
                    }
                    if(!op2)goto BADSTATEMENT;
                    s1 = (NSString *)[(NSDictionary *)op1 ofk:op2];
                }
            }else if([op iE:@"css"]){ //$v,css,$string,$sep
                if([a1 count]!=4){
                    goto BADSTATEMENT;
                }else{
                    if(![op1 respondsToSelector:@selector(componentsSeparatedByString:)]){
                        goto BADSTATEMENT;
                    }
                    if(!FILLED(op2))goto BADSTATEMENT;
                    if(![op2 isKindOfClass:[NSString class]])goto BADSTATEMENT;
                    s1 = (NSString *)[op1 componentsSeparatedByString:op2];
                }
            }else if([op iE:@"cjs"]){ //$v,cjs,$array,$join
                if([a1 count]!=4){
                    goto BADSTATEMENT;
                }else{
                    if(![op1 respondsToSelector:@selector(componentsJoinedByString:)]){
                        goto BADSTATEMENT;
                    }
                    if(!op2)goto BADSTATEMENT;
                    if(![op2 isKindOfClass:[NSString class]])goto BADSTATEMENT;
                    s1 = [(NSArray *)op1 componentsJoinedByString:op2];
                }
            }else if([op iE:@"cai"]){ //$v,cai,$string,$index
                if([a1 count]!=4){
                    goto BADSTATEMENT;
                }else{
                    int index;
                    if(![op1 respondsToSelector:@selector(characterAtIndex:)]){
                        goto BADSTATEMENT;
                    }
                    if([op2 respondsToSelector:@selector(intValue)]){
                        index = [op2 intValue];
                    }else{
                        goto BADSTATEMENT;
                    }
                    if(index < [op1 length]){
                        unichar c = [op1 characterAtIndex: index];
                        s1 = [NSString stringWithCharacters:&c length:1];
                    }else{
                        s1 = EON; // nie nil zurueckgeben
                    }
                }
            }else if([op iE:@"allk"]){ //$v,allk,$dict
                if(![op1 respondsToSelector:@selector(allKeys)]){
                    goto BADSTATEMENT;
                }
                s1 = (NSString *)[(NSDictionary *)op1 allKeys];
            }else if([op iE:@"description"]){ //$v,description,$o
                s1 = [op1 description];
            }else if([op iE:@"modul"]){ //modul,modulName	liefert das Modul namens modulNa
                s1 = MODUL(op1);
            }else if([op iE:@"allv"]){ //$v,allv,$dict
                if(![op1 respondsToSelector:@selector(allValues)]){
                    goto BADSTATEMENT;
                }
                s1 = (NSString *)[(NSDictionary *)op1 allValues];
            }else if([op iE:@"q"] || [op iE:@"sqlq"]){ //$name,q,op1		macht pbsqlqualifier mit qualifierformat op1
                s1 = (NSString *)[PBSQLQualifier qualifierWithString:op1];
            }else if([op iE:@"qand"]){ //qand,array	macht einen and-qualifier
                if(![op1 isKindOfClass:[NSArray class]])goto BADSTATEMENT;
                s1 = (NSString *)[PBSQLQualifier andQualifierWithArray:(NSArray *)op1];
            }else if([op iE:@"qor"]){ //qor,array	macht einen or-qualifier
                if(![op1 isKindOfClass:[NSArray class]])goto BADSTATEMENT;
                s1 = (NSString *)[PBSQLQualifier orQualifierWithArray:(NSArray *)op1];
            }else if([op iE:@"allq"]){ // allQualifier
                s1 = (NSString *)PBALLQ;
            }else if([op iE:@"nothingq"]){ // Nothing-Qualifier
                s1 = (NSString *)PBNOTHINGQ;
            }else if([op iE:@"setfetchcond"]){ //$name,setFetchCond,op1,op2,op3,op4[,op5] enspricht: qualifier,entityName,soa,handle,limit; liefert J oder N;
                int fetchlimit=0;
                if([a1 count]<6){
                    LOGS((@"Usage: $name,setFetchCond,qualifier,entityName,soa,handle[,limit]"));
                    goto BADSTATEMENT;
                }
                if(!FILLED(op3))op3 = nil;
                if(!FILLED(op4))op4 = nil;
                if([a1 count]>6)fetchlimit = [[ops oai:4]intValue];
                if([_APP setFetchCond:(PBSQLQualifier *)op1 forTable:[myDD tableNamed:op2] soa:(NSArray *)op3 handle:op4 limit:fetchlimit]){
                    s1=@"J";
                }else{
                    s1=@"N";
                }
            }else if([op iE:@"nextmdforhandle"]){ //$name,nextMDForHandle,op1  liefert in $name das MD bzw. nil, wenn nix mehr da
                s1 = (NSString *)[_APP nextMDForHandle:op1];
            }else if([op iE:@"nexteoforhandle"]){ //$name,nextMDForHandle,op1  liefert in $name das EO bzw. nil, wenn nix mehr da
                s1 = (NSString *)[_APP nextEOForHandle:op1];
            }else if([op iE:@"swcof"]){ //string with contents of file
                if(![myFM fileExistsAtPath:op1]){
                    s1=EON;
                }else{
                    s1 = [NSSWCOF op1];
                }
            }else if([op iE:@"attributes"]){ //file-Attribute
                s1 = EON;
                if([myFM fileExistsAtPath:op1]){
                    s1 = (NSString *)[myFM fileAttributesAtPath:op1 traverseLink:NO]; //ist ein dictionary eigentlich
                }
            }else if([op iE:@"lookup"]){ //in tabelle nachschlagen
                NSString *lookupDictName,*lookupRow,*lookupCol;
                NSDictionary *lookupDict;
                if([a1 count]!=5){
                    LOGS((@"Usage: lookup,$lookupName,$row,$col"));
                    goto BADSTATEMENT;
                }
                lookupDictName = op1;
                lookupRow = op2;
                lookupCol = op3;
                lookupDict = [varDict ofk:lookupDictName]; //liegt immer im globalen
                if(!lookupDict){
                    LOGS(([NSSWF @"no such lookupDict:%@ ",lookupDictName]));
                    goto BADSTATEMENT;
                }
                s1 = [[lookupDict ofk:lookupRow]ofk:lookupCol];
                if(!s1)s1=EON;
            }else if([op iE:@"singlevaluesql"]){ //getSingleValueAsResultFrom
                s1 = [_APP getSingleValueAsResultFrom:op1];
            }else if([op iE:@"singlerecordsql"]){ //getDictAsResultFrom
                s1 = (NSString *)[_APP getDictAsResultFrom:op1];
            }else if([op iE:@"arraysql"]){ //macht getArrayAsResultFrom:sql, liefert ein array of dictionaries
                s1 = (NSString *)[_APP getArrayAsResultFrom:op1];
            }else if([op iE:@"arraysqls"]){ //macht getArrayAsResultFrom:sql, liefert ein array of strings
                s1 = (NSString *)[_APP getStringArrayAsResultFrom:op1];
            }else if([op iE:@"nowformat"]){ //now with format
                s1 = (NSString *)[[NSCalendarDate date]descriptionWithCalendarFormat:op1];
            }else if([op iE:@"tablenamed"]){ //Tabelle besorgen
                if(!FILLED(op1))goto BADSTATEMENT;
                s1 = (NSString *)[myDD tableNamed:op1];
            }else if([op iE:@"d+"]){ // date add; oldObject muss ein normalizedDate sein
                if(!FILLED(op1))goto BADSTATEMENT;
                if(!FILLED(op2))goto BADSTATEMENT; // y,m,d,w,wd,H,M,S
                if(!oldObject)goto BADSTATEMENT;
                s1 = (NSString *)[(NSString *)oldObject nd_by_adding:[op1 intValue] interval:op2];
            }else if([op iE:@"d-"]){ // date add; oldObject muss ein normalizedDate sein
                if(!FILLED(op1))goto BADSTATEMENT;
                if(!FILLED(op2))goto BADSTATEMENT; // y,m,d,w,wd,H,M,S
                if(!oldObject)goto BADSTATEMENT;
                s1 = (NSString *)[(NSString *)oldObject nd_by_adding:[op1 intValue] * -1 interval:op2];
            }else if([op iE:@"dd"]){ // date difference; op1 u. op2 muessen normalizedDate sein
                if(!FILLED(op1))goto BADSTATEMENT;
                if(!FILLED(op2))goto BADSTATEMENT;
                s1 = [NSSWF @"%f",[(NSString *)op2 nd_deltaSecondsTo:op1]]; // op1 - op2
            }else{
                if([a1 count]>3)goto BADSTATEMENT;
                val1 = op1;
                if(!oldObject)oldObject=EON;
                varVal = [(NSString *)oldObject doubleValue];
                if([op iE:@"+"]){
                    s1 = [NSSWF @"%f",(varVal+[val1 doubleValue])];
                }else if([op iE:@"-"]){
                    s1 = [NSSWF @"%f",(varVal-[val1 doubleValue])];
                }else if([op iE:@"*"]){
                    s1 = [NSSWF @"%f",(varVal*[val1 doubleValue])];
                }else if([op iE:@"/"] && [val1 doubleValue]!=0.0){
                    s1= [NSSWF @"%f",(varVal/[val1 doubleValue])];
                }else if([op iE:@"m"] && [val1 intValue]){
                    s1= [NSSWF @"%i",((int)varVal%[val1 intValue])];
                }else{
                    LOGS((@"falscher Zuweisungsbefehl"));
                    goto BADSTATEMENT;
                }
            }
//s1 koennte auch nil sein, was dann eine exception gibt, wenn man es ins varDict tun will
            if(!s1 && [targetObject isKindOfClass:[NSMutableDictionary class]]){
                [(NSMutableDictionary *)targetObject removeObjectForKey:targetKey];
            }else{
                NS_DURING;
                [targetObject takeValue:s1 forKey:targetKey];
                NS_HANDLER;
                LOGS_Ex(([NSSWF @"value %@ keyPath: %@",s1,varName]));
                NS_ENDHANDLER;
            }
            if(debug){
                LOGS(([NSSWF @"%@ neu: %@",varName,s1]));
            }
            continue;
        }
// -----------------------------------------------------------------------------------------
// sonstige Befehle:
// Aufbau:Befehl [, Space, Operanden mit Komma getrennt]
        [ops removeAllObjects];
        op1 = op2 = op3 = op4 = 0;
        r = [s rangeOfString:@" "];
        if(r.length){
            op = [[s substringToIndex:r.location]lowercaseString];
            [self determineOperands:[[s substringFromIndex:(r.location + r.length)]componentsSeparatedByString:@","] datasource:datasource varDict:varDict localVarDict:localVarDict into:ops];
            if([ops count])op1 = [ops oai:0];
            if([ops count]>1)op2 = [ops oai:1];
            if([ops count]>2)op3 = [ops oai:2];
            if([ops count]>3)op4 = [ops oai:3];
        }else{
            op = [s lowercaseString];
        }
// ###
        if([op iE:@"say"] || [op iE:@"sayw"]){ // in scratchpad schreiben say clear; say x,y,{l,r},value; sayw x,y,{l,r},w,value
            NSMutableArray *scratchpad;
            unichar c = 160; // &nbsp;
            NSString *l_s = [NSString stringWithCharacters:&c length:1];
            int l_i,l_j;
            BOOL vw = [op iE:@"sayw"];
            int x=[op1 intValue],y=[op2 intValue],msl,w=0;
            NSString *ms=EON;
            NSRange msr;
            scratchpad = [p_parmDict ofk:@"scratchpad"];
            if(([ops count]==1 && [op1 iE:@"clear"]) || !scratchpad){
                NSString *s80 = [NSString stringWith:80 timesString:l_s];
                if(!scratchpad){
                    if(debug)LOG(@"create new scratchpad");
                    scratchpad = [NSMutableArray arrayWithCapacity:25];
                    [p_parmDict setObject:scratchpad forKey:@"scratchpad"];
                    for(l_i=0;l_i<25;l_i++){
                        NSMutableString *lms=[NSMutableString stringWithCapacity:80];
                        [lms setString:s80];
                        [scratchpad addObject:lms];
                    }
                    if([op1 iE:@"clear"])continue;
                }
                if([op1 iE:@"clear"]){
                    if(debug)LOG(@"clearing scratchpad");
                    for(l_i=0;l_i<25;l_i++){
                        [[scratchpad oai:l_i] setString:s80];
                    }
                    continue;
                }
            }
            if([ops count]<(vw?5:4)){ LOG(@"say insufficient operands"); goto BADSTATEMENT;};
            if(x<0 || x>=80){ LOG(@"say x out of range"); goto BADSTATEMENT;}
            if(y<0 || y>=25){ LOG(@"say y out of range"); goto BADSTATEMENT;}
            if(vw)w=[op4 intValue];
            ms = [ops oai:(vw?4:3)];
            for(l_i=(vw?5:4),l_j=[ops count];l_i<l_j;l_i++){
                    //mutable strings stuerzen ab bei methode cString, wenn
                    //sie umlaute enthalten, die appended wurden
                ms = [ms stringByAppendingString:[ops oai:l_i]];
            }
            if(w>0 && [ms length]>w)ms=[ms substringToIndex:w];
            msl = [ms length];
            if([op3 iE:@"l"]){
                if(x + msl > 80){
                    ms = [ms substringToIndex:(80 - x)];
                    msl = [ms length];
                }
                msr.location = x;
            }else{
                if(x - msl + 1 < 0){
                    ms = [ms substringFromIndex:msl - x - 1];
                    msl = [ms length];
                }
                msr.location = x-msl+1;
            }
            msr.length = msl;
            if(debug)LOG(([NSSWF @"ms=%@ msr.location=%i msr.length=%i",ms,msr.location,msr.length]));
            [[scratchpad oai:y]replaceCharactersInRange:msr withString:[ms replace:@" " with:l_s]];
            continue;
        }
        if([op iE:@"updat_eo"]){ //eo updaten
            PBEO *eo;
            if(!FILLED(op1))goto BADSTATEMENT;
            eo = (PBEO *)op1; //das eo
            if(eo && [eo isKindOfClass:[PBEO class]]){
                UPDAT(eo);
            }
            continue;
        }
        if([op iE:@"delet_eo"]){ //eo delete
            PBEO *eo;
            if(!FILLED(op1))goto BADSTATEMENT;
            eo = (PBEO *)op1; //das eo
            if(eo && [eo isKindOfClass:[PBEO class]]){
                DELET(eo);
            }
            continue;
        }
        if([op iE:@"insrt_eo"]){ //eo insert
            PBEO *eo;
            if(!FILLED(op1))goto BADSTATEMENT;
            eo = (PBEO *)op1; //das eo
            if(eo && [eo isKindOfClass:[PBEO class]]){
                INSRT(eo);
            }
            continue;
        }
        if([op iE:@"system"]){ //shell commando;
            NSString *_rv;
            if(!FILLED(op1))goto BADSTATEMENT;
            _rv = NSS(SYSTEM(op1));
            [varDict setObject:_rv forKey:@"_rv"];
            continue;
        }
        if([op iE:@"suchexternal"]){ // suchexternal modul,q	fuehrt Suchexternal mit Qualifier q aus
            PBWOEditor *e;
            if([ops count]!=2)goto BADSTATEMENT;
            e = (PBWOEditor *)op1;
            if(![e respondsToSelector:@selector(suchSuccessfulExternalQ:)]){
                LOGI(([NSSWF TRANSLATION(@"Modul %@ kann nicht suchen"),[e name]]));
                goto BADSTATEMENT;
            }
            if(!([op2 isKindOfClass:[PBSQLQualifier class]])){
                LOGS(([NSSWF @"kein Qualifier:%@",op2]));
                goto BADSTATEMENT;
            }
            if([e suchSuccessfulExternalQ:(PBSQLQualifier *)op2]){
                if([datasource isKindOfClass:[PBWOEditor class]])[e setCallingModul:datasource]; //koennte auch ein Portlet sein
                [datasource bringToFront:e];
            }
            continue;
        }
        if([op iE:@"executestring"]){ //anderes Script, das in einem String liegt ausfuehren mit derselben datasource u. parmdict; Name muss eindeutig sein, imports werden aufgeloest; varDict des gerufenen Scripts kommt in _rv zurureck
// op1 = Name, op2 = script-Inhalt
            NSDictionary *rd,*rv;
            if([ops count]!=2)goto BADSTATEMENT;
            rd = [_APP executeScriptNamed:op1 script:op2 datasource:datasource parmDict:p_parmDict];
            rv = [rd ofk:@"scriptRC"];
            if(rv){
                [varDict setObject:rv forKey:@"scriptRC"]; //rueckgabewert
            }
            [varDict setObject:rd forKey:@"_rv"];
            continue;
        }
        if([op iE:@"execute"]){ //anderes Script ausfuehren mit derselben datasource u. parmdict; script wird nur im scriptDict gesucht; varDict des gerufenen Scripts kommt in _rv zurureck
            NSDictionary *rd,*rv;
            if(!FILLED(op1))goto BADSTATEMENT;
            rd = [_APP executeScriptNamed:op1 datasource:datasource parmDict:p_parmDict];
            rv = [rd ofk:@"scriptRC"];
            if(rv){
                [varDict setObject:rv forKey:@"scriptRC"]; //rueckgabewert
            }
            [varDict setObject:rd forKey:@"_rv"];
            continue;
        }
        if([op hasSecurePrefix:@"log"]){ //ausdruck loggen; vorangestelltes "" nimmt den String woertlich
            NSString *s1;
            if(![ops count])goto BADSTATEMENT;
            s1 = [ops componentsJoinedByString:@" "]; // sollten strings drin sein
            if([op iE:@"log"]){
                LOGS(s1);
                continue;
            }
            if([op iE:@"logi"]){
                LOGI(s1);
                continue;
            }
            if([op iE:@"logs"]){
                LOG(s1);
                continue;
            }
            continue;
        }
        if([op iE:@"lookupbegin"]){
            NSString *lookupDictName = op1;
            NSMutableDictionary *lud;
            NSArray *colKeys=nil;
            NSString *fs = @"\t";
            int ckc = 0;
            if(!FILLED(lookupDictName)){
                LOGS(@"missing lookupDictName");
                goto BADSTATEMENT;
            }
            lud = [NSMutableDictionary dictionaryWithCapacity:10];
            [varDict setSecureObject:lud forKey:lookupDictName]; //immer global
            while(++i<j){
                NSArray *a1,*a2;
                NSMutableDictionary *rowDict;
                NSString *s = [a oai:i];
                NSString *slc = [s lowercaseString];
                if(!FILLED(s))continue; //Kommentarzeilen sind schon rausgefiltert
                if(debug){
                    LOGS(([NSSWF @"--- %@",s]));
                }
                if([slc hasSecurePrefix:@"lookupend"])break;
                if([slc hasSecurePrefix:@"lookupfs "]){ //custom fieldseparator
                    NSString *s1 = [s substringFromIndex:9];
                    if(FILLED(s1))fs = s1;
                    continue;
                }
                if(!colKeys){
                    colKeys = [s componentsSeparatedByString:fs];
                    ckc = [colKeys count];
                    if(ckc <2){
                        LOGS(@"keine Spalten");
                        goto BADSTATEMENT;
                    }
                    continue;
                }
                a1 = [s componentsSeparatedByString:fs];
                if([a1 count] < 2)continue; //Keine Zeilenwerte
                a2 = [[a1 firstObject] componentsSeparatedByString:@","]; //schluesseliste; wenn nur ein schluessel auch ok
                rowDict = [NSMutableDictionary dictionaryWithCapacity:10];
                for(ii=1,jj=[a1 count];ii<jj && ii<ckc;ii++){ //anzahl colkeys kann unterschiedlich sein wie anzahl der zeilenwerte
                    [rowDict setSecureObject:[a1 oai:ii] forKey:[colKeys oai:ii]];
                }
                for(ii=0,jj=[a2 count];ii<jj;ii++){
                    NSString *rowKey = [a2 oai:ii];
                    [lud setSecureObject:rowDict forKey:rowKey];
                }
            }
            continue;
        }
        if([op iE:@"matrixbegin"]){
            NSString *matrixName = op1;
            NSMutableArray *matrix;
            NSString *fs = @"\t";
            if(!FILLED(matrixName)){
                LOGS(@"missing matrixName");
                goto BADSTATEMENT;
            }
            matrix = [NSMutableArray arrayWithCapacity:10];
            [varDict setSecureObject:matrix forKey:matrixName]; //immer global
            while(++i<j){
                NSArray *a1;
                NSString *s = [a oai:i];
                NSString *slc = [s lowercaseString];
                if(!FILLED(s))continue; //Kommentarzeilen sind schon rausgefiltert
                if(debug){
                    LOGS(([NSSWF @"--- %@",s]));
                }
                if([slc hasSecurePrefix:@"matrixend"])break;
                if([slc hasSecurePrefix:@"lookupfs "]){ //custom fieldseparator
                    NSString *s1 = [s substringFromIndex:9];
                    if(FILLED(s1))fs = s1;
                    continue;
                }
                a1 = [s componentsSeparatedByString:fs];
                [matrix addObject:a1];
            }
            continue;
        }
        if([op iE:@"diaconfirm"]){ //Alertbox mit String, ja/nein
            if(!FILLED(op1))op1 = TRANSLATION(@"Sind Sie sicher?");
            if(!FILLED(op2))op2 = TRANSLATION(@"Zurueck");
            if(!FILLED(op3))op3 = TRANSLATION(@"Weiter");
            [_SESSION setConfirmString:op1];
            [_SESSION setConfirmBack:op2];
            [_SESSION setConfirmContinue:op3];
            [_SESSION setDialogMode:YES]; // sorgt dafuer, dass Status des Script archiviert wird u. danach forgesetzt werden kann
            [_SESSION setDialogSubMode:0];
            i++;
            break;
        }
        if([op iE:@"diaalert"]){ //Alertbox; nur zu bestaetigen
            if(!FILLED(op1))op1 = @"Achtung";
            [_SESSION setConfirmString:op1];
            [_SESSION setDialogMode:YES]; // sorgt dafuer, dass Status des Script archiviert wird u. danach forgesetzt werden kann
            [_SESSION setDialogSubMode:1];
            i++;
            break;
        }
        if([op iE:@"gosub"]){ // sprungziel muss konstant sein
            if(!FILLED(op1))goto BADSTATEMENT;
            [stack insertObject:NSS(i) atIndex:0];
            if(localVarDict)[varDictStack insertObject:localVarDict atIndex:0];
            localVarDict = [[NSMutableDictionary alloc]initWithCapacity:10];
            i = [self subNamed:op1 in:a name:lookupName];
            continue;
        }
        if(([op hasSecurePrefix:@"endsub"] || [op hasSecurePrefix:@"return"] || [op iE:@"sub"])){
// subroutinen koennen in Code eingestreut werden; einfach ueberlesen bis endsub
            if([op iE:@"sub"]){
                i = [self matchingEndsubFrom:i in:a name:lookupName]; //hinter subroutine pos.
                continue;
            }
// endsub oder return ohne sub ist bloed
            if(![stack count]){
                i = j; //nix im stack-> abbruch
                goto BADSTATEMENT;
            }
            i = [[stack firstObject]intValue];
            [stack removeObjectAtIndex:0];
            [localVarDict release];
            localVarDict = [varDictStack firstObject];
            if([varDictStack count])[varDictStack removeObjectAtIndex:0];
            continue;
        }
        if(([op hasSecurePrefix:@"else"])){
            i = [self matchingEndifFrom:i in:a name:lookupName]; //wg. continue -> i++
            continue;
        }
        if([op hasSecurePrefix:@"continuefor"]){
            i = [self matchingEndforFrom:i in:a name:lookupName] - 1; // bei endfor weitermachen wg. continue -> i++
            continue;
        }
        if(([op hasSecurePrefix:@"endwhile"] || [op hasSecurePrefix:@"continue"])){
            i = [self matchingWhileFrom:i in:a name:lookupName]-1; //wg. continue -> i++ -> while ...
            continue;
        }
        if([op hasSecurePrefix:@"breakfor"]){
            [foreachStack secureRemoveLastObject];
            i = [self matchingEndforFrom:i in:a name:lookupName]; // bei endfor weitermachen wg. continue -> i++
            continue;
        }
        if([op hasSecurePrefix:@"break"]){
            i = [self matchingEndwhileFrom:i in:a name:lookupName]; //hinter Schleife pos.
            continue;
        }
        if([op iE:@"rao"]){ //remove all objects
            if(![op1 respondsToSelector:@selector(removeAllObjects)])goto BADSTATEMENT;
            [(NSMutableArray *)op1 removeAllObjects];
            continue;
        }
        if([op iE:@"rofk"]){ //rofk Dict,key
            if([ops count]!=2)goto BADSTATEMENT;
            if(![op1 isKindOfClass:[NSMutableDictionary class]])goto BADSTATEMENT;
            [(NSMutableDictionary *)op1 removeObjectForKey:op2];
            continue;
        }
        if([op iE:@"sort"]){ //sort Array,soa
            if([ops count]!=2)goto BADSTATEMENT;
            if(![op1 isKindOfClass:[NSMutableArray class]])goto BADSTATEMENT;
            if(![op2 isKindOfClass:[NSArray class]])goto BADSTATEMENT;
            [(NSMutableArray *)op1 sortUsingKeyOrderArray:(NSArray *)op2];
            continue;
        }
        if([op iE:@"roai"]){ //roai Array,index
            int index;
            if([ops count]!=2)goto BADSTATEMENT;
            if(![op1 isKindOfClass:[NSMutableArray class]])goto BADSTATEMENT;
            index = [op2 intValue];
            if([(NSArray *)op1 count] > index){
                [(NSMutableArray *)op1 removeObjectAtIndex:index];
            }
            continue;
        }
        if([op iE:@"ioai"]){ //ioai Array,index,o
            int index;
            if([ops count]!=3)goto BADSTATEMENT;
            if(![op1 isKindOfClass:[NSMutableArray class]])goto BADSTATEMENT;
            index = [op2 intValue];
            if((int)[(NSArray *)op1 count] > (index - 1)){
                [(NSMutableArray *)op1 insertObject:op3 atIndex:index];
            }else{
                [(NSMutableArray *)op1 addObject:op3];
            }
            continue;
        }
        if([op iE:@"wtf"]){ //write to file: String,Path,[encoding(default:utf8)]
            NSStringEncoding enc;
            NSData *data;
            if([ops count]<2)goto BADSTATEMENT;
            if([ops count]>3)goto BADSTATEMENT;
            if(!([op2 isKindOfClass:[NSString class]] || [op2 isKindOfClass:[NSFileHandle class]]))goto BADSTATEMENT;
            if(op3){
                /*
                 CP1252 NSWindowsCP1252StringEncoding
                 ISOLatin1 NSISOLatin1StringEncoding
                 ISOLatin2 NSISOLatin2StringEncoding
                 Unicode NSUnicodeStringEncoding
                 ASCII NSNonLossyASCIIStringEncoding
                 */
                if([op3 iE:@"CP1252"]){
                    enc = NSWindowsCP1252StringEncoding;
                }else if([op3 iE:@"ISOLatin1"]){
                    enc = NSISOLatin1StringEncoding;
                }else if([op3 iE:@"ISOLatin2"]){
                    enc = NSISOLatin2StringEncoding;
                }else if([op3 iE:@"Unicode"]){
                    enc = NSUnicodeStringEncoding;
                }else if([op3 iE:@"ASCII"]){
                    enc = NSNonLossyASCIIStringEncoding;
                }else{
                    LOGS(([NSSWF @"unsupported encoding: %@; use: CP1252, ISOLatin1, ISOLatin2, Unicode, ASCII",op3]));
                    goto BADSTATEMENT;
                }
            }else{
                enc = NSUTF8StringEncoding;
            }
            data = [op1 dataUsingEncoding:enc allowLossyConversion:YES];
            if([op2 isKindOfClass:[NSString class]]){
                [data writeToFile:op2 atomically:YES];
            }else{
                [(NSFileHandle *)op2 writeData:data];
                [(NSFileHandle *)op2 synchronizeFile];
            }
            continue;
        }
        if([op hasSecurePrefix:@"ps"]){ // veraltet!!! nicht mehr nehmen!!! ps sender message; psr = mit returnwert
// Perform selector;
// returnwert darf nur ein NSObject sein, kein int oder double
            SEL sel;
            BOOL mitRW = [op iE:@"psr"];
            NSObject *rw = nil;
            if([ops count]<2)goto BADSTATEMENT;
            if ([op2 iE:@"nil"]){
                op2 = nil;
            }
            if ([op3 iE:@"nil"]){
                op3 = nil;
            }
            if ([op4 iE:@"nil"]){
                op4 = nil;
            }
            sel = SECURE_SELECTOR_FROM_STRING(op2);
            if(!sel){
                LOGS(([NSSWF @"selector ungueltig:%@;",op2]));
                goto BADSTATEMENT;
            }
            if(![op1 respondsToSelector:sel]){
                LOGS(([NSSWF @"%@ does not respond to selector:%@;",[op1 description],op2]));
                goto BADSTATEMENT;
            }
            if([ops count]==2){
                if(mitRW){
                    rw = [op1 performSelector:sel];
                }else{
                    [op1 performSelector:sel];
                }
            }else if([ops count]==3){
                if(mitRW){
                    rw = [op1 performSelector:sel withObject:op3];
                }else{
                    [op1 performSelector:sel withObject:op3];
                }
            }else if([ops count]==4){
                if(mitRW){
                    rw = [op1 performSelector:sel withObject:op3 withObject:op4];
                }else{
                    [op1 performSelector:sel withObject:op3 withObject:op4];
                }
            }else{
                goto BADSTATEMENT;
            }
            if(mitRW && rw){
                [varDict setObject:rw forKey:@"_rv"];
            }else{
                [varDict setObject:EON forKey:@"_rv"];
            }
            continue;
        }
        if([op iE:@"invk"]){ //invk object message arg1, arg2, ...
// NSInvocation;
            static NSString *is_nil = @"aprica_script:nil placeholder";
            NSMethodSignature *sig;
            NSInvocation *invk;
            NSMutableArray *args;
            SEL sel;
            const char *type;
            id rw = EON;
            int i,n;  // overrides i in outer loop
            if([ops count]<2)goto BADSTATEMENT;
            args = (id)[NSMutableArray array];
            for(ii=2,jj=[ops count];ii<jj;ii++){
                id invk_op = [ops oai:ii];
                if ([invk_op isKindOfClass:[NSString class]] && [invk_op iE:@"nil"]){
                    invk_op = is_nil;
                }
                [args addObject: invk_op];
            }
            sel = SECURE_SELECTOR_FROM_STRING(op2);
            if(!sel){
                LOGS(([NSSWF @"selector ungueltig:%@;",op2]));
                goto BADSTATEMENT;
            }
            if(![op1 respondsToSelector:sel]){
                LOGS(([NSSWF @"%@ does not respond to selector:%@;",[op1 description],op2]));
                goto BADSTATEMENT;
            }
            sig = [op1 methodSignatureForSelector: sel];
            if(!sig){
                LOGS(([NSSWF @"keine signatur fuer selector:%@;",op2]));
                goto BADSTATEMENT;
            }
            invk = [NSInvocation invocationWithMethodSignature: sig];
            [invk setTarget: op1];
            [invk setSelector: sel];
            for(i=0,n=[args count]; i<n; i++){
                type = [sig getArgumentTypeAtIndex: i+2];
                if (*type=='r') type++; // ignore const qualifier
                switch (*type) {
                    case _C_ID:
                    case _C_CLASS:
                      {
                          id a = [args oai: i];
// a kann auch z.B. ein PBEO sein, dann kann dieses nicht mit NSString verglichen werden
                          if ([a isKindOfClass:[NSString class]] && [a iE: is_nil]) a=nil;
                          [invk setArgument: &a atIndex: i+2];
                          break;
                      }
                    case _C_SEL:
                      {
                          id a = [args oai: i];
                          SEL v = 0;
                          if ([a isKindOfClass: [NSString class]]) {
                              v = SECURE_SELECTOR_FROM_STRING(a);
                              if (!v) {
                                  LOGS(([NSSWF @"selector ungueltig:%@;",op2]));
                                  goto BADSTATEMENT;
                              }
                          } else if ([a respondsToSelector: @selector(pointerValue)]) {
                              v = [a pointerValue];
                          } else {
                              LOGS(([NSSWF @"argument %i: %@ does not respond to pointerValue;", i, [a description]]));
                              goto BADSTATEMENT;
                          }
                          [invk setArgument: &v atIndex: i+2];
                          break;
                      }
                    case _C_CHR: // We currently assume BOOL (Apple) which can cause problems for selectors that use true chars. 
                      {
                          id a = [args oai: i];
                          char v;
                          if (![a respondsToSelector: @selector(boolValuePB3)]) {
                              LOGS(([NSSWF @"argument %i: %@ does not respond to boolValuePB3;", i, [a description]]));
                              goto BADSTATEMENT;
                          }
                          v = [a boolValuePB3] ? YES : NO;
                          [invk setArgument: &v atIndex: i+2];
                          break;
                      }
                    case _C_UCHR: // We currently assume BOOL (GNU) which can cause problems for selectors that use true chars.
                      {
                          id a = [args oai: i];
                          unsigned char v;
                          if (![a respondsToSelector: @selector(boolValuePB3)]) {
                              LOGS(([NSSWF @"argument %i: %@ does not respond to boolValuePB3;", i, [a description]]));
                              goto BADSTATEMENT;
                          }
                          v = [a boolValuePB3] ? YES : NO;
                          [invk setArgument: &v atIndex: i+2];
                          break;
                      }
                    case _C_SHT:
                      {
                          id a = [args oai: i];
                          short v;
                          if ([a isKindOfClass: [NSString class]]) {
                              v = [a intValue];
                          } else if ([a respondsToSelector: @selector(shortValue)]) {
                              v = [a shortValue];
                          } else {
                              LOGS(([NSSWF @"argument %i: %@ does not respond to shortValue;", i, [a description]]));
                              goto BADSTATEMENT;
                          }
                          [invk setArgument: &v atIndex: i+2];
                          break;
                      }
                    case _C_USHT:
                      {
                          id a = [args oai: i];
                          unsigned short v;
                          if ([a isKindOfClass: [NSString class]]) {
                              v = [a intValue];
                          } else if ([a respondsToSelector: @selector(unsignedShortValue)]) {
                              v = [a unsignedShortValue];
                          } else {
                              LOGS(([NSSWF @"argument %i: %@ does not respond to unsignedShortValue;", i, [a description]]));
                              goto BADSTATEMENT;
                          }
                          [invk setArgument: &v atIndex: i+2];
                          break;
                      }
                    case _C_INT:
                      {
                          id a = [args oai: i];
                          int v;
                          if ([a respondsToSelector: @selector(intValue)]) {
                              v = [a intValue];
                          } else {
                              LOGS(([NSSWF @"argument %i: %@ does not respond to intValue;", i, [a description]]));
                              goto BADSTATEMENT;
                          }
                          [invk setArgument: &v atIndex: i+2];
                          break;
                      }
                    case _C_UINT:
                      {
                          id a = [args oai: i];
                          unsigned int v;
                          if ([a isKindOfClass: [NSString class]]) {
                              v = [a intValue];
                          } else if ([a respondsToSelector: @selector(unsignedIntValue)]) {
                              v = [a unsignedIntValue];
                          } else {
                              LOGS(([NSSWF @"argument %i: %@ does not respond to unsignedIntValue;", i, [a description]]));
                              goto BADSTATEMENT;
                          }
                          [invk setArgument: &v atIndex: i+2];
                          break;
                      }
                    case _C_LNG:
                      {
                          id a = [args oai: i];
                          long v;
                          if ([a isKindOfClass: [NSString class]]) {
                              v = [a intValue];
                          } else if ([a respondsToSelector: @selector(longValue)]) {
                              v = [a longValue];
                          } else {
                              LOGS(([NSSWF @"argument %i: %@ does not respond to longValue;", i, [a description]]));
                              goto BADSTATEMENT;
                          }
                          [invk setArgument: &v atIndex: i+2];
                          break;
                      }
                    case _C_ULNG:
                      {
                          id a = [args oai: i];
                          unsigned long v;
                          if ([a isKindOfClass: [NSString class]]) {
                              v = [a intValue];
                          } else if ([a respondsToSelector: @selector(unsignedLongValue)]) {
                              v = [a unsignedLongValue];
                          } else {
                              LOGS(([NSSWF @"argument %i: %@ does not respond to unsignedLongValue;", i, [a description]]));
                              goto BADSTATEMENT;
                          }
                          [invk setArgument: &v atIndex: i+2];
                          break;
                      }
                    case _C_FLT:
                      {
                          id a = [args oai: i];
                          float v;
                          if ([a respondsToSelector: @selector(floatValue)]) {
                              v = [a floatValue];
                          } else {
                              LOGS(([NSSWF @"argument %i: %@ does not respond to floatValue;", i, [a description]]));
                              goto BADSTATEMENT;
                          }
                          [invk setArgument: &v atIndex: i+2];
                          break;
                      }
                    case _C_DBL:
                      {
                          id a = [args oai: i];
                          double v;
                          if ([a respondsToSelector: @selector(doubleValue)]) {
                              v = [a doubleValue];
                          } else {
                              LOGS(([NSSWF @"argument %i: %@ does not respond to doubleValue;", i, [a description]]));
                              goto BADSTATEMENT;
                          }
                          [invk setArgument: &v atIndex: i+2];
                          break;
                      }
                    case _C_PTR:
                      {
                          id a = [args oai: i];
                          void *v;
                          if ([a respondsToSelector: @selector(pointerValue)]) {
                              v = [a pointerValue];
                          } else {
                              LOGS(([NSSWF @"argument %i: %@ does not respond to pointerValue;", i, [a description]]));
                              goto BADSTATEMENT;
                          }
                          [invk setArgument: &v atIndex: i+2];
                          break;
                      }
                    case _C_CHARPTR:
                      {
                          id a = [args oai: i];
                          const char *v;
                          if ([a respondsToSelector: @selector(cString)]) {
                              v = [a cString];
                          } else {
                              LOGS(([NSSWF @"argument %i: %@ does not respond to cString;", i, [a description]]));
                              goto BADSTATEMENT;
                          }
                          [invk setArgument: &v atIndex: i+2];
                          break;
                      }
                    default:
                      {
                          LOGS(([NSSWF @"argument %i: %@ has unsupported type '%s';", i, [a description], type]));
                          goto BADSTATEMENT;
                      }
                }
            }
            [invk invoke];
            type = [sig methodReturnType];
            if (*type == 'r') type++; // skip const qualifier
            switch (*type) {
                case _C_ID:
                case _C_CLASS:
                  {
                      [invk getReturnValue: &rw];
                      break;
                  }
                case _C_SEL:
                  {
                      SEL v;
                      [invk getReturnValue: &v];
                      rw = NSStringFromSelector(v);
                      break;
                  }
                case _C_CHR:  // We assume bool (Apple)
                  {
                      BOOL v;
                      [invk getReturnValue: &v];
                      rw = (v) ? @"J" : @"N";
                      break;
                  }
                case _C_UCHR:  // We assume bool (GNU)
                  {
                      unsigned char v;
                      [invk getReturnValue: &v];
                      rw = (v) ? @"J" : @"N";
                      break;
                  }
                case _C_SHT:
                  {
                      short v;
                      [invk getReturnValue: &v];
              // rw = [[NSNumber numberWithShort: v] description];
                      rw = NSS(v);
                      break;
                  }
                case _C_USHT:
                  {
                      unsigned short v;
                      [invk getReturnValue: &v];
              // rw = [[NSNumber numberWithUnsignedShort: v] description];
                      rw = NSS(v);
                      break;
                  }
                case _C_INT:
                  {
                      int v;
                      [invk getReturnValue: &v];
                      rw = NSS(v);
                      break;
                  }
                case _C_UINT:
                  {
// warum durch NSNumber schleusen?
                      unsigned int v;
                      [invk getReturnValue: &v];
              // rw = [[NSNumber numberWithUnsignedInt: v] description];
                      rw = NSS(v);
                      break;
                  }
                case _C_LNG:
                  {
                      long v;
                      [invk getReturnValue: &v];
              // rw = [[NSNumber numberWithLong: v] description];
                      rw = NSS(v);
                      break;
                  }
                case _C_ULNG:
                  {
                      unsigned long v;
                      [invk getReturnValue: &v];
              // rw = [[NSNumber numberWithUnsignedLong: v] description];
                      rw = NSS(v);
                      break;
                  }
                case _C_FLT:
                  {
                      float v;
                      double d;
                      [invk getReturnValue: &v];
                      d = v; // ensure promotion rules are used correctly
                      rw = NSSD(d);
                      break;
                  }
                case _C_DBL:
                  {
                      double v;
                      [invk getReturnValue: &v];
                      rw = NSSD(v);
                      break;
                  }
                case _C_PTR:
                  {
                      void *v;
                      [invk getReturnValue: &v];
                      rw = [NSValue valueWithPointer: v];
                      break;
                  }
                case _C_CHARPTR:
                  {
                      char *v;
                      [invk getReturnValue: &v];
                      rw = [NSString stringWithCString: v];
                      break;
                  }
                case _C_VOID:
                  {
                      rw = EON;
                      break;
                  }
                default:
                  {
                      LOGS(([NSSWF @"return value of type '%s' for selector %@ unsupported;", type, NSStringFromSelector(sel)]));
                      goto BADSTATEMENT;
                      break;
                  }
            }
            if (rw) {
                [varDict setObject:rw forKey:@"_rv"];
            } else {
                [varDict removeObjectForKey:@"_rv"];
            }
            continue;
        }
        if([op iE:@"foreach"]){ // item,array[,index]
// es muss der Zustand eines foreach-Statements gehalten werden;
// auf einem Stack
// beim erreichen eines foreach statements wird ein foreach-Objekt erzeugt und auf den Stack gelegt
// es enthaelt das Array, Name des Item, Name des Index, eigenen Index mit 0 initialisiert
// x
// dann wird geprueft, ob der interne Index >= [array count];
// ist dies nicht der Fall, wird ins varDict das [array oai:index] unter dem Name des item gestellt
// ins varDict kommt auch der interne index unter dem name, der angegeben wurde;
// dann wird der interne index im foreachObjekt erhoeht und mit dem naechsten Statement forgefahren
// ansonsten wird das foreach-Objekt vom Stack genommen und hinter dem endfor weitergemacht;
//
// bei endfor wird das foreach-Objekt ermittelt; es ist das oberste auf dem Stack; dann geht es bei x weiter;
// bei continuefor wird zum naechsten endfor gesprungen
// bei breakfor wird das foreach-Objekt vom Stack genommen und hinter dem endfor weitergemacht
            Foreach *fe;
            if([ops count]<2)goto BADSTATEMENT;
            if([op2 isKindOfClass:[NSArray class]] && [(NSArray *)op2 count]){
                fe = [[[Foreach alloc]init]autorelease];
                [fe setItemName:op1];
                [fe setA:(NSArray *)op2];
                if(FILLED(op3)){
                    [fe setIndexName:op3];
                    [varDict setObject:NSS([fe index]) forKey:[fe indexName]];
                }
                if(localVarDict && [[fe itemName]hasSecurePrefix:@"l_"]){
                    [localVarDict setObject:[[fe a] oai:[fe index]] forKey:[fe itemName]];
                }else{
                    [varDict setObject:[[fe a] oai:[fe index]] forKey:[fe itemName]];
                }
                [fe setIndex:[fe index]+1];
                [foreachStack addObject:fe];
            }else{
                i = [self matchingEndforFrom:i in:a name:lookupName]; // hinter endfor weitermachen wg. continue -> i++
            }
            continue;
        }
        if([op hasSecurePrefix:@"endfor"]){
            Foreach *fe = [foreachStack lastObject];
            if(!fe)goto BADSTATEMENT;
            if([fe index] < [[fe a]count]){
                if(FILLED([fe indexName])){
                    [varDict setObject:NSS([fe index]) forKey:[fe indexName]];
                }
                if(localVarDict && [[fe itemName]hasSecurePrefix:@"l_"]){
                    [localVarDict setObject:[[fe a] oai:[fe index]] forKey:[fe itemName]];
                }else{
                    [varDict setObject:[[fe a] oai:[fe index]] forKey:[fe itemName]];
                }
                [fe setIndex:[fe index]+1];
                i = [self matchingForeachFrom:i in:a name:lookupName]; // hinter foreach weitermachen wg. continue -> i++
            }else{
                [foreachStack secureRemoveLastObject];
            }
            continue;
        }
        if(([op hasSecurePrefix:@"end"])){
            i = j; //ende des druck; wg. continue -> i++
            continue;
        }
        if(( [op iE:@"if"]) ||  ([op iE:@"while"])){ //bedingt ausfuehren if exp1,op,exp2 bzw. while-Schleife
            NSString *vgl;
            double d1,d2;
            BOOL negate = NO;
            BOOL erg=NO;
            if([ops count]<3)goto BADSTATEMENT;
            vgl = op2;
            if([vgl hasSecurePrefix:@"!"] && ![vgl iE:@"!="]){
                negate=YES;
                vgl = [vgl substringFromIndex:1];
            }
            if(debug){
                if([vgl iE:@"in"]){
                    LOGS(([NSSWF @"op1=%@ op3=%@... %@;",op1,op3,[[ops arrayFromIndex:2]description]]));
                }else{
                    LOGS(([NSSWF @"op1=%@ op3=%@;",op1,op3]));
                }
            }
            if([vgl iE:@"in"]){ // Auflistung alternativer Werte
                for(ii=2,jj=[ops count];ii<jj;ii++){
                    opx = [ops oai:ii];
                    if([opx isKindOfClass:[NSArray class]]){
                        erg = (NSNotFound != [(NSArray *)opx indexOfObject:op1]);
                    }else{
                        erg = ([op1 iE:opx] || (!FILLED(op1) && !FILLED(opx)));
                    }
                    if(erg) break;
                }
                if(negate)erg=!erg; if(erg)continue;
            }else if([vgl iE:@"eq"]){ //string Vergleich
                erg = ([op1 iE:op3] || (!FILLED(op1) && !FILLED(op3)));
                if(negate)erg=!erg; if(erg)continue;
            }else if([vgl iE:@"ne"]){ //string Vergleich
                erg = (![op1 iE:op3] || (!FILLED(op1) && FILLED(op3)));
                if(negate)erg=!erg; if(erg)continue;
            }else if([vgl iE:@"prefix"]){ //hasPrefix
                erg = ([op1 hasSecurePrefix:op3]);
                if(negate)erg=!erg; if(erg)continue;
            }else if([vgl iE:@"suffix"]){ //hasSuffix
                erg = ([op1 hasSecureSuffix:op3]);
                if(negate)erg=!erg; if(erg)continue;
            }else if([vgl iE:@"FILLED"]){ //test auf gefuellt; geht fuer alle Objekte;
                erg = (FILLED(op1));
                if(negate)erg=!erg; if(erg)continue;
            }else if([vgl iE:@"FILLEDNUM"]){ //test auf gefuellt und numerisch <> 0; geht fuer alle Objekte;
                erg = ((FILLED(op1)) && ![op1 iE:@"0"]);
                if(negate)erg=!erg; if(erg)continue;
            }else if([vgl iE:@"exists"]){ //test auf File existent
                erg = ([myFM fileExistsAtPath:op1]);
                if(negate)erg=!erg; if(erg)continue;
            }else if([vgl iE:@"contains"]){ //containsObject: testen
                for(ii=2,jj=[ops count];ii<jj;ii++){
                    opx = [ops oai:ii];
                    if([opx isKindOfClass:[NSArray class]]){
                        int iii,jjj;
                        for(iii=0,jjj=[(NSArray *)opx count];iii<jjj;iii++){
                            erg = ([(id)op1 containsObject:[(NSArray *)opx oai:iii]]);
                            if(erg){
                                break;
                            }
                        }
                    }else{
                        erg = ([(id)op1 containsObject:opx]);
                    }
                    if(erg){
                        break;
                    }
                }
                if(negate)erg=!erg; if(erg)continue;
            }else if([vgl iE:@"like"]){ //mit wildcards
                erg = ([op1 isLike:op3]);
                if(negate)erg=!erg; if(erg)continue;
            }else if([vgl iE:@"=="] || [vgl iE:@"="]){ //numerisch Vergleich; auch falsch geschrieben
                d1 = [op1 doubleValue];
                d2 = [op3 doubleValue];
                erg = (d1 == d2);
                if(negate)erg=!erg; if(erg)continue;
            }else if([vgl iE:@"!="]){ //numerisch Vergleich
                d1 = [op1 doubleValue];
                d2 = [op3 doubleValue];
                if(d1 != d2)continue;
            }else if([vgl iE:@">"]){ //numerisch Vergleich
                d1 = [op1 doubleValue];
                d2 = [op3 doubleValue];
                erg = (d1 > d2);
                if(negate)erg=!erg; if(erg)continue;
            }else if([vgl iE:@"<"]){ //numerisch Vergleich
                d1 = [op1 doubleValue];
                d2 = [op3 doubleValue];
                erg = (d1 < d2);
                if(negate)erg=!erg; if(erg)continue;
            }else if([vgl iE:@">="] || [vgl iE:@"=>"]){ //numerisch Vergleich
                d1 = [op1 doubleValue];
                d2 = [op3 doubleValue];
                erg = (d1 >= d2);
                if(negate)erg=!erg; if(erg)continue;
            }else if([vgl iE:@"<="] || [vgl iE:@"=<"]){ //numerisch Vergleich
                d1 = [op1 doubleValue];
                d2 = [op3 doubleValue];
                erg = (d1 <= d2);
                if(negate)erg=!erg; if(erg)continue;
            }else{
                goto BADSTATEMENT;
            }
            if([op iE:@"if"]){
                i = [self matchingEndifOrElseFrom:i in:a name:lookupName];
            }else{
                i = [self matchingEndwhileFrom:i in:a name:lookupName];
            }
            continue;
        }
        if([op iE:@"dbnr"]){ //setzt dbnr
            [_APP setDbNr:[op1 intValue]];
            continue;
        }
        if([op hasSecurePrefix:@"autorelease"]){
            [localPool release];
            localPool = [[NSAutoreleasePool alloc]init];
            continue;
        }
        if([op iE:@"lang"]){ //setzt Script-Sprache abweichend von user-sprache fuer <trans>
            [_SESSION setLang_script:[op1 intValue]];
            continue;
        }
        if([op iE:@"fieldon"]){
            for(ii=0,jj=[ops count];ii<jj;ii++){
                NSString *fieldName = [ops oai:ii];
                
        // fieldOn * braucht man nicht, dafuer gibt's allFieldsOn
                if([fieldName hasSecureSuffix:@"*"]){
                    NSArray *fields = [datasource fassos];
                    int i2,j2;
                    fieldName = [fieldName stringWithoutLastChar];
                    for(i2=0,j2=[fields count];i2<j2;i2++){
                        NSString *dbName = [[fields oai:i2]dbName];
                        if([dbName hasSecurePrefix:fieldName]){
                            [[datasource disabledFieldNames]removeObjectForKey:dbName];
                            [[datasource enabledFieldNames]setObject:@"" forKey:dbName];
                        }
                    }
                }else{
                    [[datasource disabledFieldNames]removeObjectForKey:fieldName];
                    [[datasource enabledFieldNames]setObject:@"" forKey:fieldName];
                }
            }
            continue;
        }
        if([op iE:@"fieldoff"]){
            for(ii=0,jj=[ops count];ii<jj;ii++){
                NSString *fieldName = [ops oai:ii];
                
        // fieldOff * braucht man nicht, dafuer gibt's allFieldsOff
                if([fieldName hasSecureSuffix:@"*"]){
                    NSArray *fields = [datasource fassos];
                    int i2,j2;
                    fieldName = [fieldName stringWithoutLastChar];
                    for(i2=0,j2=[fields count];i2<j2;i2++){
                        NSString *dbName = [[fields oai:i2]dbName];
                        if([dbName hasSecurePrefix:fieldName]){
                            [[datasource disabledFieldNames]setObject:@"" forKey:dbName];
                            [[datasource enabledFieldNames]removeObjectForKey:dbName];
                        }
                    }
                }else{
                    [[datasource disabledFieldNames]setObject:@"" forKey:fieldName];
                    [[datasource enabledFieldNames]removeObjectForKey:fieldName];
                }
            }
            continue;
        }
        if([op iE:@"markerror"]){
            for(ii=0,jj=[ops count];ii<jj;ii++){
                NSString *fieldName = [ops oai:ii];
                [[[datasource fassosByName]ofk:fieldName]markError];
            }
            continue;
        }
        if([op iE:@"optionstd"]){
            if([ops count]!=1)goto BADSTATEMENT;
            {
                PBWOAsso *pbas = [[datasource fassosByName]ofk:op1];
                if(!pbas)continue;
                if(![pbas hasVL])continue;
                [[pbas _vl]removeAllObjects];
                [[pbas _vl] addObjectsFromArray:[[pbas pba] vl]];
            }
            continue;
        }
        if([op iE:@"optionadd"]){
            if([ops count]<3)goto BADSTATEMENT;
            {
                PBWOAsso *pbas = [[datasource fassosByName]ofk:op1];
                if(!pbas)continue;
                if(![pbas hasVL])continue;
                if(!FILLED(op4))op4 = op3;
                [[pbas _vl] addObject:[PBVLO pbvloWithValue:op2 bez0:op3 bez1:op4]];
            }
            continue;
        }
        if([op iE:@"optionrem"]){
            if([ops count]!=2)goto BADSTATEMENT;
            {
                PBWOAsso *pbas = [[datasource fassosByName]ofk:op1];
                NSMutableArray *pbas_vl;
                if(!pbas)continue;
                if(![pbas hasVL])continue;
                pbas_vl = [pbas _vl];
                {
                    int ii,jj;
                    for(ii=0,jj=[pbas_vl count];ii<jj;ii++){
                        PBVLO *pbvlo = [pbas_vl oai:ii];
                        if([[pbvlo value]iE:op2]){
                            [pbas_vl removeObjectAtIndex:ii];
                            break;
                        }
                    }
                }
            }
            continue;
        }
        if([op hasSecurePrefix:@"allfieldson"]){
            [datasource setAllFieldsDisabled:NO];
            continue;
        }
        if([op hasSecurePrefix:@"allfieldsoff"]){
            [datasource setAllFieldsDisabled:YES];
            continue;
        }
        if([op hasSecurePrefix:@"allfieldsvisible"]){
            [[datasource hiddenFieldNames]removeAllObjects];
            continue;
        }
        if([op iE:@"fieldvisible"]){
            for(ii=0,jj=[ops count];ii<jj;ii++){
                NSString *fieldName = [ops oai:ii];
                if([fieldName iE:@"*"]){
                    [[datasource hiddenFieldNames]removeAllObjects];
                    continue;
                }
                if([fieldName hasSecureSuffix:@"*"]){
                    NSArray *fields = [datasource fassos];
                    int i2,j2;
                    fieldName = [fieldName stringWithoutLastChar];
                    for(i2=0,j2=[fields count];i2<j2;i2++){
                        NSString *dbName = [[fields oai:i2]dbName];
                        if([dbName hasSecurePrefix:fieldName])[[datasource hiddenFieldNames]removeObjectForKey:dbName];
                    }
                }else{
                    [[datasource hiddenFieldNames]removeObjectForKey:fieldName];
                }
            }
            continue;
        }
        if([op iE:@"fieldinvisible"]){
            for(ii=0,jj=[ops count];ii<jj;ii++){
                NSString *fieldName = [ops oai:ii];
                if([fieldName iE:@"*"]){
                    NSArray *fields = [datasource fassos];
                    int i2,j2;
                    for(i2=0,j2=[fields count];i2<j2;i2++){
                        NSString *dbName = [[fields oai:i2]dbName];
                        [[datasource hiddenFieldNames]setObject:@"" forKey:dbName];
                    }
                    continue;
                }
                if([fieldName hasSecureSuffix:@"*"]){
                    NSArray *fields = [datasource fassos];
                    int i2,j2;
                    fieldName = [fieldName stringWithoutLastChar];
                    for(i2=0,j2=[fields count];i2<j2;i2++){
                        NSString *dbName = [[fields oai:i2]dbName];
                        if([dbName hasSecurePrefix:fieldName])[[datasource hiddenFieldNames]setObject:@"" forKey:dbName];
                    }
                }else{
                    [[datasource hiddenFieldNames]setObject:@"" forKey:fieldName];
                }
            }
            continue;
        }
        if([op iE:@"registerinvisible"]){
            for(ii=0,jj=[ops count];ii<jj;ii++){
                NSString *fieldName = [ops oai:ii];
                if([fieldName hasSecurePrefix:@">"]){
                    [datasource removeRegisterActionWithGuiName:fieldName];
                }else{
                    [[datasource boxNameArray] removeObject:fieldName];
                }
            }
            continue;
        }
        if([op hasSecurePrefix:@"registervisible"]){
            [datasource restoreBoxNameArray];
            continue;
        }
        if([op iE:@"createbutton"]){
            [datasource setCreate_ButtonIsDisabled:[[op1 lowercaseString]iE:@"off"]];
            continue;
        }
        if([op iE:@"duplicatebutton"]){
            [datasource setDuplicate_ButtonIsDisabled:[[op1 lowercaseString]iE:@"off"]];
            continue;
        }
        if([op iE:@"deletebutton"]){
            [datasource setDelete_ButtonIsDisabled:[[op1 lowercaseString]iE:@"off"]];
            continue;
        }
        if([op iE:@"sql"]){ //sql commando; vorangestelltes "" nimmt den String woertlich
            if(FILLED(op1))[_APP evaluateSQL:op1];
            continue;
        }
        if(!pdf)goto BADSTATEMENT;
// =====================================================================================
// Druck-Kommandos
// damit kann man sich selbst ein limit setzen, um z.B. Benutzereingaben, die zuviel Seiten produzieren wuerden, abzubrechen
        if([op iE:@"pages"]){
            pages = [op1 intValue];
            continue;
        }
        if([op hasSecurePrefix:@"newpageqm"]){
            if(pageCount >= pages){
                LOGI(([NSSWF TRANSLATION(@"max. Seitenanzahl %i f. Druck ueberschritten"),pages]));
                break;
            }
            [varDict setObject:@"0" forKey:@"?line"];
            [pdf addPage];
            [CP setRotate:270];
            [CP setMediaBox:PBPDF_qm];
            pageCount++;
            fromTop = 2835;
            continue;
        }
        if([op hasSecurePrefix:@"newpagequer"]){
            if(pageCount >= pages){
                LOGI(([NSSWF TRANSLATION(@"max. Seitenanzahl %i f. Druck ueberschritten"),pages]));
                break;
            }
            [varDict setObject:@"0" forKey:@"?line"];
            [pdf addPage];
            [CP setRotate:270];
            [CP setMediaBox:PBPDF_A4quer];
            pageCount++;
            fromTop = 595;
            continue;
        }
        if([op hasSecurePrefix:@"newpagea5quer"]){
            if(pageCount >= pages){
                LOGI(([NSSWF TRANSLATION(@"max. Seitenanzahl %i f. Druck ueberschritten"),pages]));
                break;
            }
            [varDict setObject:@"0" forKey:@"?line"];
            [pdf addPage];
            [CP setRotate:270];
            [CP setMediaBox:PBPDF_A5quer];
            pageCount++;
            fromTop = 298;
            continue;
        }
        if([op iE:@"newpagewh"]){
            int w,h;
            NSString *mediaString;
            if(pageCount >= pages){
                LOGI(([NSSWF TRANSLATION(@"max. Seitenanzahl %i f. Druck ueberschritten"),pages]));
                break;
            }
            if([ops count]!=2)goto BADSTATEMENT;
            w = mmtp([op1 intValue]);
            h = mmtp([op2 intValue]);
// "0 0 842 595"
            mediaString = [NSSWF @"0 0 %i %i",w,h];
            [varDict setObject:@"0" forKey:@"?line"];
            [pdf addPage];
            [CP setMediaBox:mediaString];
            pageCount++;
            fromTop = h;
            continue;
        }
        if([op hasSecurePrefix:@"newpage"]){
            if(pageCount >= pages){
                LOGI(([NSSWF TRANSLATION(@"max. Seitenanzahl %i f. Druck ueberschritten"),pages]));
                break;
            }
            [varDict setObject:@"0" forKey:@"?line"];
            [pdf addPage];
            pageCount++;
            fromTop = 842;
            continue;
        }
        if([op hasSecurePrefix:@"lsn"]){ //linestyle normal
            APC(@"[ ] 0 d\n");
            continue;
        }
        if([op iE:@"scale"]){ //scale 10 -> 1/10 mm; 1 -> 1 mm
            scale = [op1 intValue];
            if(!scale)scale = 1;
            continue;
        }
        if([op iE:@"sprache"]){ //obsolet
            continue;
        }
        if([op iE:@"o"]){ //Delta x,y-offset  o 1,2
//wird auf alle Koordinaten angewendet; globale Verschiebung;
//wirkt relativ auf bisherigen Offset;
            if([ops count]!=2)goto BADSTATEMENT;
            xOffset += [op1 intValue];
            yOffset += [op2 intValue];
            continue;
        }
        if([op iE:@"f"]){ //font f Arial,12
            NSString *newFont = op1;
            NSString *ls = op2;
            if(![newFont iE:lastFont]){
                [lastFont release];
                lastFont = [newFont retain];
                [varDict setObject:lastFont forKey:@"_lastFont"];
            }
            if(FILLED(ls)){
                [varDict setObject:ls forKey:@"_lastSize"];
                lastSize = [ls floatValue];
            }
            continue;
        }
        if([op iE:@"s"]){ //size  s 12
            NSString *ls = op1;
            [varDict setObject:ls forKey:@"_lastSize"];
            lastSize = [ls floatValue];
            continue;
        }
        if([op iE:@"lc"]){ //lineColor  lc 85      100 =weiss, 0 schwarz;
            CHECK_PGC;
            lineColor =  [op1 floatValue] / 100.0;
            APC(([NSSWF @"%.4f G\n",lineColor]));
            if(debug){
                LOGS(([NSSWF @"linecolor neu: %.0f",lineColor * 100]));
            }
            continue;
        }
        if([op iE:@"lcrgb"] || [op iE:@"lc255"] || [op iE:@"lc#"] || [op iE:@"fcrgb"] || [op iE:@"fc255"] || [op iE:@"fc#"]){ // lineColor oder fillColor r,g,b     0..100; oder 255 oder XXXXXX
            float r,g,b;
            CHECK_PGC;
            if([op hasSuffix:@"#"]){
                if([ops count]!=1)goto BADSTATEMENT;
                if([op1 length]!=6){ LOGS(([NSSWF @"falsche Laenge:%@",op1])); goto BADSTATEMENT;}
                r = (float)[[op1 substringToIndex:2]hexValue] / 255;
                g = (float)[[[op1 substringFromIndex:2]substringToIndex:2]hexValue] / 255;
                b = (float)[[op1 substringFromIndex:4]hexValue] / 255;
            }else{
                float colorBase = (([op hasSuffix:@"255"])?255.0:100.0);
                if([ops count]!=3)goto BADSTATEMENT;
                r =  [op1 floatValue] / colorBase;
                g =  [op2 floatValue] / colorBase;
                b =  [op3 floatValue] / colorBase;
            }
            if(debug){
                LOGS(([NSSWF @"%@ :r %.4f  g %.4f b %.4f",op,r,g,b]));
            }
            if(r > 1.0 || g > 1.0 || b > 1.0)goto BADSTATEMENT;
            if([op hasPrefix:@"lc"]){
                APC(([NSSWF @"%.4f %.4f %.4f RG\n", r, g, b]));
            }else{
                APC(([NSSWF @"%.4f %.4f %.4f rg\n", r, g, b]));
            }
            continue;
        }
        if([op iE:@"lw"]){ //lineWidth  lw 30  -> 3 mm
            lineWidth = [op1 floatValue];
            CHECK_PGC;
            APC(([NSSWF @"%.4f w\n",mmtp(lineWidth)]));
            if(debug){
                LOGS(([NSSWF @"linewidth neu: %.0f",lineWidth]));
            }
            continue;
        }
        if([op iE:@"ls"]){ //linestyle x1,x2
            float x1,x2;
            if([ops count]!=2)goto BADSTATEMENT;
            x1 = mmtp([op1 floatValue]);
            x2 = mmtp([op2 floatValue]);
            if(x1 <=0)x1 = 1;
            if(x2 <=0)x2 = 1;
            [dash release];
            dash = [[NSSWF @"[%.3f %.3f] 0 d\n",x1,x2]retain];
            APC(dash);
            continue;
        }
       if([op iE:@"fc"]){ //fillColor  fc 85      100 =weiss, 0 schwarz;
            CHECK_PGC;
            fillColor =  [op1 floatValue] / 100.0;
            [varDict setObject:op1 forKey:@"_lastFillColor"];
            APC(([NSSWF @"%.4f g\n",fillColor]));
            if(debug){
                LOGS(([NSSWF @"fillColor neu: %.0f",fillColor*100]));
            }
            continue;
        }
        if([op iE:@"rf"] || [op iE:@"rl"]){ //rahmen filled rf x,y,dx,dy   x,y Koord., width, height mit current fillStroke oder rahmen leer
            float x,y,w,h;
            CHECK_PGC;
            if([ops count]!=4)goto BADSTATEMENT;
            x =  mmtp([op1 floatValue] + xOffset);
            y =  mmtpFromTop([op2 floatValue] + yOffset);
            w =  mmtp([op3 floatValue]);
            h =  mmtp([op4 floatValue])  * -1.0;
            APC(([NSSWF @"%.3f %.3f %.3f %.3f re\n", x, y, w, h]));
            if([op iE:@"rl"]){
                APC(@"S\n");
            }else{
//rahmen unsichtbar und nur fuellen; danach wieder aktuelle linienbreite
                APC((@"0 w\n"));
                APC(@"f\n");
                APC(([NSSWF @"%.4f w\n",mmtp(lineWidth)]));
            }
            if(debug){
                LOGS(([NSSWF @"x y w h = %.0f %.0f %.0f %.0f",ptmm(x),ptmmFromTop(y),ptmm(w),ptmm((-1 * h))]));
            }
            continue;
        }
        if([op iE:@"kf"] || [op iE:@"kl"]){ //kreis filled lf x,y,r   x,y Mittelp., Radius mit current fillStroke
            float x,y,r,kappa = 0.5522847498; // 4 segmente zeichnen s. http://www.whizkidtech.redprince.net/bezier/circle/kappa/
            CHECK_PGC;
            if([ops count]!=3)goto BADSTATEMENT;
            x =  mmtp([op1 floatValue] + xOffset);
            y =  mmtpFromTop([op2 floatValue] + yOffset);
            r =  mmtp([op3 floatValue]);
            
//           100 150 m begin path
//           100 83.333 200 83.333 200 150 c cubic bezier, 2 stuetzpunkte, zielpunkt
//           200 216.666 100 216.666 100 150 c
            APC(([NSSWF @"%.3f %.3f m\n", x, y - r])); // start open
            APC(([NSSWF @"%.3f %.3f %.3f %.3f %.3f %.3f c\n", x + kappa, y - r,x + r, y - kappa, x + r, y])); // ziel rechts
            APC(([NSSWF @"%.3f %.3f %.3f %.3f %.3f %.3f c\n", x + r, y + kappa,x + kappa, y + r, x, y + r])); // ziel unten
            APC(([NSSWF @"%.3f %.3f %.3f %.3f %.3f %.3f c\n", x - kappa, y + r,x - r, y + kappa, x - r, y])); // ziel links
            APC(([NSSWF @"%.3f %.3f %.3f %.3f %.3f %.3f c\n", x - r, y - kappa,x - kappa, y - r, x, y - r])); // ziel oben
            if([op iE:@"kl"]){
                APC(@"S\n");
            }else{
               //rahmen unsichtbar und nur fuellen
                APC((@"0 w\n"));
                APC(@"f\n");
                APC(([NSSWF @"%.4f w\n",mmtp(lineWidth)]));
            }
            if(debug){
                LOGS(([NSSWF @"x y r = %.0f %.0f %.0f",ptmm(x),ptmmFromTop(y),ptmm(r)]));
            }
            continue;
        }
        if([op iE:@"lvb"]){ //line  lvb x1,y1,x2,y2   2 pt. verbinden; mit current lineWidth u. grayStroke
            float x1,y1,x2,y2;
            CHECK_PGC;
            if([ops count]!=4)goto BADSTATEMENT;
            x1 = mmtp([op1 floatValue] + xOffset);
            y1 = mmtpFromTop([op2 floatValue] + yOffset);
            x2 = mmtp([op3 floatValue] + xOffset);
            y2 = mmtpFromTop([op4 floatValue] + yOffset);
            APC(([NSSWF @"%.3f %.3f m\n", x1, y1]));
            APC(([NSSWF @"%.3f %.3f l\n", x2, y2]));
            APC(@"S\n");
            if(debug){
                LOGS(([NSSWF @"x1 y1 x2 y2 = %.0f %.0f %.0f %.0f",ptmm(x1),ptmmFromTop(y1),ptmm(x2),ptmmFromTop(y2)]));
            }
            continue;
        }
        if([op iE:@"l"]){ //line  l x,y,o,l   x,y Koord., orientation, length; mit current lineWidth u. grayStroke
            float x,y,ll;
            NSString *l_op3;
            CHECK_PGC;
            if([ops count]!=4)goto BADSTATEMENT;
            if([op1 iE:@"a"]){ //appendmode;Linie hinter text beginnen
                x = lastEndpos;
            }else{
                x = mmtp([op1 floatValue] + xOffset);
            }
            y =  mmtpFromTop([op2 floatValue] + yOffset);
            ll = mmtp([op4 floatValue]);
            APC(([NSSWF @"%.3f %.3f m\n", x, y]));
            l_op3 = [op3 lowercaseString];
            if([l_op3 iE:@"x"] || [l_op3 iE:@"-"]){
                x += ll;
            }else{
                y -= ll;
            }
            APC(([NSSWF @"%.3f %.3f l\n", x, y]));
            APC(@"S\n");
            if(debug){
                LOGS(([NSSWF @"x y ll = %.0f %.0f %.0f",ptmm(x),ptmmFromTop(y),ptmm(ll)]));
            }
            continue;
        }
        if([op iE:@"?"] || [op iE:@"?b"]){ // print dBase style; ? str, ?b = bold
            float x,y;
            int line = [[varDict ofk:@"?line"] intValue];
            NSString *ms=EON;
            NSString *font;
            CHECK_PGC;
            for(ii=0,jj=[ops count];ii<jj;ii++){
                //mutable strings stuerzen ab bei methode cString, wenn
                //sie umlaute enthalten, die appended wurden
                ms = [ms stringByAppendingString:[ops oai:ii]];
            }
            x =  mmtp([[varDict ofk:@"?leftMargin"] floatValue] + xOffset);
            y =  mmtpFromTop([[varDict ofk:@"?topMargin"] floatValue] + ([[varDict ofk:@"?cr"] floatValue] * line)+ yOffset);
            if([op iE:@"?b"]){
                font = @"Courier-Bold";
            }else{
                font = [varDict ofk:@"?font"];
            }
            [pdf setFont:font size:[[varDict ofk:@"?size"]floatValue]];
            APC(@"\nBT\n");
            [pdf text:ms x:x y:y rotate:0 align:0];
            APC(@"ET\n");
            line++;
            [varDict setObject:NSS(line) forKey:@"?line"];
            if(debug){
                LOGS(([NSSWF @"? %@",ms]));
            }
            continue;
        }
        if([op iE:@"v"] || [op iE:@"vc"] || [op iE:@"vw"]){ //value v 20,45,r,%guiGesamtBetrag,...
//vc = v compact; ohne spaces bei aufzaehlungen
//vw = width; maximale breite angeben
            float x;
            double rotation = 0.0;
            NSString *formatOption;
            NSString *ms=EON;
            int maxWidth=0;
            BOOL compact = [op iE:@"vc"];
            BOOL vw = [op iE:@"vw"];
            CHECK_PGC;
            if([ops count]<(vw?5:4))goto BADSTATEMENT;
            if(vw)maxWidth=mmtp([op4 intValue]);
            ms = [ops oai:(vw?4:3)];
            for(ii=(vw?5:4),jj=[ops count];ii<jj;ii++){
                if(!compact)ms = [ms stringByAppendingString:@" "];
                //mutable strings stuerzen ab bei methode cString, wenn
                //sie umlaute enthalten, die appended wurden
                ms = [ms stringByAppendingString:[ops oai:ii]];
            }
            if(!FILLED(ms))continue;
            if([op1 iE:@"a"]){ //appendmode
                x=lastEndpos;
            }else{
                x =  mmtp([op1 floatValue] + xOffset);
                lastEndpos = x;
            }
            if(underlinePending && ulx1 == 0.0){
                ulx1 = x;
            }
            lastYpos =  mmtpFromTop([op2 floatValue] + yOffset);
            formatOption =[op3 lowercaseString];
            alignment=0;
            if([formatOption iE:@"r"]){
                alignment=1;
            }
            if([formatOption iE:@"c"]){ // center
                alignment=2;
            }
            if([formatOption hasSecurePrefix:@"d"]){  // drehung
                rotation = [[formatOption substringFromIndex:1]doubleValue];
            }
            [pdf setFont:lastFont size:lastSize];
            if(maxWidth){
                ms = [pdf stringOfWidth:maxWidth str:ms];
            }
            APC(@"\nBT\n");
            lastEndpos += [pdf stringWidth:ms];
            [pdf text:ms x:x y:lastYpos rotate:rotation align:alignment];
            APC(@"ET\n");
            if(debug){
                LOGS(([NSSWF @"x y = %.0f %.0f; op1 = %@",ptmm(x),ptmmFromTop(lastYpos),ms]));
            }
            continue;
        }
        if([op hasSecurePrefix:@"render"]){ //in file rendern; script kann danach mit dem file was machen
            NSData *renderedPDF = [pdf renderPDF];
            if(!renderedPDF){
                LOGI(TRANSLATION(@"Druck hat keine Seiten erzeugt"));
                continue;
            }
            [renderedPDF writeToFile:path atomically:YES];
            continue;
        }
        if([op hasSecurePrefix:@"dont_render"]){ //finischPDF davon abhalten, das PDF rendern zu wollen
            [pdf setWasRendered:YES];
            continue;
        }
        if([op hasSecurePrefix:@"ub"]){ //underline beginn;
            underlinePending = YES;
            ulx1 = 0.0;
            continue;
        }
        if([op hasSecurePrefix:@"ue"] && underlinePending){ //underline end;
            float uey = lastYpos - (mmtp(lastSize)/2.0);
            APC(([NSSWF @"%.3f %.3f m\n", ulx1, uey]));
            APC(([NSSWF @"%.3f %.3f l\n", lastEndpos, uey]));
            APC(@"S\n");
            underlinePending = NO;
            continue;
        }
        if([op iE:@"b"] || [op iE:@"bf"]){ //box b 20,45,120,40,r,jumperText,...
            float x,y,w,h,yDraw,yEnd;
            NSString *ms = EON;
            NSString *formatOption,*lineStr;
            BOOL isBf = [op iE:@"bf"];
            CHECK_PGC;
            if(isBf && !restString)continue;
            if([ops count]<(isBf?5:6))goto BADSTATEMENT;
            x =  mmtp([op1 floatValue] + xOffset);
            y =  mmtpFromTop([op2 floatValue] + yOffset);
            w =  mmtp([op3 floatValue]);
            h =  1;
            if(!isBf){
                [self setRestString:nil];
                for(ii=5,jj=[ops count];ii<jj;ii++){
                    if(ii>5)ms = [ms stringByAppendingString:@" "]; // literal comma: <comma>
                    ms = [ms stringByAppendingString:[ops oai:ii]];
                }
                if(!FILLED(ms))continue;
                [self setRestString:ms];
            }
            formatOption = [ops oai:4];
            alignment=0;
            if([formatOption iE:@"r"]){
                alignment=1;
            }
            if([formatOption iE:@"c"]){ // center
                alignment=2;
            }
            APC(@"\nBT\n");
            yDraw = y;
            yEnd = y - h;
            while(restString && (yDraw > yEnd)){
// restString parsen, ob es ein pdf-kommando ist, um Font u. groesse umzusetzen
                NSRange r = [restString rangeOfString:@"\n"];
                NSString *embed;
                if(r.length){
                    embed = [restString substringToIndex:r.location];
                    if([embed hasSecurePrefix:@".inline "]){
                        NSString *inlcmd = [embed substringFromIndex:8];
                        [self setRestString:[restString substringFromIndex:r.location + 1]];
                        if([inlcmd hasPrefix:@"f "]){ //font f Arial
                            NSString *newFont = [inlcmd substringFromIndex:2];
                            if(![newFont iE:lastFont]){
                                [lastFont release];
                                lastFont = [newFont retain];
                                [varDict setObject:lastFont forKey:@"_lastFont"];
                            }
                            continue;
                        }
                        if([inlcmd hasPrefix:@"s "]){ //size  s 12
                            NSString *ls = [inlcmd substringFromIndex:2];
                            lastSize = [ls floatValue];
                            [varDict setObject:ls forKey:@"_lastSize"];
                            continue;
                        }
// unknwon inline command
                        continue;
                    }
                }
                [pdf setFont:lastFont size:lastSize];
                lineStr = [pdf stringOfWidthFullWord:w str:restString];
                [pdf text:lineStr x:(alignment?x+w:x) y:yDraw rotate:0 align:alignment];
                yDraw -= lastSize;
                if([lineStr length] >= [restString length]){
                    [self setRestString:nil];
                }else{
                    [self setRestString:[restString substringFromIndex:[lineStr length]]];
                }
                if(!FILLED([restString stringWithoutSpace]))[self setRestString:nil]; //trailing blanks nicht extra drucken
            }
            APC(@"ET\n");
            if(debug){
                LOGS(([NSSWF @"x y w h = %.0f %.0f %.0f %.0f",ptmm(x),ptmmFromTop(y),ptmm(w),ptmm((-1 * h))]));
            }
            continue;
        }
        if([op iE:@"dg"]){
            NSString *gn;
            gn = op1;
            [dfn release];
            if([gn length] && [gn rangeOfString:@"/"].length){
                dfn = [gn retain]; // absoluter vollst. Pfad
            }else{
                //nur name relativ zum pdfImagePath; f. statische Icons wie z.B. Logos
                dfn = [[NSSWF @"%@/Images/%@",RESOURCEPATH,gn]retain];
            }
            continue;
        }
        if([op iE:@"g"] || [op iE:@"gw"] || [op iE:@"gh"]){ //grafik g 1275,80,400,logo.jpg -> x,y,breite,pfad
//gh = grafik height; hoehe angeben statt breite
            float imgw=0.0,imgh=0.0,x,y;
            NSString *fn,*gn;
            CHECK_PGC;
            if([ops count]!=4)goto BADSTATEMENT;
            gn = op4;
            if([gn length] && [gn hasSecurePrefix:@"/"]){
                fn = gn; // absoluter vollst. Pfad
            }else{
                //nur name relativ zum pdfImagePath; f. statische Icons wie z.B. Logos
                fn = [NSSWF @"%@/Images/%@",RESOURCEPATH,gn];
            }
            x =  mmtp([op1 floatValue] + xOffset);
            y =  mmtpFromTop([op2 floatValue] + yOffset);
            if([op iE:@"gh"]){
                imgh = mmtp([op3 floatValue]);
            }else{
                imgw = mmtp([op3 floatValue]);
            }
            [pdf jpeg:fn x:x y:y  w:&imgw h:&imgh];
            if(debug){
                LOGS(([NSSWF @"x y w = %.0f %.0f %.0f; fn = %@",ptmm(x),ptmmFromTop(y),ptmm(imgw),fn]));
            }
            continue;
        }
BADSTATEMENT:
        LOGS(([NSSWF @"%@:?? ---->%@<----",lookupName,s]));
        LOGS(([NSSWF @"?? ---->%@<----",[s hexFormat]]));
    }
    NS_HANDLER;
    LOGS_Ex(([NSSWF @"in executeScript"]));
    NS_ENDHANDLER;
    if(pdf){
        [dfn release];
        [dash release];
        [lastFont release];
    }
    [localPool release];
//  wenn dialogMode, Status des Scripts in Session speichern in der Hoffnung, dass diese Objekte mit archiviert u. auch wieder aktiviert werden; danach geht es auf jeden fall im continueScript weiter;
    if([_SESSION dialogMode]){
        [_SESSION setCs_v:v];
        [_SESSION setCs_a:a];
        [_SESSION setCs_datasource:datasource];
        [_SESSION setCs_p_parmDict:p_parmDict];
        [_SESSION setCs_stack:stack];
        [_SESSION setCs_varDictStack:varDictStack];
        [_SESSION setCs_varDict:varDict];
        [_SESSION setCs_localVarDict:localVarDict];
        [_SESSION setCs_foreachStack:foreachStack];
        [_SESSION setCs_debug:debug];
        [_SESSION setCs_i:i];
        [_SESSION setCs_j:j];
    }else{
        if([[[_APP configDict]ofk:@"logscriptnames"]iE:@"J"] && ![v rangeOfString:@"-"].length){
            LOG(([NSSWF @"<%@ end %@ %@",[@"---------------------" secureSubstringToIndex:[_SESSION scriptStackDepth]],scriptTyp,v]));
        }else{
            if([_APP logActions] && ([_SESSION scriptStackDepth]==1)){
                LOG(([NSSWF @"<- end Script %@",v]));
            }
        }
        [_SESSION dec_scriptStackDepth];
        [scriptNames secureRemoveLastObject];
    }
    return varDict;
}
- (NSString *)scriptValueForTarget:co andMethod:(NSString *)kp;
{
    id rw = EON;
    NSMethodSignature *sig;
    NSInvocation *invk;
    SEL sel = SECURE_SELECTOR_FROM_STRING(kp);
    const char *type;
    if(!sel)return EON;
    if(![co respondsToSelector:sel])return EON;
    sig = [co methodSignatureForSelector:sel];
    if(!sig)return EON;
    invk = [NSInvocation invocationWithMethodSignature:sig];
    [invk setTarget:co];
    [invk setSelector:sel];
    [invk invoke];
    type = [sig methodReturnType];
    if (*type == 'r') type++; /* skip const qualifier */
        switch (*type) {
            case _C_ID:
            case _C_CLASS:
              {
                  [invk getReturnValue: &rw];
                  return rw;
              }
            case _C_SEL:
              {
                  SEL v;
                  [invk getReturnValue: &v];
                  rw = NSStringFromSelector(v);
                  return rw;
              }
            case _C_CHR:  /* We assume bool (Apple) */
              {
                  BOOL v;
                  [invk getReturnValue: &v];
                  rw = (v) ? @"J" : @"N";
                  return rw;
              }
            case _C_UCHR:  /* We assume bool (GNU) */
              {
                  unsigned char v;
                  [invk getReturnValue: &v];
                  rw = (v) ? @"J" : @"N";
                  return rw;
              }
            case _C_SHT:
              {
                  short v;
                  [invk getReturnValue: &v];
                  rw = NSS(v);
                  return rw;
              }
            case _C_USHT:
              {
                  unsigned short v;
                  [invk getReturnValue: &v];
                  rw = NSS(v);
                  return rw;
              }
            case _C_INT:
              {
                  int v;
                  [invk getReturnValue: &v];
                  rw = NSS(v);
                  return rw;
              }
            case _C_UINT:
              {
                  unsigned int v;
                  [invk getReturnValue: &v];
                  rw = NSS(v);
                  return rw;
              }
            case _C_LNG:
              {
                  long v;
                  [invk getReturnValue: &v];
                  rw = NSS(v);
                  return rw;
              }
            case _C_ULNG:
              {
                  unsigned long v;
                  [invk getReturnValue: &v];
                  rw = NSS(v);
                  return rw;
              }
            case _C_FLT:
              {
                  float v;
                  double d;
                  [invk getReturnValue: &v];
                  d = v; /* insure promotion rules are used correctly  */
                  rw = NSSD(d);
                  return rw;
              }
            case _C_DBL:
              {
                  double v;
                  [invk getReturnValue: &v];
                  rw = NSSD(v);
                  return rw;
              }
            case _C_PTR:
              {
                  void *v;
                  [invk getReturnValue: &v];
                  rw = [NSValue valueWithPointer: v];
                  return rw;
              }
            case _C_CHARPTR:
              {
                  char *v;
                  [invk getReturnValue: &v];
                  rw = [NSString stringWithCString: v];
                  return rw;
              }
            case _C_VOID:
              {
                  rw = EON;
                  return rw;
              }
        }
        return rw;
}
@end
@implementation Application (Kalender)
- (NSString *)isFeiertag:(NSString *)s;
{
// feiertagDict fuellen mit Datum und Name
    if(!s)return nil;
    s = [s secureSubstringToIndex:8];
    return [feiertagDict ofk:s];
}
- (void)renderTermine:(NSArray *)currentTermine into:(NSMutableArray *)alles viewType:(int)viewType;
{
    NSString *linkf = @"<a style=\"white-space:normal; font-size:x-small;\" onClick=\"{ document.forms[0].clicked_event.value='%@'; document.forms[0].clicked_event_entity.value='%@'; sbm('action_script_clicked_event');}\" href=\"#\"  title=\"%@\">%@</a>";
    int i2,j2;
    for(i2=0,j2=[currentTermine count];i2<j2;i2++){
        TerminO *currentTermin = [currentTermine oai:i2];
        NSString *s;
        [alles addObject:[NSSWF @"<div class=\"KalenderTermin\" style=\"background-color:%@;\">", [[currentTermin empfaenger]vfk:@"farbe"]]];
        [alles addObject:[NSSWF @"<span><img src=\"%@\" title=\"%@\">%@</span>",[currentTermin statusIconName],[currentTermin statusName],[currentTermin zeit]]];
        [alles addObject:[currentTermin wiedervorlageS]];
        [alles addObject:[currentTermin privatS]];
        [alles addObject:[[currentTermin owner]vfk:@"kuerzel"]];
        [alles addObject:[[currentTermin empfaenger]vfk:@"kuerzel"]];
        if([currentTermin isHighPrio])[alles addObject:@"<span style=\"color:red;\">!!</span>"];
        [alles addObject:@"<br>"];
        s = [currentTermin beschreibung];
        if(viewType==viewTypeD){
            s = [s abbrevToLength:120];
        }else{
            s = [s abbrevToLength:60];
        }
        [alles addObject:[NSSWF linkf,[[currentTermin coveredEO]primaryKey],[[currentTermin coveredEO]entityName],TRANSLATION(@"zum Termin"),[s htmlEscapedString]]];
        [alles addObject:@"</div>"];
    }
}
- (void)renderWochentageInto:(NSMutableArray *)alles;
{
    NSString *workdayf = @"<td class=\"KalenderHeader\">%@</td>";
    NSString *sundayf = @"<td class=\"KalenderHeaderSunday\">%@</td>";
    [alles addObject:@"<tr bgcolor=#EDEDED>"];
    [alles addObject:[NSSWF @"<td class=\"KalenderHeaderKW\">%@</td>",TRANSLATION(@"KW")]];
    [alles addObject:[NSSWF workdayf,TRANSLATION(@"Montag")]];
    [alles addObject:[NSSWF workdayf,TRANSLATION(@"Dienstag")]];
    [alles addObject:[NSSWF workdayf,TRANSLATION(@"Mittwoch")]];
    [alles addObject:[NSSWF workdayf,TRANSLATION(@"Donnerstag")]];
    [alles addObject:[NSSWF workdayf,TRANSLATION(@"Freitag")]];
    [alles addObject:[NSSWF workdayf,TRANSLATION(@"Samstag")]];
    [alles addObject:[NSSWF sundayf,TRANSLATION(@"Sonntag")]];
    [alles addObject:@"</tr>"];
}
- (void)kalender:(PBWOEditor *)datasource;
{
// termine in ma rendern; ist ein Portlet;
// parmDict: startingDate, viewType; parameter der Buttons
// kalenderHTML
    LMAN(alles); // hier kommt fertiges html rein
    int viewType = [[[datasource parmDict] ofk:@"viewType"]intValue];
    NSString *startingDate = [[datasource parmDict] ofk:@"startingDate"];
    NSString *buttonf = @"<a onClick=\"sbm('action_script_%@');\" href=\"#\" class=\"PBActionLink\" title=\"%@\">%@</a>";
    NSString *buttonfp = @"<a onClick=\"{ document.forms[0].%@.value='%@'; sbm('action_script_%@');}\" href=\"#\" class=\"PBActionLink\" title=\"%@\">%@</a>";
    NSString *buttonfpa = @"<a onClick=\"{ document.forms[0].%@.value='%@'; sbm('action_script_%@');}\" href=\"#\" class=\"PBActionLinkActive\" title=\"%@\">%@</a>";
    NSString *buttonfp_kal = @"<a onClick=\"{ document.forms[0].%@.value='%@'; sbm('action_script_%@');}\" href=\"#\" class=\"PBActionLinkKal\" title=\"%@\">%@</a>";
    NSString *zeitraumf = @"<INPUT id=target116 onFocus=document.forms[0].submitter.value='action_script_kalender_gehe_zu'; size=10 type=text style=\"font-size:10pt;\" title='gehe zu' name=\"PortletKalender_gehe_zu\" >";  // ESC-T fuer Tag eingeben
    int startingYear,startingMonth;
    int kw;
    PBDate *startingPBDate,*renderDate,*pbd;
    int i,i1;
    LMDN(termine); // pro Tag ein Array von termin objects
    BOOL uebernehmen = [[[datasource parmDict]ofk:@"uebernehmen"]iE:@"J"];
    if(!FILLED(startingDate))startingDate = [_APP today];
    {
// zeitlich in Frage kommende Termine besorgen; zusaetzlich gefiltert um custom Qualifiers
        LMAN(lmaq);
        PBSQLQualifier *q;
        NSString *startingDateT,*endingDate;
        LMAN(tos); // termine objects
        pbd = [PBDate dateWithDBString:startingDate];
        if(viewType == viewTypeD){
            startingDateT = startingDate;
            [pbd addDay:1];
        }else if(viewType == viewTypeW){
            [pbd prevMonday];
            startingDateT = [pbd dateAsDBString];
            [pbd addDay:7];
        }else{
            [pbd erster];
            startingDateT = [pbd dateAsDBString];
            [pbd addDay:42];
        }
        endingDate = [pbd dateAsDBString];
        q = [PBSQLQualifier qualifierWithString:[NSSWF @"(termin >= '%@' and termin < '%@') or (terminb > 0 and (termin <= '%@' and terminb >= '%@'))",startingDateT,endingDate,endingDate,startingDateT]];
        [lmaq addObject:q];
        q = [PBSQLQualifier qualifierWithString:[NSSWF @"(privat = 'N' or empfaenger = '%@')",CURRENTUSER]];
        [lmaq addObject:q];
        [[datasource parmDict] setObject:lmaq forKey:@"p_kalender_qarray"]; // f. Custom-Script, um eigene Qualifiers hinzuzufĂĽgen
        [_APP executeScriptNamed:@"akte/addCustomQualifiers" datasource:datasource parmDict:[datasource parmDict]];
        q = [PBSQLQualifier andQualifierWithArray:lmaq];
        [tos addObjectsFromArray:[_APP termineFromEOs:getEOsQ(@"akte",q)]];
        [[datasource parmDict] setObject:tos forKey:@"p_kalender_termine"]; // f. Custom-Script
        [_APP executeScriptNamed:@"akte/addCustomTermine" datasource:datasource parmDict:[datasource parmDict]];
        {
// auf Tage einsortieren
            int i,j;
            TerminO *to;
            NSMutableArray *lma;
            for(i=0,j=[tos count];i<j;i++){
                NSString *termin_date;
                to = [tos oai:i];
                termin_date = [[to termin]secureSubstringToIndex:8]; // evt. Zeit abschneiden;
                lma = [termine ofk:termin_date];
                if(!lma){
                    lma = [NSMutableArray arrayWithCapacity:10];
                    [termine setSecureObject:lma forKey:termin_date]; // array von Terminobjekten pro Tag
                }
                [lma addObject:to];
            }
        }
        [[termine allObjects]makeObjectsPerformSelector:@selector(sort)];
    }
    startingPBDate = [startingDate pbdate];
    startingYear = [startingPBDate year];
    startingMonth = [startingPBDate month];
    [alles addObject:@"<div>"];
    [alles addObject:[NSSWF buttonf,@"clicked_today",TRANSLATION(@"auf Tagesdatum positionieren"),TRANSLATION(@"Heute")]];
    [alles addObject:@"--"];
// parm-name, parm-value, action-name,tool-tip,gui
    [alles addObject:[NSSWF buttonfp,@"clicked_year",NSS(startingYear-1),@"clicked_year",TRANSLATION(@"auf Jahr"),NSS(startingYear-1)]];
    [alles addObject:[NSSWF buttonfpa,@"clicked_year",NSS(startingYear),@"clicked_year",TRANSLATION(@"auf Jahr"),NSS(startingYear)]];
    [alles addObject:[NSSWF buttonfp,@"clicked_year",NSS(startingYear+1),@"clicked_year",TRANSLATION(@"auf Jahr"),NSS(startingYear+1)]];
    [alles addObject:@"--"];
// Monats-Buttons
    for(i=1;i<=12;i++){
        NSString *f = buttonfp;
        if(i==startingMonth)f=buttonfpa;
        [alles addObject:[NSSWF f,@"clicked_month",([NSSWF @"%02i",i]),@"clicked_month",TRANSLATION(@"auf Monat"),[startingPBDate monthNameFor:i]]];
    }
    [alles addObject:@"--"];
    [alles addObject:[NSSWF buttonf,@"clicked_backward",TRANSLATION(@"Frueher"),@"<<<"]];
    [alles addObject:[NSSWF buttonf,@"clicked_forward",TRANSLATION(@"Spaeter"),@">>>"]];
    [alles addObject:@"--"];
    [alles addObject:zeitraumf];
    [alles addObject:@"<br>"];
    [alles addObject:@"<table class=Kalender>"];
    switch(viewType){
        case 1:	// Woche
            [self renderWochentageInto:alles];
            renderDate = [startingDate pbdate];
            [renderDate prevMonday];
            kw = [renderDate weekOfYear];
            [alles addObject:@"<tr bgcolor=#f8f8f8>"];
            [alles addObject:@"<td style=\"padding:0px;\" bgcolor=#EDEDED valign=top>"];
            [alles addObject:[NSSWF buttonfp,@"clicked_week",NSS(kw),@"clicked_week",TRANSLATION(@"zur Woche"),NSS(kw)]];
            [alles addObject:@"</td>"];
//Tage der Wochen
            for(i1=0;i1<7;i1++){
                NSString *renderDateDB = [renderDate dateAsDBString];
                NSString *ft = [_APP isFeiertag:renderDateDB];
                if([[_APP today] iE:renderDateDB]){
                    [alles addObject:@"<td valign=top bgcolor=#D3D434 height=70>"];
                }else{
                    [alles addObject:@"<td valign=top height=70>"];
                }
                if(uebernehmen){
                    [alles addObject:[NSSWF buttonfp_kal,@"clicked_day",renderDateDB,@"uebernehmen",TRANSLATION(@"uebernehmen"),@"ueb"]];
                }else{
                    [alles addObject:[NSSWF buttonfp_kal,@"clicked_day",renderDateDB,@"add_event",TRANSLATION(@"neuer Termin hier"),@"+"]];
                }
                [alles addObject:[NSSWF buttonfp_kal,@"clicked_day",renderDateDB,@"clicked_day",TRANSLATION(@"Tagessicht"),NSS([renderDate day])]];
                if(!ft)ft=@"&nbsp;";
                [alles addObject:[NSSWF @" <span class=\"Feiertag\">%@</span>",ft]];
                [self renderTermine:[termine ofk:[renderDateDB secureSubstringToIndex:8]] into:alles viewType:viewType];
                [alles addObject:@"</td>"];
                [renderDate addDay:1];
            }
            [alles addObject:@"</tr>"];
            break;
        case 2:	// Tag
            renderDate = [startingDate pbdate];
          {
              NSString *workdayf = @"<td class=\"KalenderHeaderW\">%@</td>";
              NSString *sundayf = @"<td class=\"KalenderHeaderSundayW\">%@</td>";
              NSString *fwdn = [renderDate fullWeekdayName];
              [alles addObject:@"<tr bgcolor=#EDEDED>"];
              [alles addObject:[NSSWF @"<td class=\"KalenderHeaderKW\">%@</td>",TRANSLATION(@"KW")]];
              if(![fwdn iE:@"Sonntag"]){
                  [alles addObject:[NSSWF workdayf,TRANSLATION(fwdn)]];
              }else{
                  [alles addObject:[NSSWF sundayf,TRANSLATION(fwdn)]];
              }
              [alles addObject:@"</tr>"];
              kw = [renderDate weekOfYear];
              [alles addObject:@"<tr bgcolor=#f8f8f8>"];
              [alles addObject:@"<td style=\"padding:0px;\" bgcolor=#EDEDED valign=top>"];
              [alles addObject:[NSSWF buttonfp,@"clicked_week",NSS(kw),@"clicked_week",TRANSLATION(@"zur Woche"),NSS(kw)]];
              [alles addObject:@"</td>"];
              {
                  NSString *renderDateDB = [renderDate dateAsDBString];
                  NSString *ft = [_APP isFeiertag:renderDateDB];
                  if([[_APP today] iE:renderDateDB]){
                      [alles addObject:@"<td valign=top bgcolor=#D3D434 height=70>"];
                  }else{
                      [alles addObject:@"<td valign=top height=70>"];
                  }
                  if(uebernehmen){
                      [alles addObject:[NSSWF buttonfp_kal,@"clicked_day",renderDateDB,@"uebernehmen",TRANSLATION(@"uebernehmen"),@"ueb"]];
                  }else{
                      [alles addObject:[NSSWF buttonfp_kal,@"clicked_day",renderDateDB,@"add_event",TRANSLATION(@"neuer Termin hier"),@"+"]];
                  }
                  [alles addObject:[NSSWF buttonfp_kal,@"clicked_day",renderDateDB,@"clicked_day",TRANSLATION(@"Tagessicht"),NSS([renderDate day])]];
                  if(!ft)ft=@"&nbsp;";
                  [alles addObject:[NSSWF @" <span class=\"Feiertag\">%@</span>",ft]];
                  [self renderTermine:[termine ofk:[renderDateDB secureSubstringToIndex:8]] into:alles viewType:viewType];
                  [alles addObject:@"</td>"];
              }
              break;
          }
        default:	// Monat ----------------------------------------
            [self renderWochentageInto:alles];
//Wochen im Monat
            for(i=0;i<6;i++){
                [alles addObject:@"<tr bgcolor=#f8f8f8>"];
                [alles addObject:@"<td style=\"padding:0px;\" bgcolor=#EDEDED valign=top>"];
                renderDate = [startingDate pbdate];
                [renderDate erster];
                [renderDate prevMonday];
                [renderDate addWeek:i];
                kw = [renderDate weekOfYear];
// parm-name, parm-value, action-name,tool-tip,gui
                [alles addObject:[NSSWF buttonfp,@"clicked_week",NSS(kw),@"clicked_week",TRANSLATION(@"zur Woche"),NSS(kw)]];
                [alles addObject:@"</td>"];
                
//Tage der Wochen
                for(i1=0;i1<7;i1++){
                    NSString *renderDateDB = [renderDate dateAsDBString];
                    if([renderDate month]==startingMonth){
                        NSString *ft = [_APP isFeiertag:renderDateDB];
                        if([[_APP today] iE:renderDateDB]){
                            [alles addObject:@"<td valign=top bgcolor=#D3D434 height=70>"];
                        }else{
                            [alles addObject:@"<td valign=top height=70>"];
                        }
                        if(uebernehmen){
                            [alles addObject:[NSSWF buttonfp_kal,@"clicked_day",renderDateDB,@"uebernehmen",TRANSLATION(@"uebernehmen"),@"ueb"]];
                        }else{
                            [alles addObject:[NSSWF buttonfp_kal,@"clicked_day",renderDateDB,@"add_event",TRANSLATION(@"neuer Termin hier"),@"+"]];
                        }
                        [alles addObject:[NSSWF buttonfp_kal,@"clicked_day",renderDateDB,@"clicked_day",TRANSLATION(@"Tagessicht"),NSS([renderDate day])]];
                        if(!ft)ft=@"&nbsp;";
                        [alles addObject:[NSSWF @" <span class=\"Feiertag\">%@</span>",ft]];
                        [self renderTermine:[termine ofk:[renderDateDB secureSubstringToIndex:8]] into:alles viewType:viewType];
                    }else{
                        [alles addObject:@"<td valign=top bgcolor=#EDEDED height=70>"];
                    }
                    [alles addObject:@"</td>"];
                    [renderDate addDay:1];
                }
                [alles addObject:@"</tr>"];
            }
    }
    [alles addObject:@"</table>"];
    [alles addObject:@"</div>"];
    [alles addObject:@"<input name=\"clicked_week\" type=\"hidden\">"];
    [alles addObject:@"<input name=\"clicked_day\" type=\"hidden\">"];
    [alles addObject:@"<input name=\"clicked_month\" type=\"hidden\">"];
    [alles addObject:@"<input name=\"clicked_year\" type=\"hidden\">"];
    [alles addObject:@"<input name=\"clicked_event\" type=\"hidden\">"];
    [alles addObject:@"<input name=\"clicked_event_entity\" type=\"hidden\">"];
    [[datasource parmDict]setObject:[alles componentsJoinedByString:@""] forKey:@"kalenderHTML"];
}
- (NSArray *)termineFromEOs:(NSArray *)a;
{
//eos von gleicher entity
    int i,j;
    NSString *en;
    LMA;
    PBEO *eo;
    TerminO *to;
    j = [a count];
    if(!j)return nil;
    en = [[a oai:0]entityName];
    for(i=0;i<j;i++){
        eo = [a oai:i];
        if([en iE:@"akte"]){  //normale Termine
            NSString *von = [eo vfk:@"termin"],*bis = [eo vfk:@"terminb"];
            if(FILLED(von)){
                PBDate *pbd = [PBDate dateWithDBString:von],*pbd_von = [PBDate dateWithDBString:von],*pbd_bis=nil;
                int i_von=[pbd_von dateAsLong];
                int i_bis=i_von,i_max;
                NSString *terminv = [pbd_von dateAsDBString];
                NSString *terminzeitv = [pbd_von timeAsString];
                NSString *terminb=@"",*terminzeitb=@"";
                if(FILLED(bis)){
                    pbd_bis = [PBDate dateWithDBString:bis];
                    i_bis=[pbd_bis dateAsLong];
                    terminb=[pbd_bis dateAsDBString];
                    terminzeitb=[pbd_bis timeAsString];
                }
                if(i_bis < i_von)i_bis = i_von;
                for(i_max=0;i_von <= i_bis && i_max < 60;i_von++,i_max++){
                        // zur Sicherheit: Termine max. 60 Tage lang
                    if((to = [[TerminO alloc]init])){
                        [to setTermin:[pbd dateAsDBString]]; // f. einsortieren
                        [to setTerminv:terminv]; // f. Anzeige
                        [to setTerminzeitv:terminzeitv];
                        [to setStatus:[[eo vfk:@"aktenstatus"]intValue]];
                        [to setBeschreibung:[eo vfk:@"aktentext"]];
                        [to setStichworte:[[eo values]ofk:@"stichworte"]];
                        [to setTerminb:terminb];
                        [to setTerminzeitb:terminzeitb];
                        [to setCoveredEO:eo];
                        [to setOwner:[eo dot:@"owner"]];
                        [to setEmpfaenger:[eo dot:@"empfaenger"]];
                        [to setPrio:[[eo vfk:@"aktenprio"]intValue]];
                        [to setWiedervorlage:[[eo vfk:@"wiedervor"]iE:SC_BOOL_TRUE]];
                        [to setPrivat:[[eo vfk:@"privat"]iE:SC_BOOL_TRUE]];
                        [lma addObject:to];
                        [to release];
                    }
                    [pbd addDay:1];
                }
            }
        }
    }
    return lma;
}
@end
@implementation Application (DB)
- (void)createNPPModel;
{
// ein ASCII File erzeugen mit allen Tabellen und Attributen des Modells fuer den notepad++ zum besseren Editieren von scripts
// phys. tabellen aufsteigend sortiert, plainAttributes mit $table.dbName,=, jew. mit Label davor
    NSArray *ts = [[myDD tables]sortedArrayUsingKeyOrderArray:[NSArray soaFrom:@"dbName"]];
    int i,j;
    NSString *fn = [NSSWF @"%@/nppModel.script",MANDANTPATH];
    LMA;
    for(i=0,j=[ts count];i<j;i++){
        PBDDTable *t = [ts oai:i];
        NSArray *attrs = [t plainAttributes];
        int i1,j1;
        [lma addObject:[NSSWF @"label %@ %@",[t dbName],[t guiName]]];
        for(i1=0,j1=[attrs count];i1<j1;i1++){
            [lma addObject:[NSSWF @"$%@.%@,=,x",[t dbName],[[attrs oai:i1]dbName]]];
        }
    }
    [[lma componentsJoinedByString:@"\n"]WTF:fn];
}
- (BOOL)isReferencedEO:(PBEO *)eo;
{
// ermittelt, ob eo von einem anderen referenziert wird
    if(!eo)return NO;
    if(![eo isKindOfClass:[PBEO class]])return NO;
    {
        PBDDTable *t = [eo myTable];
        NSArray *a = [t attributesReferencingMe];
        int i,j;
        for(i=0,j=[a count];i<j;i++){
            PBDDAttribute *pba = [a oai:i];
            NSString *sql;
            NSString *s;
            NSString *pkn = [[pba myTable]primaryKeyName];
            if(!FILLED(pkn))continue;
            sql = [NSSWF @"select %@ from %@ where %@ = '%@' limit 1",pkn,[[pba myTable]dbName],[pba dbName],[eo primaryKey]];
            s = singleValueSQL(sql);
            if(FILLED(s))return YES;
        }
    }
    return NO;
}
- (NSArray *)referencingEO:(PBEO *)eo;
{
// liefert ein Array von Dictionaries aller Tabellen mit primary Keys, die auf das eo verweisen; max. 100 insges.
// max. 10 pro Tabelle
// fuer Portlet "Objektverwendung"
// nach cdate absteigend sortiert soweit moeglich
    LMA;
    if(!eo)return lma;
    if(![eo isKindOfClass:[PBEO class]])return lma;
    {
        PBDDTable *t = [eo myTable];
        NSArray *a = [t attributesReferencingMe];
        int i,j;
        for(i=0,j=[a count];i<j;i++){
            PBDDAttribute *pba = [a oai:i];
            NSString *tableName = [[pba myTable]dbName];
            NSString *guiTableName = [[pba myTable]guiName];
            NSString *guiName = [pba guiName];
            NSString *dbName = [pba dbName];
            NSString *sql;
            NSArray *a1;
            int i1,j1;
            if([[pba myTable]plainAttrNamed:@"cdate"]){
                sql = [NSSWF @"select %@ from %@ where %@ = '%@' order by cdate desc limit 10",[[pba myTable]primaryKeyName],tableName,[pba dbName],[eo primaryKey]];
            }else{
                sql = [NSSWF @"select %@ from %@ where %@ = '%@' limit 10",[[pba myTable]primaryKeyName],tableName,[pba dbName],[eo primaryKey]];
            }
            a1 = [_APP getStringArrayAsResultFrom:sql];
            for(i1=0,j1=[a1 count];i1<j1;i1++){
                NSString *pk = [a1 oai:i1];
                LMD;
                [lmd setObject:pk forKey:@"primaryKey"];
                [lmd setObject:tableName forKey:@"tableName"];
                [lmd setObject:guiTableName forKey:@"guiTableName"];
                [lmd setObject:guiName forKey:@"guiName"];
                [lmd setObject:dbName forKey:@"dbName"];
                [lma addObject:lmd];
                if([lma count]>= 100)return lma;
            }
        }
    }
    return lma;
}
- (NSString *)attributAuflistungForTable:(PBDDTable *)t withDoku:(BOOL)withDoku;
{
    NSString *s = EON;
    int ii,jj;
    NSArray *a1 = [t plainAttributes];
    s = [s stringByAppendingFormat:@"----Tabelle %@ hat diese Attribute:\n\n",[t dbName]];
        for(ii=0,jj=[a1 count];ii<jj;ii++){
            PBDDAttribute *pba = [a1 oai:ii];
            NSString *refdTableName,*line;
            if(![pba isVisible])continue;
            if([pba targetTyp] != ATTVCSELOBJ)continue;
            refdTableName = [pba refdTableName];
            line = [NSSWF @"%%selObj.%@                                                        ",[pba dbName]];
            line = [line substringToIndex:50];
            if(FILLED(refdTableName)){
                s = [s stringByAppendingFormat:@"%@  %@ --->%@\n",line,[pba guiName],refdTableName];
            }else{
                s = [s stringByAppendingFormat:@"%@  %@\n",line,[pba guiName]];
            }
            if([pba hasVL]){
                int i1,j1;
                s = [s stringByAppendingString:@"\tNV:::\n"];
                for(i1=0,j1=[[pba vl] count];i1<j1;i1++){
                    PBVLO *pbvlo = [[pba vl]oai:i1];
                    s = [s stringByAppendingFormat:@"\t%@\t%@\n",[pbvlo value],[pbvlo bez]];
                }
            }
            if(withDoku){
                NSString *doku = [pba doku0];
                if(FILLED(doku))s = [s stringByAppendingFormat:@"\t%@\n",doku];
            }
        }
        return s;
}
- (NSString *)descriForEn:(NSString *)en pk:(NSString *)pk;
{
    NSString *sql,*s=nil,*guiValue;
    PBDDAttribute *da;
    NSArray *a;
    PBDDTable *t;
    int i,j;
    NSDictionary *d;
    if(!en || !pk)return EON;
    t = [MYDD tableNamedCheap:en];
    if(!t)return EON;
    a = [t descriAttributes];
    if(![a count])return EON;
    sql = [NSSWF @"select %@ from %@ where %@ = '%@'",[[a valuesForKey:@"dbName"]componentsJoinedByString:@","],en,[t primaryKeyName],[pk mysqlEscapedString]];
    d = [self getDictAsResultFrom:sql];
    if(!d)return EON;
    for(i=0,j=[a count];i<j;i++){
        da = [a oai:i];
        guiValue = [d ofk:[da dbName]];
        if(!s){
            s = guiValue;
        }else{
            if([da hasVL]){
                guiValue = [da bezeichnungForValue:guiValue];
            }
            s = [s stringByAppendingFormat:@"-%@",guiValue];
        }
    }
    if(!s)s = EON;
    return [s abbreviated40String];
}
///////////////////////////////////////////////////////////////////////////////////////////
//	sequentielle Verarbeitungen
///////////////////////////////////////////////////////////////////////////////////////////
- (void)addFetchRequest:(NSDictionary *)fetchReq forHandle:(NSString *)handle;
{
    if(!handle || !fetchReq)return;
    if([seqAccesses ofk:handle]){
        LOGS(([NSSWF @"handle %@ bereits in Gebrauch;",handle]));
        return;
    }
    [seqAccesses setSecureObject:fetchReq forKey:handle];
}
- (NSDictionary *)fetchReqForHandle:(NSString *)handle;
{
    return [seqAccesses ofk:handle];
}
- (void)endFetchingForHandle:(NSString *)handle;
{
    NSDictionary *fetchReq = [self fetchReqForHandle:handle];
    PBMySQLChannel *ac;
    if(!fetchReq)return;
    ac = [fetchReq objectForKey:SC_channel];
    if([ac isFetchInProgress])[ac cancelFetch];
    [seqAccesses removeObjectForKey:handle];
}
- (BOOL)establishConnection;
{
    [self closeAllChannels];
    if(([self freshChannel]!=nil)){
        return YES;
    }else{
        LOGS(@"freshChannel nicht bekommen");
    }
    return NO;
}
- (BOOL)setFetchCond:(PBSQLQualifier *)q forTable:(PBDDTable *)myTable soa:(NSArray *)soa handle:(NSString *)handle;
{
    return [self setFetchCond:(PBSQLQualifier *)q forTable:(PBDDTable *)myTable soa:(NSArray *)soa handle:(NSString *)handle limit:0];
}
- (BOOL)setFetchCond:(PBSQLQualifier *)q forTable:(PBDDTable *)myTable soa:(NSArray *)soa handle:(NSString *)handle limit:(int)limit;
{
    PBMySQLChannel *ac;
    NSDictionary *fetchReq;
    NSString *wc,*lc = @"";
    NSString *s;
    NSString *ttn;
    if(!handle){
        LOGS((@"handle nicht angegeben"));
        return NO;
    }
    [self endFetchingForHandle:handle]; //zur sicherheit evt. alte handle beenden
    wc = [q string];
    if(!wc)wc=@"";
    if(FILLED(wc))wc = [NSSWF @" where %@",wc];
    if(limit)lc = [NSSWF @" limit %i",limit];
    //temp table aufbauen, gesamten Satz reinstellen;
    //damit muss nicht nochmal mit pk auf echte Table zugegriffen werden
    ttn = [[NSSWF @"tmp_%@",handle]lowercaseString]; //lower, da tablenamen generell lowercase gemacht werden
    [self evaluateSQL:[NSSWF @"drop temporary table if exists %@",ttn]];
    s = [NSSWF @"create temporary table %@ select * from %@ %@ %@",ttn,[myTable dbName],wc,lc];
    if(![self evaluateSQL:s])return NO;
    if(!(ac = [self freshChannel]))return NO;
    if(![ac selectQualifier:nil forTable:myTable tn:ttn offset:0 count:0 soa:soa])return NO;
    fetchReq = [NSDictionary dwok:ac,SC_channel,myTable,SC_pbt,@"YES",@"forUpdate",nil,nil];
    [self addFetchRequest:fetchReq forHandle:handle];
    return YES;
}
- (PBEO *)nextEOForHandle:(NSString *)handle;
{
    //liefert autoreleastes EO;
    // daher immer schoen mit AutoreleasePools arbeiten;
    // nach dem letzten wird fetch autom. endFetchingForHandle: gemacht
    //letzte erfolgreich verwendete channel wird gemerkt f. evt. update
    NSDictionary *fetchReq = [self fetchReqForHandle:handle];
    PBDDTable *myTable = (PBDDTable *)[fetchReq objectForKey:SC_pbt];
    NSString *entityName = [myTable dbName],*pk;
    NSMutableDictionary *md;
    PBEO *eo=nil;
    PBMySQLChannel *ac;
    if(!fetchReq || !myTable){
        LOG(@"no fetchReq or table");
        return nil;
    }
    ac = [fetchReq objectForKey:SC_channel];
    if(![ac isFetchInProgress]){
        [self endFetchingForHandle:handle];
        return nil;
    }
    if(!(md=[ac fetchRow])){ //den naechsten key aus temp-table
        [self endFetchingForHandle:handle];
    }else{
        //md stammt evt. aus temptable, ist aber vollstaendig;
        pk = [md ofk:[myTable primaryKeyName]];
        eo = [self eoFromDict:md entityName:entityName];
        [eo setWasFetched:YES];
    }
    return eo;
}
- (NSMutableDictionary *)nextMDForHandle:(NSString *)handle;
{
    //liefert autoreleastes md;
    NSDictionary *fetchReq = [self fetchReqForHandle:handle];
    NSMutableDictionary *md;
    PBMySQLChannel *ac;
    if(!fetchReq)return nil;
    ac = [fetchReq objectForKey:SC_channel];
    if(![ac isFetchInProgress]){
        [self endFetchingForHandle:handle];
        return nil;
    }
    if(!(md=[ac fetchRow])){ //den naechsten key aus temp-table
        [self endFetchingForHandle:handle];
    }
    return md;
}
///////////////////////////////////////////////////////////////////////////////////////////
// 		EO-Umformungen
///////////////////////////////////////////////////////////////////////////////////////////
- (PBEO *)eoFromDict:(NSDictionary *)d entityName:(NSString *)entityName;
{
    PBEO *eo;
    
    eo = [[[PBEO alloc]initWithEntityName:entityName]autorelease];
    if(!eo)return nil;
    [eo useValuesFromDictionary:d];
    return eo;
}
- (NSDictionary *)dictFromEO:(PBEO *)eo forKeys:(NSDictionary *)keyDict;
{
// gewaehrleistet, dass nur DB-Felder im Dict sind; EO-Feldinhalte sind MySQL kompatibel
    PBDDTable *myTable = [eo myTable];
    NSArray *a = [keyDict allKeys];
    PBDDAttribute *pba;
    NSString *k;
    NSString *s;
    int i,j;
    LMD;
    if(![a count]){
	// kein keyDict, ganzes EO
        a = [myTable attributesDB];
        for(i=0,j=[a count];i<j;i++){
            pba = [a oai:i];
            k = [pba dbName];
            s = [eo vfk:k];
            if(!FILLED(s)){
                [lmd setSecureObject:EON forKey:k];
                continue;
            }
            [lmd setSecureObject:s forKey:k];
        }
    }else{
	// das viel kleinere keyDict abarbeiten
        for(i=0,j=[a count];i<j;i++){
            k = [a oai:i];
            pba = [myTable plainAttrNamed:k];
            if(!pba)continue; // nicht in Tabelle
            if(![pba isDB])continue; // kein DB-Attr.
            s = [eo vfk:k];
            if(!FILLED(s)){
                [lmd setSecureObject:EON forKey:k];
                continue;
            }
            [lmd setSecureObject:s forKey:k];
        }
    }
    return lmd;
}
///////////////////////////////////////////////////////////////////////////////////////////
// 		fetch methoden
///////////////////////////////////////////////////////////////////////////////////////////
- (BOOL)refetchEO:(PBEO *)eo;
{
    NSString *entityName = [eo entityName];
    PBDDTable *myTable = [eo myTable];
    NSMutableDictionary *md;
    PBMySQLChannel *ac;
    PBSQLQualifier *q;
    if(!(eo))return NO;
    if(!(myTable))return NO;
    q = [eo pkq];
    if([q typ]==PBSQLQnothing)return NO;
    //restl. Werte beschaffen
    if(!(ac = [self freshChannel]))return NO;
    if(![ac selectQualifier:q forTable:myTable tn:[myTable dbName] offset:0 count:1 soa:nil])return NO;
    if((md=[ac fetchRow])){
        PBEO *eo1=[self eoFromDict:md entityName:entityName];
        [[eo values]removeAllObjects];
        [[eo values]addEntriesFromDictionary:[eo1 values]];
        [eo setWasFetched:YES];
    }else{
        return NO;
    }
    if([ac isFetchInProgress])[ac cancelFetch];
    return YES;
}
- (NSArray *)getBasicEOs:(PBSQLQualifier *)q entityName:(NSString *)entityName offset:(int)offset count:(int)count  soa:(NSArray *)soa;
{
// offset und count werden als limit beim select uebergeben
    PBDDTable *myTable;
    NSMutableDictionary *md;
    PBEO *fetchedEO;
    LMAS(ma,50);
    PBMySQLChannel *ac;
    if(!(myTable = [MYDD tableNamed:entityName]))return nil;
    if(!(ac = [self freshChannel]))return nil;
    if(![ac selectQualifier:q forTable:myTable tn:[myTable dbName] offset:offset count:count soa:soa]){
        LOGS(@"select Attributes failed");
        return nil;
    }
    while((md=[ac fetchRow])){
        fetchedEO = [self eoFromDict:md entityName:entityName];
        [ma addObject:fetchedEO];
        [fetchedEO setWasFetched:YES];
    }
    if([ac isFetchInProgress])[ac cancelFetch];
    return ma;
}
- (PBEO *)eoOfRelation:(NSString *)s forEo:(PBEO *)eo;
{
   NSString *fk = [eo vfk:s];
   PBDDAttribute *pba;
   if(!eo)return nil;
   if(![eo isKindOfClass:[PBEO class]])return nil;
   pba = [[myDD tableNamed:[eo entityName]] plainAttrNamed:s];
   if(!pba){
       LOGS(([NSSWF @"keine Relation %@ in %@ fuer %@",s,[eo entityName],[eo description]]));
       // PRINTCURRENTSTACK;
       return nil;
   }
   if(!FILLED(fk))return nil;
   return getEOPkValue([pba refdTableName],fk);
}
- (NSArray *)getEOs:(NSString *)entityName qualifier:(PBSQLQualifier *)q offset:(int)offset count:(int)count soa:(NSArray *)soa;
{
   NSArray *a;
   if([q typ] == PBSQLQnothing)return nil;
   a = [self getBasicEOs:q entityName:entityName offset:offset count:count soa:soa];
   return a;
}
/* code-beispiel
v = [NSSWF @"select %@ from %@ where %@ = '%@'",[kps oai:1],rtn,[[MYDD tableNamedCheap:rtn] primaryKeyName],v];
v = [_APP getSingleValueAsResultFrom:v];
*/
///////////////////////////////////////////////////////////////////////////////////////////
// 		low level sql
///////////////////////////////////////////////////////////////////////////////////////////
- (unsigned)evaluateSQL:(NSString *)s;
{
//wenn kein result benoetigt wird, diese Methode nehmen
//stellt sicher, dass ein eventuelles result gefreed wird und der channel damit wieder zur verfuegung steht
//wird ein result benoetigt, die gleichnamige Methode am Channel aufrufen und selber dafuer sorgen, dass der fetch beendet wird;
    PBMySQLChannel *ac;
    unsigned result;
    if(!FILLED(s))return 0;
    if(!(ac = [self freshChannel])){
        LOG(@"--- keinen Channel bekommen");
        return 0;
    }
    if(!(ac = [self freshChannel]))return 0;
    result = [ac evaluateSQL:s];
    [ac cancelFetch];
    return result;
}
- (NSString *)getSingleValueAsResultFrom:(NSString *)s;
{
// returned single Value
// falls was nicht klappt, EON
    PBMySQLChannel *ac;
    NSString *rs;
    unsigned result;
    NSDictionary *d;
    if(!FILLED(s))return EON;
    if(!(ac = [self freshChannel]))return EON;
// LOGS(s);
    result = [ac evaluateSQL:s];
    if(![ac isFetchInProgress])return EON;
    [ac setSelectedAttributes:[NSArray arrayWithObject:@"result"]];
    d = [ac fetchRow];
    [ac cancelFetch];
    if(!d)return EON;
// LOGS([d description]);
    rs = [[d allValues]firstObject];
    if(!FILLED(rs))rs=EON;
    return rs;
}
- (NSDictionary *)getDictAsResultFrom:(NSString *)s;
{
// returned single dictionary
    PBMySQLChannel *ac;
    unsigned result;
    NSDictionary *d;
    if(!FILLED(s))return nil;
    if(!(ac = [self freshChannel])){
        LOG(@"keinen Channel bekommen.");
        return nil;
    }
    result = [ac evaluateSQL:s];
    if(![ac isFetchInProgress])return nil;
    [ac setSelectedAttributes:[ac describeResults]];
    d = [ac fetchRow];
    [ac cancelFetch];
    return d;
}
- (NSArray *)getArrayAsResultFrom:(NSString *)s;
{
// returned array of dictionaries
    PBMySQLChannel *ac;
    unsigned result;
    NSDictionary *d;
    LMA;
    if(!FILLED(s))return lma;
    if(!(ac = [self freshChannel]))return lma;
    result = [ac evaluateSQL:s];
    if(![ac isFetchInProgress])return lma;
    [ac setSelectedAttributes:[ac describeResults]];
    while((d=[ac fetchRow])){
        [lma addObject:d];
    }
    [ac cancelFetch];
    return lma;
}
- (NSArray *)getStringArrayAsResultFrom:(NSString *)s;
{
    NSArray *a3 = [_APP getArrayAsResultFrom:s]; //das sind dictionaries
    LMAN(lma3);
    int i3,j3;
    for(i3=0,j3=[a3 count];i3<j3;i3++){
        [lma3 addObject:[[[a3 oai:i3]allObjects]firstObject]];
    }
    return lma3;
}
///////////////////////////////////////////////////////////////////////////////////////////
// 		EO Handling
///////////////////////////////////////////////////////////////////////////////////////////
- (void)copyPosFrom:(PBEO *)k1 to:(PBEO *)k2 posEn:(NSString *)posEn;
{
// nach 
    PBEO *p2,*p1;
    NSArray *a;
    int i,j;
    if(!k1 || !k2)return;
    a = [self positionenFor:k1 posEn:posEn];
    for(i=0,j=[a count];i<j;i++){
        p1 = [a oai:i];
        p2 = NEW_EO(posEn);
        [p2 takeValuesOfSameNameFromEo:p1];
        [p2 tvfk([k2 primaryKey],@"masterkey")]; //Kopfkey 2 in neue pos haengen
        [p2 tvfk(nil,[p2 primaryKeyName])];
        [parmDict setObject:k1 forKey:@"p_k1"];
        [parmDict setObject:k2 forKey:@"p_k2"];
        [parmDict setObject:p1 forKey:@"p_p1"];
//will/didInsert/didCreate macht keinen Sinn, weil diese davon ausgehen, den PBWOPosEditor oder einen PBWOEditor als datasource zu haben
        [parmDict setObject:p2 forKey:@"p_eo"];
        [_APP executeScriptNamed:[NSSWF @"%@/willCopyPos",[currentComponent name]] datasource:(PBWOEditor *)currentComponent parmDict:parmDict];
        INSRT(p2);
        [_APP executeScriptNamed:[NSSWF @"%@/didCopyPos",[currentComponent name]] datasource:(PBWOEditor *)currentComponent parmDict:parmDict];
    }
}
- (NSArray *)positionenFor:(PBEO *)k1 posEn:(NSString *)posEn;
{
    return getEOsKnKv(posEn,@"masterkey",[k1 primaryKey]);
}
- (PBEO *)createEOforEN:(NSString *)entityName;
{
    PBEO	*eo;
    NSArray	*allAttr;
    int	i,j;
    int dt;
    PBDDTable	*myTable = [myDD tableNamed:entityName];
    PBDDAttribute *cdate = [myTable plainAttrNamed:@"cdate"];
   // Felder initialisieren
    if(!myTable){
        return nil;
    }
    eo = [[PBEO alloc]initWithEntityName:entityName];
    if(!eo)return nil;
// Statistikfelder, damit schon mal was drinsteht, wenn man nach "neu" auf das System-Tab geht
    [[eo values] tvfk(CURRENTUSER,@"cuser")];
    [[eo values] tvfk(CURRENTUSER,@"luser")];
    if(cdate){
        [[eo values] tvfk([_APP now],@"cdate")];
        [[eo values] tvfk([_APP now],@"ldate")];
    }
    // alle int-Felder auf 0;///
    // nicht nur Felder in DB damit insb. numerische parameter Felder initialsiert werden.
    allAttr = [myTable plainAttributes];
    for(i=0,j=[allAttr count];i<j;i++){
        PBDDAttribute *pba = [allAttr oai:i];
        NSString *initialValue = [pba initialValue];
        NSString *dbName = [pba dbName];
// f. debug           if([dbName iE:@"teilanzahl"])LOGS(([NSSWF @"%@ = %@",dbName,initialValue]));
        if(FILLED(initialValue)){
            if([initialValue iE:@"$today"])initialValue = [_APP today];
            if([initialValue iE:@"$now"])initialValue = [_APP now];
            if([initialValue iE:@"CURRENTUSER"])initialValue = CURRENTUSER;
            [[eo values] tvfk(initialValue,dbName)];
// f. debug               if([dbName iE:@"teilanzahl"])LOGS(([NSSWF @"%@ = %@ set",dbName,initialValue]));
           continue;
        }
// f. debug           if([dbName iE:@"teilanzahl"])LOGS(([NSSWF @"%@ = %@ not set",dbName,initialValue]));
        if(FILLED([pba expression]))continue;
        if([pba targetTyp]!=ATTVCSELOBJ)continue;
        dt = [pba dataTyp];
        if([pba isNumeric]){
            [[eo values] tvfk([NSString dbFromDouble:0.0 pba:pba],dbName)];
        }
        if([pba dataTyp] == DT_BOOL){
            if([dbName iE:NAME_OF_AKTIV_FLAG]){
                [[eo values] tvfk(SC_BOOL_TRUE,dbName)];
            }else{
                [[eo values] tvfk(SC_BOOL_FALSE,dbName)];
            }
        }
// hier koennte bei VLs noch der default-Entry gezogen werden; ist aber eigentlich durch den initialValue aus dem Modell schon abgebildet
    }
    return [eo autorelease];
}
- (BOOL)insertEO:(PBEO *)eo;
{
    //raw: ohne Pruefungen u. ohne Cache
    NSDictionary *eod;
    NSString *en;
    PBDDTable *myTable;
    PBDDAttribute *cdate;
    PBMySQLChannel *ac;
    if([_APP orbDebug]){
        LOGS(([NSSWF @"--> insertEO; %@.",[eo description]]));
    }
    if(!eo){
        LOGS(@"kein EO uebergeben");
        // PRINTCURRENTSTACK;
        return NO;
    }
    en = [eo entityName];
    myTable = [eo myTable];
    if(!myTable){
        LOGS(([NSSWF @"keine solche Table:%@",en]));
        return NO;
    }
    if(![[myTable primaryKeyAttr]isSerialPK] && !FILLEDNUM([eo primaryKey])){
        LOGS(([NSSWF @"INSERT %@ failed; no primaryKey",[eo description]]));
        return NO;
    }
    [[eo values] tvfk(CURRENTUSER,@"cuser")];
    [[eo values] tvfk(CURRENTUSER,@"luser")];
    cdate = [myTable plainAttrNamed:@"cdate"];
    if(cdate){
        [[eo values] tvfk([_APP now],@"cdate")];
        [[eo values] tvfk([_APP now],@"ldate")];
    }
    eod = [self dictFromEO:eo forKeys:nil]; //alle Werte
    if(![eod count]){
        LOGS(([NSSWF @"INSERT %@ failed; conversion to dictionary failed;",[eo description]]));
        return NO;
    }
    if(!(ac = [self freshChannel])){
        LOGS(([NSSWF @"INSERT %@ failed; no channel;",[eo description]]));
        return NO;
    }
    if(![ac insertRow:eod forTable:myTable]){
        LOGS(([NSSWF @"INSERT %@ failed; (s. vorherige Meldung)",[eo description]]));
        return NO;
    }
// wenn es ein serial ist, den vergebenen Wert holen
    if([[myTable primaryKeyAttr]isSerialPK]){
        if([[eo primaryKey]intValue] == 0)[eo setPrimaryKey:singleValueSQL(@"select LAST_INSERT_ID()")];
    }
    [eo setDescri:nil];
    [eo setWasFetched:YES];
    return YES;
}
- (BOOL)updateEO:(PBEO *)eo;
{
    PBDDTable *myTable;
    NSString *en,*pk;
    NSDictionary *eod;
    PBMySQLChannel *ac;
    PBDDAttribute *ldate;
    if([_APP orbDebug]){
//        LOGS(([NSSWF @"--> updateEO; %@.",[eo description]]));
    }
    if(!eo){
        LOGS(@"kein EO uebergeben.");
        // PRINTCURRENTSTACK;
        return NO;
    }
    en = [eo entityName];
    myTable = [eo myTable];
    if(!myTable){
        LOGS(([NSSWF @"UPDAT %@ failed; no table",[eo description]]));
        return NO;
    }
    if(![[eo oldValues]count])return YES;	//nix zu tun
    
//statistic felder erst hier versorgen, wenn feststeht, dass auch andere Felder geaendert
    if(![[eo oldValues]ofk:@"luser"])[eo tvfk(CURRENTUSER,@"luser")]; //wenn nicht explizit geaendert...
    ldate = [myTable plainAttrNamed:@"ldate"];
    if(ldate){
        [eo tvfk([_APP now],@"ldate")];
    }
    eod = [self dictFromEO:eo forKeys:[eo oldValues]];
    if(![eod count])return YES; //nix zu tun
    if(!(ac = [self freshChannel])){
        LOGS(([NSSWF @"UPDAT %@ failed; no channel",[eo description]]));
        return NO;
    }
    pk = [eo primaryKey];
    if(![ac updateRow:eod forTable:myTable pk:[pk mysqlEscapedString]]){
        LOGS(([NSSWF @"UPDAT %@ failed; (s. vorherige Meldung)",[eo description]]));
        return NO;
    }
    [[eo changedValues]removeAllObjects];
    [[eo changedValues]addEntriesFromDictionary:[eo oldValues]]; //damit man in didUpdate feststellen kann, was sich geaendert hat
    [[eo oldValues]removeAllObjects];
    [eo setDescri:nil];
    return YES;
}
- (BOOL)deleteEO:(PBEO *)eo;
{
    PBSQLQualifier *q;
    NSString *en;
    PBDDTable *myTable;
    PBMySQLChannel *ac;
    if([_APP orbDebug]){
        LOGS(([NSSWF @"--> deleteEO; %@.",[eo description]]));
    }
    if(!eo){
        LOGS(@"kein EO uebergeben.");
        // PRINTCURRENTSTACK;
        return NO;
    }
    en = [eo entityName];
    myTable = [eo myTable];
    if(!myTable){
        LOGS(([NSSWF @"keine solche Entity:%@",en]));
        return NO;
    }
    if(!(ac = [self freshChannel]))return NO;
    q = [eo pkq];
    if(![ac deleteRowsDescribedByQualifier:q forTable:myTable]){
        LOGS(([NSSWF @"DELET %@ failed; (s. vorherige Meldung)",[eo description]]));
        return NO;
    }
    return YES;
}
///////////////////////////////////////////////////////////////////////////////////////////
//	channel handling
///////////////////////////////////////////////////////////////////////////////////////////
- (void)closeAllChannels;
{
    int i,j;
    PBMySQLChannel *ac;
    for(i=0,j=[channelPool count];i<j;i++){
        ac = [channelPool oai:i];
        if([ac isOpen]){
            if([ac isFetchInProgress])[ac cancelFetch];
            [ac closeChannel];
        }
    }
    [channelPool removeAllObjects];
}
- (PBMySQLChannel *)freshChannel;
{
    //alle channelPool durchschauen; wenn einer geclosed ist, open u. verwenden;
    // wenn einer !fetchin Progress, verwenden
    //der channel muss danach sofoert verwendet werden, sonst wird er nochmal vergeben...
    PBMySQLChannel *c;
    int i,j;
 //   LOGS(([NSSWF @"channelpool count =%i",j]));
// in geschlossenen Channels einen wiederverwertbaren suchen
// rueckwaerts, damit der Index richtig bleibt
    for(i=[channelPool count]-1;i>=0;i--){
        c = [channelPool objectAtIndex:i];
        if([c isOpen])continue;
        if([c dbNr] != dbNr)continue;
        if(![c openChannel]){
            LOGS(@"konnte alten Adaptorchannel nicht oeffnen.");
            [channelPool removeObjectAtIndex:i]; //mit Index;
            continue;
        }
//        LOGS(([NSSWF @"returning reopened channel; channelpool count =%i",j]));
        return c;	
    }
// in offenen channels einen wiederverwertbaren suchen
    for(i=0,j=[channelPool count];i<j;i++){
        c = [channelPool objectAtIndex:i];
        if([c dbNr] != dbNr)continue;
        if(![c isFetchInProgress]){
//            LOGS(([NSSWF @"reuseing open channel; channelpool count =%i",j]));
            return c;
        }
    }
    c = [[PBMySQLChannel alloc]init];
    if(!c){
        LOGS(@"keinen Adaptorchannel erhalten.");
        LOGS(([NSSWF @"channelpool count =%i",j]));
        return nil;
    }
    if(![c openChannel]){
        LOGS(@"konnte neuen Adaptorchannel nicht oeffnen.");
        LOGS(([NSSWF @"channelpool count =%i",j]));
        return nil;
    }
    [channelPool addObject:c];
    if([_APP orbDebug])LOGS(NSS([channelPool count]));
    return c;	
}
///////////////////////////////////////////////////////////////////////////////////////////
//	SQL related
///////////////////////////////////////////////////////////////////////////////////////////
- (NSMutableString *)sqlValuesStringFromDict:(NSDictionary *)d forTable:(PBDDTable *)t;
{
    //dict schon mit dictFromEO vorbereitet: nur noch db-Attribute, nur noch delta bei update, alle werte im db-Format
    //hier nur noch quoten und escapen;
    //pass f. insert und update
    NSArray *a,*a1;
    int i,j;
    NSMutableString *ms = [NSMutableString stringWithCapacity:1024];
    NSString *colName,*colValue;
    
    if(!d || !t)return nil;
    [ms setString:EON];
    a = [d allKeys]; a1 = [d allValues];
    for(i=0,j=[a count];i<j;i++){
        colName = [a oai:i];
        colValue = [a1 oai:i];
        if(!FILLED(colValue)){
            colValue=@"\"\""; //immer leer wg. uniq-Feldern; 
        }else{
            colValue = [NSString stringWithFormat:@"\"%@\"",[colValue mysqlEscapedString]]; //immer quoten; zahlen eigentlich nicht
        }
        if(i)[ms appendString:@", "];
        [ms appendFormat:@"%@=%@",colName,colValue];
    }
    return ms;
}
- (NSString *)orderbyClauseFromSoa:(NSArray *)soa;
{
    NSMutableString *obyc;
    int i,j=[soa count];
    PBSortOrdering *pbso;
    NSString *k,*ad;
    SEL sel;
    
    if(!j)return EON;
    obyc = [NSMutableString stringWithCapacity:100];
    for(i=0;i<j;i++){
        pbso = [soa oai:i];
        k = [pbso key];
        if(!FILLED(k))continue;
        if(!FILLED(obyc))[obyc setString:@"order by "];
        sel = [pbso selector];
        if(sel_eq(sel,EOCompareAscending) || sel_eq(sel,@selector(compareNumeric:)) || sel_eq(sel,@selector(compare:)) || sel_eq(sel,@selector(compareCaseInsensitive:))){
            ad = @"ASC";
        }else{
            ad = @"DESC";
        }
        if(i)[obyc appendString:@", "];
        [obyc appendFormat:@"%@ %@ ",k,ad];
    }
    return obyc; 
}
- (NSString *)sqlFormatResetSerial:(PBDDTable *)t;
{
// alternativ: alter table %@ AUTO_INCREMENT=1;
    PBDDAttribute *pbat = [t primaryKeyAttr];
    NSString *tn,*sn;
    LMA;
    if(![pbat isSerialPK])return @"";
    tn = [t dbName];
    sn = [pbat dbName];
    [lma addObject:[NSSWF @"alter table %@ add   auto_increment_bak INTEGER",tn]];
    [lma addObject:[NSSWF @"update %@ set auto_increment_bak = %@",tn,sn]];
    [lma addObject:[NSSWF @"alter table %@ drop  %@",tn,sn]];
    [lma addObject:[NSSWF @"alter table %@ add   %@ INTEGER NOT NULL auto_increment PRIMARY KEY",tn,sn]];
    [lma addObject:[NSSWF @"update %@ set %@ = auto_increment_bak",tn,sn]];
    [lma addObject:[NSSWF @"alter table %@ drop auto_increment_bak",tn]];
    return [lma componentsJoinedByString:@"\n"];
}
- (NSString *)sqlFormatCt:(PBDDTable *)t;
{
    return [self sqlFormatCt:t tn:[t dbName] temp:NO];
}
- (NSString *)sqlFormatCt:(PBDDTable *)t tn:(NSString *)tn temp:(BOOL)temp;
{
    static NSMutableString *s;
    NSString *constraint,*temporary;
    int	i,j,rac=0;
    NSArray	*a;
    PBDDAttribute	*pba;
    if(!s){
        s = [[NSMutableString alloc]initWithCapacity:1000];
    }
    if(temp){
        temporary = @"temporary";
    }else{
        temporary = EON;
    }
// vorher muss im DD reorg gemacht worden sein;
    [s setString:EON];
    if([t isRealTable]){
        a = [t attributesDB];
        [s appendFormat:@"create %@ table %@ (\n",temporary,[tn lowercaseString]];
        constraint = EON;
        for(i=0,j=[a count];i<j;i++){
            pba = [a oai:i];
            if(rac)[s appendString:@",\n"];
            [s appendString:[self sqlFormatCANew:pba]];
            
            rac++;
        }
        [s appendString:@");\n"];
        return s;
    }else{
        return EON;
    }
}
- (NSString *)sqlFormatCANew:(PBDDAttribute *)pba;
{
    NSString *atn,*dbTyp =  @"CHAR(1)",*s;
    atn = [[pba dbName]lowercaseString];
    if([pba isSerialPK]){
        return [NSSWF @"%@ INTEGER NOT NULL auto_increment PRIMARY KEY",atn];
    }
    switch([pba dataTyp]){
        case DT_CHAR:
            if([pba length]<4){
                dbTyp = [NSSWF @"char(%i)",[pba length]];
            }else if([pba length]<256){
                dbTyp = [NSSWF @"varchar(%i)",[pba length]];
            }else{
                dbTyp =  [NSSWF @"text"];
            }
            break;
        case DT_DATE:
            dbTyp =  @"DATE";
            break;
        case DT_DATETIME:
            dbTyp =  @"DATETIME";
            break;
        case DT_MONEY:
            dbTyp =  @"DECIMAL(11,2)"; //platz f. vorzeichen
            break;
        case DT_FLOAT:
            dbTyp =  [NSSWF @"DECIMAL(%i,%i)",[pba length],[pba nak]]; //
            break;
        case DT_INT:
            dbTyp =  @"INTEGER";
            break;
        case DT_BOOL:
            dbTyp =  @"CHAR(1)";
            break;
    }
    s = [NSSWF @"    %@ %@",atn,dbTyp];
    if([pba isPK]){
        s = [s stringByAppendingString:@" NOT NULL PRIMARY KEY"];
    }
    return s;
}
- (void)readArialuni_cmap;
{
//		      Char 0F50 -> Index 2334
    NSString *s = [NSSWCOF [NSSWF @"%@/arialuni_cmap.txt",GLOBALCONFIGPATH]];
    NSArray *a = [s componentsSeparatedByString:@"\n"];
    int i,j;
    for(i=0,j=65535;i<j;i++)arialuni_cmap[i]=0;
    for(i=0,j=[a count];i<j;i++){
        unsigned short uni;
        s = [a oai:i];
        uni = [[[s secureSubstringFromIndex:13]secureSubstringToIndex:4]hexValue];
        arialuni_cmap[uni]=[[s secureSubstringFromIndex:27]intValue];
    }
}
- (void)readArialuni_hmtx;
{
//    17896. advWid: 2048, LSdBear: 113
// die hmtx sind nach cid organisiert und lueckenlos
    NSString *s = [NSSWCOF [NSSWF @"%@/arialuni_hmtx.txt",GLOBALCONFIGPATH]];
    NSArray *a = [s componentsSeparatedByString:@"\n"];
    NSString *sep = @". advWid: ";
    int i,j;
    for(i=0,j=65535;i<j;i++)arialuni_hmtx[i]=1000;
    for(i=0,j=[a count];i<j;i++){
        NSArray *a1 = [[a oai:i]componentsSeparatedByString:sep];
        if([a1 count]!=2)continue;
        arialuni_hmtx[i]=(unsigned short)[[[[[a1 oai:1]stringWithoutSpace]componentsSeparatedByString:@","]firstObject]floatValue] / 2.023; //ist viel zu breit
    }
}
- (NSString *)cidStringFrom:(NSString *)s;
{
// die unicode characters in cid hex-zahlen umwandeln u. < > drumrum fuer PDF
    int j = [s length];
    int i=0;
    NSMutableString *ms = [NSMutableString stringWithCapacity:(j * 4) + 3];
    [ms setString:@"<"];
    for(i=0,j=[s length];i<j;i++){
        unsigned short cid=0;
        unichar uni = [s characterAtIndex:i];
        cid = arialuni_cmap[uni];
        if(cid)[ms appendString:[NSSWF @"%04x",cid]]; //gibt sonst kaestchen
    }
    [ms appendString:@">"];
    return ms;
}
- (unsigned short)cidForUnichar:(unichar)uni;
{
    return arialuni_cmap[uni];
}
- (unsigned short)widthForCid:(unsigned short)cid;
{
    return arialuni_hmtx[cid];
}
- (unsigned short)widthForUnichar:(unichar)uni;
{
    return [self widthForCid:[self cidForUnichar:uni]];
}
@end
@implementation Application (CEOH)
// das hier wird auch noch aufgeloest und in Scripts verlagert; 
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
// methoden fuer verschiedene Tabellen
- (NSArray *)helementv3_directChildrenOf:(PBEO *)eo;
{
    return getEOsKnKv(@"helpdeskv3",@"parentelement",[eo primaryKey]);
}
- (void)helementv3_genPrimKey:(PBEO *)eo inParentEO:(PBEO *)peo;
{
    if(!peo){ //root element
        return;
    }else{ //innerhalb parent den naechsten schluessel
        NSArray *a = [[self helementv3_directChildrenOf:peo]valuesForKey:@"pid"];
        int i,j,lk=0;
        if(!a){
            [eo tvfk(([NSSWF @"%@.0",[peo primaryKey]]),@"pid")]; //erstes element unter diesem parent
            return;
        }
        for(i=0,j=[a count];i<j;i++){  //aeltestes Geschwister festsellen
            NSString *s = [a oai:i];
            int lk1;
            lk1 = [[[s componentsSeparatedByString:@"."]lastObject]intValue];
            if(lk1 > lk)lk = lk1;
        }
        lk++;
        [eo tvfk(([NSSWF @"%@.%i",[peo primaryKey],lk]),@"pid")];
    }
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
- (void)flagsToGruppenstring:(PBEO *)eo;
{
// beim Speichern
    NSString *gs = @"";
    int i;
    for(i=0;i<ANZ_GRUPPEN;i++){
        NSString *gn = [NSSWF @"gruppe%i",i];
        if([[eo vfk:gn]iE:@"J"]){
            gs = [gs stringByAppendingString:@"x"];
        }else{
            gs = [gs stringByAppendingString:@"-"];
        }
    }
    [eo tvfk(gs,@"gruppenstring")];
}
- (void)gruppenstringToFlags:(PBEO *)eo;
{
// beim Laden
    NSString *gs = [eo vfk:@"gruppenstring"];
    int i;
    for(i=0;i<ANZ_GRUPPEN;i++){
        NSString *gn = [NSSWF @"gruppe%i",i];
        if([[[gs charAt:i]lowercaseString]iE:@"x"]){
            [eo tvfk(@"J",gn)];
        }else{
            [eo tvfk(@"N",gn)];
        }
    }
}
@end
@implementation Application (Webpublishing)
// Webpublisher
- (void)unreferencedFiles;
{
// holt alle Filenamen aus Images und dursucht
// alle \img und \dl Zeilen danach; nicht gefundene werden zum Löschen vorgeschlagen;
    NSString *bp = [NSSWF @"%@/web_publish/%@",MANDANTPATH,[configDict ofk:@"web_publish_base"]];  // Directory relativ zu web_publish; ohne fuehrenden /; von hier wird der Input gelesen;
    NSString *imgp = [NSSWF @"%@/Images",bp];
    NSArray *a = [myFM directoryContentsAtPath:imgp];
    int i,j;
    NSString *dlAndImg = [[self dlAndImgIn:bp]componentsJoinedByString:@"\n"];
    LMA;
    NSString *allSource = [NSSWF @"%@\n%@\%@",dlAndImg,[NSSWCOF [NSSWF @"%@/web.css",bp]],[NSSWCOF [NSSWF @"%@/web_template.html",bp]]];
    for(i=0,j=[a count];i<j;i++){
        NSString *fn = [[a oai:i]stringWithForwardSlashes];
        if(![allSource rangeOfString:fn].length)[lma addObject:[NSSWF @"rm %@/%@",imgp,fn]];
    }
    [[lma componentsJoinedByString:@"\n"] WTF:[NSSWF @"%@/unreferencedFiles.sh",bp]];
    [allSource WTF:[NSSWF @"%@/allSource.txt",bp]];
}
- (NSString *)titleFromFn:(NSString *)fn;
{
// liefert den vom Filenamen abgeleiteten Titel; wird die Ueberschrift und angezeigter Text des Links im Menu (Navigation);
    NSRange r = [fn rangeOfString:@" "];
    NSString *s;
    NSString *product = [configDict ofk:@"product"];
    if(!FILLED(product))product = @"Intars";
    if(r.length == 0){
        s = fn;
    }else{
        s = [fn substringFromIndex:r.location + r.length];
    }
    if([s hasSecureSuffix:@".txt"])s = [s stringWithoutSuffix:@".txt"];
    return [s replace:@"IntarS 5.1" with:product];
}
- (NSString *)section:(int)i;
{
    switch(i){
        case 0: return @"chapter";
        case 1: return @"section";
        case 2: return @"subsection";
        case 3: return @"subsubsection";
    }
    return @"subsubsection";
}
- (void)publishDirectory:(NSString *)dir;
{
    NSArray *a = [[myFM directoryContentsAtPath:dir]sortedArray];
    int i,j;
    LMAN(latexma);
    NSArray *a1;
    int i1,j1;
    NSString *product = [configDict ofk:@"product"];
    BOOL mit_bild_fn = ([[[_APP configDict]ofk:@"mit_bild_fn"]iE:@"J"]);
    if(!FILLED(product))product = @"Intars";
    for(i=0,j=[a count];i<j;i++){
        NSString *fn = [a oai:i];
        NSString *completeFn = [dir stringByAppendingFormat:@"/%@",fn];
        NSDictionary *fa = [myFM fileAttributesAtPath:completeFn traverseLink:NO];
        if([[fa ofk:NSFileType]iE:NSFileTypeRegular] && [fn hasSecureSuffix:@".txt"] && ![fn hasSecurePrefix:@"_idee"]){ //
            BOOL addBR = NO;
            BOOL inTT = NO;
            BOOL inText = NO;
            BOOL inOL = NO;
            BOOL inUL = NO;
            PBEO *eo = NEW_EO(@"webpublisher");
            LMA;
            [eo tvfk(NSS(nestinglevel),@"nestinglevel")];
            [eo tvfk([self urlFromCompleteFn:[completeFn withoutPrefix:basePath]],@"url")];
            [eo tvfk([self titleFromFn:fn],@"title")]; // Sortierung des Filenamens bis zum ersten Space abschneiden;
#include "renderHTML.h"
            [eo tvfk(lma,@"lines")]; // als Array belassen f. 2. pass
            [eo tvfk(@"J",@"isfinal")];
            [h3eos addObject:eo];
            [allLATeX appendString:[NSSWF @"\n\\%@{%@}\n%@",[self section:gliederungsTiefe],[[eo vfk:@"title"]latexEscapedString],[latexma componentsJoinedByString:@" "]]];
            continue;
        }
        if([[fa ofk:NSFileType]iE:NSFileTypeDirectory] && ![fn iE:@"Images"]   && ![fn iE:@".svn"]){
            PBEO *eo = NEW_EO(@"webpublisher");
            [eo tvfk(NSS(nestinglevel),@"nestinglevel")];
            [eo tvfk([self urlFromCompleteFn:[completeFn withoutPrefix:basePath]],@"url")];
            [eo tvfk([self titleFromFn:fn],@"title")];
            [eo tvfk(EON,@"content")];
            [h3eos addObject:eo];
            [allLATeX appendString:[NSSWF @"\n\\%@{%@}",[self section:gliederungsTiefe],[[eo vfk:@"title"]latexEscapedString]]];
            nestinglevel++;
            gliederungsTiefe++;	//wg. kompatib. zu renderHTML
            [self publishDirectory:completeFn];
            nestinglevel--;
            gliederungsTiefe--;
        }
    }
}
- (NSArray *)dlAndImgIn:(NSString *)dir;
{
    NSArray *a = [[myFM directoryContentsAtPath:dir]sortedArray];
    int i,j;
    LMA;
    for(i=0,j=[a count];i<j;i++){
        NSString *fn = [a oai:i];
        NSString *completeFn = [dir stringByAppendingFormat:@"/%@",fn];
        NSDictionary *fa = [myFM fileAttributesAtPath:completeFn traverseLink:NO];
        if([[fa ofk:NSFileType]iE:NSFileTypeRegular] && [fn hasSecureSuffix:@".txt"] && ![fn hasSecurePrefix:@"_idee"]){ //
            NSString *file = [NSSWCOF completeFn];
            NSArray *lines = [file componentsSeparatedByString:@"\n"];
            int i1,j1;
            for(i1=0,j1=[lines count];i1<j1;i1++){
                NSString *line = [lines oai:i1];
                if([line hasSecurePrefix:@"\\dl"] || [line hasSecurePrefix:@"\\img"])[lma addObject:line];
            }
            continue;
        }
        if([[fa ofk:NSFileType]iE:NSFileTypeDirectory] && ![fn iE:@"Images"] && ![fn iE:@".svn"]){
            [lma addObjectsFromArray:[self dlAndImgIn:completeFn]];
        }
    }
    return lma;
}
- (NSString *)urlFromCompleteFn:(NSString *)completeFn;
{
// Sortierzahl vorne weg; .txt -> .html
// completeFn ist relativ zum basePath;
// url soll sein ohne fuehrenden / und ohne targetPath und ohne Suffix
// es wird daraus die URL und der Meta Title gebaut 
    NSArray *a = [[completeFn stringWithForwardSlashes]componentsSeparatedByString:@"/"];
    int i,j;
    LMA;
    NSString *s;
    NSString *product = [configDict ofk:@"product"];
    if(!FILLED(product))product = @"Intars";
    for(i=0,j=[a count];i<j;i++){
        NSRange r;
        s = [a oai:i];
        r = [s rangeOfString:@" "];
        if(r.length > 0){
            s = [s substringFromIndex:r.location + r.length];
        }
        if([s hasSecureSuffix:@".txt"])s = [s stringWithoutSuffix:@".txt"];
        [lma addObject:s];
    }
    if([[lma firstObject]iE:@""])[lma removeObjectAtIndex:0];
    s = [lma componentsJoinedByString:@"/"];
    return [s replace:@"IntarS 5.1" with:product];
}
- (NSString *)navLinesFor:(PBEO *)eo;
{
    LMA;
    int i,j;
    NSString *url = [eo vfk:@"url"];
    int nl = [[eo vfk:@"nestinglevel"]intValue];
    int currentNL = 0;
    BOOL increasing = YES;
    for(i=0,j=[h3eos count];i<j;i++){
        PBEO *eo1 = [h3eos oai:i];
        NSString *url1 = [eo1 vfk:@"url"];
        int nl1 = [[eo1 vfk:@"nestinglevel"]intValue];
        BOOL wasAdded = NO;
        if(nl1 == currentNL){
            [lma addObject:[self navLinkFor:eo1 eo:eo]];
            wasAdded = YES;
        }
        if(increasing){
            if([url hasSecurePrefix:url1]){
                if(!wasAdded)[lma addObject:[self navLinkFor:eo1 eo:eo]];
                currentNL++;
                if(currentNL > nl){
                    currentNL = nl;
                    increasing = NO;
                }
            }
        }else{
            if(nl1 < currentNL){
                [lma addObject:[self navLinkFor:eo1 eo:eo]];
                currentNL--;
            }
        }
    }
    return [lma componentsJoinedByString:@""];
}
- (NSString *)navLinkFor:(PBEO *)navEO eo:(PBEO *)eo;
{
    NSString *navLinkDir = @"<tr><td nowrap>%@ <a class=\"navLinkDir\" href=\"/%@/%@.html\">&raquo; %@</a></td></tr>";
    NSString *navLinkFile = @"<tr><td nowrap>%@ <a class=\"navLinkFile\" href=\"/%@/%@.html\">%@</a></td></tr>";
    NSString *navLinkSelf = @"<tr><td nowrap>%@ <a class=\"navLinkSelf\" href=\"/%@/%@.html\">%@</a></td></tr>";
    NSString *nestingImage=@"";
    int nl = [[navEO vfk:@"nestinglevel"]intValue];
    if(nl){
        nestingImage = [NSSWF @"<img src=\"/%@/Images/1a.gif\" alt=\"\" width=%i height=1 border=0>",targetPath,nl*10];
    }
    if([[navEO vfk:@"url"]iE:[eo vfk:@"url"]]){
        return [NSSWF navLinkSelf,nestingImage,targetPath,[[[navEO vfk:@"url"]urlEncodedString]umlautExpandedString],[navEO vfk:@"title"]];
    }
    if([[navEO vfk:@"isfinal"]iE:@"J"]){
        return [NSSWF navLinkFile,nestingImage,targetPath,[[[navEO vfk:@"url"]urlEncodedString]umlautExpandedString],[navEO vfk:@"title"]];
    }else{
        return [NSSWF navLinkDir,nestingImage,targetPath,[[[navEO vfk:@"urlff"]urlEncodedString]umlautExpandedString],[navEO vfk:@"title"]];
    }
}
- (void)publish;
{
    NSString *web_template,*web_template_path;
    int i,j;
    BOOL first = YES;
    LMD;
    [self setBasePath:[NSSWF @"%@/web_publish/%@",MANDANTPATH,[configDict ofk:@"web_publish_base"]]]; // Directory relativ zu web_publish; ohne fuehrenden /; von hier wird der Input gelesen; parametrisierbar, um Buecher oder verschiedene Webseiten zu rendern
    [self setTargetPath:[configDict ofk:@"web_publish_target"]]; // relativ zu htdocs; ohne fuehrenden /
// targetPath-Directory clearen und Images neu reinstellen
    [myFM removeFileAtPath:[NSSWF @"%@/web/%@",RESOURCEPATH,targetPath] handler:nil];
    [myFM createAllDirsAtPath:[NSSWF @"%@/web/%@/Images",RESOURCEPATH,targetPath]];
    SYSTEM(([NSSWF @"cp -rf %@/Images/*.* %@/web/%@/Images",basePath,RESOURCEPATH,targetPath]));
     SYSTEM(([NSSWF @"cp %@/web.css %@/web/%@/Images",basePath,RESOURCEPATH,targetPath]));
     if(![myFM fileExistsAtPath:basePath]){
         LOGI(([NSSWF TRANSLATION(@"basePath %@ nicht gefunden"),basePath]));
         return;
     }
     [allLATeX setString:[NSSWF [NSSWCOF [NSSWF @"%@/publish_template.tex",basePath]],basePath]]; // graphicspath in tex rein
     [h3eos removeAllObjects];
     nestinglevel = 0;
     gliederungsTiefe = 0;
     [self publishDirectory:basePath];
     [allLATeX appendString:@"\\end{document}"];
     [allLATeX writeToFileLatin1:[NSSWF @"%@/web/%@/Publish.tex",RESOURCEPATH,targetPath]];
// dictionary aufbauen, URL f. ID
     for(i=0,j=[h3eos count];i<j;i++){
         PBEO *eo = [h3eos oai:i];
         NSString *internal_id = [eo vfk:@"internal_id"];
         if(FILLED(internal_id))[lmd setObject:eo forKey:internal_id];
     }
// rendern
// den urlff first final ermitteln: erste angezeigte Seite
     for(i=0,j=[h3eos count];i<j;i++){
         PBEO *eo = [h3eos oai:i];
         int i1;
         if([[eo vfk:@"isfinal"]iE:@"J"])continue;
         for(i1=i+1;i1<j;i1++){
             PBEO *eo1 = [h3eos oai:i1];
             if([[eo1 vfk:@"isfinal"]iE:@"J"]){
                 [eo tvfk([eo1 vfk:@"url"],@"urlff")]; // first final
                 break;
             }
         }
     }
// template laden
     web_template_path = [NSSWF @"%@/web_template.html",basePath];
     web_template = [NSSWCOF web_template_path];
     if(!FILLED(web_template)){
         LOGS(([NSSWF @"web_template %@ nicht gefunden",web_template_path]));
         return;
     }
     web_template = [web_template replace:@"${targetPath}" with:targetPath];
     
// alle final eos verarbeiten; pro eo wird ein .html file geschrieben; dazu die Nav-Leiste kunstvoll generieren; alle Directories auf dem Weg anlegen
     for(i=0,j=[h3eos count];i<j;i++){
         PBEO *eo = [h3eos oai:i];
         NSString *htmlPath,*htmlFile;
         NSString *navLines;
         NSString *meta_title;
         int i1,j1;
         NSMutableArray *lines = [eo vfk:@"lines"];
         if([[eo vfk:@"isfinal"]iE:@"N"])continue;
// internal links aufloesen
         for(i1=0,j1=[lines count];i1<j1;i1++){
             NSString *line = [lines oai:i1];
             if([line hasSecurePrefix:@"\\ai "]){
                 NSArray *a2 = [line componentsSeparatedByString:@"{"];
                 NSString *internal_id,*arg2;
                 internal_id = [[a2 oai:1]stringWithoutLastChar]; // id
                 arg2 = [[a2 oai:2]stringWithoutLastChar]; // text
                 if(FILLED(internal_id)){
                     PBEO *eo_target = [lmd ofk:internal_id];
                     if(FILLED(eo_target)){
                         line = [NSSWF @"<a href=\"/%@/%@.html\">%@</a>",targetPath,[eo_target vfk:@"url"],arg2];
                         [lines insertObject:line atIndex:i1];
                         [lines removeObjectAtIndex:i1 + 1];
                     }
                 }
             }
         }
         navLines = [self navLinesFor:eo];
         meta_title = [eo vfk:@"meta_title"];
         if(!FILLED(meta_title))meta_title = [NSSWF @"%@/%@",targetPath,[eo vfk:@"url"]];
         htmlFile = [NSSWF web_template,meta_title,[[eo vfk:@"meta_description"] htmlEscapedString],[[eo vfk:@"meta_keywords"] htmlEscapedString],navLines,[[eo vfk:@"title"] htmlEscapedString],[lines componentsJoinedByString:@""]];
         htmlPath = [[NSSWF @"%@/web/%@/%@.html",RESOURCEPATH,targetPath,[eo vfk:@"url"]]umlautExpandedString]; // url ist relativ zum /
         [myFM createAllDirsAtPath:[htmlPath stringByDeletingLastPathComponent]];
         [htmlFile WTF:htmlPath];
// erstes File als index.html wegschreiben
// URL /Aprica2/web
         if(first){
             [htmlFile WTF:[NSSWF @"%@/web/%@/index.html",RESOURCEPATH,targetPath]];
             first = NO;
         }
     }
     {
// in htdocs installieren; dazu altes erstmal loeschen
         NSString *htdocsPath = [NSSWF @"%@/%@",htdocs,[configDict ofk:@"web_publish_target"]];
         [myFM removeFileAtPath:htdocsPath handler:nil];
         [myFM copyPath:[[NSSWF @"%@/web/%@",RESOURCEPATH,targetPath]umlautExpandedString] toPath:htdocsPath handler:nil];
     }
}
@end
@implementation Application (XML)
- (NSString *)encodeObjectXMLRPC:o methodName:(NSString *)methodName single:(BOOL)single;
{
// o muss ein Dictionary oder Array sein
// methodName ist ein frei waehlbarer name
    NSMutableString *ms = [NSMutableString stringWithCapacity:1000];
    [ms setString:@"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"];
    /*
     <methodCall>
     <methodName>examples.getStateName</methodName>
     <params>
     </params>
     </methodCall>
     */
    [ms appendString:@"<methodCall>\n"];
    [ms appendString:@"<methodName>"];
    [ms appendString:[methodName xmlEscapedString]];
    [ms appendString:@"</methodName>\n"];
    if(FILLED(o)){
        [ms appendString:@"<params>\n"];
        if([o isKindOfClass:[NSDictionary class]]){
            [ms appendString:@"<param>\n"];
            [self encodeDictionaryXMLRPC:o inXML:ms nestingLevel:0];
            [ms appendString:@"</param>\n"];
        }else if([o isKindOfClass:[NSArray class]]){
            if(single){
                int i,j;
                for(i=0,j=[o count];i<j;i++){
                    [ms appendString:@"<param>\n"];
                    [ms appendString:@"<value>"];
                    [ms appendString:[[o oai:i] xmlEscapedString]];
                    [ms appendString:@"</value>\n"];
                    [ms appendString:@"</param>\n"];
                }
            }else{
                [ms appendString:@"<param>\n"];
                [self encodeArrayXMLRPC:o inXML:ms nestingLevel:0];
                [ms appendString:@"</param>\n"];
            }
        }else{
            [ms appendString:@"<param>\n"];
            [ms appendString:@"<value>"];
            [ms appendString:[o xmlEscapedString]];
            [ms appendString:@"</value>\n"];
            [ms appendString:@"</param>\n"];
        }
        [ms appendString:@"</params>\n"];
    }
    [ms appendString:@"</methodCall>\n"];
    return ms;
}
- (void)encodeDictionaryXMLRPC:(NSDictionary *)d inXML:(NSMutableString *)ms nestingLevel:(int)nl;
{
// interne Methode
    /*
    <value>
    <struct>
       <member>
          <name>...</name>
          <value>...</value>
       </member>
    </struct>
    </value>
    */
    NSArray *a1=[d allKeys];
    NSArray *a2=[d allObjects];
    // NSString *nesting = [NSString stringWith:nl timesString:@"\t"];
    int i,j;
    [ms appendString:@"<value>\n"];
    [ms appendString:@"<struct>\n"];
    for(i=0,j=[a1 count];i<j;i++){
        NSString *k = [a1 oai:i];
        id o;
        [ms appendString:@"<member>\n"];
        [ms appendString:@"<name>"];
        [ms appendString:[k xmlEscapedString]];
        [ms appendString:@"</name>\n"];
        o=[a2 oai:i];
        if([o isKindOfClass:[NSString class]]){
            [ms appendString:@"<value>"];
        [ms appendString:[o xmlEscapedString]];
            [ms appendString:@"</value>\n"];
        }else{
            if([o isKindOfClass:[NSDictionary class]]){
                [self encodeDictionaryXMLRPC:o inXML:ms nestingLevel:nl + 1];
            }else if([o isKindOfClass:[NSArray class]]){
                [self encodeArrayXMLRPC:o inXML:ms nestingLevel:nl + 1];
            }
        }
        [ms appendString:@"</member>\n"];
    }
    [ms appendString:@"</struct>\n"];
    [ms appendString:@"</value>\n"];
}
- (void)encodeArrayXMLRPC:(NSArray *)a inXML:(NSMutableString *)ms nestingLevel:(int)nl;
{
// interne Methode
    /*
     <value>
     <array>
        <data>
           <value>...</value>
         </data>
     </array>
     </value>
    */
    // NSString *nesting = [NSString stringWith:nl timesString:@"\t"];
    int i,j;
    [ms appendString:@"<value>\n"];
    [ms appendString:@"<array>\n"];
    [ms appendString:@"<data>\n"];
    for(i=0,j=[a count];i<j;i++){
        id o=[a oai:i];
        if([o isKindOfClass:[NSString class]]){
            [ms appendString:@"<value>"];
            [ms appendString:[o xmlEscapedString]];
            [ms appendString:@"</value>\n"];
        }else{
            if([o isKindOfClass:[NSDictionary class]]){
                [self encodeDictionaryXMLRPC:o inXML:ms nestingLevel:nl + 1];
            }else if([o isKindOfClass:[NSArray class]]){
                [self encodeArrayXMLRPC:o inXML:ms nestingLevel:nl + 1];
            }
        }
    }
    [ms appendString:@"</data>\n"];
    [ms appendString:@"</array>\n"];
    [ms appendString:@"</value>\n"];
}
- (NSString *)encodeObject:o withDocType:(NSString *)docType;
{
// o muss ein Dictionary oder Array sein
// docType ist ein frei waehlbarer name
    NSMutableString *ms = [NSMutableString stringWithCapacity:1000];
    [ms setString:@"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"];
    if([o isKindOfClass:[NSDictionary class]]){
        [self encodeDictionary:o inXML:ms forName:docType  nestingLevel:0];
    }else if([o isKindOfClass:[NSArray class]]){
        [self encodeArray:o inXML:ms forName:docType  nestingLevel:0];
    }else{
        LOGS(@"falsche Klasse; muss Dictionary oder Array sein");
        return @"";
    }
    return ms;
}
- (void)encodeDictionary:(NSDictionary *)d inXML:(NSMutableString *)ms forName:(NSString *)s nestingLevel:(int)nl;
{
// interne Methode
    NSArray *a1=[d allKeys];
    NSArray *a2=[d allObjects];
    NSString *dictName = [s xmlEscapedString];
    NSString *nesting = [NSString stringWith:nl timesString:@"\t"];
    int i,j;
    [ms appendString:[NSSWF @"%@<%@>\n",nesting,dictName]];
    for(i=0,j=[a1 count];i<j;i++){
        NSString *k = [a1 oai:i];
        id o=[a2 oai:i];
        if([o isKindOfClass:[NSString class]]){
            NSString *s1 = [k xmlEscapedString];
            [ms appendString:[NSSWF @"%@\t<%@>%@</%@>\n",nesting,s1,[o xmlEscapedString],s1]];
        }else{
            if([o isKindOfClass:[NSDictionary class]]){
                [self encodeDictionary:o inXML:ms forName:k nestingLevel:nl + 1];
            }else if([o isKindOfClass:[NSArray class]]){
                [self encodeArray:o inXML:ms forName:k  nestingLevel:nl + 1];
            }
        }
    }
    [ms appendString:[NSSWF @"%@</%@>\n",nesting,dictName]];
}
- (void)encodeArray:(NSArray *)a inXML:(NSMutableString *)ms forName:(NSString *)s nestingLevel:(int)nl;
{
// interne Methode
    NSString *arrayName = [s xmlEscapedString];
    NSString *nesting = [NSString stringWith:nl timesString:@"\t"];
    int i,j;
    [ms appendString:[NSSWF @"%@<%@>\n",nesting,arrayName]];
    for(i=0,j=[a count];i<j;i++){
        id o=[a oai:i];
        if([o isKindOfClass:[NSString class]]){
            [ms appendString:[NSSWF @"%@\t<NSArrayItem>%@</NSArrayItem>\n",nesting,[o xmlEscapedString]]];
        }else{
            if([o isKindOfClass:[NSDictionary class]]){
                [self encodeDictionary:o inXML:ms forName:@"NSArrayItem" nestingLevel:nl + 1];
            }else if([o isKindOfClass:[NSArray class]]){
                [self encodeArray:o inXML:ms forName:@"NSArrayItem" nestingLevel:nl + 1];
            }
        }
    }
    [ms appendString:[NSSWF @"%@</%@>\n",nesting,arrayName]];
}
- (id)objectFromXML:(NSString *)xml;
{
// erst den Baum aufbauen; danach analysieren und entscheiden, was Dictionaries und Arrays sind;
    XMLObject *rootObject = [self objectTreeFromXML:xml];
    if(!rootObject)return nil;
// jetzt den Baum analysieren
   if([rootObject determineConreteContainer]){
       if([rootObject ma])return [rootObject ma];
       if([rootObject md])return [rootObject md];
   }
   return nil;
}
- (XMLObject *)objectTreeFromXML:(NSString *)xml;
{
    XMLObject *rootObject = nil,*currentObject=nil;
    NSString *xmlname;
    NSRange r;
    r = [xml rangeOfString:@"<?"];
    if(r.length){
        xml = [xml secureSubstringFromIndex:r.location + r.length];
        r = [xml rangeOfString:@"?>"];
        if(!(r.length)){
            LOGS(([NSSWF @"unmatched <? %@",[xml abbreviated60String]]));
            return nil;
        }else{
            xml = [xml secureSubstringFromIndex:r.location + r.length];
        }
    }
    while(YES){
// ist das naechste non-white-space Zeichen ein < kommt ein Objekt oder Kommentar oder endetag, sonst der Content des currentObject
        xml = [xml stringWithoutLeadingWhiteSpaceCRLF];
        if(!FILLED(xml))break; // fertig;
        if([xml characterAtIndex:0] == '<'){
            if([xml hasSecurePrefix:@"<!--"]){
// ein Kommentar
                xml = [xml substringFromIndex:4];
                r = [xml rangeOfString:@"-->"];
                if(!(r.length)){
                    LOGS(([NSSWF @"missing end of comment --> %@",[xml abbreviated60String]]));
                    return nil;
                }else{
                    xml = [xml secureSubstringFromIndex:r.location + r.length];
                }
            }else if([xml hasSecurePrefix:@"</"]){
// beendet currentObject;
// name im endetag muss mit name des currentObject uebereinstimmen
                xml = [xml substringFromIndex:2];
                r = [xml rangeOfString:@">"];
                if(!(r.length)){
                    LOGS(([NSSWF @"missing > in endtag %@",[xml abbreviated60String]]));
                    return nil;
                }else{
                    xmlname = [[xml secureSubstringToIndex:r.location]stringBySubstitutingXMLEscapes];
                    if(!FILLED(xmlname)){
                        LOGS(([NSSWF @"empty Name in endtag %@ ",[xml abbreviated60String]]));
                        return nil;
                    }
                    if(![xmlname iE:[currentObject name]]){
                        LOGS(([NSSWF @"Name %@ doesn't match name of starttag %@",[xml abbreviated60String],[currentObject name]]));
                        return nil;
                    }
                    xml = [xml secureSubstringFromIndex:r.location + r.length];
                    
// dieses Objekt ist fertig geparsed
                    currentObject = [currentObject parent];
                }
            }else{
// hier beginnt vermutlich ein Name
                xml = [xml substringFromIndex:1];
                r = [xml rangeOfString:@">"];
                if(!(r.length)){
                    LOGS(([NSSWF @"missing > %@",[xml abbreviated60String]]));
                    return nil;
                }else{
                    NSRange r1;
                    XMLObject *o;
                    xmlname = [[xml secureSubstringToIndex:r.location]stringBySubstitutingXMLEscapes];
                    r1 = [xmlname rangeOfString:@" "];
                    if(r1.length){
                        // Attribute des Namens vergessen wir jetzt mal
                        xmlname = [xmlname secureSubstringToIndex:r1.location];
                    }
                    if(!FILLED(xmlname)){
                        LOGS(([NSSWF @"empty Name %@",[xml abbreviated60String]]));
                        return nil;
                    }
                    o = [XMLObject xmlObjectWithName:xmlname];
                    [o setTyp:XMLObjectTyp_Container];
                    [[currentObject children]addObject:o];
                    [o setParent:currentObject];
                    currentObject = o;
                    if(!rootObject){
                        rootObject = currentObject; 
                    }
                    xml = [xml secureSubstringFromIndex:r.location + r.length];
                }
            }
        }else{
            [currentObject setTyp:XMLObjectTyp_Element];
// content des element
            r = [xml rangeOfString:@"</"];
            if(!(r.length)){
                LOGS(([NSSWF @"missing endtag of element </ %@",[xml abbreviated60String]]));
                return nil;
            }else{
                [currentObject setContent:[[xml secureSubstringToIndex:r.location]stringBySubstitutingXMLEscapes]];
                xml = [xml secureSubstringFromIndex:r.location + r.length];
// name im endetag muss mit name des currentObject uebereinstimmen
                r = [xml rangeOfString:@">"];
                if(!(r.length)){
                    LOGS(([NSSWF @"missing > in endtag %@",[xml abbreviated60String]]));
                    return nil;
                }else{
                    xmlname = [[xml secureSubstringToIndex:r.location]stringBySubstitutingXMLEscapes];
                    if(!FILLED(xmlname)){
                        LOGS(([NSSWF @"empty Name in endtag %@",[xml abbreviated60String]]));
                        return nil;
                    }
                    if(![xmlname iE:[currentObject name]]){
                        LOGS(([NSSWF @"Name %@ doesn't match name of starttag %@",[xml abbreviated60String],[currentObject name]]));
                        return nil;
                    }
                    xml = [xml substringFromIndex:r.location + r.length];
// dieses Objekt ist fertig geparsed
                    currentObject = [currentObject parent];
                }
            }
        }
    }
    if(!rootObject){
        LOGS(@"no rootObject in xml");
        return nil;
    }
    if([rootObject typ]==XMLObjectTyp_Element){
        LOGS(@"rootObject ist kein Container-Objekt");
        return nil;
    }
    return rootObject;
}
- (NSData *)httpGet:(NSString *)uri host:(NSString *)host;
{
    NSMutableData *response = [NSMutableData dataWithCapacity:4096];
    PBSocket *socket;
    if(!FILLED(uri) || !FILLED(host)){LOGS(@"no host/uri"); return response;}
    if(!(socket = [PBSocket socket])){LOGS(@"no socket"); return response;}
    [socket connectToHostName:host port:80];
    if(![socket connected]){LOGS(@"no connect"); return response;}
    [socket writeString:[NSSWF @"GET %@ HTTP/1.0\r\nHost: %@\r\n\r\n",uri,host]];
    [socket readData:response];
    return response;
}
- (NSData *)httpPost:(NSString *)uri host:(NSString *)host soa:(NSString *)soa parm:(NSDictionary *)parm docType:(NSString *)docType;
{
// soa ist der optionale Name eines soa-Aufrufes; in Aprica ist dies ein Script-Name;
// parm ist ein Dictionary, das in XML umgewandelt zum host transportiert wird
// docType ist der optionale Name des XML-Dokuments; falls leer, wird ein default genommen;
    NSMutableData *response = [NSMutableData dataWithCapacity:4096];
    PBSocket *socket;
    NSMutableString *ms = [NSMutableString stringWithCapacity:4096]; // hier wird der request zusammengebaut
    if(!FILLED(uri) || !FILLED(host)){LOGS(@"no host/uri"); return response;}
    if(!(socket = [PBSocket socket])){LOGS(@"no socket"); return response;}
    [socket connectToHostName:host port:80];
    if(![socket connected]){LOGS(@"no connect"); return response;}
    [ms setString:[NSSWF @"POST %@ HTTP/1.0\r\n",uri]];
    [ms appendString:[NSSWF @"Host: %@\r\n",host]];
    if(FILLED(soa)){
        [ms appendString:[NSSWF @"soa: %@\r\n",soa]]; // ein zusaetzlicher Header nimmt das Kommando auf
    }
    if(parm){
        NSString *xml;
        if(!FILLED(docType))docType = @"pirmin";
        xml = [self encodeObject:parm withDocType:docType];
        [ms appendString:[NSSWF @"Content-Length: %i\r\n\r\n",[xml length]]];
        [ms appendString:xml];
    }else{
        [ms appendString:@"Content-Length: 0\r\n\r\n"];
    }
    if(log_changes)LOG(ms);
    [socket writeString:ms];
    [socket readData:response];
    return response;
}
- (NSData *)httpPostXMLRPC:(NSString *)uri host:(NSString *)host methodName:(NSString *)methodName params:params single:(BOOL)single;
{
// nach http://www.xmlrpc.com/spec
/*
 <methodCall>
    <methodName>examples.getStateName</methodName>
    <params>
       <param>
 <value>
 <struct>
    <member>
       <name>...</name>
       <value>...</value>
    </member>
</struct>
</value>
        </param>
     </params>
 </methodCall>
*/
    NSMutableData *response = [NSMutableData dataWithCapacity:4096];
    PBSocket *socket;
    NSMutableString *ms = [NSMutableString stringWithCapacity:4096]; // hier wird der request zusammengebaut
    NSString *xml;
    if(!FILLED(uri) || !FILLED(host)){LOGS(@"no host/uri"); return response;}
    if(!(socket = [PBSocket socket])){LOGS(@"no socket"); return response;}
    [socket connectToHostName:host port:80];
    if(![socket connected]){LOGS(@"no connect"); return response;}
    [ms setString:[NSSWF @"POST %@ HTTP/1.0\r\n",uri]];
    [ms appendString:[NSSWF @"Host: %@\r\n",host]];
    [ms appendString:@"Content-Type: text/xml;chartype=UTF-8\r\n"];
    xml = [self encodeObjectXMLRPC:params methodName:methodName single:single];
    [ms appendString:[NSSWF @"Content-Length: %i\r\n\r\n",[xml length]]];
    [ms appendString:xml];
    if(log_changes)LOG(ms);
    [socket writeString:ms];
    [socket readData:response];
    return response;
}
@end
Foto