#include #define DEBUG 0 #define kComponentSignatureString "BBPy.LM" #include #include #include //#include #include #include #include #include #include #if DEBUG void debugf_(const char* func,const char* fileName,long line, const char*fmt,...) { va_list arg; char msg[256]; va_start(arg, fmt); vsnprintf(msg,256 ,fmt, arg); DebugAssert(COMPONENT_SIGNATURE, DEBUG_NO_OPTIONS, kComponentSignatureString ": " , msg, nil, fileName, line, 0 ); //debug_string(msg); } #define debugf(FMT,...) debugf_( __FUNCTION__,__FILE__, __LINE__,FMT,__VA_ARGS__); #else #define debugf(FMT,...) #endif typedef const char *Str; enum{ kPyBBLMStringSubst = kBBLMFirstUserRunKind }; #define iswordchar(x) (isalnum(x)||x=='_') struct runloc{ bool past_gap; long pos; long last_start; unsigned char*p; }; char start(struct runloc& r,BBLMParamBlock &pb) { r.past_gap = false; r.last_start = pb.fCalcRunParams.fStartOffset; r.pos = pb.fCalcRunParams.fStartOffset; r.p = ((unsigned char*)pb.fText) + pb.fCalcRunParams.fStartOffset; // Adjust for the gap if weĠre not already past it. if ((!r.past_gap) && (r.pos >= pb.fTextGapLocation)){ r.p += pb.fTextGapLength; r.past_gap = true; } return *r.p; } char nextchar(struct runloc&r,BBLMParamBlock &pb) { if ( r.pos< pb.fTextLength){ ++r.pos; ++r.p; if ((!r.past_gap) && (r.pos >= pb.fTextGapLocation)){ r.p += pb.fTextGapLength; r.past_gap = true; } return *r.p; } else{ return 0; } } bool addRun(BBLMRunCode kind, int start,int len , const BBLMCallbackBlock& bblm_callbacks) { if (len > 0){ // Tie off the code run we were in, unless the length is zero. debugf("Run %d %d:%d", kind, start, start+len-1 ); return bblmAddRun( &bblm_callbacks, 'Pyth', kind, start, len, false); } else{ return true; } } bool addRunBefore (BBLMRunCode kind,struct runloc& r, const BBLMCallbackBlock& bblm_callbacks) { bool more_runs = addRun(kind, r.last_start, r.pos - r.last_start, bblm_callbacks); r.last_start = r.pos; return more_runs; } bool addRunTo (BBLMRunCode kind, struct runloc& r, const BBLMCallbackBlock& bblm_callbacks) { bool more_runs = addRun(kind, r.last_start, r.pos - r.last_start+1, bblm_callbacks); r.last_start = r.pos+1; return more_runs; } bool colorstr( char delim, BBLMParamBlock &pb, struct runloc &r, const BBLMCallbackBlock &bblm_callbacks) { bool tripple = false , pers = false, lookup = false, more_runs = true; char c = nextchar(r,pb); if (c == delim){ c = nextchar(r,pb); if (c == delim){ tripple = true; c = nextchar(r,pb); } else{ //double return addRunBefore(kBBLMRunIsSingleString,r,bblm_callbacks); } } while (c && more_runs){ if (pers ){ if (isalpha(c)){ more_runs = addRunTo(kPyBBLMStringSubst,r,bblm_callbacks); } else if (c == '('){ lookup = true; } } pers = false; if (c == delim){ if (tripple){ if ((c = nextchar(r,pb))== delim && (c = nextchar(r,pb)) == delim){ break; // end of tripple-quote. } } else{ break; // end of single-quote. } } else if (c== '\\'){ nextchar(r,pb); } else if (c=='\r'||c=='\n'){ if (!tripple){ break; } } else if (c=='%'){ more_runs = addRunBefore(kBBLMRunIsSingleString,r,bblm_callbacks); pers = true; } else if (c==')' && lookup){ more_runs = addRunTo(kPyBBLMStringSubst,r,bblm_callbacks); lookup = false; } c = nextchar(r,pb); } return more_runs && addRunTo(lookup?kPyBBLMStringSubst:kBBLMRunIsSingleString,r,bblm_callbacks); } bool colorcomment(BBLMParamBlock &pb, struct runloc &r, const BBLMCallbackBlock &bblm_callbacks) { while (char c = nextchar(r,pb)){ if (c=='\r'|| c=='\n'){ break; } } return addRunTo(kBBLMRunIsLineComment,r,bblm_callbacks); } void CalculateRuns(BBLMParamBlock &pb, const BBLMCallbackBlock &bblm_callbacks) { const struct rundesc *state = NULL; bool more_runs=true; struct runloc r; char c = start(r,pb); while (c && more_runs){ loop: // Process a char if (state==NULL){ //If we're in the basic 'code' state, check for each interesting char (rundelims[i].start). switch (c){ case '\'': case '"': more_runs = addRunBefore(kBBLMRunIsCode,r,bblm_callbacks); if (more_runs){ more_runs = colorstr(c,pb,r,bblm_callbacks); } break; case '#' : more_runs = addRunBefore(kBBLMRunIsCode,r,bblm_callbacks); if (more_runs){ more_runs = colorcomment(pb,r,bblm_callbacks); } break; default: break; } } c = nextchar(r,pb); } if (more_runs){ addRunBefore(kBBLMRunIsCode,r,bblm_callbacks); } } static void AdjustRange(BBLMParamBlock ¶ms, const BBLMCallbackBlock &callbacks) { DescType language; BBLMRunCode kind; SInt32 charPos; SInt32 length; UInt32 index = params.fAdjustRangeParams.fStartIndex; while( index > 0 && bblmGetRun(&callbacks, index, language, kind, charPos, length) && (kind==kPyBBLMStringSubst||kind==kBBLMRunIsSingleString)){ index--; }; params.fAdjustRangeParams.fStartIndex = index; } // The next couple funcs process the text of a file assumming it's in 1 piece in memory, // so they may not be called from CalculateRuns. bool matchword(BBLMParamBlock &pb, const char *pat ,unsigned long *pos) { const char *asciText = (const char *) (pb.fTextIsUnicode?NULL:pb.fText); int i; for (i=0; pat[i]; i++){ if (*pos+i>=pb.fTextLength){ return false; } if (asciText[*pos+i] != pat[i]){ return false; } } if ((*pos+i= 0){ for (int i=0; i <= nest; i++){ if (indent<=indents[i]){ nest = i; indents[nest]=indent; goto x; } } indents[++nest]=indent; x: if (matchword(pb,"def",&pos)){ addItem( pb, pos, nest, kBBLMFunctionMark, &bblm_callbacks); } else if (matchword(pb, "class", &pos)){ addItem( pb, pos, nest, kBBLMTypedef, &bblm_callbacks); } } eat_line(pb,&pos); } } OSErr main( BBLMParamBlock ¶ms, const BBLMCallbackBlock &bblm_callbacks, const BBXTCallbackBlock &bbxt_callbacks) { OSErr result; if ((params.fSignature != kBBLMParamBlockSignature) || (params.fLength < sizeof(BBLMParamBlock))) { return paramErr; } switch (params.fMessage) { case kBBLMInitMessage: case kBBLMDisposeMessage: { result = noErr; // nothing to do break; } case kBBLMCalculateRunsMessage: CalculateRuns(params, bblm_callbacks); result = noErr; break; case kBBLMScanForFunctionsMessage: ScanForFunctions(params, bblm_callbacks); result = noErr; break; case kBBLMAdjustRangeMessage: AdjustRange(params, bblm_callbacks); result = noErr; break; case kBBLMMapRunKindToColorCodeMessage: switch (params.fMapRunParams.fRunKind){ case kPyBBLMStringSubst: params.fMapRunParams.fColorCode = kBBLMSGMLAttributeNameColor; params.fMapRunParams.fMapped = true; break; default: params.fMapRunParams.fMapped = false; } result = noErr; break; case kBBLMEscapeStringMessage: case kBBLMAdjustEndMessage: case kBBLMMapColorCodeToColorMessage: case kBBLMSetCategoriesMessage: case kBBLMMatchKeywordMessage: { result = userCanceledErr; break; } default: { result = paramErr; break; } } return result; }