Upgrade scintilla to 3.6.7
[TortoiseGit.git] / ext / scintilla / src / Editor.h
bloba779a84305bf666b682b55ea95a30c7c27c0d127
1 // Scintilla source code edit control
2 /** @file Editor.h
3 ** Defines the main editor class.
4 **/
5 // Copyright 1998-2011 by Neil Hodgson <neilh@scintilla.org>
6 // The License.txt file describes the conditions under which this software may be distributed.
8 #ifndef EDITOR_H
9 #define EDITOR_H
11 #ifdef SCI_NAMESPACE
12 namespace Scintilla {
13 #endif
15 /**
17 class Timer {
18 public:
19 bool ticking;
20 int ticksToWait;
21 enum {tickSize = 100};
22 TickerID tickerID;
24 Timer();
27 /**
29 class Idler {
30 public:
31 bool state;
32 IdlerID idlerID;
34 Idler();
37 /**
38 * When platform has a way to generate an event before painting,
39 * accumulate needed styling range and other work items in
40 * WorkNeeded to avoid unnecessary work inside paint handler
42 class WorkNeeded {
43 public:
44 enum workItems {
45 workNone=0,
46 workStyle=1,
47 workUpdateUI=2
49 enum workItems items;
50 Position upTo;
52 WorkNeeded() : items(workNone), upTo(0) {}
53 void Reset() {
54 items = workNone;
55 upTo = 0;
57 void Need(workItems items_, Position pos) {
58 if ((items_ & workStyle) && (upTo < pos))
59 upTo = pos;
60 items = static_cast<workItems>(items | items_);
64 /**
65 * Hold a piece of text selected for copying or dragging, along with encoding and selection format information.
67 class SelectionText {
68 std::string s;
69 public:
70 bool rectangular;
71 bool lineCopy;
72 int codePage;
73 int characterSet;
74 SelectionText() : rectangular(false), lineCopy(false), codePage(0), characterSet(0) {}
75 ~SelectionText() {
77 void Clear() {
78 s.clear();
79 rectangular = false;
80 lineCopy = false;
81 codePage = 0;
82 characterSet = 0;
84 void Copy(const std::string &s_, int codePage_, int characterSet_, bool rectangular_, bool lineCopy_) {
85 s = s_;
86 codePage = codePage_;
87 characterSet = characterSet_;
88 rectangular = rectangular_;
89 lineCopy = lineCopy_;
90 FixSelectionForClipboard();
92 void Copy(const SelectionText &other) {
93 Copy(other.s, other.codePage, other.characterSet, other.rectangular, other.lineCopy);
95 const char *Data() const {
96 return s.c_str();
98 size_t Length() const {
99 return s.length();
101 size_t LengthWithTerminator() const {
102 return s.length() + 1;
104 bool Empty() const {
105 return s.empty();
107 private:
108 void FixSelectionForClipboard() {
109 // To avoid truncating the contents of the clipboard when pasted where the
110 // clipboard contains NUL characters, replace NUL characters by spaces.
111 std::replace(s.begin(), s.end(), '\0', ' ');
115 struct WrapPending {
116 // The range of lines that need to be wrapped
117 enum { lineLarge = 0x7ffffff };
118 int start; // When there are wraps pending, will be in document range
119 int end; // May be lineLarge to indicate all of document after start
120 WrapPending() {
121 start = lineLarge;
122 end = lineLarge;
124 void Reset() {
125 start = lineLarge;
126 end = lineLarge;
128 void Wrapped(int line) {
129 if (start == line)
130 start++;
132 bool NeedsWrap() const {
133 return start < end;
135 bool AddRange(int lineStart, int lineEnd) {
136 const bool neededWrap = NeedsWrap();
137 bool changed = false;
138 if (start > lineStart) {
139 start = lineStart;
140 changed = true;
142 if ((end < lineEnd) || !neededWrap) {
143 end = lineEnd;
144 changed = true;
146 return changed;
152 class Editor : public EditModel, public DocWatcher {
153 // Private so Editor objects can not be copied
154 explicit Editor(const Editor &);
155 Editor &operator=(const Editor &);
157 protected: // ScintillaBase subclass needs access to much of Editor
159 /** On GTK+, Scintilla is a container widget holding two scroll bars
160 * whereas on Windows there is just one window with both scroll bars turned on. */
161 Window wMain; ///< The Scintilla parent window
162 Window wMargin; ///< May be separate when using a scroll view for wMain
164 /** Style resources may be expensive to allocate so are cached between uses.
165 * When a style attribute is changed, this cache is flushed. */
166 bool stylesValid;
167 ViewStyle vs;
168 int technology;
169 Point sizeRGBAImage;
170 float scaleRGBAImage;
172 MarginView marginView;
173 EditView view;
175 int cursorMode;
177 bool hasFocus;
178 bool mouseDownCaptures;
180 int xCaretMargin; ///< Ensure this many pixels visible on both sides of caret
181 bool horizontalScrollBarVisible;
182 int scrollWidth;
183 bool verticalScrollBarVisible;
184 bool endAtLastLine;
185 int caretSticky;
186 int marginOptions;
187 bool mouseSelectionRectangularSwitch;
188 bool multipleSelection;
189 bool additionalSelectionTyping;
190 int multiPasteMode;
192 int virtualSpaceOptions;
194 KeyMap kmap;
196 Timer timer;
197 Timer autoScrollTimer;
198 enum { autoScrollDelay = 200 };
200 Idler idler;
202 Point lastClick;
203 unsigned int lastClickTime;
204 Point doubleClickCloseThreshold;
205 int dwellDelay;
206 int ticksToDwell;
207 bool dwelling;
208 enum { selChar, selWord, selSubLine, selWholeLine } selectionType;
209 Point ptMouseLast;
210 enum { ddNone, ddInitial, ddDragging } inDragDrop;
211 bool dropWentOutside;
212 SelectionPosition posDrop;
213 int hotSpotClickPos;
214 int lastXChosen;
215 int lineAnchorPos;
216 int originalAnchorPos;
217 int wordSelectAnchorStartPos;
218 int wordSelectAnchorEndPos;
219 int wordSelectInitialCaretPos;
220 int targetStart;
221 int targetEnd;
222 int searchFlags;
223 int topLine;
224 int posTopLine;
225 int lengthForEncode;
227 int needUpdateUI;
229 enum { notPainting, painting, paintAbandoned } paintState;
230 bool paintAbandonedByStyling;
231 PRectangle rcPaint;
232 bool paintingAllText;
233 bool willRedrawAll;
234 WorkNeeded workNeeded;
235 int idleStyling;
236 bool needIdleStyling;
238 int modEventMask;
240 SelectionText drag;
242 int caretXPolicy;
243 int caretXSlop; ///< Ensure this many pixels visible on both sides of caret
245 int caretYPolicy;
246 int caretYSlop; ///< Ensure this many lines visible on both sides of caret
248 int visiblePolicy;
249 int visibleSlop;
251 int searchAnchor;
253 bool recordingMacro;
255 int foldAutomatic;
257 // Wrapping support
258 WrapPending wrapPending;
260 bool convertPastes;
262 Editor();
263 virtual ~Editor();
264 virtual void Initialise() = 0;
265 virtual void Finalise();
267 void InvalidateStyleData();
268 void InvalidateStyleRedraw();
269 void RefreshStyleData();
270 void SetRepresentations();
271 void DropGraphics(bool freeObjects);
272 void AllocateGraphics();
274 // The top left visible point in main window coordinates. Will be 0,0 except for
275 // scroll views where it will be equivalent to the current scroll position.
276 virtual Point GetVisibleOriginInMain() const;
277 Point DocumentPointFromView(Point ptView) const; // Convert a point from view space to document
278 int TopLineOfMain() const; // Return the line at Main's y coordinate 0
279 virtual PRectangle GetClientRectangle() const;
280 virtual PRectangle GetClientDrawingRectangle();
281 PRectangle GetTextRectangle() const;
283 virtual int LinesOnScreen() const;
284 int LinesToScroll() const;
285 int MaxScrollPos() const;
286 SelectionPosition ClampPositionIntoDocument(SelectionPosition sp) const;
287 Point LocationFromPosition(SelectionPosition pos);
288 Point LocationFromPosition(int pos);
289 int XFromPosition(int pos);
290 int XFromPosition(SelectionPosition sp);
291 SelectionPosition SPositionFromLocation(Point pt, bool canReturnInvalid=false, bool charPosition=false, bool virtualSpace=true);
292 int PositionFromLocation(Point pt, bool canReturnInvalid = false, bool charPosition = false);
293 SelectionPosition SPositionFromLineX(int lineDoc, int x);
294 int PositionFromLineX(int line, int x);
295 int LineFromLocation(Point pt) const;
296 void SetTopLine(int topLineNew);
298 virtual bool AbandonPaint();
299 virtual void RedrawRect(PRectangle rc);
300 virtual void DiscardOverdraw();
301 virtual void Redraw();
302 void RedrawSelMargin(int line=-1, bool allAfter=false);
303 PRectangle RectangleFromRange(Range r, int overlap);
304 void InvalidateRange(int start, int end);
306 bool UserVirtualSpace() const {
307 return ((virtualSpaceOptions & SCVS_USERACCESSIBLE) != 0);
309 int CurrentPosition() const;
310 bool SelectionEmpty() const;
311 SelectionPosition SelectionStart();
312 SelectionPosition SelectionEnd();
313 void SetRectangularRange();
314 void ThinRectangularRange();
315 void InvalidateSelection(SelectionRange newMain, bool invalidateWholeSelection=false);
316 void InvalidateWholeSelection();
317 void SetSelection(SelectionPosition currentPos_, SelectionPosition anchor_);
318 void SetSelection(int currentPos_, int anchor_);
319 void SetSelection(SelectionPosition currentPos_);
320 void SetSelection(int currentPos_);
321 void SetEmptySelection(SelectionPosition currentPos_);
322 void SetEmptySelection(int currentPos_);
323 enum AddNumber { addOne, addEach };
324 void MultipleSelectAdd(AddNumber addNumber);
325 bool RangeContainsProtected(int start, int end) const;
326 bool SelectionContainsProtected();
327 int MovePositionOutsideChar(int pos, int moveDir, bool checkLineEnd=true) const;
328 SelectionPosition MovePositionOutsideChar(SelectionPosition pos, int moveDir, bool checkLineEnd=true) const;
329 void MovedCaret(SelectionPosition newPos, SelectionPosition previousPos, bool ensureVisible);
330 void MovePositionTo(SelectionPosition newPos, Selection::selTypes selt=Selection::noSel, bool ensureVisible=true);
331 void MovePositionTo(int newPos, Selection::selTypes selt=Selection::noSel, bool ensureVisible=true);
332 SelectionPosition MovePositionSoVisible(SelectionPosition pos, int moveDir);
333 SelectionPosition MovePositionSoVisible(int pos, int moveDir);
334 Point PointMainCaret();
335 void SetLastXChosen();
337 void ScrollTo(int line, bool moveThumb=true);
338 virtual void ScrollText(int linesToMove);
339 void HorizontalScrollTo(int xPos);
340 void VerticalCentreCaret();
341 void MoveSelectedLines(int lineDelta);
342 void MoveSelectedLinesUp();
343 void MoveSelectedLinesDown();
344 void MoveCaretInsideView(bool ensureVisible=true);
345 int DisplayFromPosition(int pos);
347 struct XYScrollPosition {
348 int xOffset;
349 int topLine;
350 XYScrollPosition(int xOffset_, int topLine_) : xOffset(xOffset_), topLine(topLine_) {}
351 bool operator==(const XYScrollPosition &other) const {
352 return (xOffset == other.xOffset) && (topLine == other.topLine);
355 enum XYScrollOptions {
356 xysUseMargin=0x1,
357 xysVertical=0x2,
358 xysHorizontal=0x4,
359 xysDefault=xysUseMargin|xysVertical|xysHorizontal};
360 XYScrollPosition XYScrollToMakeVisible(const SelectionRange &range, const XYScrollOptions options);
361 void SetXYScroll(XYScrollPosition newXY);
362 void EnsureCaretVisible(bool useMargin=true, bool vert=true, bool horiz=true);
363 void ScrollRange(SelectionRange range);
364 void ShowCaretAtCurrentPosition();
365 void DropCaret();
366 void CaretSetPeriod(int period);
367 void InvalidateCaret();
368 virtual void NotifyCaretMove();
369 virtual void UpdateSystemCaret();
371 bool Wrapping() const;
372 void NeedWrapping(int docLineStart=0, int docLineEnd=WrapPending::lineLarge);
373 bool WrapOneLine(Surface *surface, int lineToWrap);
374 enum wrapScope {wsAll, wsVisible, wsIdle};
375 bool WrapLines(enum wrapScope ws);
376 void LinesJoin();
377 void LinesSplit(int pixelWidth);
379 void PaintSelMargin(Surface *surface, PRectangle &rc);
380 void RefreshPixMaps(Surface *surfaceWindow);
381 void Paint(Surface *surfaceWindow, PRectangle rcArea);
382 long FormatRange(bool draw, Sci_RangeToFormat *pfr);
383 int TextWidth(int style, const char *text);
385 virtual void SetVerticalScrollPos() = 0;
386 virtual void SetHorizontalScrollPos() = 0;
387 virtual bool ModifyScrollBars(int nMax, int nPage) = 0;
388 virtual void ReconfigureScrollBars();
389 void SetScrollBars();
390 void ChangeSize();
392 void FilterSelections();
393 int RealizeVirtualSpace(int position, unsigned int virtualSpace);
394 SelectionPosition RealizeVirtualSpace(const SelectionPosition &position);
395 void AddChar(char ch);
396 virtual void AddCharUTF(const char *s, unsigned int len, bool treatAsDBCS=false);
397 void ClearBeforeTentativeStart();
398 void InsertPaste(const char *text, int len);
399 enum PasteShape { pasteStream=0, pasteRectangular = 1, pasteLine = 2 };
400 void InsertPasteShape(const char *text, int len, PasteShape shape);
401 void ClearSelection(bool retainMultipleSelections = false);
402 void ClearAll();
403 void ClearDocumentStyle();
404 void Cut();
405 void PasteRectangular(SelectionPosition pos, const char *ptr, int len);
406 virtual void Copy() = 0;
407 virtual void CopyAllowLine();
408 virtual bool CanPaste();
409 virtual void Paste() = 0;
410 void Clear();
411 void SelectAll();
412 void Undo();
413 void Redo();
414 void DelCharBack(bool allowLineStartDeletion);
415 virtual void ClaimSelection() = 0;
417 static int ModifierFlags(bool shift, bool ctrl, bool alt, bool meta=false, bool super=false);
418 virtual void NotifyChange() = 0;
419 virtual void NotifyFocus(bool focus);
420 virtual void SetCtrlID(int identifier);
421 virtual int GetCtrlID() { return ctrlID; }
422 virtual void NotifyParent(SCNotification scn) = 0;
423 virtual void NotifyStyleToNeeded(int endStyleNeeded);
424 void NotifyChar(int ch);
425 void NotifySavePoint(bool isSavePoint);
426 void NotifyModifyAttempt();
427 virtual void NotifyDoubleClick(Point pt, int modifiers);
428 virtual void NotifyDoubleClick(Point pt, bool shift, bool ctrl, bool alt);
429 void NotifyHotSpotClicked(int position, int modifiers);
430 void NotifyHotSpotClicked(int position, bool shift, bool ctrl, bool alt);
431 void NotifyHotSpotDoubleClicked(int position, int modifiers);
432 void NotifyHotSpotDoubleClicked(int position, bool shift, bool ctrl, bool alt);
433 void NotifyHotSpotReleaseClick(int position, int modifiers);
434 void NotifyHotSpotReleaseClick(int position, bool shift, bool ctrl, bool alt);
435 bool NotifyUpdateUI();
436 void NotifyPainted();
437 void NotifyIndicatorClick(bool click, int position, int modifiers);
438 void NotifyIndicatorClick(bool click, int position, bool shift, bool ctrl, bool alt);
439 bool NotifyMarginClick(Point pt, int modifiers);
440 bool NotifyMarginClick(Point pt, bool shift, bool ctrl, bool alt);
441 void NotifyNeedShown(int pos, int len);
442 void NotifyDwelling(Point pt, bool state);
443 void NotifyZoom();
445 void NotifyModifyAttempt(Document *document, void *userData);
446 void NotifySavePoint(Document *document, void *userData, bool atSavePoint);
447 void CheckModificationForWrap(DocModification mh);
448 void NotifyModified(Document *document, DocModification mh, void *userData);
449 void NotifyDeleted(Document *document, void *userData);
450 void NotifyStyleNeeded(Document *doc, void *userData, int endPos);
451 void NotifyLexerChanged(Document *doc, void *userData);
452 void NotifyErrorOccurred(Document *doc, void *userData, int status);
453 void NotifyMacroRecord(unsigned int iMessage, uptr_t wParam, sptr_t lParam);
455 void ContainerNeedsUpdate(int flags);
456 void PageMove(int direction, Selection::selTypes selt=Selection::noSel, bool stuttered = false);
457 enum { cmSame, cmUpper, cmLower };
458 virtual std::string CaseMapString(const std::string &s, int caseMapping);
459 void ChangeCaseOfSelection(int caseMapping);
460 void LineTranspose();
461 void Duplicate(bool forLine);
462 virtual void CancelModes();
463 void NewLine();
464 SelectionPosition PositionUpOrDown(SelectionPosition spStart, int direction, int lastX);
465 void CursorUpOrDown(int direction, Selection::selTypes selt);
466 void ParaUpOrDown(int direction, Selection::selTypes selt);
467 int StartEndDisplayLine(int pos, bool start);
468 int VCHomeDisplayPosition(int position);
469 int VCHomeWrapPosition(int position);
470 int LineEndWrapPosition(int position);
471 int HorizontalMove(unsigned int iMessage);
472 int DelWordOrLine(unsigned int iMessage);
473 virtual int KeyCommand(unsigned int iMessage);
474 virtual int KeyDefault(int /* key */, int /*modifiers*/);
475 int KeyDownWithModifiers(int key, int modifiers, bool *consumed);
476 int KeyDown(int key, bool shift, bool ctrl, bool alt, bool *consumed=0);
478 void Indent(bool forwards);
480 virtual CaseFolder *CaseFolderForEncoding();
481 long FindText(uptr_t wParam, sptr_t lParam);
482 void SearchAnchor();
483 long SearchText(unsigned int iMessage, uptr_t wParam, sptr_t lParam);
484 long SearchInTarget(const char *text, int length);
485 void GoToLine(int lineNo);
487 virtual void CopyToClipboard(const SelectionText &selectedText) = 0;
488 std::string RangeText(int start, int end) const;
489 void CopySelectionRange(SelectionText *ss, bool allowLineCopy=false);
490 void CopyRangeToClipboard(int start, int end);
491 void CopyText(int length, const char *text);
492 void SetDragPosition(SelectionPosition newPos);
493 virtual void DisplayCursor(Window::Cursor c);
494 virtual bool DragThreshold(Point ptStart, Point ptNow);
495 virtual void StartDrag();
496 void DropAt(SelectionPosition position, const char *value, size_t lengthValue, bool moving, bool rectangular);
497 void DropAt(SelectionPosition position, const char *value, bool moving, bool rectangular);
498 /** PositionInSelection returns true if position in selection. */
499 bool PositionInSelection(int pos);
500 bool PointInSelection(Point pt);
501 bool PointInSelMargin(Point pt) const;
502 Window::Cursor GetMarginCursor(Point pt) const;
503 void TrimAndSetSelection(int currentPos_, int anchor_);
504 void LineSelection(int lineCurrentPos_, int lineAnchorPos_, bool wholeLine);
505 void WordSelection(int pos);
506 void DwellEnd(bool mouseMoved);
507 void MouseLeave();
508 virtual void ButtonDownWithModifiers(Point pt, unsigned int curTime, int modifiers);
509 virtual void ButtonDown(Point pt, unsigned int curTime, bool shift, bool ctrl, bool alt);
510 void ButtonMoveWithModifiers(Point pt, int modifiers);
511 void ButtonMove(Point pt);
512 void ButtonUp(Point pt, unsigned int curTime, bool ctrl);
514 void Tick();
515 bool Idle();
516 virtual void SetTicking(bool on);
517 enum TickReason { tickCaret, tickScroll, tickWiden, tickDwell, tickPlatform };
518 virtual void TickFor(TickReason reason);
519 virtual bool FineTickerAvailable();
520 virtual bool FineTickerRunning(TickReason reason);
521 virtual void FineTickerStart(TickReason reason, int millis, int tolerance);
522 virtual void FineTickerCancel(TickReason reason);
523 virtual bool SetIdle(bool) { return false; }
524 virtual void SetMouseCapture(bool on) = 0;
525 virtual bool HaveMouseCapture() = 0;
526 void SetFocusState(bool focusState);
528 int PositionAfterArea(PRectangle rcArea) const;
529 void StyleToPositionInView(Position pos);
530 int PositionAfterMaxStyling(int posMax, bool scrolling) const;
531 void StartIdleStyling(bool truncatedLastStyling);
532 void StyleAreaBounded(PRectangle rcArea, bool scrolling);
533 void IdleStyling();
534 virtual void IdleWork();
535 virtual void QueueIdleWork(WorkNeeded::workItems items, int upTo=0);
537 virtual bool PaintContains(PRectangle rc);
538 bool PaintContainsMargin();
539 void CheckForChangeOutsidePaint(Range r);
540 void SetBraceHighlight(Position pos0, Position pos1, int matchStyle);
542 void SetAnnotationHeights(int start, int end);
543 virtual void SetDocPointer(Document *document);
545 void SetAnnotationVisible(int visible);
547 int ExpandLine(int line);
548 void SetFoldExpanded(int lineDoc, bool expanded);
549 void FoldLine(int line, int action);
550 void FoldExpand(int line, int action, int level);
551 int ContractedFoldNext(int lineStart) const;
552 void EnsureLineVisible(int lineDoc, bool enforcePolicy);
553 void FoldChanged(int line, int levelNow, int levelPrev);
554 void NeedShown(int pos, int len);
555 void FoldAll(int action);
557 int GetTag(char *tagValue, int tagNumber);
558 int ReplaceTarget(bool replacePatterns, const char *text, int length=-1);
560 bool PositionIsHotspot(int position) const;
561 bool PointIsHotspot(Point pt);
562 void SetHotSpotRange(Point *pt);
563 Range GetHotSpotRange() const;
564 void SetHoverIndicatorPosition(int position);
565 void SetHoverIndicatorPoint(Point pt);
567 int CodePage() const;
568 virtual bool ValidCodePage(int /* codePage */) const { return true; }
569 int WrapCount(int line);
570 void AddStyledText(char *buffer, int appendLength);
572 virtual sptr_t DefWndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) = 0;
573 void StyleSetMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam);
574 sptr_t StyleGetMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam);
576 static const char *StringFromEOLMode(int eolMode);
578 static sptr_t StringResult(sptr_t lParam, const char *val);
579 static sptr_t BytesResult(sptr_t lParam, const unsigned char *val, size_t len);
581 public:
582 // Public so the COM thunks can access it.
583 bool IsUnicodeMode() const;
584 // Public so scintilla_send_message can use it.
585 virtual sptr_t WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam);
586 // Public so scintilla_set_id can use it.
587 int ctrlID;
588 // Public so COM methods for drag and drop can set it.
589 int errorStatus;
590 friend class AutoSurface;
591 friend class SelectionLineIterator;
595 * A smart pointer class to ensure Surfaces are set up and deleted correctly.
597 class AutoSurface {
598 private:
599 Surface *surf;
600 public:
601 AutoSurface(Editor *ed, int technology = -1) : surf(0) {
602 if (ed->wMain.GetID()) {
603 surf = Surface::Allocate(technology != -1 ? technology : ed->technology);
604 if (surf) {
605 surf->Init(ed->wMain.GetID());
606 surf->SetUnicodeMode(SC_CP_UTF8 == ed->CodePage());
607 surf->SetDBCSMode(ed->CodePage());
611 AutoSurface(SurfaceID sid, Editor *ed, int technology = -1) : surf(0) {
612 if (ed->wMain.GetID()) {
613 surf = Surface::Allocate(technology != -1 ? technology : ed->technology);
614 if (surf) {
615 surf->Init(sid, ed->wMain.GetID());
616 surf->SetUnicodeMode(SC_CP_UTF8 == ed->CodePage());
617 surf->SetDBCSMode(ed->CodePage());
621 ~AutoSurface() {
622 delete surf;
624 Surface *operator->() const {
625 return surf;
627 operator Surface *() const {
628 return surf;
632 #ifdef SCI_NAMESPACE
634 #endif
636 #endif