Sync to Wine-20050310:
authorGé van Geldorp <ge@gse.nl>
Tue, 15 Mar 2005 09:04:29 +0000 (09:04 +0000)
committerGé van Geldorp <ge@gse.nl>
Tue, 15 Mar 2005 09:04:29 +0000 (09:04 +0000)
import

svn path=/trunk/; revision=14091

24 files changed:
reactos/include/wine/richole.h [new file with mode: 0644]
reactos/lib/riched20/Makefile.in [new file with mode: 0644]
reactos/lib/riched20/Makefile.ros-template [new file with mode: 0644]
reactos/lib/riched20/caret.c [new file with mode: 0644]
reactos/lib/riched20/context.c [new file with mode: 0644]
reactos/lib/riched20/editor.c [new file with mode: 0644]
reactos/lib/riched20/editor.h [new file with mode: 0644]
reactos/lib/riched20/editstr.h [new file with mode: 0644]
reactos/lib/riched20/list.c [new file with mode: 0644]
reactos/lib/riched20/makefile [new file with mode: 0644]
reactos/lib/riched20/paint.c [new file with mode: 0644]
reactos/lib/riched20/para.c [new file with mode: 0644]
reactos/lib/riched20/reader.c [new file with mode: 0644]
reactos/lib/riched20/riched20.spec [new file with mode: 0644]
reactos/lib/riched20/richole.c [new file with mode: 0644]
reactos/lib/riched20/row.c [new file with mode: 0644]
reactos/lib/riched20/rtf.h [new file with mode: 0644]
reactos/lib/riched20/run.c [new file with mode: 0644]
reactos/lib/riched20/string.c [new file with mode: 0644]
reactos/lib/riched20/style.c [new file with mode: 0644]
reactos/lib/riched20/undo.c [new file with mode: 0644]
reactos/lib/riched20/wrap.c [new file with mode: 0644]
reactos/lib/uuid/uuid.c
reactos/w32api/include/richedit.h

diff --git a/reactos/include/wine/richole.h b/reactos/include/wine/richole.h
new file mode 100644 (file)
index 0000000..4a4f3df
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Compatibility header
+ *
+ * This header is wrapper to allow compilation of Wine DLLs under ReactOS
+ * build system. It contains definitions commonly refered to as Wineisms
+ * and definitions that are missing in w32api.
+ */
+
+#include <richedit.h>
+
+#include_next <richole.h>
+
+#ifndef WINE_RICHOLE_H_INCLUDED
+#define WINE_RICHOLE_H_INCLUDED
+
+#ifdef COBJMACROS
+/*** IUnknown methods ***/
+#define IRichEditOle_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b)
+#define IRichEditOle_AddRef(p) (p)->lpVtbl->AddRef(p)
+#define IRichEditOle_Release(p) (p)->lpVtbl->Release(p)
+/*** IRichEditOle methods ***/
+#define IRichEditOle_GetClientSite(p,a) (p)->lpVtbl->GetClientSite(p,a)
+#define IRichEditOle_GetObjectCount(p) (p)->lpVtbl->GetObjectCount(p)
+#define IRichEditOle_GetLinkCount(p) (p)->lpVtbl->GetLinkCount(p)
+#define IRichEditOle_GetObject(p,a,b,c) (p)->lpVtbl->GetObject(p,a,b,c)
+#define IRichEditOle_InsertObject(p,a) (p)->lpVtbl->InsertObject(p,a)
+#define IRichEditOle_ConvertObject(p,a,b,c) (p)->lpVtbl->ConvertObject(p,a,b,c)
+#define IRichEditOle_ActivateAs(p,a,b) (p)->lpVtbl->ActivateAs(p,a,b)
+#define IRichEditOle_SetHostNames(p,a,b) (p)->lpVtbl->SetHostNames(p,a,b)
+#define IRichEditOle_SetLinkAvailable(p,a,b) (p)->lpVtbl->SetLinkAvailable(p,a,b)
+#define IRichEditOle_SetDvaspect(p,a,b) (p)->lpVtbl->SetDvaspect(p,a,b)
+#define IRichEditOle_HandsOffStorage(p,a) (p)->lpVtbl->HandsOffStorage(p,a)
+#define IRichEditOle_SaveCompleted(p,a,b) (p)->lpVtbl->SaveCompleted(p,a,b)
+#define IRichEditOle_InPlaceDeactivate(p) (p)->lpVtbl->InPlaceDeactivate(p)
+#define IRichEditOle_ContextSensitiveHelp(p,a) (p)->lpVtbl->ContextSensitiveHelp(p,a)
+#define IRichEditOle_GetClipboardData(p,a,b,c) (p)->lpVtbl->GetClipboardData(p,a,b,c)
+#define IRichEditOle_ImportDataObject(p,a,b,c) (p)->lpVtbl->ImportDataObject(p,a,b,c)
+#endif
+
+#endif /* WINE_RICHOLE_H_INCLUDED */
diff --git a/reactos/lib/riched20/Makefile.in b/reactos/lib/riched20/Makefile.in
new file mode 100644 (file)
index 0000000..03602d9
--- /dev/null
@@ -0,0 +1,27 @@
+TOPSRCDIR = @top_srcdir@
+TOPOBJDIR = ../..
+SRCDIR    = @srcdir@
+VPATH     = @srcdir@
+MODULE    = riched20.dll
+IMPORTS   = user32 gdi32 kernel32
+EXTRALIBS = -luuid
+
+C_SRCS = \
+       caret.c \
+       context.c \
+       editor.c \
+       list.c \
+       paint.c \
+       para.c \
+       reader.c \
+       richole.c \
+       row.c \
+       run.c \
+       string.c \
+       style.c \
+       undo.c \
+       wrap.c
+
+@MAKE_DLL_RULES@
+
+### Dependencies:
diff --git a/reactos/lib/riched20/Makefile.ros-template b/reactos/lib/riched20/Makefile.ros-template
new file mode 100644 (file)
index 0000000..0f77336
--- /dev/null
@@ -0,0 +1,19 @@
+# $Id$
+
+TARGET_NAME = riched20
+
+TARGET_OBJECTS = @C_SRCS@
+
+TARGET_CFLAGS = @EXTRADEFS@ -D__REACTOS__ -D__WINESRC__
+
+TARGET_SDKLIBS = @IMPORTS@ wine.a wine_uuid.a ntdll.a
+
+TARGET_BASE = $(TARGET_BASE_LIB_SETUPAPI)
+
+TARGET_NORC = yes
+
+default: all
+
+DEP_OBJECTS = $(TARGET_OBJECTS)
+
+include $(TOOLS_PATH)/depend.mk
diff --git a/reactos/lib/riched20/caret.c b/reactos/lib/riched20/caret.c
new file mode 100644 (file)
index 0000000..e3ba8b1
--- /dev/null
@@ -0,0 +1,977 @@
+/*
+ * RichEdit - Caret and selection functions.
+ *
+ * Copyright 2004 by Krzysztof Foltman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#include "editor.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(richedit);
+
+void ME_GetSelection(ME_TextEditor *editor, int *from, int *to)
+{
+  *from = ME_GetCursorOfs(editor, 0);
+  *to =   ME_GetCursorOfs(editor, 1);
+  
+  if (*from > *to)
+  {
+    int tmp = *from;
+    *from = *to;
+    *to = tmp;    
+  }
+}
+
+int ME_GetTextLength(ME_TextEditor *editor)
+{
+  return ME_CharOfsFromRunOfs(editor, ME_FindItemBack(editor->pBuffer->pLast, diRun), 0);   
+}
+
+void ME_SetSelection(ME_TextEditor *editor, int from, int to)
+{
+  if (from == 0 && to == -1)
+  {
+    editor->pCursors[1].pRun = ME_FindItemFwd(editor->pBuffer->pFirst, diRun); 
+    editor->pCursors[1].nOffset = 0; 
+    editor->pCursors[0].pRun = ME_FindItemBack(editor->pBuffer->pLast, diRun); 
+    editor->pCursors[0].nOffset = 0; 
+    ME_Repaint(editor);
+    ME_ClearTempStyle(editor);
+    return;
+  }
+  if (from == -1)
+  {
+    editor->pCursors[1] = editor->pCursors[0]; 
+    ME_Repaint(editor);
+    ME_ClearTempStyle(editor);
+    return;
+  }
+  if (from>to)
+  {
+    int tmp = from;
+    from = to;
+    to = tmp;
+  }
+  ME_RunOfsFromCharOfs(editor, from, &editor->pCursors[1].pRun, &editor->pCursors[1].nOffset);
+  ME_RunOfsFromCharOfs(editor, to, &editor->pCursors[0].pRun, &editor->pCursors[0].nOffset);  
+}
+
+void ME_MoveCaret(ME_TextEditor *editor)
+{
+  HDC hDC = GetDC(editor->hWnd);
+  ME_Context c;
+
+  ME_Cursor *pCursor = &editor->pCursors[0];
+  ME_DisplayItem *pCursorRun = pCursor->pRun;
+  ME_DisplayItem *pSizeRun = pCursor->pRun;
+  
+  ME_InitContext(&c, editor, hDC);
+  assert(!pCursor->nOffset || !editor->bCaretAtEnd);
+  
+  if (pCursorRun->type == diRun) {
+    ME_DisplayItem *row = ME_FindItemBack(pCursorRun, diStartRowOrParagraph);
+    if (row) {
+      ME_DisplayItem *run = pCursorRun;
+      ME_DisplayItem *para;
+      SIZE sz = {0, 0};
+      if (!pCursor->nOffset && !editor->bCaretAtEnd)
+      {
+        ME_DisplayItem *prev = ME_FindItemBack(pCursorRun, diRunOrStartRow);
+        if (prev->type == diRun)
+          pSizeRun = prev;
+      }
+      assert(row->type == diStartRow); /* paragraph -> run without start row ?*/
+      para = ME_FindItemBack(row, diParagraph);
+      if (editor->bCaretAtEnd && !pCursor->nOffset && 
+          run == ME_FindItemFwd(row, diRun))
+      {
+        ME_DisplayItem *tmp = ME_FindItemBack(row, diRunOrParagraph);
+        if (tmp->type == diRun)
+        {
+          row = ME_FindItemBack(tmp, diStartRow);
+          pSizeRun = run = tmp;
+          sz = ME_GetRunSize(&c, &run->member.run, ME_StrLen(run->member.run.strText));
+        }
+      }
+      if (pCursor->nOffset && !(run->member.run.nFlags & MERF_SKIPPED)) {
+        sz = ME_GetRunSize(&c, &run->member.run, pCursor->nOffset);
+      }
+      CreateCaret(editor->hWnd, NULL, 0, pSizeRun->member.run.nAscent+pSizeRun->member.run.nDescent);
+      SetCaretPos(run->member.run.pt.x+sz.cx,
+        para->member.para.nYPos+row->member.row.nBaseline+pSizeRun->member.run.pt.y-pSizeRun->member.run.nAscent-GetScrollPos(editor->hWnd, SB_VERT));
+    } else {
+      assert(0 == "Wrapped paragraph run without a row?");
+      CreateCaret(editor->hWnd, NULL, 0, 10);
+      SetCaretPos(0,0);
+    }
+  }  
+  else {
+    assert(0 == "Cursor not on a run");
+    CreateCaret(editor->hWnd, NULL, 0, 10); /* FIXME use global font */
+    SetCaretPos(0,0);
+  }
+  ME_DestroyContext(&c);
+  ReleaseDC(editor->hWnd, hDC);
+}
+
+void ME_ShowCaret(ME_TextEditor *ed)
+{
+  ME_MoveCaret(ed);
+  ShowCaret(ed->hWnd);
+}
+
+void ME_HideCaret(ME_TextEditor *ed)
+{
+  HideCaret(ed->hWnd);
+  DestroyCaret();
+}
+
+void ME_InternalDeleteText(ME_TextEditor *editor, int nOfs, 
+  int nChars)
+{
+  ME_Cursor c;
+  int shift = 0;
+  
+  while(nChars > 0)
+  {
+    ME_Run *run;
+    ME_CursorFromCharOfs(editor, nOfs, &c);
+    run = &c.pRun->member.run;
+    if (run->nFlags & MERF_ENDPARA) {
+      if (!ME_FindItemFwd(c.pRun, diParagraph))
+      {
+        return;
+      }
+      ME_JoinParagraphs(editor, ME_GetParagraph(c.pRun));
+      /* ME_SkipAndPropagateCharOffset(p->pRun, shift); */
+      ME_CheckCharOffsets(editor);
+      nChars--;
+      continue;
+    }
+    else
+    {
+      ME_Cursor cursor;
+      int nIntendedChars = nChars;
+      int nCharsToDelete = nChars;
+      int i;
+      int loc = c.nOffset;
+      
+      ME_FindItemBack(c.pRun, diParagraph)->member.para.nFlags |= MEPF_REWRAP;
+      
+      cursor = c;
+      ME_StrRelPos(run->strText, loc, &nChars);
+      /* nChars is the number of characters that should be deleted from the
+         FOLLOWING runs (these AFTER cursor.pRun)
+         nCharsToDelete is a number of chars to delete from THIS run */
+      nCharsToDelete -= nChars;
+      shift -= nCharsToDelete;
+      TRACE("Deleting %d (intended %d-remaning %d) chars at %d in '%s' (%d)\n", 
+        nCharsToDelete, nIntendedChars, nChars, c.nOffset, 
+        debugstr_w(run->strText->szData), run->strText->nLen);
+
+      if (!c.nOffset && ME_StrVLen(run->strText) == nCharsToDelete)
+      {
+        /* undo = reinsert whole run */
+        /* nOfs is a character offset (from the start of the document
+           to the current (deleted) run */
+        ME_UndoItem *pUndo = ME_AddUndoItem(editor, diUndoInsertRun, c.pRun);
+        if (pUndo)
+          pUndo->di.member.run.nCharOfs = nOfs;
+      }
+      else
+      {
+        /* undo = reinsert partial run */
+        ME_UndoItem *pUndo = ME_AddUndoItem(editor, diUndoInsertRun, c.pRun);
+        if (pUndo) {
+          ME_DestroyString(pUndo->di.member.run.strText);
+          pUndo->di.member.run.nCharOfs = nOfs;
+          pUndo->di.member.run.strText = ME_MakeStringN(run->strText->szData+c.nOffset, nCharsToDelete);
+        }
+      }
+      TRACE("Post deletion string: %s (%d)\n", debugstr_w(run->strText->szData), run->strText->nLen);
+      TRACE("Shift value: %d\n", shift);
+      ME_StrDeleteV(run->strText, c.nOffset, nCharsToDelete);
+      
+      /* update cursors (including c) */
+      for (i=-1; i<editor->nCursors; i++) {
+        ME_Cursor *pThisCur = editor->pCursors + i; 
+        if (i == -1) pThisCur = &c;
+        if (pThisCur->pRun == cursor.pRun) {
+          if (pThisCur->nOffset > cursor.nOffset) {
+            if (pThisCur->nOffset-cursor.nOffset < nCharsToDelete)
+              pThisCur->nOffset = cursor.nOffset;
+            else
+              pThisCur->nOffset -= nCharsToDelete;
+            assert(pThisCur->nOffset >= 0);
+            assert(pThisCur->nOffset <= ME_StrVLen(run->strText));
+          }
+          if (pThisCur->nOffset == ME_StrVLen(run->strText))
+          {
+            pThisCur->pRun = ME_FindItemFwd(pThisCur->pRun, diRunOrParagraphOrEnd);
+            assert(pThisCur->pRun->type == diRun);
+            pThisCur->nOffset = 0;
+          }
+        }
+      }
+      
+      /* c = updated data now */
+      
+      if (c.pRun == cursor.pRun)
+        ME_SkipAndPropagateCharOffset(c.pRun, shift);
+      else
+        ME_PropagateCharOffset(c.pRun, shift);
+
+      if (!ME_StrVLen(cursor.pRun->member.run.strText))
+      {
+        TRACE("Removing useless run\n");
+        ME_Remove(cursor.pRun);
+        ME_DestroyDisplayItem(cursor.pRun);
+      }
+      
+      shift = 0;
+      /*
+      ME_CheckCharOffsets(editor);
+      */
+      continue;
+    }
+  }
+}
+
+void ME_DeleteTextAtCursor(ME_TextEditor *editor, int nCursor, 
+  int nChars)
+{  
+  assert(nCursor>=0 && nCursor<editor->nCursors);
+  ME_InternalDeleteText(editor, ME_GetCursorOfs(editor, nCursor), nChars);
+}
+
+static WCHAR wszSpace[] = {' ', 0};
+
+/* FIXME this is temporary, just to have something to test how bad graphics handler is */
+void ME_InsertGraphicsFromCursor(ME_TextEditor *editor, int nCursor)
+{
+  ME_Cursor *pCursor = &editor->pCursors[nCursor];
+  ME_DisplayItem *pItem = NULL;
+  ME_DisplayItem *pNewRun = NULL;
+  ME_Style *pStyle = ME_GetInsertStyle(editor, nCursor);
+  ME_UndoItem *pUndo;
+  
+  /* FIXME no no no */
+  if (ME_IsSelection(editor))
+    ME_DeleteSelection(editor);
+
+  pUndo = ME_AddUndoItem(editor, diUndoDeleteRun, NULL);
+  if (pUndo) {
+    pUndo->nStart = pCursor->nOffset + pCursor->pRun->member.run.nCharOfs + ME_GetParagraph(pCursor->pRun)->member.para.nCharOfs;
+    pUndo->nLen = 1;
+  }
+  if (pCursor->nOffset)
+  {
+    ME_SplitRunSimple(editor, pCursor->pRun, pCursor->nOffset);
+  }
+  pItem = pCursor->pRun;
+  pNewRun = ME_MakeRun(pStyle, ME_MakeStringN(wszSpace, 1), MERF_GRAPHICS);
+  pNewRun->member.run.nCharOfs = pCursor->pRun->member.run.nCharOfs;
+  ME_InsertBefore(pCursor->pRun, pNewRun);
+  ME_PropagateCharOffset(pItem, 1);
+  ME_CheckCharOffsets(editor);
+  ME_SendSelChange(editor);
+}
+
+void ME_InsertTextFromCursor(ME_TextEditor *editor, int nCursor, 
+  const WCHAR *str, int len, ME_Style *style)
+{
+  const WCHAR *pos;
+  ME_Cursor *p = NULL;
+
+  assert(style);
+  editor->bCaretAtEnd = FALSE;
+
+  /*
+  if (!style)
+    style = ME_GetInsertStyle(editor, nCursor);
+  else
+    ME_AddRefStyle(style);
+    */
+  ME_AddRefStyle(style);
+  
+  /* FIXME really HERE ? */
+  if (ME_IsSelection(editor))
+    ME_DeleteSelection(editor);
+
+  assert(nCursor>=0 && nCursor<editor->nCursors);
+  if (len == -1)
+    len = lstrlenW(str);
+  pos = str;
+  /* FIXME this sucks - no respect for unicode (what else can be a line separator in unicode?) */
+  while(pos-str < len && *pos != '\r' && *pos != '\n')
+    pos++;
+  /* handle EOLs */
+  if (pos-str < len) {   
+    ME_DisplayItem *tp, *end_run;
+    ME_Paragraph *para;
+    ME_Style *tmp_style;
+    if (pos!=str)
+      ME_InsertTextFromCursor(editor, nCursor, str, pos-str, style);
+    p = &editor->pCursors[nCursor];
+    tp = ME_FindItemBack(p->pRun, diParagraph);
+    para = &tp->member.para;
+    assert(tp);
+    if (p->nOffset) {
+      ME_SplitRunSimple(editor, p->pRun, p->nOffset);
+      p = &editor->pCursors[nCursor];
+    }
+    tmp_style = ME_GetInsertStyle(editor, nCursor);
+    /* ME_SplitParagraph increases style refcount */
+    tp = ME_SplitParagraph(editor, p->pRun, p->pRun->member.run.style);
+    p->pRun = ME_FindItemFwd(tp, diRun);
+    end_run = ME_FindItemBack(tp, diRun);
+    ME_ReleaseStyle(end_run->member.run.style);
+    end_run->member.run.style = tmp_style;
+    p->nOffset = 0;
+    if(pos-str < len && *pos =='\r')
+      pos++;
+    if(pos-str < len && *pos =='\n')
+      pos++;
+    if(pos-str < len) {
+      ME_InsertTextFromCursor(editor, nCursor, pos, len-(pos-str), style);
+    }
+    ME_ReleaseStyle(style);
+    return;
+  }
+  p = &editor->pCursors[nCursor];
+  if (style) {
+    ME_DisplayItem *pNewRun = NULL;
+
+    assert(p->pRun->type == diRun);
+    pNewRun = ME_MakeRun(style, ME_MakeStringN(str, len), 0); /* addrefs style */
+    ME_InsertRun(editor, ME_CharOfsFromRunOfs(editor, p->pRun, p->nOffset), pNewRun);
+    ME_DestroyDisplayItem(pNewRun);
+    ME_ReleaseStyle(style);
+    return;
+  } else {
+    assert(0);
+  }
+}
+
+BOOL ME_ArrowLeft(ME_TextEditor *editor, ME_Cursor *p)
+{
+  if (p->nOffset) {
+    p->nOffset = ME_StrRelPos2(p->pRun->member.run.strText, p->nOffset, -1);
+    return TRUE;
+  }
+  else
+  {
+    ME_DisplayItem *pRun = ME_FindItemBack(p->pRun, diRunOrParagraph);
+    assert(pRun);
+    if (pRun->type == diRun) {
+      p->pRun = pRun;
+      assert(p->pRun->type == diRun);
+      assert(pRun->member.run.strText->nLen);
+      p->nOffset = pRun->member.run.strText->nLen;
+      if (p->nOffset) {
+        p->nOffset = ME_StrRelPos2(pRun->member.run.strText, p->nOffset, -1);
+        return TRUE;
+      }
+      else
+        assert(0);
+    }
+    if (pRun->type == diParagraph)
+    {
+      if (pRun->member.para.prev_para->type == diTextStart)
+        return FALSE;
+      assert(pRun->member.para.prev_para->type == diParagraph);
+      pRun = ME_FindItemBack(pRun, diRunOrParagraph);
+      /* every paragraph ought to have at least one run */
+      assert(pRun && pRun->type == diRun);
+      assert(pRun->member.run.nFlags & MERF_ENDPARA);
+      p->pRun = pRun;
+      p->nOffset = 0;
+      return TRUE;
+    }
+    assert(0);
+  }
+}
+
+BOOL ME_ArrowRight(ME_TextEditor *editor, ME_Cursor *p)
+{
+  int new_ofs = ME_StrRelPos2(p->pRun->member.run.strText, p->nOffset, 1);
+  if (new_ofs<p->pRun->member.run.strText->nLen) {
+    p->nOffset = new_ofs;
+  }
+  else
+  {
+    ME_DisplayItem *pRun = ME_FindItemFwd(p->pRun, diRun);
+    if (pRun) {
+      p->pRun = pRun;
+      assert(p->pRun->type == diRun);
+      p->nOffset = 0;
+    }
+  }
+  return TRUE;
+}
+
+int ME_GetCursorOfs(ME_TextEditor *editor, int nCursor)
+{
+  ME_Cursor *pCursor = &editor->pCursors[nCursor];
+  
+  return ME_GetParagraph(pCursor->pRun)->member.para.nCharOfs
+    + pCursor->pRun->member.run.nCharOfs + pCursor->nOffset;
+}
+
+int ME_FindPixelPos(ME_TextEditor *editor, int x, int y, ME_Cursor *result, BOOL *is_eol)
+{
+  ME_DisplayItem *p = editor->pBuffer->pFirst->member.para.next_para;
+  int rx = 0;
+  
+  if (is_eol)
+    *is_eol = 0;
+
+  while(p != editor->pBuffer->pLast)
+  {
+    if (p->type == diParagraph)
+    {
+      int ry = y - p->member.para.nYPos;
+      if (ry < 0)
+      {
+        result->pRun = ME_FindItemFwd(p, diRun);
+        result->nOffset = 0;
+        return 0;
+      }
+      if (ry >= p->member.para.nHeight)
+      {
+        p = p->member.para.next_para;
+        continue;
+      }
+      p = ME_FindItemFwd(p, diStartRow);
+      y = ry;
+      continue;
+    }
+    if (p->type == diStartRow)
+    {
+      int ry = y - p->member.row.nYPos;
+      if (ry < 0)
+        return 0;
+      if (ry >= p->member.row.nHeight)
+      {
+        p = ME_FindItemFwd(p, diStartRowOrParagraphOrEnd);
+        if (p->type != diStartRow)
+          return 0;
+        continue;
+      }
+      p = ME_FindItemFwd(p, diRun);
+      continue;
+    }
+    if (p->type == diRun)
+    {
+      ME_DisplayItem *pp;
+      rx = x - p->member.run.pt.x;
+      if (rx < 0)
+        rx = 0;
+      if (rx >= p->member.run.nWidth) /* not this run yet... find next item */
+      {
+        pp = p;
+        do {
+          p = p->next;
+          if (p->type == diRun)
+          {
+            rx = x - p->member.run.pt.x;
+            goto continue_search;
+          }
+          if (p->type == diStartRow)
+          {
+            p = ME_FindItemFwd(p, diRun);
+            if (is_eol)
+              *is_eol = 1;
+            rx = 0; /* FIXME not sure */
+            goto found_here;
+          }
+          if (p->type == diParagraph || p->type == diTextEnd)
+          {
+            rx = 0; /* FIXME not sure */
+            p = pp;
+            goto found_here;
+          }
+        } while(1);
+        continue;
+      }
+    found_here:
+      if (p->member.run.nFlags & MERF_ENDPARA)
+        rx = 0;
+      result->pRun = p;
+      result->nOffset = ME_CharFromPointCursor(editor, rx, &p->member.run);
+      if (editor->pCursors[0].nOffset == p->member.run.strText->nLen && rx)
+      {
+        result->pRun = ME_FindItemFwd(editor->pCursors[0].pRun, diRun);
+        result->nOffset = 0;
+      }
+      return 1;
+    }
+    assert(0);
+  continue_search:
+    ;
+  }
+  result->pRun = ME_FindItemBack(p, diRun);
+  result->nOffset = 0;
+  assert(result->pRun->member.run.nFlags & MERF_ENDPARA);
+  return 0;
+}
+
+void ME_LButtonDown(ME_TextEditor *editor, int x, int y)
+{
+  ME_Cursor tmp_cursor;
+  int is_selection = 0;
+  
+  editor->nUDArrowX = -1;
+  
+  y += GetScrollPos(editor->hWnd, SB_VERT);  
+
+  tmp_cursor = editor->pCursors[0];
+  is_selection = ME_IsSelection(editor);
+
+  ME_FindPixelPos(editor, x, y, &editor->pCursors[0], &editor->bCaretAtEnd);
+  
+  if (GetKeyState(VK_SHIFT)>=0)
+  {
+    editor->pCursors[1] = editor->pCursors[0];
+  }
+  else
+  {
+    if (!is_selection) {
+      editor->pCursors[1] = tmp_cursor;
+      is_selection = 1;
+    }
+  }
+  HideCaret(editor->hWnd);
+  ME_MoveCaret(editor);
+  if (is_selection)
+    ME_Repaint(editor);
+  ShowCaret(editor->hWnd);
+  ME_ClearTempStyle(editor);
+  ME_SendSelChange(editor);
+}
+
+void ME_MouseMove(ME_TextEditor *editor, int x, int y)
+{
+  ME_Cursor tmp_cursor;
+  
+  y += GetScrollPos(editor->hWnd, SB_VERT);  
+
+  tmp_cursor = editor->pCursors[0];
+  if (!ME_FindPixelPos(editor, x, y, &editor->pCursors[0], &editor->bCaretAtEnd))
+    /* return */;
+  
+  if (tmp_cursor.pRun == editor->pCursors[0].pRun && 
+      tmp_cursor.nOffset == editor->pCursors[0].nOffset)
+    return;
+  
+  HideCaret(editor->hWnd);
+  ME_MoveCaret(editor);
+  ME_Repaint(editor);
+  ShowCaret(editor->hWnd);
+  ME_SendSelChange(editor);
+}
+
+static ME_DisplayItem *ME_FindRunInRow(ME_TextEditor *editor, ME_DisplayItem *pRow, 
+                                int x, int *pOffset, int *pbCaretAtEnd)
+{
+  ME_DisplayItem *pNext, *pLastRun;
+  pNext = ME_FindItemFwd(pRow, diRunOrStartRow);
+  assert(pNext->type == diRun);
+  pLastRun = pNext;
+  *pbCaretAtEnd = FALSE;
+  do {
+    int run_x = pNext->member.run.pt.x;
+    int width = pNext->member.run.nWidth;
+    if (x < run_x)
+    {
+      if (pOffset) *pOffset = 0;
+      return pNext;
+    }
+    if (x >= run_x && x < run_x+width)
+    {
+      int ch = ME_CharFromPointCursor(editor, x-run_x, &pNext->member.run);
+      ME_String *s = pNext->member.run.strText;
+      if (ch < s->nLen) {
+        if (pOffset)
+          *pOffset = ch;
+        return pNext;          
+      }
+    }
+    pLastRun = pNext;
+    pNext = ME_FindItemFwd(pNext, diRunOrStartRow);
+  } while(pNext && pNext->type == diRun);
+  
+  if ((pLastRun->member.run.nFlags & MERF_ENDPARA) == 0)
+  {
+    pNext = ME_FindItemFwd(pNext, diRun);
+    if (pbCaretAtEnd) *pbCaretAtEnd = 1;
+    if (pOffset) *pOffset = 0;
+    return pNext;
+  } else {
+    if (pbCaretAtEnd) *pbCaretAtEnd = 0;
+    if (pOffset) *pOffset = 0;
+    return pLastRun;
+  }
+}
+
+static int ME_GetXForArrow(ME_TextEditor *editor, ME_Cursor *pCursor)
+{
+  ME_DisplayItem *pRun = pCursor->pRun;
+  int x;
+
+  if (editor->nUDArrowX != -1)
+    x = editor->nUDArrowX;
+  else {
+    if (editor->bCaretAtEnd)
+    {
+      pRun = ME_FindItemBack(pRun, diRun);
+      assert(pRun);
+      x = pRun->member.run.pt.x + pRun->member.run.nWidth;
+    }
+    else {
+      x = pRun->member.run.pt.x;
+      x += ME_PointFromChar(editor, &pRun->member.run, pCursor->nOffset);
+    }
+    editor->nUDArrowX = x;
+  }
+  return x;
+}
+
+void ME_ArrowUp(ME_TextEditor *editor, ME_Cursor *pCursor)
+{
+  ME_DisplayItem *pRun = pCursor->pRun;
+  ME_DisplayItem *pItem, *pItem2;
+  int x = ME_GetXForArrow(editor, pCursor);
+  
+  if (editor->bCaretAtEnd && !pCursor->nOffset)
+  {
+    pRun = ME_FindItemBack(pRun, diRun);
+    if (!pRun)
+      return;
+  }
+  
+  /* start of this row */
+  pItem = ME_FindItemBack(pRun, diStartRow);
+  assert(pItem);
+  /* start of the previous row */
+  pItem2 = ME_FindItemBack(pItem, diStartRow);
+  /* no previous row = the first line of the first paragraph */
+  if (!pItem2) /* can't go up - don't go BOL (as in MS richedit) */
+    return;
+  /* FIXME
+  ME_WrapTextParagraph(editor, ME_FindItemBack(pItem2, diParagraph));
+  */
+  pCursor->pRun = ME_FindRunInRow(editor, pItem2, x, &pCursor->nOffset, &editor->bCaretAtEnd);
+}
+
+void ME_ArrowDown(ME_TextEditor *editor, ME_Cursor *pCursor)
+{
+  ME_DisplayItem *pRun = pCursor->pRun;
+  ME_DisplayItem *pItem;
+  int x = ME_GetXForArrow(editor, pCursor);
+  if (!pCursor->nOffset && editor->bCaretAtEnd)
+  {
+    pRun = ME_FindItemBack(pRun, diRun);
+/*    x = pRun->member.run.pt.x + pRun->member.run.nWidth; */
+  }
+  /* start of the next row */
+  pItem = ME_FindItemFwd(pRun, diStartRow);
+  /* FIXME If diParagraph is before diStartRow, wrap the next paragraph?
+  */
+  if (!pItem)
+  {
+    /* next row not found - ignore */
+    return;
+  }
+  pCursor->pRun = ME_FindRunInRow(editor, pItem, x, &pCursor->nOffset, &editor->bCaretAtEnd);
+  assert(pCursor->pRun);
+  assert(pCursor->pRun->type == diRun);
+}
+
+void ME_ArrowHome(ME_TextEditor *editor, ME_Cursor *pCursor)
+{
+  ME_DisplayItem *pRow = ME_FindItemBack(pCursor->pRun, diStartRow);
+  if (pRow) {
+    ME_DisplayItem *pRun;
+    if (editor->bCaretAtEnd && !pCursor->nOffset) {
+      pRow = ME_FindItemBack(pRow, diStartRow);
+      if (!pRow)
+        return;
+    }
+    pRun = ME_FindItemFwd(pRow, diRun);
+    if (pRun) {
+      pCursor->pRun = pRun;
+      pCursor->nOffset = 0;
+    }
+  }
+  editor->bCaretAtEnd = FALSE;
+}
+
+void ME_ArrowCtrlHome(ME_TextEditor *editor, ME_Cursor *pCursor)
+{
+  ME_DisplayItem *pRow = ME_FindItemBack(pCursor->pRun, diTextStart);
+  if (pRow) {
+    ME_DisplayItem *pRun = ME_FindItemFwd(pRow, diRun);
+    if (pRun) {
+      pCursor->pRun = pRun;
+      pCursor->nOffset = 0;
+    }
+  }
+}
+
+void ME_ArrowEnd(ME_TextEditor *editor, ME_Cursor *pCursor)
+{
+  ME_DisplayItem *pRow;
+  
+  if (editor->bCaretAtEnd && !pCursor->nOffset)
+    return;
+  
+  pRow = ME_FindItemFwd(pCursor->pRun, diStartRowOrParagraphOrEnd);
+  assert(pRow);
+  if (pRow->type == diStartRow) {
+    /* FIXME WTF was I thinking about here ? */
+    ME_DisplayItem *pRun = ME_FindItemFwd(pRow, diRun);
+    assert(pRun);
+    pCursor->pRun = pRun;
+    pCursor->nOffset = 0;
+    editor->bCaretAtEnd = 1;
+    return;
+  }
+  pCursor->pRun = ME_FindItemBack(pRow, diRun);
+  assert(pCursor->pRun && pCursor->pRun->member.run.nFlags & MERF_ENDPARA);
+  pCursor->nOffset = 0;
+  editor->bCaretAtEnd = FALSE;
+}
+      
+void ME_ArrowCtrlEnd(ME_TextEditor *editor, ME_Cursor *pCursor)
+{
+  ME_DisplayItem *p = ME_FindItemFwd(pCursor->pRun, diTextEnd);
+  assert(p);
+  p = ME_FindItemBack(p, diRun);
+  assert(p);
+  assert(p->member.run.nFlags & MERF_ENDPARA);
+  pCursor->pRun = p;
+  pCursor->nOffset = 0;
+  editor->bCaretAtEnd = FALSE;
+}
+
+BOOL ME_IsSelection(ME_TextEditor *editor)
+{
+  return memcmp(&editor->pCursors[0], &editor->pCursors[1], sizeof(ME_Cursor))!=0;
+}
+
+int ME_GetSelCursor(ME_TextEditor *editor, int dir)
+{
+  int cdir = ME_GetCursorOfs(editor, 0) - ME_GetCursorOfs(editor, 1);
+  
+  if (cdir*dir>0)
+    return 0;
+  else
+    return 1;
+}
+      
+BOOL ME_CancelSelection(ME_TextEditor *editor, int dir)
+{
+  int cdir;
+  
+  if (GetKeyState(VK_SHIFT)<0)
+    return FALSE;
+  if (!memcmp(&editor->pCursors[0], &editor->pCursors[1], sizeof(ME_Cursor)))
+    return FALSE;
+  
+  cdir = ME_GetCursorOfs(editor, 0) - ME_GetCursorOfs(editor, 1);
+  
+  if (cdir*dir>0)
+    editor->pCursors[1] = editor->pCursors[0];
+  else
+    editor->pCursors[0] = editor->pCursors[1];
+  /* FIXME optimize */
+  ME_MarkAllForWrapping(editor);
+  ME_Repaint(editor);
+  return TRUE;
+}
+
+void ME_RepaintSelection(ME_TextEditor *editor, ME_Cursor *pTempCursor)
+{
+  ME_Cursor old_anchor = editor->pCursors[1];
+  BOOL bRedraw = FALSE;
+  bRedraw = memcmp(&editor->pCursors[0], &editor->pCursors[1], sizeof(ME_Cursor));
+  
+  if (bRedraw)
+  {
+    /* FIXME optimize */
+    ME_MarkAllForWrapping(editor);
+  }
+  
+  if (GetKeyState(VK_SHIFT)>=0) /* cancelling selection */
+  {
+    /* any selection was present ? if so, it's no more, repaint ! */
+    editor->pCursors[1] = editor->pCursors[0];
+    if (memcmp(pTempCursor, &old_anchor, sizeof(ME_Cursor))) {
+      ME_Repaint(editor);
+      return;
+    }
+    return;
+  }
+  else
+  {
+    if (!memcmp(pTempCursor, &editor->pCursors[1], sizeof(ME_Cursor))) /* starting selection */
+    {
+      editor->pCursors[1] = *pTempCursor;
+    }
+  }
+
+  ME_Repaint(editor);
+}
+
+void ME_DeleteSelection(ME_TextEditor *editor)
+{
+  int from, to;
+  ME_GetSelection(editor, &from, &to);
+  ME_DeleteTextAtCursor(editor, ME_GetSelCursor(editor,-1), to-from);
+}
+
+ME_Style *ME_GetSelectionInsertStyle(ME_TextEditor *editor)
+{
+  ME_Style *style;
+  int from, to;
+  ME_Cursor c;
+  
+  ME_GetSelection(editor, &from, &to);
+  ME_CursorFromCharOfs(editor, from, &c);
+  if (from != to) {
+    style = c.pRun->member.run.style;
+    ME_AddRefStyle(style); /* ME_GetInsertStyle has already done that */
+  }
+  else
+    style = ME_GetInsertStyle(editor, 0);
+  return style;
+}
+
+void ME_SendSelChange(ME_TextEditor *editor)
+{
+  SELCHANGE sc;
+  if (!(editor->nEventMask & ENM_SELCHANGE))
+    return;
+  sc.nmhdr.hwndFrom = editor->hWnd;
+  sc.nmhdr.idFrom = GetWindowLongW(editor->hWnd, GWLP_ID);
+  sc.nmhdr.code = EN_SELCHANGE;
+  SendMessageW(editor->hWnd, EM_EXGETSEL, 0, (LPARAM)&sc.chrg);
+  sc.seltyp = SEL_EMPTY;
+  if (sc.chrg.cpMin != sc.chrg.cpMax)
+    sc.seltyp |= SEL_TEXT;
+  if (sc.chrg.cpMin < sc.chrg.cpMax+1) /* wth were RICHEDIT authors thinking ? */
+    sc.seltyp |= SEL_MULTICHAR;
+  SendMessageW(GetParent(editor->hWnd), WM_NOTIFY, sc.nmhdr.idFrom, (LPARAM)&sc);
+}
+
+BOOL ME_ArrowKey(ME_TextEditor *editor, int nVKey, int nCtrl)
+{
+  int nCursor = 0;
+  ME_Cursor *p = &editor->pCursors[nCursor];
+  ME_Cursor tmp_curs = *p;
+  
+  switch(nVKey) {
+    case VK_UP:
+      ME_ArrowUp(editor, p);
+      ME_ClearTempStyle(editor);
+      ME_RepaintSelection(editor, &tmp_curs);
+      ME_SendSelChange(editor);
+      return TRUE;
+    case VK_DOWN:
+      ME_ArrowDown(editor, p);
+      ME_ClearTempStyle(editor);
+      ME_RepaintSelection(editor, &tmp_curs);
+      ME_SendSelChange(editor);
+      return TRUE;
+  }
+  
+  editor->nUDArrowX = -1;
+  switch(nVKey) {
+    case VK_BACK: { /* FIXME backspace and delete aren't the same, they act different wrt paragraph style of the merged paragraph */
+      if (GetWindowLongW(editor->hWnd, GWL_STYLE) & ES_READONLY)
+        return FALSE;
+      if (ME_IsSelection(editor))
+      {
+        editor->bCaretAtEnd = FALSE; /* FIXME or maybe not */
+        ME_DeleteSelection(editor);
+        ME_UpdateRepaint(editor);
+        return TRUE;
+      }
+      if (ME_ArrowLeft(editor, p)) {
+        editor->bCaretAtEnd = FALSE; /* FIXME or maybe not */
+        ME_MoveCaret(editor);
+        ME_DeleteTextAtCursor(editor, nCursor, 1);
+        ME_UpdateRepaint(editor);
+      }
+      return TRUE;
+    }
+    case VK_DELETE: {
+      if (GetWindowLongW(editor->hWnd, GWL_STYLE) & ES_READONLY)
+        return FALSE;
+      /* editor->bCaretAtEnd = 0; FIXME or maybe not */
+      if (ME_IsSelection(editor))
+      {
+        ME_DeleteSelection(editor);
+        ME_UpdateRepaint(editor);
+        return TRUE;
+      }
+      ME_DeleteTextAtCursor(editor, nCursor, 1);
+      ME_UpdateRepaint(editor);
+      return TRUE;
+    }
+    case VK_HOME: {
+      if (GetKeyState(VK_CONTROL)<0)
+        ME_ArrowCtrlHome(editor, p);
+      else
+        ME_ArrowHome(editor, p);
+      editor->bCaretAtEnd = 0;
+      ME_ClearTempStyle(editor);
+      ME_RepaintSelection(editor, &tmp_curs);
+      ME_SendSelChange(editor);
+      return TRUE;
+    }
+    case VK_END: 
+      if (GetKeyState(VK_CONTROL)<0)
+        ME_ArrowCtrlEnd(editor, p);
+      else
+        ME_ArrowEnd(editor, p);
+      ME_ClearTempStyle(editor);
+      ME_RepaintSelection(editor, &tmp_curs);
+      ME_SendSelChange(editor);
+      return TRUE;
+    case VK_LEFT:
+      editor->bCaretAtEnd = 0;
+      if (ME_CancelSelection(editor, -1))
+        return TRUE;
+      ME_ArrowLeft(editor, p);
+      ME_RepaintSelection(editor, &tmp_curs);
+      ME_ClearTempStyle(editor);
+      ME_SendSelChange(editor);
+      return TRUE;
+    case VK_RIGHT:
+      editor->bCaretAtEnd = 0;
+      if (ME_CancelSelection(editor, +1))
+        return TRUE;
+      ME_ArrowRight(editor, p);
+      ME_RepaintSelection(editor, &tmp_curs);
+      ME_ClearTempStyle(editor);
+      ME_SendSelChange(editor);
+      return TRUE;
+  }
+  return FALSE;
+}
diff --git a/reactos/lib/riched20/context.c b/reactos/lib/riched20/context.c
new file mode 100644 (file)
index 0000000..62b0259
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * RichEdit - Operation context functions
+ *
+ * Copyright 2004 by Krzysztof Foltman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "editor.h"
+
+void ME_InitContext(ME_Context *c, ME_TextEditor *editor, HDC hDC)
+{
+  c->nSequence = editor->nSequence++;  
+  c->hDC = hDC;
+  c->editor = editor;
+  c->pt.x = 0;
+  c->pt.y = 0;
+  c->hbrMargin = CreateSolidBrush(RGB(224,224,224));
+  GetClientRect(editor->hWnd, &c->rcView);
+}
+
+void ME_DestroyContext(ME_Context *c)
+{
+  DeleteObject(c->hbrMargin);
+}
diff --git a/reactos/lib/riched20/editor.c b/reactos/lib/riched20/editor.c
new file mode 100644 (file)
index 0000000..eec9847
--- /dev/null
@@ -0,0 +1,1020 @@
+/*
+ * RichEdit - functions dealing with editor object
+ *
+ * Copyright 2004 by Krzysztof Foltman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* 
+  API implementation status:
+  
+  Messages (ANSI versions not done yet)
+  - EM_AUTOURLDETECT 2.0
+  - EM_CANPASTE
+  + EM_CANREDO 2.0
+  + EM_CANUNDO
+  - EM_CHARFROMPOS
+  - EM_DISPLAYBAND
+  + EM_EMPTYUNDOBUFFER
+  + EM_EXGETSEL
+  - EM_EXLIMITTEXT
+  - EM_EXLINEFROMCHAR
+  + EM_EXSETSEL
+  - EM_FINDTEXT
+  - EM_FINDTEXTEX
+  - EM_FINDWORDBREAK
+  - EM_FMTLINES
+  - EM_FORMATRANGE
+  - EM_GETCHARFORMAT (partly done)
+  + EM_GETEVENTMASK
+  - EM_GETFIRSTVISIBLELINE
+  - EM_GETIMECOLOR 1.0asian
+  - EM_GETIMECOMPMODE 2.0
+  - EM_GETIMEOPTIONS 1.0asian
+  - EM_GETIMESTATUS
+  - EM_GETLANGOPTIONS 2.0
+  - EM_GETLIMITTEXT
+  - EM_GETLINE        
+  - EM_GETLINECOUNT   returns number of rows, not of paragraphs
+  + EM_GETMODIFY
+  - EM_GETOLEINTERFACE
+  - EM_GETOPTIONS
+  + EM_GETPARAFORMAT
+  - EM_GETPUNCTUATION 1.0asian
+  - EM_GETRECT
+  - EM_GETREDONAME 2.0
+  + EM_GETSEL
+  + EM_GETSELTEXT (ANSI&Unicode)
+! - EM_GETTHUMB
+  - EM_GETTEXTMODE 2.0
+? + EM_GETTEXTRANGE (ANSI&Unicode)
+  - EM_GETUNDONAME
+  - EM_GETWORDBREAKPROC
+  - EM_GETWORDBREAKPROCEX
+  - EM_GETWORDWRAPMODE 1.0asian
+  - EM_HIDESELECTION
+  - EM_LIMITTEXT
+  - EM_LINEFROMCHAR
+  - EM_LINEINDEX
+  - EM_LINELENGTH
+  - EM_LINESCROLL
+  - EM_PASTESPECIAL
+  - EM_POSFROMCHARS
+  - EM_REDO 2.0
+  - EM_REQUESTRESIZE
+  + EM_REPLACESEL (proper style?) ANSI&Unicode
+  - EM_SCROLL
+  - EM_SCROLLCARET
+  - EM_SELECTIONTYPE
+  + EM_SETBKGNDCOLOR
+  - EM_SETCHARFORMAT (partly done, no ANSI)
+  + EM_SETEVENTMASK (few notifications supported)
+  - EM_SETIMECOLOR 1.0asian
+  - EM_SETIMEOPTIONS 1.0asian
+  - EM_SETLANGOPTIONS 2.0
+  - EM_SETLIMITTEXT
+  + EM_SETMODIFY (not sure if implementation is correct)
+  - EM_SETOLECALLBACK
+  - EM_SETOPTIONS
+  + EM_SETPARAFORMAT
+  - EM_SETPUNCTUATION 1.0asian
+  + EM_SETREADONLY no beep on modification attempt
+  - EM_SETRECT
+  - EM_SETRECTNP (EM_SETRECT without repainting) - not supported in RICHEDIT
+  + EM_SETSEL
+  - EM_SETTARGETDEVICE
+  - EM_SETTEXTMODE 2.0
+  - EM_SETUNDOLIMIT 2.0
+  - EM_SETWORDBREAKPROC
+  - EM_SETWORDBREAKPROCEX
+  - EM_SETWORDWRAPMODE 1.0asian
+  - EM_STOPGROUPTYPING 2.0
+  - EM_STREAMIN
+  - EM_STREAMOUT
+  - EM_UNDO
+  + WM_CHAR
+  + WM_CLEAR
+  - WM_COPY (lame implementation, no RTF support)
+  - WM_CUT (lame implementation, no RTF support)
+  + WM_GETDLGCODE (the current implementation is incomplete)
+  + WM_GETTEXT (ANSI&Unicode)
+  + WM_GETTEXTLENGTH (ANSI version sucks)
+  - WM_PASTE
+  - WM_SETFONT
+  + WM_SETTEXT (resets undo stack !) (proper style?) ANSI&Unicode
+  - WM_STYLECHANGING
+  - WM_STYLECHANGED (things like read-only flag)
+  - WM_UNICHAR
+  
+  Notifications
+  
+  * EN_CHANGE (sent from the wrong place)
+  - EN_CORRECTTEXT
+  - EN_DROPFILES
+  - EN_ERRSPACE
+  - EN_HSCROLL
+  - EN_IMECHANGE
+  + EN_KILLFOCUS
+  - EN_LINK
+  - EN_MAXTEXT
+  - EN_MSGFILTER
+  - EN_OLEOPFAILED
+  - EN_PROTECTED
+  - EN_REQUESTRESIZE
+  - EN_SAVECLIPBOARD
+  + EN_SELCHANGE 
+  + EN_SETFOCUS
+  - EN_STOPNOUNDO
+  * EN_UPDATE (sent from the wrong place)
+  - EN_VSCROLL
+  
+  Styles
+  
+  - ES_AUTOHSCROLL
+  - ES_AUTOVSCROLL
+  - ES_CENTER
+  - ES_DISABLENOSCROLL (scrollbar is always visible)
+  - ES_EX_NOCALLOLEINIT
+  - ES_LEFT
+  - ES_MULTILINE (currently single line controls aren't supported)
+  - ES_NOIME
+  - ES_READONLY (I'm not sure if beeping is the proper behaviour)
+  - ES_RIGHT
+  - ES_SAVESEL
+  - ES_SELFIME
+  - ES_SUNKEN
+  - ES_VERTICAL
+  - ES_WANTRETURN (don't know how to do WM_GETDLGCODE part)
+  - WS_SETFONT
+  - WS_HSCROLL
+  - WS_VSCROLL
+*/
+
+/*
+ * RICHED20 TODO (incomplete):
+ *
+ * - font caching
+ * - add remaining CHARFORMAT/PARAFORMAT fields
+ * - right/center align should strip spaces from the beginning
+ * - more advanced navigation (Ctrl-arrows, PageUp/PageDn)
+ * - tabs
+ * - pictures (not just smiling faces that lack API support ;-) )
+ * - OLE objects
+ * - calculate heights of pictures (half-done)
+ * - EM_STREAMIN/EM_STREAMOUT
+ * - horizontal scrolling (not even started)
+ * - fix scrollbars and refresh (it sucks bigtime)
+ * - hysteresis during wrapping (related to scrollbars appearing/disappearing)
+ * - should remember maximum row width for wrap hysteresis
+ * - find/replace
+ * - how to implement EM_FORMATRANGE and EM_DISPLAYBAND ? (Mission Impossible)
+ * - italic cursor with italic fonts
+ * - IME
+ * - most notifications aren't sent at all (the most important ones are)
+ * - when should EN_SELCHANGE be sent after text change ? (before/after EN_UPDATE?)
+ * - WM_SETTEXT may use wrong style (but I'm 80% sure it's OK)
+ * - EM_GETCHARFORMAT with SCF_SELECTION may not behave 100% like in original (but very close)
+ * - bugs in end-of-text handling (the gray bar) could get me in jail ;-)
+ * - determination of row size
+ * - end-of-paragraph marks should be of reasonable size
+ *
+ * Bugs that are probably fixed, but not so easy to verify:
+ * - EN_UPDATE/EN_CHANGE are handled very incorrectly (should be OK now)
+ * - undo for ME_JoinParagraphs doesn't store paragraph format ? (it does)
+ * - check/fix artificial EOL logic (bCursorAtEnd, hardly logical)
+ * - caret shouldn't be displayed when selection isn't empty
+ * - check refcounting in style management functions (looks perfect now, but no bugs is suspicious)
+ * - undo for setting default format (done, might be buggy)
+ * - styles might be not released properly (looks like they work like charm, but who knows?
+ *
+ */
+
+#include "editor.h"
+#include <ole2.h>
+#include <richole.h>
+#include <winreg.h>
+#define NO_SHLWAPI_STREAM 
+#include <shlwapi.h>
+
+#include "rtf.h"
+WINE_DEFAULT_DEBUG_CHANNEL(richedit);
+
+int me_debug = 0;
+HANDLE me_heap = NULL;
+
+ME_TextBuffer *ME_MakeText() {
+  
+  ME_TextBuffer *buf = ALLOC_OBJ(ME_TextBuffer);
+
+  ME_DisplayItem *p1 = ME_MakeDI(diTextStart);
+  ME_DisplayItem *p2 = ME_MakeDI(diTextEnd);
+  
+  p1->prev = NULL;
+  p1->next = p2;
+  p2->prev = p1;
+  p2->next = NULL;
+  p1->member.para.next_para = p2;
+  p2->member.para.prev_para = p1;
+  p2->member.para.nCharOfs = 0;  
+  
+  buf->pFirst = p1;
+  buf->pLast = p2;
+  buf->pCharStyle = NULL;
+  
+  return buf;
+}
+
+#define STREAMIN_BUFFER_SIZE 4096 /* M$ compatibility */
+
+static LRESULT ME_StreamInText(ME_TextEditor *editor, DWORD dwFormat, EDITSTREAM *stream, ME_Style *style)
+{
+  BYTE buffer[STREAMIN_BUFFER_SIZE+1];
+  WCHAR wszText[STREAMIN_BUFFER_SIZE+1];
+  
+  TRACE("%08lx %p\n", dwFormat, stream);
+  stream->dwError = 0;
+  
+  do {
+    long nDataSize = 0, nWideChars = 0;
+    stream->dwError = stream->pfnCallback(stream->dwCookie, 
+      (dwFormat & SF_UNICODE ? (BYTE *)wszText : buffer), 
+      STREAMIN_BUFFER_SIZE, &nDataSize);
+    
+    if (stream->dwError)
+      break;
+    if (!nDataSize)
+      break;
+      
+    if (!(dwFormat & SF_UNICODE))
+    {
+      /* FIXME? this is doomed to fail on true MBCS like UTF-8, luckily they're unlikely to be used as CP_ACP */
+      nWideChars = MultiByteToWideChar(CP_ACP, 0, buffer, nDataSize, wszText, STREAMIN_BUFFER_SIZE);
+    }
+    else
+      nWideChars = nDataSize>>1;
+    ME_InsertTextFromCursor(editor, 0, wszText, nWideChars, style);
+    if (nDataSize<STREAMIN_BUFFER_SIZE)
+      break;
+  } while(1);
+  ME_CommitUndo(editor);    
+  return 0;
+}
+
+static LRESULT ME_StreamIn(ME_TextEditor *editor, DWORD format, EDITSTREAM *stream)
+{
+  RTF_Info parser;
+  ME_Style *style;
+
+  TRACE("%p %p\n", stream, editor->hWnd);
+  
+  if (format & SFF_SELECTION) {
+    style = ME_GetSelectionInsertStyle(editor);
+    SendMessageW(editor->hWnd, WM_CLEAR, 0, 0);
+  }
+  else {
+    style = editor->pBuffer->pDefaultStyle;
+    ME_AddRefStyle(style);
+    SendMessageA(editor->hWnd, EM_SETSEL, 0, 0);    
+    SetWindowTextA(editor->hWnd, "");
+    ME_ClearTempStyle(editor);
+  }
+
+  if (format & SF_RTF) {
+    /* setup the RTF parser */
+    memset(&parser, 0, sizeof parser);
+    RTFSetEditStream(&parser, stream);
+    parser.rtfFormat = format&(SF_TEXT|SF_RTF);
+    parser.hwndEdit = editor->hWnd;
+    WriterInit(&parser);
+    RTFInit(&parser);
+    BeginFile(&parser);
+  
+    /* do the parsing */
+    RTFRead(&parser);
+    RTFFlushOutputBuffer(&parser);
+  }
+  else if (format & SF_TEXT)
+    ME_StreamInText(editor, format, stream, style);
+  else
+    ERR("EM_STREAMIN without SF_TEXT or SF_RTF\n");
+  /* put the cursor at the top */
+  if (!(format & SFF_SELECTION))
+    SendMessageA(editor->hWnd, EM_SETSEL, 0, 0);
+  else
+  {
+    /* FIXME where to put cursor now ? */
+  }
+  ME_ReleaseStyle(style);
+
+  return 0;
+}
+
+ME_TextEditor *ME_MakeEditor(HWND hWnd) {
+  ME_TextEditor *ed = ALLOC_OBJ(ME_TextEditor);
+  HDC hDC;
+  int i;
+  ed->hWnd = hWnd;
+  ed->pBuffer = ME_MakeText();
+  hDC = GetDC(hWnd);
+  ME_MakeFirstParagraph(hDC, ed->pBuffer);
+  ReleaseDC(hWnd, hDC);
+  ed->bCaretShown = FALSE;
+  ed->nCursors = 3;
+  ed->pCursors = ALLOC_N_OBJ(ME_Cursor, ed->nCursors);
+  ed->pCursors[0].pRun = ME_FindItemFwd(ed->pBuffer->pFirst, diRun);
+  ed->pCursors[0].nOffset = 0;
+  ed->pCursors[1].pRun = ME_FindItemFwd(ed->pBuffer->pFirst, diRun);
+  ed->pCursors[1].nOffset = 0;
+  ed->nLastTotalLength = ed->nTotalLength = 0;
+  ed->nScrollPos = 0;
+  ed->nUDArrowX = -1;
+  ed->nSequence = 0;
+  ed->rgbBackColor = -1;
+  ed->bCaretAtEnd = FALSE;
+  ed->nEventMask = 0;
+  ed->nModifyStep = 0;
+  ed->pUndoStack = ed->pRedoStack = NULL;
+  ed->nUndoMode = umAddToUndo;
+  ed->nParagraphs = 1;
+  ed->nLastSelStart = ed->nLastSelEnd = 0;
+  for (i=0; i<HFONT_CACHE_SIZE; i++)
+  {
+    ed->pFontCache[i].nRefs = 0;
+    ed->pFontCache[i].nAge = 0;
+    ed->pFontCache[i].hFont = NULL;
+  }
+  ME_CheckCharOffsets(ed);
+  return ed;
+}
+
+void ME_DestroyEditor(ME_TextEditor *editor)
+{
+  ME_DisplayItem *pFirst = editor->pBuffer->pFirst;
+  ME_DisplayItem *p = pFirst, *pNext = NULL;
+  int i;
+  
+  ME_ClearTempStyle(editor);
+  ME_EmptyUndoStack(editor);
+  while(p) {
+    pNext = p->next;
+    ME_DestroyDisplayItem(p);    
+    p = pNext;
+  }
+  ME_ReleaseStyle(editor->pBuffer->pDefaultStyle);
+  for (i=0; i<HFONT_CACHE_SIZE; i++)
+  {
+    if (editor->pFontCache[i].hFont)
+      DeleteObject(editor->pFontCache[i].hFont);
+  }
+    
+  FREE_OBJ(editor);
+}
+
+#define UNSUPPORTED_MSG(e) \
+  case e: \
+    FIXME(#e ": stub\n"); \
+    return DefWindowProcW(hWnd, msg, wParam, lParam);
+
+/******************************************************************
+ *        RichEditANSIWndProc (RICHED20.10)
+ */
+LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
+  HDC hDC;
+  PAINTSTRUCT ps;
+  SCROLLINFO si;
+  ME_TextEditor *editor = (ME_TextEditor *)GetWindowLongW(hWnd, 0);
+  TRACE("msg %d %08x %08lx\n", msg, wParam, lParam);
+  switch(msg) {
+  
+  UNSUPPORTED_MSG(EM_AUTOURLDETECT)
+  UNSUPPORTED_MSG(EM_CANPASTE)
+  UNSUPPORTED_MSG(EM_CHARFROMPOS)
+  UNSUPPORTED_MSG(EM_DISPLAYBAND)
+  UNSUPPORTED_MSG(EM_EXLIMITTEXT)
+  UNSUPPORTED_MSG(EM_EXLINEFROMCHAR)
+  UNSUPPORTED_MSG(EM_FINDTEXT)
+  UNSUPPORTED_MSG(EM_FINDTEXTEX)
+  UNSUPPORTED_MSG(EM_FINDWORDBREAK)
+  UNSUPPORTED_MSG(EM_FMTLINES)
+  UNSUPPORTED_MSG(EM_FORMATRANGE)
+  UNSUPPORTED_MSG(EM_GETFIRSTVISIBLELINE)
+  UNSUPPORTED_MSG(EM_GETIMECOMPMODE)
+  /* UNSUPPORTED_MSG(EM_GETIMESTATUS) missing in Wine headers */
+  UNSUPPORTED_MSG(EM_GETLANGOPTIONS)
+  UNSUPPORTED_MSG(EM_GETLIMITTEXT)
+  UNSUPPORTED_MSG(EM_GETLINE)
+  UNSUPPORTED_MSG(EM_GETLINECOUNT)
+  /* UNSUPPORTED_MSG(EM_GETOLEINTERFACE) separate stub */
+  UNSUPPORTED_MSG(EM_GETOPTIONS)
+  UNSUPPORTED_MSG(EM_GETRECT)
+  UNSUPPORTED_MSG(EM_GETREDONAME)
+  UNSUPPORTED_MSG(EM_GETTEXTMODE)
+  UNSUPPORTED_MSG(EM_GETUNDONAME)
+  UNSUPPORTED_MSG(EM_GETWORDBREAKPROC)
+  UNSUPPORTED_MSG(EM_GETWORDBREAKPROCEX)
+  UNSUPPORTED_MSG(EM_HIDESELECTION)
+  UNSUPPORTED_MSG(EM_LIMITTEXT) /* also known as EM_SETLIMITTEXT */
+  UNSUPPORTED_MSG(EM_LINEFROMCHAR)
+  UNSUPPORTED_MSG(EM_LINEINDEX)
+  UNSUPPORTED_MSG(EM_LINELENGTH)
+  UNSUPPORTED_MSG(EM_LINESCROLL)
+  UNSUPPORTED_MSG(EM_PASTESPECIAL)
+/*  UNSUPPORTED_MSG(EM_POSFROMCHARS) missing in Wine headers */
+  UNSUPPORTED_MSG(EM_REQUESTRESIZE)
+  UNSUPPORTED_MSG(EM_SCROLL)
+  UNSUPPORTED_MSG(EM_SCROLLCARET)
+  UNSUPPORTED_MSG(EM_SELECTIONTYPE)
+  UNSUPPORTED_MSG(EM_SETLANGOPTIONS)
+  UNSUPPORTED_MSG(EM_SETOLECALLBACK)
+  UNSUPPORTED_MSG(EM_SETOPTIONS)
+  UNSUPPORTED_MSG(EM_SETRECT)
+  UNSUPPORTED_MSG(EM_SETRECTNP)
+  UNSUPPORTED_MSG(EM_SETTARGETDEVICE)
+  UNSUPPORTED_MSG(EM_SETTEXTMODE)
+  UNSUPPORTED_MSG(EM_SETUNDOLIMIT)
+  UNSUPPORTED_MSG(EM_SETWORDBREAKPROC)
+  UNSUPPORTED_MSG(EM_SETWORDBREAKPROCEX)
+  UNSUPPORTED_MSG(EM_STREAMOUT)
+  UNSUPPORTED_MSG(WM_SETFONT)
+  UNSUPPORTED_MSG(WM_PASTE)
+  UNSUPPORTED_MSG(WM_STYLECHANGING)
+  UNSUPPORTED_MSG(WM_STYLECHANGED)
+/*  UNSUPPORTED_MSG(WM_UNICHAR) FIXME missing in Wine headers */
+    
+/* Messages specific to Richedit controls */
+  
+  case EM_STREAMIN:
+   return ME_StreamIn(editor, wParam, (EDITSTREAM*)lParam);
+  case WM_GETDLGCODE:
+  {
+    UINT code = DLGC_WANTCHARS|DLGC_WANTARROWS;
+    if (GetWindowLongW(hWnd, GWL_STYLE)&ES_WANTRETURN)
+      code |= 0; /* FIXME what can we do here ? ask for messages and censor them ? */
+    return code;
+  }
+  case WM_NCCREATE:
+  {
+    CREATESTRUCTW *pcs = (CREATESTRUCTW *)lParam;
+    editor = ME_MakeEditor(hWnd);
+    SetWindowLongW(hWnd, 0, (long)editor);
+    pcs = 0; /* ignore */
+    return TRUE;
+  }
+  case EM_EMPTYUNDOBUFFER:
+    ME_EmptyUndoStack(editor);
+    return 0;
+  case EM_GETSEL:
+  {
+    ME_GetSelection(editor, (int *)wParam, (int *)lParam);
+    if (!((wParam|lParam) & 0xFFFF0000))
+      return (lParam<<16)|wParam;
+    return -1;
+  }
+  case EM_EXGETSEL:
+  {
+    CHARRANGE *pRange = (CHARRANGE *)lParam;
+    ME_GetSelection(editor, (int *)&pRange->cpMin, (int *)&pRange->cpMax);
+    return 0;
+  }
+  case EM_CANUNDO:
+    return editor->pUndoStack != NULL;
+  case EM_CANREDO:
+    return editor->pRedoStack != NULL;
+  case EM_UNDO:
+    ME_Undo(editor);
+    return 0;
+  case EM_REDO:
+    ME_Redo(editor);
+    return 0;
+  case EM_SETSEL:
+  {
+    ME_SetSelection(editor, wParam, lParam);
+    ME_Repaint(editor);
+    ME_SendSelChange(editor);
+    return 0;
+  }
+  case EM_EXSETSEL:
+  {
+    CHARRANGE *pRange = (CHARRANGE *)lParam;
+    ME_SetSelection(editor, pRange->cpMin, pRange->cpMax);
+    /* FIXME optimize */
+    ME_Repaint(editor);
+    ME_SendSelChange(editor);
+    return 0;
+  }
+  case EM_SETBKGNDCOLOR:
+  {
+    LRESULT lColor = ME_GetBackColor(editor);
+    if (wParam)
+      editor->rgbBackColor = -1;
+    else
+      editor->rgbBackColor = lParam; 
+    InvalidateRect(hWnd, NULL, TRUE);
+    UpdateWindow(hWnd);
+    return lColor;
+  }
+  case EM_GETMODIFY:
+    return editor->nModifyStep == 0 ? 0 : 1;
+  case EM_SETMODIFY:
+  {
+    if (wParam)
+      editor->nModifyStep = 0x80000000;
+    else
+      editor->nModifyStep = 0;
+    
+    return 0;
+  }
+  case EM_SETREADONLY:
+  {
+    long nStyle = GetWindowLongW(hWnd, GWL_STYLE);
+    if (wParam)
+      nStyle |= ES_READONLY;
+    else
+      nStyle &= ~ES_READONLY;
+    SetWindowLongW(hWnd, GWL_STYLE, nStyle);
+    ME_Repaint(editor);
+    return 0;
+  }
+  case EM_SETEVENTMASK:
+    editor->nEventMask = lParam;
+    return 0;
+  case EM_GETEVENTMASK:
+    return editor->nEventMask;
+  case EM_SETCHARFORMAT:
+  {
+    CHARFORMAT2W buf, *p;
+    p = ME_ToCF2W(&buf, (CHARFORMAT2W *)lParam);
+    if (!wParam)
+      ME_SetDefaultCharFormat(editor, p);
+    else if (wParam == (SCF_WORD | SCF_SELECTION))
+      FIXME("word selection not supported\n");
+    else if (wParam == SCF_ALL)
+      ME_SetCharFormat(editor, 0, ME_GetTextLength(editor), p);
+    else
+      ME_SetSelectionCharFormat(editor, p);
+    ME_CommitUndo(editor);
+    ME_UpdateRepaint(editor);
+    return 0;
+  }
+  case EM_GETCHARFORMAT:
+  {
+    CHARFORMAT2W tmp;
+    tmp.cbSize = sizeof(tmp);
+    if (!wParam)
+      ME_GetDefaultCharFormat(editor, &tmp);
+    else
+      ME_GetSelectionCharFormat(editor, &tmp);
+    ME_CopyToCFAny((CHARFORMAT2W *)lParam, &tmp);
+    return 0;
+  }
+  case EM_SETPARAFORMAT:
+    ME_SetSelectionParaFormat(editor, (PARAFORMAT2 *)lParam);
+    ME_CommitUndo(editor);
+    return 0;
+  case EM_GETPARAFORMAT:
+    ME_GetSelectionParaFormat(editor, (PARAFORMAT2 *)lParam);
+    return 0;
+  case WM_CLEAR:
+  {
+    int from, to;
+    ME_GetSelection(editor, &from, &to);
+    ME_InternalDeleteText(editor, from, to-from);
+    ME_CommitUndo(editor);
+    ME_UpdateRepaint(editor);
+    return 0;
+  }
+  case EM_REPLACESEL:
+  {
+    int from, to;
+    ME_Style *style;
+    LPWSTR wszText = ME_ToUnicode(hWnd, (void *)lParam);
+    size_t len = lstrlenW(wszText);
+    TRACE("EM_REPLACESEL - %s\n", debugstr_w(wszText));
+    
+    ME_GetSelection(editor, &from, &to);
+    style = ME_GetSelectionInsertStyle(editor);
+    ME_InternalDeleteText(editor, from, to-from);
+    ME_InsertTextFromCursor(editor, 0, wszText, len, style);
+    ME_ReleaseStyle(style);
+    ME_EndToUnicode(hWnd, wszText);
+    /* drop temporary style if line end */
+    /* FIXME question: does abc\n mean: put abc, clear temp style, put \n? (would require a change) */  
+    if (len>0 && wszText[len-1] == '\n')
+      ME_ClearTempStyle(editor);
+      
+    ME_CommitUndo(editor);
+    if (!wParam)
+      ME_EmptyUndoStack(editor);
+    ME_UpdateRepaint(editor);
+    return 0;
+  }
+  case WM_SETTEXT:
+  {
+    LPWSTR wszText = ME_ToUnicode(hWnd, (void *)lParam);
+    TRACE("WM_SETTEXT - %s\n", (char *)(wszText)); /* debugstr_w() */
+    ME_InternalDeleteText(editor, 0, ME_GetTextLength(editor));
+    /* uses default style! */
+    ME_InsertTextFromCursor(editor, 0, wszText, -1, editor->pBuffer->pDefaultStyle);
+    ME_EndToUnicode(hWnd, wszText);
+    ME_CommitUndo(editor);
+    ME_EmptyUndoStack(editor);
+    ME_UpdateRepaint(editor);
+    return 0;
+  }
+  case WM_CUT:
+  case WM_COPY:
+  {
+    int from, to, pars;
+    WCHAR *data;
+    HANDLE hData;
+    
+    if (!OpenClipboard(hWnd))
+      return 0;
+      
+    EmptyClipboard();
+    ME_GetSelection(editor, &from, &to);
+    pars = ME_CountParagraphsBetween(editor, from, to);
+    hData = GlobalAlloc(GMEM_MOVEABLE, sizeof(WCHAR)*(to-from+pars+1));
+    data = (WCHAR *)GlobalLock(hData);
+    ME_GetTextW(editor, data, from, to-from, TRUE);
+    GlobalUnlock(hData);
+    SetClipboardData(CF_UNICODETEXT, hData);
+    CloseClipboard();
+    if (msg == WM_CUT)
+    {
+      ME_InternalDeleteText(editor, from, to-from);
+      ME_CommitUndo(editor);
+      ME_UpdateRepaint(editor);
+    }
+    return 0;
+  }
+  case WM_GETTEXTLENGTH:
+    return ME_GetTextLength(editor);
+  case WM_GETTEXT:
+  {
+    TEXTRANGEW tr; /* W and A differ only by rng->lpstrText */
+    tr.chrg.cpMin = 0;
+    tr.chrg.cpMax = wParam-1;
+    tr.lpstrText = (WCHAR *)lParam;
+    return RichEditANSIWndProc(hWnd, EM_GETTEXTRANGE, 0, (LPARAM)&tr);
+  }
+  case EM_GETSELTEXT:
+  {
+    int from, to;
+    TEXTRANGEW tr; /* W and A differ only by rng->lpstrText */
+    ME_GetSelection(editor, &from, &to);
+    tr.chrg.cpMin = from;
+    tr.chrg.cpMax = to;
+    tr.lpstrText = (WCHAR *)lParam;
+    return RichEditANSIWndProc(hWnd, EM_GETTEXTRANGE, 0, (LPARAM)&tr);
+  }
+  case EM_GETTEXTRANGE:
+  {
+    TEXTRANGEW *rng = (TEXTRANGEW *)lParam;
+    if (IsWindowUnicode(hWnd))
+      return ME_GetTextW(editor, rng->lpstrText, rng->chrg.cpMin, rng->chrg.cpMax-rng->chrg.cpMin, FALSE);
+    else
+    {
+      int nLen = rng->chrg.cpMax-rng->chrg.cpMin;
+      WCHAR *p = ALLOC_N_OBJ(WCHAR, nLen+1);
+      int nChars = ME_GetTextW(editor, p, rng->chrg.cpMin, nLen, FALSE);
+      /* FIXME this is a potential security hole (buffer overrun) 
+         if you know more about wchar->mbyte conversion please explain
+      */
+      WideCharToMultiByte(CP_ACP, 0, p, nChars+1, (char *)rng->lpstrText, nLen+1, NULL, NULL);
+      FREE_OBJ(p);
+      return nChars;
+    }
+    return ME_GetTextW(editor, rng->lpstrText, rng->chrg.cpMin, rng->chrg.cpMax-rng->chrg.cpMin, FALSE);
+  }
+  case WM_CREATE:
+    ME_CommitUndo(editor);
+    ME_WrapMarkedParagraphs(editor);
+    ME_MoveCaret(editor);
+    return 0;
+  case WM_DESTROY:
+    ME_DestroyEditor(editor);
+    SetWindowLongW(hWnd, 0, 0);
+    return 0;
+  case WM_LBUTTONDOWN:
+    SetFocus(hWnd);
+    ME_LButtonDown(editor, (short)LOWORD(lParam), (short)HIWORD(lParam));
+    SetCapture(hWnd);
+    break;
+  case WM_MOUSEMOVE:
+    if (GetCapture() == hWnd)
+      ME_MouseMove(editor, (short)LOWORD(lParam), (short)HIWORD(lParam));
+    break;
+  case WM_LBUTTONUP:
+    if (GetCapture() == hWnd)
+      ReleaseCapture();
+    break;
+  case WM_PAINT:
+    hDC = BeginPaint(hWnd, &ps);
+    ME_PaintContent(editor, hDC, FALSE, &ps.rcPaint);
+    EndPaint(hWnd, &ps);
+    break;
+  case WM_SETFOCUS:
+    ME_ShowCaret(editor);
+    ME_SendOldNotify(editor, EN_SETFOCUS);
+    return 0;
+  case WM_KILLFOCUS:
+    ME_HideCaret(editor);
+    ME_SendOldNotify(editor, EN_KILLFOCUS);
+    return 0;
+  case WM_ERASEBKGND:
+  {
+    HDC hDC = (HDC)wParam;
+    RECT rc;
+    COLORREF rgbBG = ME_GetBackColor(editor);
+    if (GetUpdateRect(hWnd,&rc,TRUE))
+    {
+      HBRUSH hbr = CreateSolidBrush(rgbBG);
+      FillRect(hDC, &rc, hbr);
+      DeleteObject(hbr);
+    }
+    return 1;
+  }
+  case WM_COMMAND:
+    TRACE("editor wnd command = %d\n", LOWORD(wParam));
+    return 0;
+  case WM_KEYDOWN:
+    if (ME_ArrowKey(editor, LOWORD(wParam), GetKeyState(VK_CONTROL)<0)) {
+      ME_CommitUndo(editor);
+      ME_EnsureVisible(editor, editor->pCursors[0].pRun);
+      HideCaret(hWnd);
+      ME_MoveCaret(editor);
+      ShowCaret(hWnd);
+      return 0;
+    }
+    if (GetKeyState(VK_CONTROL)<0)
+    {
+      if (LOWORD(wParam)=='W')
+      {
+        CHARFORMAT2W chf;
+        char buf[2048];
+        ME_GetSelectionCharFormat(editor, &chf);
+        ME_DumpStyleToBuf(&chf, buf);
+        MessageBoxA(NULL, buf, "Style dump", MB_OK);
+      }
+      if (LOWORD(wParam)=='Q')
+      {
+        ME_CheckCharOffsets(editor);
+      }
+    }
+    goto do_default;
+  case WM_CHAR: 
+  {
+    WCHAR wstr;
+    if (GetWindowLongW(editor->hWnd, GWL_STYLE) & ES_READONLY) {
+      MessageBeep(MB_ICONERROR);
+      return 0; /* FIXME really 0 ? */
+    }
+    wstr = LOWORD(wParam);
+    if (((unsigned)wstr)>=' ' || wstr=='\r') {
+      /* FIXME maybe it would make sense to call EM_REPLACESEL instead ? */
+      ME_Style *style = ME_GetInsertStyle(editor, 0);
+      ME_SaveTempStyle(editor);
+      ME_InsertTextFromCursor(editor, 0, &wstr, 1, style);
+      ME_ReleaseStyle(style);
+      ME_CommitUndo(editor);
+      ME_UpdateRepaint(editor);
+    }
+    return 0;
+  }
+  case WM_VSCROLL: 
+  {
+    si.cbSize = sizeof(SCROLLINFO);
+    si.fMask = SIF_PAGE|SIF_POS|SIF_RANGE|SIF_TRACKPOS;
+    GetScrollInfo(hWnd, SB_VERT, &si);
+    switch(LOWORD(wParam)) {
+    case SB_THUMBTRACK:
+      SetScrollPos(hWnd, SB_VERT, si.nTrackPos, FALSE);
+      ScrollWindow(hWnd, 0, si.nPos-si.nTrackPos, NULL, NULL);
+      /* InvalidateRect(hWnd, NULL, TRUE); */
+      UpdateWindow(hWnd);
+      break;
+    }
+    break;
+  }
+  case WM_SIZE:
+  {
+    ME_MarkAllForWrapping(editor);
+    ME_Repaint(editor);
+    return DefWindowProcW(hWnd, msg, wParam, lParam);
+  }
+  case EM_GETOLEINTERFACE:
+  {
+    LPVOID *ppvObj = (LPVOID*) lParam;
+    FIXME("EM_GETOLEINTERFACE %p: stub\n", ppvObj);
+    return CreateIRichEditOle(ppvObj);
+  }
+  default:
+  do_default:
+    return DefWindowProcW(hWnd, msg, wParam, lParam);
+  }
+  return 0L;
+}
+
+/******************************************************************
+ *        RichEdit10ANSIWndProc (RICHED20.9)
+ */
+LRESULT WINAPI RichEdit10ANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+  /* FIXME: this is NOT the same as 2.0 version */
+  return RichEditANSIWndProc(hWnd, msg, wParam, lParam);
+}
+
+void ME_SendOldNotify(ME_TextEditor *editor, int nCode)
+{
+  HWND hWnd = editor->hWnd;
+  SendMessageA(GetParent(hWnd), WM_COMMAND, (nCode<<16)|GetWindowLongW(hWnd, GWLP_ID), (LPARAM)hWnd);
+}
+
+int ME_CountParagraphsBetween(ME_TextEditor *editor, int from, int to)
+{
+  ME_DisplayItem *item = ME_FindItemFwd(editor->pBuffer->pFirst, diParagraph);
+  int i = 0;
+  
+  while(item && item->member.para.next_para->member.para.nCharOfs <= from)
+    item = item->member.para.next_para;
+  if (!item)
+    return 0;
+  while(item && item->member.para.next_para->member.para.nCharOfs <= to) {
+    item = item->member.para.next_para;
+    i++;
+  }
+  return i;
+}
+
+int ME_GetTextW(ME_TextEditor *editor, WCHAR *buffer, int nStart, int nChars, int bCRLF)
+{
+  ME_DisplayItem *item = ME_FindItemFwd(editor->pBuffer->pFirst, diParagraph);
+  int nWritten = 0;
+  
+  while(item && item->member.para.next_para->member.para.nCharOfs <= nStart)
+    item = ME_FindItemFwd(item, diParagraph);
+  if (!item) {
+    *buffer = L'\0';
+    return 0;
+  }
+  nStart -= item->member.para.nCharOfs;
+
+  do {  
+    item = ME_FindItemFwd(item, diRun);
+  } while(item && (item->member.run.nCharOfs + ME_StrLen(item->member.run.strText) <= nStart));
+  assert(item);    
+  
+  nStart -= item->member.run.nCharOfs;
+  
+  if (nStart)
+  {
+    int nLen = ME_StrLen(item->member.run.strText) - nStart;
+    if (nLen > nChars)
+      nLen = nChars;
+    CopyMemory(buffer, item->member.run.strText->szData + nStart, sizeof(WCHAR)*nLen);
+    nChars -= nLen;
+    nWritten += nLen;
+    if (!nChars)
+      return nWritten;
+    buffer += nLen;
+    nStart = 0;
+    item = ME_FindItemFwd(item, diRun);
+  }
+  
+  while(nChars && item)
+  {
+    int nLen = ME_StrLen(item->member.run.strText);
+    if (nLen > nChars)
+      nLen = nChars;
+      
+    if (item->member.run.nFlags & MERF_ENDPARA)
+    {
+      if (bCRLF) {
+        *buffer++ = '\r';
+        nWritten++;
+      }        
+      *buffer = '\n';
+      assert(nLen == 1);
+    }
+    else      
+      CopyMemory(buffer, item->member.run.strText->szData, sizeof(WCHAR)*nLen);
+    nChars -= nLen;
+    nWritten += nLen;
+    buffer += nLen;    
+      
+    if (!nChars)
+    {
+      *buffer = L'\0';
+      return nWritten;
+    }
+    item = ME_FindItemFwd(item, diRun);
+  }
+  *buffer = L'\0';
+  return nWritten;  
+}
+
+static WCHAR wszClassName[] = {'R', 'i', 'c', 'h', 'E', 'd', 'i', 't', '2', '0', 'W', 0};
+static WCHAR wszClassName50[] = {'R', 'i', 'c', 'h', 'E', 'd', 'i', 't', '5', '0', 'W', 0};
+
+void ME_RegisterEditorClass(HINSTANCE hInstance)
+{
+  BOOL bResult;
+  WNDCLASSW wcW;
+  WNDCLASSA wcA;
+  
+  wcW.style = CS_HREDRAW | CS_VREDRAW;
+  wcW.lpfnWndProc = RichEditANSIWndProc;
+  wcW.cbClsExtra = 0;
+  wcW.cbWndExtra = 4;
+  wcW.hInstance = NULL; /* hInstance would register DLL-local class */
+  wcW.hIcon = NULL;
+  wcW.hCursor = LoadCursorW(NULL, MAKEINTRESOURCEW(IDC_IBEAM));
+  wcW.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH);
+  wcW.lpszMenuName = NULL;
+  wcW.lpszClassName = wszClassName;
+  bResult = RegisterClassW(&wcW);  
+  assert(bResult);
+  wcW.lpszClassName = wszClassName50;
+  bResult = RegisterClassW(&wcW);  
+  assert(bResult);
+
+  wcA.style = CS_HREDRAW | CS_VREDRAW;
+  wcA.lpfnWndProc = RichEditANSIWndProc;
+  wcA.cbClsExtra = 0;
+  wcA.cbWndExtra = 4;
+  wcA.hInstance = NULL; /* hInstance would register DLL-local class */
+  wcA.hIcon = NULL;
+  wcA.hCursor = LoadCursorW(NULL, MAKEINTRESOURCEW(IDC_IBEAM));
+  wcA.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH);
+  wcA.lpszMenuName = NULL;
+  wcA.lpszClassName = "RichEdit20A";
+  bResult = RegisterClassA(&wcA);  
+  assert(bResult);
+  wcA.lpszClassName = "RichEdit50A";
+  bResult = RegisterClassA(&wcA);  
+  assert(bResult);
+}
+
+BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+{
+    TRACE("\n");
+    switch (fdwReason)
+    {
+    case DLL_PROCESS_ATTACH:
+      DisableThreadLibraryCalls(hinstDLL);
+      me_heap = HeapCreate (0, 0x10000, 0);
+      ME_RegisterEditorClass(hinstDLL);
+      break;
+
+    case DLL_PROCESS_DETACH:
+      UnregisterClassW(wszClassName, 0);
+      UnregisterClassW(wszClassName50, 0);
+      UnregisterClassA("RichEdit20A", 0);
+      UnregisterClassA("RichEdit50A", 0);
+      HeapDestroy (me_heap);
+      me_heap = NULL;
+      break;
+    }
+    return TRUE;
+}
+
+/******************************************************************
+ *        CreateTextServices (RICHED20.4)
+ *
+ * FIXME should be ITextHost instead of void*
+ */
+HRESULT WINAPI CreateTextServices(IUnknown *punkOuter, void *pITextHost,
+    IUnknown **ppUnk)
+{
+  FIXME("stub\n");
+  /* FIXME should support aggregation */
+  if (punkOuter)
+    return CLASS_E_NOAGGREGATION;
+    
+  return E_FAIL; /* E_NOTIMPL isn't allowed by MSDN */
+}
+
+/******************************************************************
+ *        REExtendedRegisterClass (RICHED20.8)
+ *
+ * FIXME undocumented
+ */
+void WINAPI REExtendedRegisterClass(void)
+{
+  FIXME("stub\n");
+}
diff --git a/reactos/lib/riched20/editor.h b/reactos/lib/riched20/editor.h
new file mode 100644 (file)
index 0000000..8749fd2
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ * RichEdit - prototypes for functions and macro definitions
+ *
+ * Copyright 2004 by Krzysztof Foltman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "editstr.h"
+
+#define ALLOC_OBJ(type) (type *)HeapAlloc(me_heap, 0, sizeof(type))
+#define ALLOC_N_OBJ(type, count) (type *)HeapAlloc(me_heap, 0, count*sizeof(type))
+#define FREE_OBJ(ptr) HeapFree(me_heap, 0, ptr)
+
+/* style.c */
+ME_Style *ME_MakeStyle(CHARFORMAT2W *style);
+void ME_AddRefStyle(ME_Style *item);
+void ME_ReleaseStyle(ME_Style *item);
+ME_Style *ME_GetInsertStyle(ME_TextEditor *editor, int nCursor);
+ME_Style *ME_ApplyStyle(ME_Style *sSrc, CHARFORMAT2W *style);
+HFONT ME_SelectStyleFont(ME_TextEditor *editor, HDC hDC, ME_Style *s);
+void ME_UnselectStyleFont(ME_TextEditor *editor, HDC hDC, ME_Style *s, HFONT hOldFont);
+void ME_InitCharFormat2W(CHARFORMAT2W *pFmt);
+void ME_SaveTempStyle(ME_TextEditor *editor);
+void ME_ClearTempStyle(ME_TextEditor *editor);
+void ME_DumpStyleToBuf(CHARFORMAT2W *pFmt, char buf[2048]);
+void ME_DumpStyle(ME_Style *s);
+CHARFORMAT2W *ME_ToCF2W(CHARFORMAT2W *to, CHARFORMAT2W *from);
+void ME_CopyToCF2W(CHARFORMAT2W *to, CHARFORMAT2W *from);
+CHARFORMAT2W *ME_ToCFAny(CHARFORMAT2W *to, CHARFORMAT2W *from);
+void ME_CopyToCFAny(CHARFORMAT2W *to, CHARFORMAT2W *from);
+void ME_CopyCharFormat(CHARFORMAT2W *pDest, CHARFORMAT2W *pSrc); /* only works with 2W structs */
+
+/* list.c */
+void ME_InsertBefore(ME_DisplayItem *diWhere, ME_DisplayItem *diWhat);
+void ME_Remove(ME_DisplayItem *diWhere);
+ME_DisplayItem *ME_FindItemBack(ME_DisplayItem *di, ME_DIType nTypeOrClass);
+ME_DisplayItem *ME_FindItemFwd(ME_DisplayItem *di, ME_DIType nTypeOrClass);
+ME_DisplayItem *ME_FindItemBackOrHere(ME_DisplayItem *di, ME_DIType nTypeOrClass);
+ME_DisplayItem *ME_FindItemFwdOrHere(ME_DisplayItem *di, ME_DIType nTypeOrClass);
+BOOL ME_DITypesEqual(ME_DIType type, ME_DIType nTypeOrClass);
+ME_DisplayItem *ME_MakeDI(ME_DIType type);
+void ME_DestroyDisplayItem(ME_DisplayItem *item);
+void ME_DumpDocument(ME_TextBuffer *buffer);
+const char *ME_GetDITypeName(ME_DIType type);
+
+/* string.c */
+int ME_GetOptimalBuffer(int nLen);
+ME_String *ME_MakeString(LPCWSTR szText);
+ME_String *ME_MakeStringN(LPCWSTR szText, int nMaxChars);
+ME_String *ME_StrDup(ME_String *s);
+void ME_DestroyString(ME_String *s);
+void ME_AppendString(ME_String *s1, ME_String *s2);
+ME_String *ME_ConcatString(ME_String *s1, ME_String *s2);
+ME_String *ME_VSplitString(ME_String *orig, int nVPos);
+int ME_IsWhitespaces(ME_String *s);
+int ME_IsSplitable(ME_String *s);
+/* int ME_CalcSkipChars(ME_String *s); */
+int ME_StrLen(ME_String *s);
+int ME_StrVLen(ME_String *s);
+int ME_FindNonWhitespaceV(ME_String *s, int nVChar);
+int ME_FindWhitespaceV(ME_String *s, int nVChar);
+int ME_GetCharFwd(ME_String *s, int nPos); /* get char starting from start */
+int ME_GetCharBack(ME_String *s, int nPos); /* get char starting from \0  */
+int ME_StrRelPos(ME_String *s, int nVChar, int *pRelChars);
+int ME_StrRelPos2(ME_String *s, int nVChar, int nRelChars);
+int ME_VPosToPos(ME_String *s, int nVPos);
+int ME_PosToVPos(ME_String *s, int nPos);
+void ME_StrDeleteV(ME_String *s, int nVChar, int nChars);
+/* smart helpers for A<->W conversions, they reserve/free memory and call MultiByte<->WideChar functions */
+LPWSTR ME_ToUnicode(HWND hWnd, LPVOID psz);
+void ME_EndToUnicode(HWND hWnd, LPVOID psz);
+LPSTR ME_ToAnsi(HWND hWnd, LPVOID psz);
+void ME_EndToAnsi(HWND hWnd, LPVOID psz);
+
+
+/* note: those two really return the first matching offset (starting from EOS)+1 
+ * in other words, an offset of the first trailing white/black */
+int ME_ReverseFindNonWhitespaceV(ME_String *s, int nVChar);
+int ME_ReverseFindWhitespaceV(ME_String *s, int nVChar);
+
+/* row.c */
+ME_DisplayItem *ME_FindRowStart(ME_Context *c, ME_DisplayItem *run, int nRelPos);
+ME_DisplayItem *ME_RowStart(ME_DisplayItem *item);
+ME_DisplayItem *ME_RowEnd(ME_DisplayItem *item);
+void ME_RenumberParagraphs(ME_DisplayItem *item); /* TODO */
+
+/* run.c */
+ME_DisplayItem *ME_MakeRun(ME_Style *s, ME_String *strData, int nFlags);
+/* note: ME_InsertRun inserts a copy of the specified run - so you need to destroy the original */
+ME_DisplayItem *ME_InsertRun(ME_TextEditor *editor, int nCharOfs, ME_DisplayItem *pItem);
+void ME_CheckCharOffsets(ME_TextEditor *editor);
+void ME_PropagateCharOffset(ME_DisplayItem *p, int shift);
+void ME_GetGraphicsSize(ME_TextEditor *editor, ME_Run *run, SIZE *pSize);
+int ME_CharFromPoint(ME_TextEditor *editor, int cx, ME_Run *run);
+/* this one accounts for 1/2 char tolerance */
+int ME_CharFromPointCursor(ME_TextEditor *editor, int cx, ME_Run *run);
+int ME_PointFromChar(ME_TextEditor *editor, ME_Run *pRun, int nOffset);
+int ME_GetLastSplittablePlace(ME_Context *c, ME_Run *run);
+int ME_CanJoinRuns(ME_Run *run1, ME_Run *run2);
+void ME_JoinRuns(ME_TextEditor *editor, ME_DisplayItem *p);
+ME_DisplayItem *ME_SplitRun(ME_Context *c, ME_DisplayItem *item, int nChar);
+ME_DisplayItem *ME_SplitRunSimple(ME_TextEditor *editor, ME_DisplayItem *item, int nChar);
+int ME_FindSplitPoint(ME_Context *c, POINT *pt, ME_Run *run, int desperate);
+void ME_UpdateRunFlags(ME_TextEditor *editor, ME_Run *run);
+ME_DisplayItem *ME_SplitFurther(ME_TextEditor *editor, ME_DisplayItem *run);
+void ME_CalcRunExtent(ME_Context *c, ME_Run *run);
+SIZE ME_GetRunSize(ME_Context *c, ME_Run *run, int nLen);
+void ME_CursorFromCharOfs(ME_TextEditor *editor, int nCharOfs, ME_Cursor *pCursor);
+void ME_RunOfsFromCharOfs(ME_TextEditor *editor, int nCharOfs, ME_DisplayItem **ppRun, int *pOfs);
+int ME_CharOfsFromRunOfs(ME_TextEditor *editor, ME_DisplayItem *pRun, int nOfs);
+void ME_SkipAndPropagateCharOffset(ME_DisplayItem *p, int shift);
+void ME_SetCharFormat(ME_TextEditor *editor, int nFrom, int nLen, CHARFORMAT2W *pFmt);
+void ME_SetSelectionCharFormat(ME_TextEditor *editor, CHARFORMAT2W *pFmt);
+void ME_GetCharFormat(ME_TextEditor *editor, int nFrom, int nLen, CHARFORMAT2W *pFmt);
+void ME_GetSelectionCharFormat(ME_TextEditor *editor, CHARFORMAT2W *pFmt);
+void ME_GetDefaultCharFormat(ME_TextEditor *editor, CHARFORMAT2W *pFmt);
+void ME_SetDefaultCharFormat(ME_TextEditor *editor, CHARFORMAT2W *mod);
+
+/* caret.c */
+void ME_SetSelection(ME_TextEditor *editor, int from, int to);
+void ME_HideCaret(ME_TextEditor *ed);
+void ME_ShowCaret(ME_TextEditor *ed);
+void ME_MoveCaret(ME_TextEditor *ed);
+int ME_FindPixelPos(ME_TextEditor *editor, int x, int y, ME_Cursor *result, BOOL *is_eol);
+void ME_LButtonDown(ME_TextEditor *editor, int x, int y);
+void ME_MouseMove(ME_TextEditor *editor, int x, int y);
+void ME_DeleteTextAtCursor(ME_TextEditor *editor, int nCursor, int nChars);
+void ME_InsertTextFromCursor(ME_TextEditor *editor, int nCursor, 
+                             const WCHAR *str, int len, ME_Style *style);
+void ME_SetCharFormat(ME_TextEditor *editor, int nOfs, int nChars, CHARFORMAT2W *pFmt);
+BOOL ME_ArrowKey(ME_TextEditor *ed, int nVKey, int nCtrl);
+
+void ME_InitContext(ME_Context *c, ME_TextEditor *editor, HDC hDC);
+void ME_DestroyContext(ME_Context *c);
+ME_Style *GetInsertStyle(ME_TextEditor *editor, int nCursor);
+void ME_MustBeWrapped(ME_Context *c, ME_DisplayItem *para);
+int ME_GetCursorOfs(ME_TextEditor *editor, int nCursor);
+void ME_GetSelection(ME_TextEditor *editor, int *from, int *to);
+int ME_CountParagraphsBetween(ME_TextEditor *editor, int from, int to);
+BOOL ME_IsSelection(ME_TextEditor *editor);
+void ME_DeleteSelection(ME_TextEditor *editor);
+void ME_SendSelChange(ME_TextEditor *editor);
+void ME_InsertGraphicsFromCursor(ME_TextEditor *editor, int nCursor);
+void ME_InternalDeleteText(ME_TextEditor *editor, int nOfs, int nChars);
+int ME_GetTextLength(ME_TextEditor *editor);
+ME_Style *ME_GetSelectionInsertStyle(ME_TextEditor *editor);
+
+/* wrap.c */
+void ME_PrepareParagraphForWrapping(ME_Context *c, ME_DisplayItem *tp);
+ME_DisplayItem *ME_MakeRow(int height, int baseline, int width);
+void ME_InsertRowStart(ME_WrapContext *wc, ME_DisplayItem *pEnd);
+void ME_WrapTextParagraph(ME_Context *c, ME_DisplayItem *tp);
+void ME_WrapMarkedParagraphs(ME_TextEditor *editor);
+
+/* para.c */
+ME_DisplayItem *ME_GetParagraph(ME_DisplayItem *run); 
+void ME_MakeFirstParagraph(HDC hDC, ME_TextBuffer *editor);
+ME_DisplayItem *ME_SplitParagraph(ME_TextEditor *editor, ME_DisplayItem *rp, ME_Style *style);
+ME_DisplayItem *ME_JoinParagraphs(ME_TextEditor *editor, ME_DisplayItem *tp);
+void ME_DumpParaStyle(ME_Paragraph *s);
+void ME_DumpParaStyleToBuf(PARAFORMAT2 *pFmt, char buf[2048]);
+void ME_SetParaFormat(ME_TextEditor *editor, ME_DisplayItem *para, PARAFORMAT2 *pFmt);
+void ME_SetSelectionParaFormat(ME_TextEditor *editor, PARAFORMAT2 *pFmt);
+void ME_GetParaFormat(ME_TextEditor *editor, ME_DisplayItem *para, PARAFORMAT2 *pFmt);
+void ME_GetSelectionParaFormat(ME_TextEditor *editor, PARAFORMAT2 *pFmt);
+/* marks from first up to (but not including) last */
+void ME_MarkForWrapping(ME_TextEditor *editor, ME_DisplayItem *first, ME_DisplayItem *last);
+void ME_MarkAllForWrapping(ME_TextEditor *editor);
+
+/* paint.c */
+void ME_PaintContent(ME_TextEditor *editor, HDC hDC, BOOL bOnlyNew, RECT *rcUpdate);
+void ME_Repaint(ME_TextEditor *editor);
+void ME_UpdateRepaint(ME_TextEditor *editor);
+void ME_DrawParagraph(ME_Context *c, ME_DisplayItem *paragraph);
+void ME_UpdateScrollBar(ME_TextEditor *editor, int ypos);
+int ME_GetScrollPos(ME_TextEditor *editor);
+void ME_EnsureVisible(ME_TextEditor *editor, ME_DisplayItem *pRun);
+COLORREF ME_GetBackColor(ME_TextEditor *editor);
+
+/* richole.c */
+extern LRESULT CreateIRichEditOle(LPVOID *);
+
+/* wintest.c */
+
+/* editor.c */
+void ME_RegisterEditorClass();
+ME_TextEditor *ME_MakeEditor(HWND hWnd);
+void ME_DestroyEditor(ME_TextEditor *editor);
+void ME_SendOldNotify(ME_TextEditor *editor, int nCode);
+ME_UndoItem *ME_AddUndoItem(ME_TextEditor *editor, ME_DIType type, ME_DisplayItem *di);
+void ME_CommitUndo(ME_TextEditor *editor);
+void ME_Undo(ME_TextEditor *editor);
+void ME_Redo(ME_TextEditor *editor);
+void ME_EmptyUndoStack(ME_TextEditor *editor);
+int ME_GetTextW(ME_TextEditor *editor, WCHAR *buffer, int nStart, int nChars, BOOL bCRLF);
+
+extern int me_debug;
+extern HANDLE me_heap;
+extern void DoWrap(ME_TextEditor *editor);
diff --git a/reactos/lib/riched20/editstr.h b/reactos/lib/riched20/editstr.h
new file mode 100644 (file)
index 0000000..d1f4819
--- /dev/null
@@ -0,0 +1,258 @@
+/*
+ * RichEdit - structures and constant
+ *
+ * Copyright 2004 by Krzysztof Foltman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __EDITSTR_H
+#define __EDITSTR_H
+
+#ifndef _WIN32_IE
+#define _WIN32_IE 0x0400
+#endif
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <windef.h>
+#include <winbase.h>
+#include <winnls.h>
+#include <winnt.h>
+#include <wingdi.h>
+#include <winuser.h>
+#include <richedit.h>
+#include <commctrl.h>
+
+#include "wine/debug.h"
+
+typedef struct tagME_String
+{
+  WCHAR *szData;
+  int nLen, nBuffer;
+} ME_String;
+
+typedef struct tagME_Style
+{
+  CHARFORMAT2W fmt;
+
+  HFONT hFont; /* cached font for the style */
+  TEXTMETRICW tm; /* cached font metrics for the style */
+  int nRefs; /* reference count */
+  int nSequence; /* incremented when cache needs to be rebuilt, ie. every screen redraw */
+} ME_Style;
+
+typedef enum {
+  diTextStart, /* start of the text buffer */
+  diParagraph, /* paragraph start */
+  diRun, /* run (sequence of chars with the same character format) */
+  diStartRow, /* start of the row (line of text on the screen) */
+  diTextEnd, /* end of the text buffer */
+  
+  /********************* these below are meant for finding only *********************/
+  diStartRowOrParagraph, /* 5 */
+  diStartRowOrParagraphOrEnd,
+  diRunOrParagraph,
+  diRunOrStartRow,
+  diParagraphOrEnd,
+  diRunOrParagraphOrEnd, /* 10 */
+  
+  diUndoInsertRun, /* 11 */
+  diUndoDeleteRun, /* 12 */
+  diUndoJoinParagraphs, /* 13 */
+  diUndoSplitParagraph, /* 14 */
+  diUndoSetParagraphFormat, /* 15 */
+  diUndoSetCharFormat, /* 16 */
+  diUndoEndTransaction, /* 17 */
+  diUndoSetDefaultCharFormat, /* 18 */
+} ME_DIType;
+
+/******************************** run flags *************************/
+#define MERF_STYLEFLAGS 0x0FFF
+/* run contains non-text content, which has its own rules for wrapping, sizing etc */
+#define MERF_GRAPHICS 1
+
+/* run is splittable (contains white spaces in the middle or end) */
+#define MERF_SPLITTABLE 0x001000
+/* run starts with whitespaces */
+#define MERF_STARTWHITE 0x002000
+/* run ends with whitespaces */
+#define MERF_ENDWHITE   0x004000
+/* run is completely made of whitespaces */
+#define MERF_WHITESPACE 0x008000
+/* run is a last (dummy) run in the paragraph */
+#define MERF_SKIPPED    0x010000
+/* flags that are calculated during text wrapping */
+#define MERF_CALCBYWRAP 0x0F0000
+/* the "end of paragraph" run, contains 1 character */
+#define MERF_ENDPARA    0x100000
+
+/* those flags are kept when the row is split */
+#define MERF_SPLITMASK (~(0))
+
+/******************************** para flags *************************/
+
+/* this paragraph was already wrapped and hasn't changed, every change resets that flag */
+#define MEPF_REWRAP 1
+#define MEPF_REPAINT 2
+
+/******************************** structures *************************/
+
+struct tagME_DisplayItem;
+
+typedef struct tagME_Run
+{
+  ME_String *strText;
+  ME_Style *style;
+  int nCharOfs; /* relative to para's offset */
+  int nWidth; /* width of full run, width of leading&trailing ws */
+  int nFlags;
+  int nAscent, nDescent; /* pixels above/below baseline */
+  POINT pt; /* relative to para's position */
+} ME_Run;
+
+typedef struct tagME_Document {
+  struct tagME_DisplayItem *def_char_style;
+  struct tagME_DisplayItem *def_para_style;
+  int last_wrapped_line;
+} ME_Document;
+
+typedef struct tagME_Paragraph
+{
+  PARAFORMAT2 *pFmt;
+  int nLeftMargin, nRightMargin, nFirstMargin;
+  int nCharOfs;
+  int nFlags;
+  int nYPos, nHeight;
+  int nLastPaintYPos, nLastPaintHeight;
+  struct tagME_DisplayItem *prev_para, *next_para, *document;
+} ME_Paragraph;
+
+typedef struct tagME_Row
+{
+  int nHeight;
+  int nBaseline;
+  int nWidth;
+  int nLMargin;
+  int nRMargin;
+  int nYPos;
+} ME_Row;
+
+typedef struct tagME_DisplayItem
+{
+  ME_DIType type;
+  struct tagME_DisplayItem *prev, *next;
+  union {
+    ME_Run run;
+    ME_Row row;
+    ME_Paragraph para;
+    ME_Document doc; /* not used */
+    ME_Style *ustyle; /* used by diUndoSetCharFormat */
+  } member;
+} ME_DisplayItem;
+
+typedef struct tagME_UndoItem
+{
+  ME_DisplayItem di;
+  int nStart, nLen;
+} ME_UndoItem;
+
+typedef struct tagME_TextBuffer
+{
+  ME_DisplayItem *pFirst, *pLast;
+  ME_Style *pCharStyle;
+  ME_Style *pDefaultStyle;
+} ME_TextBuffer;
+
+typedef struct tagME_Cursor
+{
+  ME_DisplayItem *pRun;
+  int nOffset;
+} ME_Cursor;
+
+typedef enum {
+  umAddToUndo,
+  umAddToRedo,
+  umIgnore,
+  umAddBackToUndo
+} ME_UndoMode;
+
+typedef struct tagME_FontCacheItem
+{
+  LOGFONTW lfSpecs;
+  HFONT hFont;
+  int nRefs;
+  int nAge;
+} ME_FontCacheItem;
+
+#define HFONT_CACHE_SIZE 10
+
+typedef struct tagME_TextEditor
+{
+  HWND hWnd;
+  BOOL bCaretShown;
+  ME_TextBuffer *pBuffer;
+  ME_Cursor *pCursors;
+  int nCursors;
+  SIZE sizeWindow;
+  int nScrollPos;
+  int nTotalLength, nLastTotalLength;
+  int nUDArrowX;
+  int nSequence;
+  int nOldSelFrom, nOldSelTo;
+  COLORREF rgbBackColor;
+  BOOL bCaretAtEnd;
+  int nEventMask;
+  int nModifyStep;
+  ME_DisplayItem *pUndoStack, *pRedoStack;
+  ME_UndoMode nUndoMode;
+  int nParagraphs;
+  int nLastSelStart, nLastSelEnd;
+  ME_FontCacheItem pFontCache[HFONT_CACHE_SIZE];
+} ME_TextEditor;
+
+typedef struct tagME_Context
+{
+  HDC hDC;
+  POINT pt;
+  POINT ptRowOffset;
+  RECT rcView;
+  HBRUSH hbrMargin;
+
+  /* those are valid inside ME_WrapTextParagraph and related */
+  POINT ptFirstRun;
+  ME_TextEditor *editor;
+  int nSequence;
+} ME_Context;
+
+typedef struct tagME_WrapContext
+{
+  ME_Style *style;
+  ME_Context *context;
+  int nLeftMargin, nRightMargin, nFirstMargin;
+  int nTotalWidth, nAvailWidth;
+  int nRow;
+  POINT pt;
+  BOOL bOverflown;
+  ME_DisplayItem *pRowStart;
+  
+  ME_DisplayItem *pLastSplittableRun;
+  POINT ptLastSplittableRun;
+} ME_WrapContext;  
+
+#endif
diff --git a/reactos/lib/riched20/list.c b/reactos/lib/riched20/list.c
new file mode 100644 (file)
index 0000000..e4e1f40
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * RichEdit - Basic operations on double linked lists.
+ *
+ * Copyright 2004 by Krzysztof Foltman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#include "editor.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(riched20);
+
+void ME_InsertBefore(ME_DisplayItem *diWhere, ME_DisplayItem *diWhat)
+{
+  diWhat->next = diWhere;
+  diWhat->prev = diWhere->prev;
+
+  diWhere->prev->next = diWhat;
+  diWhat->next->prev = diWhat;
+}
+
+void ME_Remove(ME_DisplayItem *diWhere)
+{
+  ME_DisplayItem *diNext = diWhere->next;
+  ME_DisplayItem *diPrev = diWhere->prev;
+  assert(diNext);
+  assert(diPrev);
+  diPrev->next = diNext;
+  diNext->prev = diPrev;
+}
+
+ME_DisplayItem *ME_FindItemBack(ME_DisplayItem *di, ME_DIType nTypeOrClass)
+{
+  if (!di)
+    return NULL;
+  di = di->prev;
+  while(di!=NULL) {
+    if (ME_DITypesEqual(di->type, nTypeOrClass))
+      return di;
+    di = di->prev;
+  }
+  return NULL;
+}
+
+ME_DisplayItem *ME_FindItemBackOrHere(ME_DisplayItem *di, ME_DIType nTypeOrClass)
+{
+  while(di!=NULL) {
+    if (ME_DITypesEqual(di->type, nTypeOrClass))
+      return di;
+    di = di->prev;
+  }
+  return NULL;
+}
+
+ME_DisplayItem *ME_FindItemFwd(ME_DisplayItem *di, ME_DIType nTypeOrClass)
+{
+  if (!di) return NULL;
+  di = di->next;
+  while(di!=NULL) {
+    if (ME_DITypesEqual(di->type, nTypeOrClass))
+      return di;
+    di = di->next;
+  }
+  return NULL;
+}
+
+ME_DisplayItem *ME_FindItemFwdOrHere(ME_DisplayItem *di, ME_DIType nTypeOrClass)
+{
+  while(di!=NULL) {
+    if (ME_DITypesEqual(di->type, nTypeOrClass))
+      return di;
+    di = di->next;
+  }
+  return NULL;
+}
+
+BOOL ME_DITypesEqual(ME_DIType type, ME_DIType nTypeOrClass)
+{
+  if (type==nTypeOrClass)
+    return TRUE;
+  if (nTypeOrClass==diRunOrParagraph && (type==diRun || type==diParagraph))
+    return TRUE;
+  if (nTypeOrClass==diRunOrStartRow && (type==diRun || type==diStartRow))
+    return TRUE;
+  if (nTypeOrClass==diParagraphOrEnd && (type==diTextEnd || type==diParagraph))
+    return TRUE;
+  if (nTypeOrClass==diStartRowOrParagraph && (type==diStartRow || type==diParagraph))
+    return TRUE;
+  if (nTypeOrClass==diStartRowOrParagraphOrEnd 
+    && (type==diStartRow || type==diParagraph || type==diTextEnd))
+    return TRUE;
+  if (nTypeOrClass==diRunOrParagraphOrEnd 
+    && (type==diRun || type==diParagraph || type==diTextEnd))
+    return TRUE;
+  return FALSE;
+}
+
+void ME_DestroyDisplayItem(ME_DisplayItem *item) {
+/*  TRACE("type=%s\n", ME_GetDITypeName(item->type)); */
+  if (item->type==diParagraph || item->type == diUndoSetParagraphFormat) {
+    FREE_OBJ(item->member.para.pFmt);
+  }
+  if (item->type==diRun || item->type == diUndoInsertRun) {
+    ME_ReleaseStyle(item->member.run.style);
+    ME_DestroyString(item->member.run.strText);
+  }
+  if (item->type==diUndoSetCharFormat || item->type==diUndoSetDefaultCharFormat) {
+    ME_ReleaseStyle(item->member.ustyle);
+  }
+  FREE_OBJ(item);
+}
+
+ME_DisplayItem *ME_MakeDI(ME_DIType type) {
+  ME_DisplayItem *item = ALLOC_OBJ(ME_DisplayItem);
+  ZeroMemory(item, sizeof(ME_DisplayItem));
+  item->type = type;
+  item->prev = item->next = NULL;
+  if (type == diParagraph || type == diUndoSplitParagraph) {
+    item->member.para.pFmt = ALLOC_OBJ(PARAFORMAT2);
+    item->member.para.pFmt->cbSize = sizeof(PARAFORMAT2);
+    item->member.para.pFmt->dwMask = 0;
+    item->member.para.nFlags = MEPF_REWRAP;
+  }
+    
+  return item;
+}
+
+const char *ME_GetDITypeName(ME_DIType type)
+{
+  switch(type)
+  {
+    case diParagraph: return "diParagraph";
+    case diRun: return "diRun";
+    case diTextStart: return "diTextStart";
+    case diTextEnd: return "diTextEnd";
+    case diStartRow: return "diStartRow";
+    case diUndoEndTransaction: return "diUndoEndTransaction";
+    case diUndoSetParagraphFormat: return "diUndoSetParagraphFormat";
+    case diUndoSetCharFormat: return "diUndoSetCharFormat";
+    case diUndoInsertRun: return "diUndoInsertRun";
+    case diUndoDeleteRun: return "diUndoDeleteRun";
+    case diUndoJoinParagraphs: return "diJoinParagraphs";
+    case diUndoSplitParagraph: return "diSplitParagraph";
+    case diUndoSetDefaultCharFormat: return "diUndoSetDefaultCharFormat";
+    default: return "?";
+  }
+}
+
+void ME_DumpDocument(ME_TextBuffer *buffer)
+{
+  /* FIXME this is useless, */
+  ME_DisplayItem *pItem = buffer->pFirst;
+  TRACE("DOCUMENT DUMP START\n");
+  while(pItem) {
+    switch(pItem->type)
+    {
+      case diTextStart:
+        TRACE("Start");
+        break;
+      case diParagraph:
+        TRACE("\nParagraph(ofs=%d)", pItem->member.para.nCharOfs);
+        break;
+      case diStartRow:
+        TRACE(" - StartRow");
+        break;
+      case diRun:
+        TRACE(" - Run(\"%s\", %d)", debugstr_w(pItem->member.run.strText->szData), 
+          pItem->member.run.nCharOfs);
+        break;
+      case diTextEnd:
+        TRACE("\nEnd\n");
+        break;
+      default:
+        break;
+    }
+    pItem = pItem->next;
+  }
+  TRACE("DOCUMENT DUMP END\n");
+}
diff --git a/reactos/lib/riched20/makefile b/reactos/lib/riched20/makefile
new file mode 100644 (file)
index 0000000..faf2fc0
--- /dev/null
@@ -0,0 +1,9 @@
+# $Id: makefile 12852 2005-01-06 13:58:04Z mf $\r
+\r
+PATH_TO_TOP = ../..\r
+\r
+TARGET_TYPE = winedll\r
+\r
+include $(PATH_TO_TOP)/rules.mak\r
+\r
+include $(TOOLS_PATH)/helper.mk\r
diff --git a/reactos/lib/riched20/paint.c b/reactos/lib/riched20/paint.c
new file mode 100644 (file)
index 0000000..90b8d9d
--- /dev/null
@@ -0,0 +1,430 @@
+/*
+ * RichEdit - painting functions
+ *
+ * Copyright 2004 by Krzysztof Foltman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "editor.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(richedit);
+
+void ME_PaintContent(ME_TextEditor *editor, HDC hDC, BOOL bOnlyNew, RECT *rcUpdate) {
+  ME_DisplayItem *item;
+  ME_Context c;
+  int yoffset;
+
+  editor->nSequence++;
+  yoffset = GetScrollPos(editor->hWnd, SB_VERT);
+  ME_InitContext(&c, editor, hDC);
+  SetBkMode(hDC, TRANSPARENT);
+  ME_MoveCaret(editor);
+  item = editor->pBuffer->pFirst->next;
+  c.pt.y -= yoffset;
+  while(item != editor->pBuffer->pLast) {
+    assert(item->type == diParagraph);
+    if (!bOnlyNew || (item->member.para.nFlags & MEPF_REPAINT))
+    {
+      BOOL bPaint = (rcUpdate == NULL);
+      if (rcUpdate)
+        bPaint = c.pt.y<rcUpdate->bottom && 
+          c.pt.y+item->member.para.nHeight>rcUpdate->top;
+      if (bPaint)
+      {
+        ME_DrawParagraph(&c, item);
+        item->member.para.nFlags &= ~MEPF_REPAINT;
+      }
+    }
+    c.pt.y += item->member.para.nHeight;
+    item = item->member.para.next_para;
+  }
+  if (c.pt.y<c.rcView.bottom) {
+    RECT rc;
+    int xs = c.rcView.left, xe = c.rcView.right;
+    int ys = c.pt.y, ye = c.rcView.bottom;
+    
+    if (bOnlyNew)
+    {
+      int y1 = editor->nTotalLength-yoffset, y2 = editor->nLastTotalLength-yoffset;
+      if (y1<y2)
+        ys = y1, ye = y2+1;
+      else
+        ys = ye;
+    }
+    
+    if (rcUpdate && ys!=ye)
+    {
+      xs = rcUpdate->left, xe = rcUpdate->right;
+      if (rcUpdate->top > ys)
+        ys = rcUpdate->top;
+      if (rcUpdate->bottom < ye)
+        ye = rcUpdate->bottom;
+    }
+    
+    rc.left = xs; /* FIXME remove if it's not necessary anymore */
+    rc.top = c.pt.y;
+    rc.right = xe;
+    rc.bottom = c.pt.y+1;
+    FillRect(hDC, &rc, (HBRUSH)GetStockObject(BLACK_BRUSH));
+
+    if (ys == c.pt.y) /* don't overwrite the top bar */
+      ys++;
+    if (ye>ys) {
+      rc.left = xs;
+      rc.top = ys;
+      rc.right = xe;
+      rc.bottom = ye;
+      /* this is not supposed to be gray, I know, but lets keep it gray for now for debugging purposes */
+      FillRect(hDC, &rc, (HBRUSH)GetStockObject(LTGRAY_BRUSH));
+    }
+  }
+  editor->nLastTotalLength = editor->nTotalLength;
+  ME_DestroyContext(&c);
+}
+
+void ME_MarkParagraphRange(ME_TextEditor *editor, ME_DisplayItem *p1,
+                           ME_DisplayItem *p2, int nFlags)
+{
+  ME_DisplayItem *p3;  
+  if (p1 == p2)
+  {
+    p1->member.para.nFlags |= nFlags;
+    return;
+  }
+  if (p1->member.para.nCharOfs > p2->member.para.nCharOfs)
+    p3 = p1, p1 = p2, p2 = p3;
+    
+  p1->member.para.nFlags |= nFlags;
+  do {
+    p1 = p1->member.para.next_para;
+    p1->member.para.nFlags |= nFlags;
+  } while (p1 != p2);
+}
+
+void ME_MarkOffsetRange(ME_TextEditor *editor, int from, int to, int nFlags)
+{
+  ME_Cursor c1, c2;
+  ME_CursorFromCharOfs(editor, from, &c1);
+  ME_CursorFromCharOfs(editor, to, &c2);
+  
+  ME_MarkParagraphRange(editor, ME_GetParagraph(c1.pRun), ME_GetParagraph(c2.pRun), nFlags);
+}
+
+void ME_MarkSelectionForRepaint(ME_TextEditor *editor)
+{
+  int from, to, from2, to2, end;
+  
+  end = ME_GetTextLength(editor);
+  ME_GetSelection(editor, &from, &to);
+  from2 = editor->nLastSelStart;
+  to2 = editor->nLastSelEnd;
+  if (from<from2) ME_MarkOffsetRange(editor, from, from2, MEPF_REPAINT);
+  if (from>from2) ME_MarkOffsetRange(editor, from2, from, MEPF_REPAINT);
+  if (to<to2) ME_MarkOffsetRange(editor, to, to2, MEPF_REPAINT);
+  if (to>to2) ME_MarkOffsetRange(editor, to2, to, MEPF_REPAINT);
+
+  editor->nLastSelStart = from;
+  editor->nLastSelEnd = to;
+}
+
+void ME_Repaint(ME_TextEditor *editor)
+{
+  ME_Cursor *pCursor = &editor->pCursors[0];
+  ME_DisplayItem *pRun = NULL;
+  int nOffset = -1;
+  HDC hDC;
+  
+  int nCharOfs = ME_CharOfsFromRunOfs(editor, pCursor->pRun, pCursor->nOffset);
+  ME_RunOfsFromCharOfs(editor, nCharOfs, &pRun, &nOffset);
+  assert(pRun == pCursor->pRun);
+  assert(nOffset == pCursor->nOffset);
+  ME_MarkSelectionForRepaint(editor);
+  ME_WrapMarkedParagraphs(editor);
+  hDC = GetDC(editor->hWnd);
+  ME_HideCaret(editor);
+  ME_PaintContent(editor, hDC, TRUE, NULL);
+  ReleaseDC(editor->hWnd, hDC);
+  ME_ShowCaret(editor);
+}
+
+void ME_UpdateRepaint(ME_TextEditor *editor)
+{
+/*
+  InvalidateRect(editor->hWnd, NULL, TRUE);
+  */
+  ME_SendOldNotify(editor, EN_CHANGE);
+  ME_Repaint(editor);
+  ME_SendOldNotify(editor, EN_UPDATE);
+  ME_SendSelChange(editor);
+}
+
+void ME_DrawTextWithStyle(ME_Context *c, int x, int y, LPCWSTR szText, int nChars, 
+  ME_Style *s, int *width, int nSelFrom, int nSelTo, int ymin, int cy) {
+  HDC hDC = c->hDC;
+  HGDIOBJ hOldFont;
+  COLORREF rgbOld, rgbBack;
+  hOldFont = ME_SelectStyleFont(c->editor, hDC, s);
+  rgbBack = ME_GetBackColor(c->editor);
+  if ((s->fmt.dwMask & CFM_COLOR) && (s->fmt.dwEffects & CFE_AUTOCOLOR))
+    rgbOld = SetTextColor(hDC, GetSysColor(COLOR_WINDOWTEXT));
+  else
+    rgbOld = SetTextColor(hDC, s->fmt.crTextColor);
+  ExtTextOutW(hDC, x, y, 0, NULL, szText, nChars, NULL);
+  if (width) {
+    SIZE sz;
+    GetTextExtentPoint32W(hDC, szText, nChars, &sz);
+    *width = sz.cx;
+  }
+  if (nSelFrom < nChars && nSelTo >= 0 && nSelFrom<nSelTo)
+  {
+    SIZE sz;
+    if (nSelFrom < 0) nSelFrom = 0;
+    if (nSelTo > nChars) nSelTo = nChars;
+    GetTextExtentPoint32W(hDC, szText, nSelFrom, &sz);
+    x += sz.cx;
+    GetTextExtentPoint32W(hDC, szText+nSelFrom, nSelTo-nSelFrom, &sz);
+    PatBlt(hDC, x, ymin, sz.cx, cy, DSTINVERT);
+  }
+  SetTextColor(hDC, rgbOld);
+  ME_UnselectStyleFont(c->editor, hDC, s, hOldFont);
+}
+
+void ME_DebugWrite(HDC hDC, POINT *pt, WCHAR *szText) {
+  int align = SetTextAlign(hDC, TA_LEFT|TA_TOP);
+  HGDIOBJ hFont = SelectObject(hDC, GetStockObject(DEFAULT_GUI_FONT));
+  COLORREF color = SetTextColor(hDC, RGB(128,128,128));
+  TextOutW(hDC, pt->x, pt->y, szText, lstrlenW(szText));
+  SelectObject(hDC, hFont);
+  SetTextAlign(hDC, align);
+  SetTextColor(hDC, color);
+}
+
+void ME_DrawGraphics(ME_Context *c, int x, int y, ME_Run *run, 
+                     ME_Paragraph *para, BOOL selected) {
+  SIZE sz;
+  int xs, ys, xe, ye, h, ym, width, eyes;
+  ME_GetGraphicsSize(c->editor, run, &sz);
+  xs = run->pt.x;
+  ys = y-sz.cy;
+  xe = xs+sz.cx;
+  ye = y;
+  h = ye-ys;
+  ym = ys+h/4;
+  width = sz.cx;
+  eyes = width/8;
+  /* draw a smiling face :) */
+  Ellipse(c->hDC, xs, ys, xe, ye);
+  Ellipse(c->hDC, xs+width/8, ym, x+width/8+eyes, ym+eyes);
+  Ellipse(c->hDC, xs+7*width/8-eyes, ym, xs+7*width/8, ym+eyes);
+  MoveToEx(c->hDC, xs+width/8, ys+3*h/4-eyes, NULL);
+  LineTo(c->hDC, xs+width/8, ys+3*h/4);
+  LineTo(c->hDC, xs+7*width/8, ys+3*h/4);
+  LineTo(c->hDC, xs+7*width/8, ys+3*h/4-eyes);
+  if (selected)
+  {
+    /* descent is usually (always?) 0 for graphics */
+    PatBlt(c->hDC, x, y-run->nAscent, sz.cx, run->nAscent+run->nDescent, DSTINVERT);    
+  }
+}
+
+void ME_DrawRun(ME_Context *c, int x, int y, ME_DisplayItem *rundi, ME_Paragraph *para) {
+  ME_Run *run = &rundi->member.run;
+  int runofs = run->nCharOfs+para->nCharOfs;
+  
+  if (run->nFlags & MERF_GRAPHICS) {
+    int blfrom, blto;
+    ME_GetSelection(c->editor, &blfrom, &blto);
+    ME_DrawGraphics(c, x, y, run, para, (runofs >= blfrom) && (runofs < blto));
+  } else
+  {
+    int blfrom, blto;
+    ME_DisplayItem *start = ME_FindItemBack(rundi, diStartRow);
+    ME_GetSelection(c->editor, &blfrom, &blto);
+    
+    ME_DrawTextWithStyle(c, x, y, 
+      run->strText->szData, ME_StrVLen(run->strText), run->style, NULL, 
+        blfrom-runofs, blto-runofs, c->pt.y+start->member.row.nYPos, start->member.row.nHeight);
+  }
+}
+
+COLORREF ME_GetBackColor(ME_TextEditor *editor)
+{
+/* Looks like I was seriously confused
+    return GetSysColor((GetWindowLong(editor->hWnd, GWL_STYLE) & ES_READONLY) ? COLOR_3DFACE: COLOR_WINDOW);
+*/
+  if (editor->rgbBackColor == -1)
+    return GetSysColor(COLOR_WINDOW);
+  else
+    return editor->rgbBackColor;
+}
+
+void ME_DrawParagraph(ME_Context *c, ME_DisplayItem *paragraph) {
+  int align = SetTextAlign(c->hDC, TA_BASELINE);
+  ME_DisplayItem *p;
+  ME_Run *run;
+  ME_Paragraph *para = NULL;
+  RECT rc, rcPara;
+  int y = c->pt.y;
+  int height = 0, baseline = 0, no=0, pno = 0;
+  int xs, xe;
+  int visible = 0;
+  int nMargWidth = 0;
+  
+  c->pt.x = c->rcView.left;
+  rcPara.left = c->rcView.left;
+  rcPara.right = c->rcView.right;
+  for (p = paragraph; p!=paragraph->member.para.next_para; p = p->next) {
+    switch(p->type) {
+      case diParagraph:
+        para = &p->member.para;
+        break;
+      case diStartRow:
+        assert(para);
+        nMargWidth = (pno==0?para->nFirstMargin:para->nLeftMargin);
+        xs = c->rcView.left+nMargWidth;
+        xe = c->rcView.right-para->nRightMargin;
+        y += height;
+        rcPara.top = y;
+        rcPara.bottom = y+p->member.row.nHeight;
+        visible = RectVisible(c->hDC, &rcPara);
+        if (visible) {
+          HBRUSH hbr;
+          /* left margin */
+          rc.left = c->rcView.left;
+          rc.right = c->rcView.left+nMargWidth;
+          rc.top = y;
+          rc.bottom = y+p->member.row.nHeight;
+          FillRect(c->hDC, &rc, c->hbrMargin);
+          /* right margin */
+          rc.left = xe;
+          rc.right = c->rcView.right;
+          FillRect(c->hDC, &rc, c->hbrMargin);
+          rc.left = c->rcView.left+para->nLeftMargin;
+          rc.right = xe;
+          hbr = CreateSolidBrush(ME_GetBackColor(c->editor));
+          FillRect(c->hDC, &rc, hbr);
+          DeleteObject(hbr);
+        }
+        if (me_debug)
+        {
+          const WCHAR wszRowDebug[] = {'r','o','w','[','%','d',']',0};
+          WCHAR buf[128];
+          POINT pt = c->pt;
+          wsprintfW(buf, wszRowDebug, no);
+          pt.y = 12+y;
+          ME_DebugWrite(c->hDC, &pt, buf);
+        }
+        
+        height = p->member.row.nHeight;
+        baseline = p->member.row.nBaseline;
+        pno++;
+        break;
+      case diRun:
+        assert(para);
+        run = &p->member.run;
+        if (visible && me_debug) {
+          rc.left = c->rcView.left+run->pt.x;
+          rc.right = c->rcView.left+run->pt.x+run->nWidth;
+          rc.top = c->pt.y+run->pt.y;
+          rc.bottom = c->pt.y+run->pt.y+height;
+          TRACE("rc = (%ld, %ld, %ld, %ld)\n", rc.left, rc.top, rc.right, rc.bottom);
+          if (run->nFlags & MERF_SKIPPED)
+            DrawFocusRect(c->hDC, &rc);
+          else
+            FrameRect(c->hDC, &rc, GetSysColorBrush(COLOR_GRAYTEXT));
+        }
+        if (visible)
+          ME_DrawRun(c, run->pt.x, c->pt.y+run->pt.y+baseline, p, &paragraph->member.para);
+        if (me_debug)
+        {
+          /* I'm using %ls, hope wsprintfW is not going to use wrong (4-byte) WCHAR version */
+          const WCHAR wszRunDebug[] = {'[','%','d',':','%','x',']',' ','%','l','s',0};
+          WCHAR buf[2560];
+          POINT pt;
+          pt.x = run->pt.x;
+          pt.y = c->pt.y + run->pt.y;
+          wsprintfW(buf, wszRunDebug, no, p->member.run.nFlags, p->member.run.strText->szData);
+          ME_DebugWrite(c->hDC, &pt, buf);
+        }
+        /* c->pt.x += p->member.run.nWidth; */
+        break;
+      default:
+        break;
+    }
+    no++;
+  }
+  SetTextAlign(c->hDC, align);
+}
+
+void ME_UpdateScrollBar(ME_TextEditor *editor, int ypos)
+{
+  float perc = 0.0;
+  SCROLLINFO si;
+  HWND hWnd = editor->hWnd;
+  int overflow = editor->nTotalLength - editor->sizeWindow.cy;
+  si.cbSize = sizeof(SCROLLINFO);
+  si.fMask = SIF_PAGE|SIF_POS|SIF_RANGE|SIF_TRACKPOS;
+  GetScrollInfo(hWnd, SB_VERT, &si);
+  
+  if (ypos < 0) {
+    if (si.nMax<1) si.nMax = 1;
+    perc = 1.0*si.nPos/si.nMax;
+    ypos = perc*overflow;
+  }
+  if (ypos >= overflow && overflow > 0)
+    ypos = overflow - 1;
+
+  if (overflow > 0) {
+    EnableScrollBar(hWnd, SB_VERT, ESB_ENABLE_BOTH);
+    SetScrollRange(hWnd, SB_VERT, 0, overflow, FALSE);
+    SetScrollPos(hWnd, SB_VERT, ypos, TRUE);
+  } else {
+    EnableScrollBar(hWnd, SB_VERT, ESB_DISABLE_BOTH);
+    SetScrollRange(hWnd, SB_VERT, 0, 0, FALSE);
+    SetScrollPos(hWnd, SB_VERT, 0, TRUE);
+  }
+  if (ypos != si.nPos)
+  {
+    TRACE("ScrollWindow(%d, %d, %d, %0.4f)\n", si.nPos, si.nMax, ypos, perc);
+    ScrollWindow(hWnd, 0, si.nPos - ypos, NULL, NULL);
+    UpdateWindow(hWnd);
+  }
+}
+
+int ME_GetScrollPos(ME_TextEditor *editor)
+{
+  return GetScrollPos(editor->hWnd, SB_VERT);
+}
+
+void ME_EnsureVisible(ME_TextEditor *editor, ME_DisplayItem *pRun)
+{
+  ME_DisplayItem *pRow = ME_FindItemBack(pRun, diStartRow);
+  ME_DisplayItem *pPara = ME_FindItemBack(pRun, diParagraph);
+  int y, yrel, yheight;
+  
+  assert(pRow);
+  assert(pPara);
+  
+  y = pPara->member.para.nYPos+pRow->member.row.nYPos;
+  yheight = pRow->member.row.nHeight;
+  yrel = y - ME_GetScrollPos(editor);
+  if (yrel < 0)
+    ME_UpdateScrollBar(editor, y);
+  else if (yrel + yheight > editor->sizeWindow.cy)
+  {
+    ME_UpdateScrollBar(editor, y + yheight - editor->sizeWindow.cy);  
+  }
+}
diff --git a/reactos/lib/riched20/para.c b/reactos/lib/riched20/para.c
new file mode 100644 (file)
index 0000000..ecd8e49
--- /dev/null
@@ -0,0 +1,358 @@
+/*
+ * RichEdit - functions working on paragraphs of text (diParagraph).
+ * 
+ * Copyright 2004 by Krzysztof Foltman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */ 
+
+#include "editor.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(richedit);
+
+static WCHAR wszParagraphSign[] = {0xB6, 0};
+
+void ME_MakeFirstParagraph(HDC hDC, ME_TextBuffer *text)
+{
+  PARAFORMAT2 fmt;
+  CHARFORMAT2W cf;
+  LOGFONTW lf;
+  HFONT hf;
+  ME_DisplayItem *para = ME_MakeDI(diParagraph);
+  ME_DisplayItem *run;
+  ME_Style *style;
+
+  hf = (HFONT)GetStockObject(SYSTEM_FONT);
+  assert(hf);
+  GetObjectW(hf, sizeof(LOGFONTW), &lf);
+  ZeroMemory(&cf, sizeof(cf));
+  cf.cbSize = sizeof(cf);
+  cf.dwMask = CFM_BACKCOLOR|CFM_COLOR|CFM_FACE|CFM_SIZE|CFM_CHARSET;
+  cf.dwMask |= CFM_ALLCAPS|CFM_BOLD|CFM_DISABLED|CFM_EMBOSS|CFM_HIDDEN;
+  cf.dwMask |= CFM_IMPRINT|CFM_ITALIC|CFM_LINK|CFM_OUTLINE|CFM_PROTECTED;
+  cf.dwMask |= CFM_REVISED|CFM_SHADOW|CFM_SMALLCAPS|CFM_STRIKEOUT;
+  cf.dwMask |= CFM_SUBSCRIPT|CFM_UNDERLINE;
+  
+  cf.dwEffects = CFE_AUTOCOLOR | CFE_AUTOBACKCOLOR;
+  lstrcpyW(cf.szFaceName, lf.lfFaceName);
+  cf.yHeight=lf.lfHeight*1440/GetDeviceCaps(hDC, LOGPIXELSY);
+  if (lf.lfWeight>=700) /* FIXME correct weight ? */
+    cf.dwEffects |= CFE_BOLD;
+  cf.wWeight = lf.lfWeight;
+  if (lf.lfItalic) cf.dwEffects |= CFE_ITALIC;
+  if (lf.lfUnderline) cf.dwEffects |= CFE_UNDERLINE;
+  if (lf.lfStrikeOut) cf.dwEffects |= CFE_STRIKEOUT;
+  
+  ZeroMemory(&fmt, sizeof(fmt));
+  fmt.cbSize = sizeof(fmt);
+  fmt.dwMask = PFM_ALIGNMENT | PFM_OFFSET | PFM_STARTINDENT | PFM_RIGHTINDENT;
+
+  CopyMemory(para->member.para.pFmt, &fmt, sizeof(PARAFORMAT2));
+  
+  style = ME_MakeStyle(&cf);
+  text->pDefaultStyle = style;
+  
+  run = ME_MakeRun(style, ME_MakeString(wszParagraphSign), MERF_ENDPARA);
+  run->member.run.nCharOfs = 0;
+
+  ME_InsertBefore(text->pLast, para);
+  ME_InsertBefore(text->pLast, run);
+  para->member.para.prev_para = text->pFirst;
+  para->member.para.next_para = text->pLast;
+  text->pFirst->member.para.next_para = para;
+  text->pLast->member.para.prev_para = para;
+
+  text->pLast->member.para.nCharOfs = 1;
+}
+void ME_MarkAllForWrapping(ME_TextEditor *editor)
+{
+  ME_MarkForWrapping(editor, editor->pBuffer->pFirst->member.para.next_para, editor->pBuffer->pLast);
+}
+
+void ME_MarkForWrapping(ME_TextEditor *editor, ME_DisplayItem *first, ME_DisplayItem *last)
+{
+  while(first != last)
+  {
+    first->member.para.nFlags |= MEPF_REWRAP;
+    first = first->member.para.next_para;
+  }
+}
+
+/* split paragraph at the beginning of the run */
+ME_DisplayItem *ME_SplitParagraph(ME_TextEditor *editor, ME_DisplayItem *run, ME_Style *style)
+{
+  ME_DisplayItem *next_para = NULL;
+  ME_DisplayItem *run_para = NULL;
+  ME_DisplayItem *new_para = ME_MakeDI(diParagraph);
+  ME_DisplayItem *end_run = ME_MakeRun(style,ME_MakeString(wszParagraphSign), MERF_ENDPARA);
+  ME_UndoItem *undo = NULL;
+  int ofs;
+  ME_DisplayItem *pp;
+  
+  assert(run->type == diRun);  
+
+  run_para = ME_GetParagraph(run);
+  assert(run_para->member.para.pFmt->cbSize == sizeof(PARAFORMAT2));
+
+  ofs = end_run->member.run.nCharOfs = run->member.run.nCharOfs;
+  next_para = run_para->member.para.next_para;
+  assert(next_para == ME_FindItemFwd(run_para, diParagraphOrEnd));
+  
+  undo = ME_AddUndoItem(editor, diUndoJoinParagraphs, NULL);
+  if (undo)
+    undo->nStart = run_para->member.para.nCharOfs + ofs;
+  
+  /* the new paragraph will have a different starting offset, so let's update its runs */
+  pp = run;
+  while(pp->type == diRun) {
+    pp->member.run.nCharOfs -= ofs;
+    pp = ME_FindItemFwd(pp, diRunOrParagraphOrEnd);
+  }
+  new_para->member.para.nCharOfs = ME_GetParagraph(run)->member.para.nCharOfs+ofs;
+  new_para->member.para.nCharOfs += 1;
+  
+  new_para->member.para.nFlags = MEPF_REWRAP; /* FIXME copy flags (if applicable) */
+  /* FIXME initialize format style and call ME_SetParaFormat blah blah */
+  CopyMemory(new_para->member.para.pFmt, run_para->member.para.pFmt, sizeof(PARAFORMAT2));
+  
+  /* FIXME remove this as soon as nLeftMargin etc are replaced with proper fields of PARAFORMAT2 */
+  new_para->member.para.nLeftMargin = run_para->member.para.nLeftMargin;
+  new_para->member.para.nRightMargin = run_para->member.para.nRightMargin;
+  new_para->member.para.nFirstMargin = run_para->member.para.nFirstMargin;
+  
+  /* insert paragraph into paragraph double linked list */
+  new_para->member.para.prev_para = run_para;
+  new_para->member.para.next_para = next_para;
+  run_para->member.para.next_para = new_para;
+  next_para->member.para.prev_para = new_para;
+
+  /* insert end run of the old paragraph, and new paragraph, into DI double linked list */
+  ME_InsertBefore(run, new_para);
+  ME_InsertBefore(new_para, end_run);
+
+  /* force rewrap of the */
+  run_para->member.para.prev_para->member.para.nFlags |= MEPF_REWRAP;
+  new_para->member.para.prev_para->member.para.nFlags |= MEPF_REWRAP;
+  
+  /* we've added the end run, so we need to modify nCharOfs in the next paragraphs */
+  ME_PropagateCharOffset(next_para, 1);
+  editor->nParagraphs++;
+  
+  return new_para;
+}
+
+/* join tp with tp->member.para.next_para, keeping tp's style; this
+ * is consistent with the original */
+ME_DisplayItem *ME_JoinParagraphs(ME_TextEditor *editor, ME_DisplayItem *tp)
+{
+  ME_DisplayItem *pNext, *pFirstRunInNext, *pRun, *pTmp;
+  int i, shift;
+  ME_UndoItem *undo = NULL;
+
+  assert(tp->type == diParagraph);
+  assert(tp->member.para.next_para);
+  assert(tp->member.para.next_para->type == diParagraph);
+  
+  pNext = tp->member.para.next_para;
+  
+  {
+    /* null char format operation to store the original char format for the ENDPARA run */
+    CHARFORMAT2W fmt;
+    ME_InitCharFormat2W(&fmt);
+    ME_SetCharFormat(editor, pNext->member.para.nCharOfs-1, 1, &fmt);
+  }
+  undo = ME_AddUndoItem(editor, diUndoSplitParagraph, NULL);
+  if (undo)
+  {
+    undo->nStart = pNext->member.para.nCharOfs-1;
+    assert(pNext->member.para.pFmt->cbSize == sizeof(PARAFORMAT2));
+    CopyMemory(undo->di.member.para.pFmt, pNext->member.para.pFmt, sizeof(PARAFORMAT2));
+  }
+  
+  shift = pNext->member.para.nCharOfs - tp->member.para.nCharOfs - 1;
+  
+  pRun = ME_FindItemBack(pNext, diRunOrParagraph);
+  pFirstRunInNext = ME_FindItemFwd(pNext, diRunOrParagraph);
+  
+  assert(pRun);
+  assert(pRun->type == diRun);
+  assert(pRun->member.run.nFlags & MERF_ENDPARA);
+  assert(pFirstRunInNext->type == diRun);
+  
+  /* if some cursor points at end of paragraph, make it point to the first
+     run of the next joined paragraph */
+  for (i=0; i<editor->nCursors; i++) {
+    if (editor->pCursors[i].pRun == pRun) {
+      editor->pCursors[i].pRun = pFirstRunInNext;
+      editor->pCursors[i].nOffset = 0;
+    }
+  }
+
+  pTmp = pNext;
+  do {
+    pTmp = ME_FindItemFwd(pTmp, diRunOrParagraphOrEnd);
+    if (pTmp->type != diRun)
+      break;
+    TRACE("shifting \"%s\" by %d (previous %d)\n", debugstr_w(pTmp->member.run.strText->szData), shift, pTmp->member.run.nCharOfs);
+    pTmp->member.run.nCharOfs += shift;
+  } while(1);
+  
+  ME_Remove(pRun);
+  ME_DestroyDisplayItem(pRun);
+
+  tp->member.para.next_para = pNext->member.para.next_para;
+  pNext->member.para.next_para->member.para.prev_para = tp;
+  ME_Remove(pNext);
+  ME_DestroyDisplayItem(pNext);
+
+  ME_PropagateCharOffset(tp->member.para.next_para, -1);
+  
+  ME_CheckCharOffsets(editor);
+  
+  editor->nParagraphs--;
+  tp->member.para.nFlags |= MEPF_REWRAP;
+  return tp;
+}
+
+ME_DisplayItem *ME_GetParagraph(ME_DisplayItem *item) {
+  return ME_FindItemBackOrHere(item, diParagraph);
+}
+
+static void ME_DumpStyleEffect(char **p, const char *name, PARAFORMAT2 *fmt, int mask)
+{
+  *p += sprintf(*p, "%-22s%s\n", name, (fmt->dwMask & mask) ? ((fmt->wEffects & mask) ? "yes" : "no") : "N/A");
+}
+
+void ME_DumpParaStyleToBuf(PARAFORMAT2 *pFmt, char buf[2048])
+{
+  /* FIXME only PARAFORMAT styles implemented */
+  char *p;
+  p = buf;
+  p += sprintf(p, "Alignment:            %s\n",
+    !(pFmt->dwMask & PFM_ALIGNMENT) ? "N/A" :
+      ((pFmt->wAlignment == PFA_LEFT) ? "left" :
+        ((pFmt->wAlignment == PFA_RIGHT) ? "right" :
+          ((pFmt->wAlignment == PFA_CENTER) ? "center" :
+            /*((pFmt->wAlignment == PFA_JUSTIFY) ? "justify" : "incorrect")*/
+            "incorrect"))));
+
+  if (pFmt->dwMask & PFM_OFFSET)
+    p += sprintf(p, "Offset:               %d\n", (int)pFmt->dxOffset);
+  else
+    p += sprintf(p, "Offset:               N/A\n");
+    
+  if (pFmt->dwMask & PFM_OFFSETINDENT)
+    p += sprintf(p, "Offset indent:        %d\n", (int)pFmt->dxStartIndent);
+  else
+    p += sprintf(p, "Offset indent:        N/A\n");
+    
+  if (pFmt->dwMask & PFM_STARTINDENT)
+    p += sprintf(p, "Start indent:         %d\n", (int)pFmt->dxStartIndent);
+  else
+    p += sprintf(p, "Start indent:         N/A\n");
+    
+  if (pFmt->dwMask & PFM_RIGHTINDENT)
+    p += sprintf(p, "Right indent:         %d\n", (int)pFmt->dxRightIndent);
+  else
+    p += sprintf(p, "Right indent:         N/A\n");
+    
+  ME_DumpStyleEffect(&p, "Page break before:", pFmt, PFM_PAGEBREAKBEFORE);
+}
+
+void ME_SetParaFormat(ME_TextEditor *editor, ME_DisplayItem *para, PARAFORMAT2 *pFmt)
+{
+  PARAFORMAT2 copy;
+  assert(sizeof(*para->member.para.pFmt) == sizeof(PARAFORMAT2));
+  ME_AddUndoItem(editor, diUndoSetParagraphFormat, para);
+  
+  CopyMemory(&copy, para->member.para.pFmt, sizeof(PARAFORMAT2));
+
+  if (pFmt->dwMask & PFM_ALIGNMENT)
+    para->member.para.pFmt->wAlignment = pFmt->wAlignment;
+    
+  /* FIXME to be continued (indents, bulleting and such) */
+
+  if (memcmp(&copy, para->member.para.pFmt, sizeof(PARAFORMAT2)))
+    para->member.para.nFlags |= MEPF_REWRAP;
+}
+
+void ME_SetSelectionParaFormat(ME_TextEditor *editor, PARAFORMAT2 *pFmt)
+{
+  int nFrom, nTo;
+  ME_DisplayItem *para, *para_end, *run;
+  int nOffset;
+  
+  ME_GetSelection(editor, &nFrom, &nTo);
+  if (nTo>nFrom) /* selection consists of chars from nFrom up to nTo-1 */
+    nTo--;
+  
+  ME_RunOfsFromCharOfs(editor, nFrom, &run, &nOffset);
+  para = ME_GetParagraph(run);
+  ME_RunOfsFromCharOfs(editor, nTo, &run, &nOffset);
+  para_end = ME_GetParagraph(run);
+  
+  do {
+    ME_SetParaFormat(editor, para, pFmt);
+    if (para == para_end)
+      break;
+    para = para->member.para.next_para;
+  } while(1);
+  ME_Repaint(editor);
+}
+
+void ME_GetParaFormat(ME_TextEditor *editor, ME_DisplayItem *para, PARAFORMAT2 *pFmt)
+{
+  if (pFmt->cbSize >= sizeof(PARAFORMAT2))
+  {
+    CopyMemory(pFmt, para->member.para.pFmt, sizeof(PARAFORMAT2));
+    return;
+  }
+  CopyMemory(pFmt, para->member.para.pFmt, pFmt->cbSize);  
+}
+
+void ME_GetSelectionParaFormat(ME_TextEditor *editor, PARAFORMAT2 *pFmt)
+{
+  int nFrom, nTo;
+  ME_DisplayItem *para, *para_end, *run;
+  int nOffset;
+  PARAFORMAT2 tmp;
+  
+  ME_GetSelection(editor, &nFrom, &nTo);
+  if (nTo>nFrom) /* selection consists of chars from nFrom up to nTo-1 */
+    nTo--;
+  
+  ME_RunOfsFromCharOfs(editor, nFrom, &run, &nOffset);
+  para = ME_GetParagraph(run);
+  ME_RunOfsFromCharOfs(editor, nTo, &run, &nOffset);
+  para_end = ME_GetParagraph(run);
+  
+  ME_GetParaFormat(editor, para, pFmt);
+  if (para == para_end) return;
+  
+  do {
+    ZeroMemory(&tmp, sizeof(tmp));
+    tmp.cbSize = sizeof(tmp);
+    ME_GetParaFormat(editor, para, &tmp);
+    assert(tmp.dwMask & PFM_ALIGNMENT);
+    
+    if (pFmt->wAlignment != tmp.wAlignment)
+      pFmt->dwMask &= ~PFM_ALIGNMENT;
+    
+    if (para == para_end)
+      return;
+    para = para->member.para.next_para;
+  } while(1);
+}
diff --git a/reactos/lib/riched20/reader.c b/reactos/lib/riched20/reader.c
new file mode 100644 (file)
index 0000000..3f800b6
--- /dev/null
@@ -0,0 +1,3786 @@
+/*
+ * WINE RTF file reader
+ *
+ * Portions Copyright 2004 Mike McCormack for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ * Derived from RTF Tools by Paul DuBois (dubois@primate.wisc.edu)
+ * Homepage: http://www.snake.net/software/RTF/
+ * Original license follows:
+ */
+
+/*
+ * reader.c - RTF file reader.  Release 1.10.
+ *
+ * ....
+ *
+ * Author: Paul DuBois dubois@primate.wisc.edu
+ *
+ * This software may be redistributed without restriction and used for
+ * any purpose whatsoever.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+#include "rtf.h"
+
+#include "windef.h"
+#include "winbase.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(richedit);
+
+extern HANDLE me_heap;
+
+static int      _RTFGetChar(RTF_Info *);
+static void    _RTFGetToken (RTF_Info *);
+static void    _RTFGetToken2 (RTF_Info *);
+static int     GetChar (RTF_Info *);
+static void    ReadFontTbl (RTF_Info *);
+static void    ReadColorTbl (RTF_Info *);
+static void    ReadStyleSheet (RTF_Info *);
+static void    ReadInfoGroup (RTF_Info *);
+static void    ReadPictGroup (RTF_Info *);
+static void    ReadObjGroup (RTF_Info *);
+static void    LookupInit (void);
+static void    Lookup (RTF_Info *, char *);
+static int     Hash (char*);
+
+static void    CharSetInit (RTF_Info *);
+static void    ReadCharSetMaps (RTF_Info *);
+
+
+/*
+ RTF ANSI character set (\ansi) general map
+ These are taken from the ISO-Latin-1 (ISO-8859-1) encodings, with
+ a few additions
+
+ Field 1 is the standard character name which the character value in
+ field 2 maps onto.  (It doesn't mean "to produce the character in field 1,
+ use the value in field 2.)
+
+ The character value may be given either as a single character (which will be
+ converted to the ASCII value of the character), or in numeric format, either
+ in decimal or 0xyy as hex yy.  Single or double quotes may be used to quote
+ characters.*/
+
+int ansi_gen[] =
+{
+  rtfSC_formula         ,0x06,
+  rtfSC_nobrkhyphen     ,0x1e,
+  rtfSC_opthyphen       ,0x1f,
+  rtfSC_space           ,' ',
+  rtfSC_exclam          ,'!',
+  rtfSC_quotedbl        ,'"',
+  rtfSC_numbersign      ,'#',
+  rtfSC_dollar          ,'$',
+  rtfSC_percent         ,'%',
+  rtfSC_ampersand       ,'&',
+  rtfSC_quoteright      ,'\'',
+  rtfSC_parenleft       ,'(',
+  rtfSC_parenright      ,')',
+  rtfSC_asterisk        ,'*',
+  rtfSC_plus            ,'+',
+  rtfSC_comma           ,',',
+  rtfSC_hyphen          ,'-',
+  rtfSC_period          ,'.',
+  rtfSC_slash           ,'/',
+  rtfSC_zero            ,'0',
+  rtfSC_one             ,'1',
+  rtfSC_two             ,'2',
+  rtfSC_three           ,'3',
+  rtfSC_four            ,'4',
+  rtfSC_five            ,'5',
+  rtfSC_six             ,'6',
+  rtfSC_seven           ,'7',
+  rtfSC_eight           ,'8',
+  rtfSC_nine            ,'9',
+  rtfSC_colon           ,':',
+  rtfSC_semicolon       ,';',
+  rtfSC_less            ,'<',
+  rtfSC_equal           ,'=',
+  rtfSC_greater         ,'>',
+  rtfSC_question        ,'?',
+  rtfSC_at              ,'@',
+  rtfSC_A               ,'A',
+  rtfSC_B               ,'B',
+  rtfSC_C               ,'C',
+  rtfSC_D               ,'D',
+  rtfSC_E               ,'E',
+  rtfSC_F               ,'F',
+  rtfSC_G               ,'G',
+  rtfSC_H               ,'H',
+  rtfSC_I               ,'I',
+  rtfSC_J               ,'J',
+  rtfSC_K               ,'K',
+  rtfSC_L               ,'L',
+  rtfSC_M               ,'M',
+  rtfSC_N               ,'N',
+  rtfSC_O               ,'O',
+  rtfSC_P               ,'P',
+  rtfSC_Q               ,'Q',
+  rtfSC_R               ,'R',
+  rtfSC_S               ,'S',
+  rtfSC_T               ,'T',
+  rtfSC_U               ,'U',
+  rtfSC_V               ,'V',
+  rtfSC_W               ,'W',
+  rtfSC_X               ,'X',
+  rtfSC_Y               ,'Y',
+  rtfSC_Z               ,'Z',
+  rtfSC_bracketleft     ,'[',
+  rtfSC_backslash       ,'\\',
+  rtfSC_bracketright    ,']',
+  rtfSC_asciicircum     ,'^',
+  rtfSC_underscore      ,'_',
+  rtfSC_quoteleft       ,'`',
+  rtfSC_a               ,'a',
+  rtfSC_b               ,'b',
+  rtfSC_c               ,'c',
+  rtfSC_d               ,'d',
+  rtfSC_e               ,'e',
+  rtfSC_f               ,'f',
+  rtfSC_g               ,'g',
+  rtfSC_h               ,'h',
+  rtfSC_i               ,'i',
+  rtfSC_j               ,'j',
+  rtfSC_k               ,'k',
+  rtfSC_l               ,'l',
+  rtfSC_m               ,'m',
+  rtfSC_n               ,'n',
+  rtfSC_o               ,'o',
+  rtfSC_p               ,'p',
+  rtfSC_q               ,'q',
+  rtfSC_r               ,'r',
+  rtfSC_s               ,'s',
+  rtfSC_t               ,'t',
+  rtfSC_u               ,'u',
+  rtfSC_v               ,'v',
+  rtfSC_w               ,'w',
+  rtfSC_x               ,'x',
+  rtfSC_y               ,'y',
+  rtfSC_z               ,'z',
+  rtfSC_braceleft       ,'{',
+  rtfSC_bar             ,'|',
+  rtfSC_braceright      ,'}',
+  rtfSC_asciitilde      ,'~',
+  rtfSC_nobrkspace      ,0xa0,
+  rtfSC_exclamdown      ,0xa1,
+  rtfSC_cent            ,0xa2,
+  rtfSC_sterling        ,0xa3,
+  rtfSC_currency        ,0xa4,
+  rtfSC_yen             ,0xa5,
+  rtfSC_brokenbar       ,0xa6,
+  rtfSC_section         ,0xa7,
+  rtfSC_dieresis        ,0xa8,
+  rtfSC_copyright       ,0xa9,
+  rtfSC_ordfeminine     ,0xaa,
+  rtfSC_guillemotleft   ,0xab,
+  rtfSC_logicalnot      ,0xac,
+  rtfSC_opthyphen       ,0xad,
+  rtfSC_registered      ,0xae,
+  rtfSC_macron          ,0xaf,
+  rtfSC_degree          ,0xb0,
+  rtfSC_plusminus       ,0xb1,
+  rtfSC_twosuperior     ,0xb2,
+  rtfSC_threesuperior   ,0xb3,
+  rtfSC_acute           ,0xb4,
+  rtfSC_mu              ,0xb5,
+  rtfSC_paragraph       ,0xb6,
+  rtfSC_periodcentered   ,0xb7,
+  rtfSC_cedilla         ,0xb8,
+  rtfSC_onesuperior     ,0xb9,
+  rtfSC_ordmasculine    ,0xba,
+  rtfSC_guillemotright   ,0xbb,
+  rtfSC_onequarter      ,0xbc,
+  rtfSC_onehalf         ,0xbd,
+  rtfSC_threequarters   ,0xbe,
+  rtfSC_questiondown    ,0xbf,
+  rtfSC_Agrave          ,0xc0,
+  rtfSC_Aacute          ,0xc1,
+  rtfSC_Acircumflex     ,0xc2,
+  rtfSC_Atilde          ,0xc3,
+  rtfSC_Adieresis       ,0xc4,
+  rtfSC_Aring           ,0xc5,
+  rtfSC_AE              ,0xc6,
+  rtfSC_Ccedilla        ,0xc7,
+  rtfSC_Egrave          ,0xc8,
+  rtfSC_Eacute          ,0xc9,
+  rtfSC_Ecircumflex     ,0xca,
+  rtfSC_Edieresis       ,0xcb,
+  rtfSC_Igrave          ,0xcc,
+  rtfSC_Iacute          ,0xcd,
+  rtfSC_Icircumflex     ,0xce,
+  rtfSC_Idieresis       ,0xcf,
+  rtfSC_Eth             ,0xd0,
+  rtfSC_Ntilde          ,0xd1,
+  rtfSC_Ograve          ,0xd2,
+  rtfSC_Oacute          ,0xd3,
+  rtfSC_Ocircumflex     ,0xd4,
+  rtfSC_Otilde          ,0xd5,
+  rtfSC_Odieresis       ,0xd6,
+  rtfSC_multiply        ,0xd7,
+  rtfSC_Oslash          ,0xd8,
+  rtfSC_Ugrave          ,0xd9,
+  rtfSC_Uacute          ,0xda,
+  rtfSC_Ucircumflex     ,0xdb,
+  rtfSC_Udieresis       ,0xdc,
+  rtfSC_Yacute          ,0xdd,
+  rtfSC_Thorn           ,0xde,
+  rtfSC_germandbls      ,0xdf,
+  rtfSC_agrave          ,0xe0,
+  rtfSC_aacute          ,0xe1,
+  rtfSC_acircumflex     ,0xe2,
+  rtfSC_atilde          ,0xe3,
+  rtfSC_adieresis       ,0xe4,
+  rtfSC_aring           ,0xe5,
+  rtfSC_ae              ,0xe6,
+  rtfSC_ccedilla        ,0xe7,
+  rtfSC_egrave          ,0xe8,
+  rtfSC_eacute          ,0xe9,
+  rtfSC_ecircumflex     ,0xea,
+  rtfSC_edieresis       ,0xeb,
+  rtfSC_igrave          ,0xec,
+  rtfSC_iacute          ,0xed,
+  rtfSC_icircumflex     ,0xee,
+  rtfSC_idieresis       ,0xef,
+  rtfSC_eth             ,0xf0,
+  rtfSC_ntilde          ,0xf1,
+  rtfSC_ograve          ,0xf2,
+  rtfSC_oacute          ,0xf3,
+  rtfSC_ocircumflex     ,0xf4,
+  rtfSC_otilde          ,0xf5,
+  rtfSC_odieresis       ,0xf6,
+  rtfSC_divide          ,0xf7,
+  rtfSC_oslash          ,0xf8,
+  rtfSC_ugrave          ,0xf9,
+  rtfSC_uacute          ,0xfa,
+  rtfSC_ucircumflex     ,0xfb,
+  rtfSC_udieresis       ,0xfc,
+  rtfSC_yacute          ,0xfd,
+  rtfSC_thorn           ,0xfe,
+  rtfSC_ydieresis       ,0xff
+};
+
+/*
+ * RTF ANSI character set (\ansi) Symbol font map
+ *
+ * Field 1 is the standard character name which the character value in
+ * field 2 maps onto.  (It doesn't mean "to produce the character in field 1,
+ * use the value in field 2.)
+ *
+ * The character value may be given either as a single character (which will be
+ * converted to the ASCII value of the character), or in numeric format, either
+ * in decimal or 0xyy as hex yy.  Single or double quotes may be used to quote
+ * characters.
+ *
+ */
+
+int ansi_sym[] =
+{
+  rtfSC_formula        ,0x06,
+  rtfSC_nobrkhyphen    ,0x1e,
+  rtfSC_opthyphen      ,0x1f,
+  rtfSC_space         ,' ',
+  rtfSC_exclam         ,'!',
+  rtfSC_universal      ,'"',
+  rtfSC_mathnumbersign ,'#',
+  rtfSC_existential    ,'$',
+  rtfSC_percent        ,'%',
+  rtfSC_ampersand      ,'&',
+  rtfSC_suchthat       ,'\\',
+  rtfSC_parenleft      ,'(',
+  rtfSC_parenright     ,')',
+  rtfSC_mathasterisk   ,'*',
+  rtfSC_mathplus       ,'+',
+  rtfSC_comma         ,',',
+  rtfSC_mathminus      ,'-',
+  rtfSC_period         ,'.',
+  rtfSC_slash         ,'/',
+  rtfSC_zero          ,'0',
+  rtfSC_one           ,'1',
+  rtfSC_two           ,'2',
+  rtfSC_three         ,'3',
+  rtfSC_four          ,'4',
+  rtfSC_five          ,'5',
+  rtfSC_six           ,'6',
+  rtfSC_seven         ,'7',
+  rtfSC_eight         ,'8',
+  rtfSC_nine          ,'9',
+  rtfSC_colon         ,':',
+  rtfSC_semicolon      ,';',
+  rtfSC_less          ,'<',
+  rtfSC_mathequal      ,'=',
+  rtfSC_greater        ,'>',
+  rtfSC_question       ,'?',
+  rtfSC_congruent      ,'@',
+  rtfSC_Alpha         ,'A',
+  rtfSC_Beta          ,'B',
+  rtfSC_Chi           ,'C',
+  rtfSC_Delta         ,'D',
+  rtfSC_Epsilon        ,'E',
+  rtfSC_Phi           ,'F',
+  rtfSC_Gamma         ,'G',
+  rtfSC_Eta           ,'H',
+  rtfSC_Iota          ,'I',
+  rtfSC_Kappa         ,'K',
+  rtfSC_Lambda         ,'L',
+  rtfSC_Mu            ,'M',
+  rtfSC_Nu            ,'N',
+  rtfSC_Omicron        ,'O',
+  rtfSC_Pi            ,'P',
+  rtfSC_Theta         ,'Q',
+  rtfSC_Rho           ,'R',
+  rtfSC_Sigma         ,'S',
+  rtfSC_Tau           ,'T',
+  rtfSC_Upsilon        ,'U',
+  rtfSC_varsigma       ,'V',
+  rtfSC_Omega         ,'W',
+  rtfSC_Xi            ,'X',
+  rtfSC_Psi           ,'Y',
+  rtfSC_Zeta          ,'Z',
+  rtfSC_bracketleft    ,'[',
+  rtfSC_backslash      ,'\\',
+  rtfSC_bracketright   ,']',
+  rtfSC_asciicircum    ,'^',
+  rtfSC_underscore     ,'_',
+  rtfSC_quoteleft      ,'`',
+  rtfSC_alpha         ,'a',
+  rtfSC_beta          ,'b',
+  rtfSC_chi           ,'c',
+  rtfSC_delta         ,'d',
+  rtfSC_epsilon        ,'e',
+  rtfSC_phi           ,'f',
+  rtfSC_gamma         ,'g',
+  rtfSC_eta           ,'h',
+  rtfSC_iota          ,'i',
+  rtfSC_kappa         ,'k',
+  rtfSC_lambda         ,'l',
+  rtfSC_mu            ,'m',
+  rtfSC_nu            ,'n',
+  rtfSC_omicron        ,'o',
+  rtfSC_pi            ,'p',
+  rtfSC_theta         ,'q',
+  rtfSC_rho           ,'r',
+  rtfSC_sigma         ,'s',
+  rtfSC_tau           ,'t',
+  rtfSC_upsilon        ,'u',
+  rtfSC_omega         ,'w',
+  rtfSC_xi            ,'x',
+  rtfSC_psi           ,'y',
+  rtfSC_zeta          ,'z',
+  rtfSC_braceleft      ,'{',
+  rtfSC_bar           ,'|',
+  rtfSC_braceright     ,'}',
+  rtfSC_mathtilde      ,'~'
+};
+
+/*
+ *  Output sequence map for rtf2text
+ *
+ *  Field 1 is the standard character name.  Field 2 is the output sequence
+ *  to produce for that character.
+ *
+ *  The output sequence is simply a string of characters.  If it contains
+ *  whitespace, it may be quoted.  If it contains quotes, it may be quoted
+ *  with a different quote character.
+ *
+ *  characters in ASCII range (32-127
+ */
+
+const char *text_map[] = {
+  "space"            ," ",
+  "exclam"           ,"!",
+  "quotedbl"         ,"\"",
+  "numbersign"        ,"#",
+  "dollar"           ,"$",
+  "percent"          ,"%",
+  "ampersand"        ,"&",
+  "quoteright"        ,"'",
+  "parenleft"        ,"(",
+  "parenright"        ,")",
+  "asterisk"         ,"*",
+  "plus"             ,"+",
+  "comma"            ,",",
+  "hyphen"           ,"-",
+  "period"           ,".",
+  "slash"            ,"/",
+  "zero"             ,"0",
+  "one"              ,"1",
+  "two"              ,"2",
+  "three"            ,"3",
+  "four"             ,"4",
+  "five"             ,"5",
+  "six"              ,"6",
+  "seven"            ,"7",
+  "eight"            ,"8",
+  "nine"             ,"9",
+  "colon"            ,":",
+  "semicolon"        ,";",
+  "less"             ,"<",
+  "equal"            ,"=",
+  "greater"          ,">",
+  "question"         ,"?",
+  "at"               ,"@",
+  "A"                ,"A",
+  "B"                ,"B",
+  "C"                ,"C",
+  "D"                ,"D",
+  "E"                ,"E",
+  "F"                ,"F",
+  "G"                ,"G",
+  "H"                ,"H",
+  "I"                ,"I",
+  "J"                ,"J",
+  "K"                ,"K",
+  "L"                ,"L",
+  "M"                ,"M",
+  "N"                ,"N",
+  "O"                ,"O",
+  "P"                ,"P",
+  "Q"                ,"Q",
+  "R"                ,"R",
+  "S"                ,"S",
+  "T"                ,"T",
+  "U"                ,"U",
+  "V"                ,"V",
+  "W"                ,"W",
+  "X"                ,"X",
+  "Y"                ,"Y",
+  "Z"                ,"Z",
+  "bracketleft"       ,"[",
+  "backslash"        ,"\\",
+  "bracketright"      ,"]",
+  "asciicircum"       ,"^",
+  "underscore"        ,"_",
+  "quoteleft"        ,"`",
+  "a"                ,"a",
+  "b"                ,"b",
+  "c"                ,"c",
+  "d"                ,"d",
+  "e"                ,"e",
+  "f"                ,"f",
+  "g"                ,"g",
+  "h"                ,"h",
+  "i"                ,"i",
+  "j"                ,"j",
+  "k"                ,"k",
+  "l"                ,"l",
+  "m"                ,"m",
+  "n"                ,"n",
+  "o"                ,"o",
+  "p"                ,"p",
+  "q"                ,"q",
+  "r"                ,"r",
+  "s"                ,"s",
+  "t"                ,"t",
+  "u"                ,"u",
+  "v"                ,"v",
+  "w"                ,"w",
+  "x"                ,"x",
+  "y"                ,"y",
+  "z"                ,"z",
+  "braceleft"        ,"{",
+  "bar"              ,"|",
+  "braceright"        ,"}",
+  "asciitilde"        ,"~",
+  "AE"               ,"AE",
+  "OE"               ,"OE",
+  "acute"            ,"'",
+  "ae"               ,"ae",
+  "angleleft"        ,"<",
+  "angleright"        ,">",
+  "arrowboth"        ,"<->",
+  "arrowdblboth"      ,"<=>",
+  "arrowdblleft"      ,"<=",
+  "arrowdblright"     ,"=>",
+  "arrowleft"        ,"<-",
+  "arrowright"        ,"->",
+  "bullet"           ,"o",
+  "cent"             ,"cent",
+  "circumflex"        ,"^",
+  "copyright"        ,"(c)",
+  "copyrightsans"     ,"(c)",
+  "degree"           ,"deg.",
+  "divide"           ,"/",
+  "dotlessi"         ,"i",
+  "ellipsis"         ,"...",
+  "emdash"           ,"--",
+  "endash"           ,"-",
+  "fi"               ,"fi",
+  "fl"               ,"fl",
+  "fraction"         ,"/",
+  "germandbls"        ,"ss",
+  "grave"            ,"`",
+  "greaterequal"      ,">=",
+  "guillemotleft"     ,"<<",
+  "guillemotright"    ,">>",
+  "guilsinglleft"     ,"<",
+  "guilsinglright"    ,">",
+  "lessequal"        ,"<=",
+  "logicalnot"        ,"~",
+  "mathasterisk"      ,"*",
+  "mathequal"        ,"=",
+  "mathminus"        ,"-",
+  "mathnumbersign"    ,"#",
+  "mathplus"         ,"+",
+  "mathtilde"        ,"~",
+  "minus"            ,"-",
+  "mu"               ,"u",
+  "multiply"         ,"x",
+  "nobrkhyphen"       ,"-",
+  "nobrkspace"        ," ",
+  "notequal"         ,"!=",
+  "oe"               ,"oe",
+  "onehalf"          ,"1/2",
+  "onequarter"        ,"1/4",
+  "periodcentered"    ,".",
+  "plusminus"        ,"+/-",
+  "quotedblbase"      ,",,",
+  "quotedblleft"      ,"\"",
+  "quotedblright"     ,"\"",
+  "quotesinglbase"    ,",",
+  "registered"        ,"reg.",
+  "registersans"      ,"reg.",
+  "threequarters"     ,"3/4",
+  "tilde"            ,"~",
+  "trademark"        ,"(TM)",
+  "trademarksans"     ,"(TM)"
+};
+
+/*
+ * This array is used to map standard character names onto their numeric codes.
+ * The position of the name within the array is the code.
+ * stdcharnames.h is generated in the ../h directory.
+ */
+
+const char *stdCharName[] =
+{
+       "nothing",
+       "space",
+       "exclam",
+       "quotedbl",
+       "numbersign",
+       "dollar",
+       "percent",
+       "ampersand",
+       "quoteright",
+       "parenleft",
+       "parenright",
+       "asterisk",
+       "plus",
+       "comma",
+       "hyphen",
+       "period",
+       "slash",
+       "zero",
+       "one",
+       "two",
+       "three",
+       "four",
+       "five",
+       "six",
+       "seven",
+       "eight",
+       "nine",
+       "colon",
+       "semicolon",
+       "less",
+       "equal",
+       "greater",
+       "question",
+       "at",
+       "A",
+       "B",
+       "C",
+       "D",
+       "E",
+       "F",
+       "G",
+       "H",
+       "I",
+       "J",
+       "K",
+       "L",
+       "M",
+       "N",
+       "O",
+       "P",
+       "Q",
+       "R",
+       "S",
+       "T",
+       "U",
+       "V",
+       "W",
+       "X",
+       "Y",
+       "Z",
+       "bracketleft",
+       "backslash",
+       "bracketright",
+       "asciicircum",
+       "underscore",
+       "quoteleft",
+       "a",
+       "b",
+       "c",
+       "d",
+       "e",
+       "f",
+       "g",
+       "h",
+       "i",
+       "j",
+       "k",
+       "l",
+       "m",
+       "n",
+       "o",
+       "p",
+       "q",
+       "r",
+       "s",
+       "t",
+       "u",
+       "v",
+       "w",
+       "x",
+       "y",
+       "z",
+       "braceleft",
+       "bar",
+       "braceright",
+       "asciitilde",
+       "exclamdown",
+       "cent",
+       "sterling",
+       "fraction",
+       "yen",
+       "florin",
+       "section",
+       "currency",
+       "quotedblleft",
+       "guillemotleft",
+       "guilsinglleft",
+       "guilsinglright",
+       "fi",
+       "fl",
+       "endash",
+       "dagger",
+       "daggerdbl",
+       "periodcentered",
+       "paragraph",
+       "bullet",
+       "quotesinglbase",
+       "quotedblbase",
+       "quotedblright",
+       "guillemotright",
+       "ellipsis",
+       "perthousand",
+       "questiondown",
+       "grave",
+       "acute",
+       "circumflex",
+       "tilde",
+       "macron",
+       "breve",
+       "dotaccent",
+       "dieresis",
+       "ring",
+       "cedilla",
+       "hungarumlaut",
+       "ogonek",
+       "caron",
+       "emdash",
+       "AE",
+       "ordfeminine",
+       "Lslash",
+       "Oslash",
+       "OE",
+       "ordmasculine",
+       "ae",
+       "dotlessi",
+       "lslash",
+       "oslash",
+       "oe",
+       "germandbls",
+       "Aacute",
+       "Acircumflex",
+       "Adieresis",
+       "Agrave",
+       "Aring",
+       "Atilde",
+       "Ccedilla",
+       "Eacute",
+       "Ecircumflex",
+       "Edieresis",
+       "Egrave",
+       "Eth",
+       "Iacute",
+       "Icircumflex",
+       "Idieresis",
+       "Igrave",
+       "Ntilde",
+       "Oacute",
+       "Ocircumflex",
+       "Odieresis",
+       "Ograve",
+       "Otilde",
+       "Scaron",
+       "Thorn",
+       "Uacute",
+       "Ucircumflex",
+       "Udieresis",
+       "Ugrave",
+       "Yacute",
+       "Ydieresis",
+       "aacute",
+       "acircumflex",
+       "adieresis",
+       "agrave",
+       "aring",
+       "atilde",
+       "brokenbar",
+       "ccedilla",
+       "copyright",
+       "degree",
+       "divide",
+       "eacute",
+       "ecircumflex",
+       "edieresis",
+       "egrave",
+       "eth",
+       "iacute",
+       "icircumflex",
+       "idieresis",
+       "igrave",
+       "logicalnot",
+       "minus",
+       "multiply",
+       "ntilde",
+       "oacute",
+       "ocircumflex",
+       "odieresis",
+       "ograve",
+       "onehalf",
+       "onequarter",
+       "onesuperior",
+       "otilde",
+       "plusminus",
+       "registered",
+       "thorn",
+       "threequarters",
+       "threesuperior",
+       "trademark",
+       "twosuperior",
+       "uacute",
+       "ucircumflex",
+       "udieresis",
+       "ugrave",
+       "yacute",
+       "ydieresis",
+       "Alpha",
+       "Beta",
+       "Chi",
+       "Delta",
+       "Epsilon",
+       "Phi",
+       "Gamma",
+       "Eta",
+       "Iota",
+       "Kappa",
+       "Lambda",
+       "Mu",
+       "Nu",
+       "Omicron",
+       "Pi",
+       "Theta",
+       "Rho",
+       "Sigma",
+       "Tau",
+       "Upsilon",
+       "varUpsilon",
+       "Omega",
+       "Xi",
+       "Psi",
+       "Zeta",
+       "alpha",
+       "beta",
+       "chi",
+       "delta",
+       "epsilon",
+       "phi",
+       "varphi",
+       "gamma",
+       "eta",
+       "iota",
+       "kappa",
+       "lambda",
+       "mu",
+       "nu",
+       "omicron",
+       "pi",
+       "varpi",
+       "theta",
+       "vartheta",
+       "rho",
+       "sigma",
+       "varsigma",
+       "tau",
+       "upsilon",
+       "omega",
+       "xi",
+       "psi",
+       "zeta",
+       "nobrkspace",
+       "nobrkhyphen",
+       "lessequal",
+       "greaterequal",
+       "infinity",
+       "integral",
+       "notequal",
+       "radical",
+       "radicalex",
+       "approxequal",
+       "apple",
+       "partialdiff",
+       "opthyphen",
+       "formula",
+       "lozenge",
+       "universal",
+       "existential",
+       "suchthat",
+       "congruent",
+       "therefore",
+       "perpendicular",
+       "minute",
+       "club",
+       "diamond",
+       "heart",
+       "spade",
+       "arrowboth",
+       "arrowleft",
+       "arrowup",
+       "arrowright",
+       "arrowdown",
+       "second",
+       "proportional",
+       "equivalence",
+       "arrowvertex",
+       "arrowhorizex",
+       "carriagereturn",
+       "aleph",
+       "Ifraktur",
+       "Rfraktur",
+       "weierstrass",
+       "circlemultiply",
+       "circleplus",
+       "emptyset",
+       "intersection",
+       "union",
+       "propersuperset",
+       "reflexsuperset",
+       "notsubset",
+       "propersubset",
+       "reflexsubset",
+       "element",
+       "notelement",
+       "angle",
+       "gradient",
+       "product",
+       "logicaland",
+       "logicalor",
+       "arrowdblboth",
+       "arrowdblleft",
+       "arrowdblup",
+       "arrowdblright",
+       "arrowdbldown",
+       "angleleft",
+       "registersans",
+       "copyrightsans",
+       "trademarksans",
+       "angleright",
+       "mathplus",
+       "mathminus",
+       "mathasterisk",
+       "mathnumbersign",
+       "dotmath",
+       "mathequal",
+       "mathtilde",
+        (char *) NULL
+};
+
+int _RTFGetChar(RTF_Info *info)
+{
+       int ch;
+
+       TRACE("\n");
+
+       /* if the last buffer wasn't full, it's EOF */
+  if (info->dwInputSize > 0 &&
+    info->dwInputSize == info->dwInputUsed && info->dwInputSize < sizeof(info->InputBuffer))
+    return EOF;
+  if (info->dwInputSize <= info->dwInputUsed)
+       {
+               long count = 0;
+               info->editstream.dwError = info->editstream.pfnCallback(info->editstream.dwCookie, 
+                       info->InputBuffer, sizeof(info->InputBuffer), &count);
+       /* if error, it's EOF */
+               if (info->editstream.dwError)
+                 return EOF;
+       /* if no bytes read, it's EOF */
+               if(count == 0)
+                       return EOF;
+               info->dwInputSize = count;
+               info->dwInputUsed = 0;
+       }
+       ch = info->InputBuffer[info->dwInputUsed++];
+       if (!ch)
+                return EOF;
+       return ch;
+}
+
+void RTFSetEditStream(RTF_Info *info, EDITSTREAM *es)
+{
+       TRACE("\n");
+
+       info->editstream.dwCookie = es->dwCookie;
+       info->editstream.dwError  = es->dwError;
+       info->editstream.pfnCallback = es->pfnCallback;
+}
+
+/*
+ * Initialize the reader.  This may be called multiple times,
+ * to read multiple files.  The only thing not reset is the input
+ * stream; that must be done with RTFSetStream().
+ */
+
+void RTFInit(RTF_Info *info)
+{
+       int     i;
+       RTFColor        *cp;
+       RTFFont         *fp;
+       RTFStyle        *sp;
+       RTFStyleElt     *eltList, *ep;
+
+       TRACE("\n");
+
+       if (info->rtfTextBuf == (char *) NULL)  /* initialize the text buffers */
+       {
+               info->rtfTextBuf = RTFAlloc (rtfBufSiz);
+               info->pushedTextBuf = RTFAlloc (rtfBufSiz);
+               if (info->rtfTextBuf == (char *) NULL
+                       || info->pushedTextBuf == (char *) NULL)
+                       RTFPanic (info,"Cannot allocate text buffers.");
+               info->rtfTextBuf[0] = info->pushedTextBuf[0] = '\0';
+       }
+
+       RTFFree (info->inputName);
+       RTFFree (info->outputName);
+       info->inputName = info->outputName = (char *) NULL;
+
+       /* initialize lookup table */
+       LookupInit ();
+
+       for (i = 0; i < rtfMaxClass; i++)
+               RTFSetClassCallback (info, i, (RTFFuncPtr) NULL);
+       for (i = 0; i < rtfMaxDestination; i++)
+               RTFSetDestinationCallback (info, i, (RTFFuncPtr) NULL);
+
+       /* install built-in destination readers */
+       RTFSetDestinationCallback (info, rtfFontTbl, ReadFontTbl);
+       RTFSetDestinationCallback (info, rtfColorTbl, ReadColorTbl);
+       RTFSetDestinationCallback (info, rtfStyleSheet, ReadStyleSheet);
+       RTFSetDestinationCallback (info, rtfInfo, ReadInfoGroup);
+       RTFSetDestinationCallback (info, rtfPict, ReadPictGroup);
+       RTFSetDestinationCallback (info, rtfObject, ReadObjGroup);
+
+
+       RTFSetReadHook (info, (RTFFuncPtr) NULL);
+
+       /* dump old lists if necessary */
+
+       while (info->fontList != (RTFFont *) NULL)
+       {
+               fp = info->fontList->rtfNextFont;
+               RTFFree (info->fontList->rtfFName);
+               RTFFree ((char *) info->fontList);
+               info->fontList = fp;
+       }
+       while (info->colorList != (RTFColor *) NULL)
+       {
+               cp = info->colorList->rtfNextColor;
+               RTFFree ((char *) info->colorList);
+               info->colorList = cp;
+       }
+       while (info->styleList != (RTFStyle *) NULL)
+       {
+               sp = info->styleList->rtfNextStyle;
+               eltList = info->styleList->rtfSSEList;
+               while (eltList != (RTFStyleElt *) NULL)
+               {
+                       ep = eltList->rtfNextSE;
+                       RTFFree (eltList->rtfSEText);
+                       RTFFree ((char *) eltList);
+                       eltList = ep;
+               }
+               RTFFree (info->styleList->rtfSName);
+               RTFFree ((char *) info->styleList);
+               info->styleList = sp;
+       }
+
+       info->rtfClass = -1;
+       info->pushedClass = -1;
+       info->pushedChar = EOF;
+
+       info->rtfLineNum = 0;
+       info->rtfLinePos = 0;
+       info->prevChar = EOF;
+       info->bumpLine = 0;
+
+       CharSetInit (info);
+       info->csTop = 0;
+}
+
+/*
+ * Set or get the input or output file name.  These are never guaranteed
+ * to be accurate, only insofar as the calling program makes them so.
+ */
+
+void RTFSetInputName(RTF_Info *info, char *name)
+{
+       TRACE("\n");
+
+       if ((info->inputName = RTFStrSave (name)) == (char *) NULL)
+               RTFPanic (info,"RTFSetInputName: out of memory");
+}
+
+
+char *RTFGetInputName(RTF_Info *info)
+{
+       return (info->inputName);
+}
+
+
+void RTFSetOutputName(RTF_Info *info, char *name)
+{
+       TRACE("\n");
+
+       if ((info->outputName = RTFStrSave (name)) == (char *) NULL)
+               RTFPanic (info, "RTFSetOutputName: out of memory");
+}
+
+
+char *RTFGetOutputName(RTF_Info *info)
+{
+       return (info->outputName);
+}
+
+
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ * Callback table manipulation routines
+ */
+
+
+/*
+ * Install or return a writer callback for a token class
+ */
+
+void RTFSetClassCallback(RTF_Info *info, int class, RTFFuncPtr callback)
+{
+       if (class >= 0 && class < rtfMaxClass)
+               info->ccb[class] = callback;
+}
+
+
+RTFFuncPtr RTFGetClassCallback(RTF_Info *info, int class)
+{
+       if (class >= 0 && class < rtfMaxClass)
+               return (info->ccb[class]);
+       return ((RTFFuncPtr) NULL);
+}
+
+
+/*
+ * Install or return a writer callback for a destination type
+ */
+
+void RTFSetDestinationCallback(RTF_Info *info, int dest, RTFFuncPtr callback)
+{
+       if (dest >= 0 && dest < rtfMaxDestination)
+               info->dcb[dest] = callback;
+}
+
+
+RTFFuncPtr RTFGetDestinationCallback(RTF_Info *info, int dest)
+{
+       if (dest >= 0 && dest < rtfMaxDestination)
+               return (info->dcb[dest]);
+       return ((RTFFuncPtr) NULL);
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ * Token reading routines
+ */
+
+
+/*
+ * Read the input stream, invoking the writer's callbacks
+ * where appropriate.
+ */
+
+void RTFRead(RTF_Info *info)
+{
+       while (RTFGetToken (info) != rtfEOF)
+               RTFRouteToken (info);
+}
+
+
+/*
+ * Route a token.  If it's a destination for which a reader is
+ * installed, process the destination internally, otherwise
+ * pass the token to the writer's class callback.
+ */
+
+void RTFRouteToken(RTF_Info *info)
+{
+       RTFFuncPtr      p;
+
+       TRACE("\n");
+
+       if (info->rtfClass < 0 || info->rtfClass >= rtfMaxClass)        /* watchdog */
+       {
+               RTFPanic (info,"Unknown class %d: %s (reader malfunction)",
+                                                       info->rtfClass, info->rtfTextBuf);
+       }
+       if (RTFCheckCM (info, rtfControl, rtfDestination))
+       {
+               /* invoke destination-specific callback if there is one */
+               if ((p = RTFGetDestinationCallback (info, info->rtfMinor))
+                                                       != (RTFFuncPtr) NULL)
+               {
+                       (*p) (info);
+                       return;
+               }
+       }
+       /* invoke class callback if there is one */
+       if ((p = RTFGetClassCallback (info, info->rtfClass)) != (RTFFuncPtr) NULL)
+               (*p) (info);
+}
+
+
+/*
+ * Skip to the end of the current group.  When this returns,
+ * writers that maintain a state stack may want to call their
+ * state unstacker; global vars will still be set to the group's
+ * closing brace.
+ */
+
+void RTFSkipGroup(RTF_Info *info)
+{
+       int     level = 1;
+
+       TRACE("\n");
+
+       while (RTFGetToken (info) != rtfEOF)
+       {
+               if (info->rtfClass == rtfGroup)
+               {
+                       if (info->rtfMajor == rtfBeginGroup)
+                               ++level;
+                       else if (info->rtfMajor == rtfEndGroup)
+                       {
+                               if (--level < 1)
+                                       break;  /* end of initial group */
+                       }
+               }
+       }
+}
+
+
+/*
+ * Read one token.  Call the read hook if there is one.  The
+ * token class is the return value.  Returns rtfEOF when there
+ * are no more tokens.
+ */
+
+int RTFGetToken(RTF_Info *info)
+{
+       RTFFuncPtr      p;
+
+       TRACE("\n");
+
+       for (;;)
+       {
+               _RTFGetToken (info);
+               if ((p = RTFGetReadHook (info)) != (RTFFuncPtr) NULL)
+                       (*p) (info);    /* give read hook a look at token */
+
+               /* Silently discard newlines, carriage returns, nulls.  */
+               if (!(info->rtfClass == rtfText && info->rtfFormat != SF_TEXT
+                       && (info->rtfMajor == '\r' || info->rtfMajor == '\n' || info->rtfMajor == '\0')))
+                       break;
+       }
+       return (info->rtfClass);
+}
+
+
+/*
+ * Install or return a token reader hook.
+ */
+
+void RTFSetReadHook(RTF_Info *info, RTFFuncPtr f)
+{
+       info->readHook = f;
+}
+
+
+RTFFuncPtr RTFGetReadHook(RTF_Info *info)
+{
+       return (info->readHook);
+}
+
+
+void RTFUngetToken(RTF_Info *info)
+{
+       TRACE("\n");
+
+       if (info->pushedClass >= 0)     /* there's already an ungotten token */
+               RTFPanic (info,"cannot unget two tokens");
+       if (info->rtfClass < 0)
+               RTFPanic (info,"no token to unget");
+       info->pushedClass = info->rtfClass;
+       info->pushedMajor = info->rtfMajor;
+       info->pushedMinor = info->rtfMinor;
+       info->pushedParam = info->rtfParam;
+       (void) strcpy (info->pushedTextBuf, info->rtfTextBuf);
+}
+
+
+int RTFPeekToken(RTF_Info *info)
+{
+       _RTFGetToken (info);
+       RTFUngetToken (info);
+       return (info->rtfClass);
+}
+
+
+static void _RTFGetToken(RTF_Info *info)
+{
+       RTFFont *fp;
+
+       TRACE("\n");
+
+        if (info->rtfFormat == SF_TEXT) {
+            info->rtfMajor = GetChar (info);
+            info->rtfMinor = rtfSC_nothing;
+            info->rtfParam = rtfNoParam;
+            info->rtfTextBuf[info->rtfTextLen = 0] = '\0';
+            if (info->rtfMajor == EOF)
+                info->rtfClass = rtfEOF;
+            else
+               info->rtfClass = rtfText;
+           return;
+       }
+
+       /* first check for pushed token from RTFUngetToken() */
+
+       if (info->pushedClass >= 0)
+       {
+               info->rtfClass = info->pushedClass;
+               info->rtfMajor = info->pushedMajor;
+               info->rtfMinor = info->pushedMinor;
+               info->rtfParam = info->pushedParam;
+               (void) strcpy (info->rtfTextBuf, info->pushedTextBuf);
+               info->rtfTextLen = strlen (info->rtfTextBuf);
+               info->pushedClass = -1;
+               return;
+       }
+
+       /*
+        * Beyond this point, no token is ever seen twice, which is
+        * important, e.g., for making sure no "}" pops the font stack twice.
+        */
+
+       _RTFGetToken2 (info);
+       if (info->rtfClass == rtfText)  /* map RTF char to standard code */
+               info->rtfMinor = RTFMapChar (info, info->rtfMajor);
+
+       /*
+        * If auto-charset stuff is activated, see if anything needs doing,
+        * like reading the charset maps or switching between them.
+        */
+
+       if (info->autoCharSetFlags == 0)
+               return;
+
+       if ((info->autoCharSetFlags & rtfReadCharSet)
+               && RTFCheckCM (info, rtfControl, rtfCharSet))
+       {
+               ReadCharSetMaps (info);
+       }
+       else if ((info->autoCharSetFlags & rtfSwitchCharSet)
+               && RTFCheckCMM (info, rtfControl, rtfCharAttr, rtfFontNum))
+       {
+               if ((fp = RTFGetFont (info, info->rtfParam)) != (RTFFont *) NULL)
+               {
+                       if (strncmp (fp->rtfFName, "Symbol", 6) == 0)
+                               info->curCharSet = rtfCSSymbol;
+                       else
+                               info->curCharSet = rtfCSGeneral;
+                       RTFSetCharSet (info, info->curCharSet);
+               }
+       }
+       else if ((info->autoCharSetFlags & rtfSwitchCharSet) && info->rtfClass == rtfGroup)
+       {
+               switch (info->rtfMajor)
+               {
+               case rtfBeginGroup:
+                       if (info->csTop >= maxCSStack)
+                               RTFPanic (info, "_RTFGetToken: stack overflow");
+                       info->csStack[info->csTop++] = info->curCharSet;
+                       break;
+               case rtfEndGroup:
+                       /*
+                        * If stack top is 1 at this point, we are ending the
+                        * group started by the initial {, which ends the
+                        * RTF stream
+                        */
+                       if (info->csTop <= 0)
+                               RTFPanic (info,"_RTFGetToken: stack underflow");
+                       else if (info->csTop == 1)
+                               info->rtfClass = rtfEOF;
+                       else
+                       {
+                               info->curCharSet = info->csStack[--info->csTop];
+                               RTFSetCharSet (info, info->curCharSet);
+                       }
+                       break;
+               }
+       }
+}
+
+
+/* this shouldn't be called anywhere but from _RTFGetToken() */
+
+static void _RTFGetToken2(RTF_Info *info)
+{
+       int     sign;
+       int     c;
+
+       TRACE("\n");
+
+       /* initialize token vars */
+
+       info->rtfClass = rtfUnknown;
+       info->rtfParam = rtfNoParam;
+       info->rtfTextBuf[info->rtfTextLen = 0] = '\0';
+
+       /* get first character, which may be a pushback from previous token */
+
+       if (info->pushedChar != EOF)
+       {
+               c = info->pushedChar;
+               info->rtfTextBuf[info->rtfTextLen++] = c;
+               info->rtfTextBuf[info->rtfTextLen] = '\0';
+               info->pushedChar = EOF;
+       }
+       else if ((c = GetChar (info)) == EOF)
+       {
+               info->rtfClass = rtfEOF;
+               return;
+       }
+
+       if (c == '{')
+       {
+               info->rtfClass = rtfGroup;
+               info->rtfMajor = rtfBeginGroup;
+               return;
+       }
+       if (c == '}')
+       {
+               info->rtfClass = rtfGroup;
+               info->rtfMajor = rtfEndGroup;
+               return;
+       }
+       if (c != '\\')
+       {
+               /*
+                * Two possibilities here:
+                * 1) ASCII 9, effectively like \tab control symbol
+                * 2) literal text char
+                */
+               if (c == '\t')                  /* ASCII 9 */
+               {
+                       info->rtfClass = rtfControl;
+                       info->rtfMajor = rtfSpecialChar;
+                       info->rtfMinor = rtfTab;
+               }
+               else
+               {
+                       info->rtfClass = rtfText;
+                       info->rtfMajor = c;
+               }
+               return;
+       }
+       if ((c = GetChar (info)) == EOF)
+       {
+               /* early eof, whoops (class is rtfUnknown) */
+               return;
+       }
+       if (!isalpha (c))
+       {
+               /*
+                * Three possibilities here:
+                * 1) hex encoded text char, e.g., \'d5, \'d3
+                * 2) special escaped text char, e.g., \{, \}
+                * 3) control symbol, e.g., \_, \-, \|, \<10>
+                */
+               if (c == '\'')                          /* hex char */
+               {
+               int     c2;
+
+                       if ((c = GetChar (info)) != EOF && (c2 = GetChar (info)) != EOF)
+                       {
+                               /* should do isxdigit check! */
+                               info->rtfClass = rtfText;
+                               info->rtfMajor = RTFCharToHex (c) * 16
+                                               + RTFCharToHex (c2);
+                               return;
+                       }
+                       /* early eof, whoops (class is rtfUnknown) */
+                       return;
+               }
+
+               /* escaped char */
+               /*if (index (":{}\\", c) != (char *) NULL)*/ /* escaped char */
+               if (c == ':' || c == '{' || c == '}' || c == '\\')
+               {
+                       info->rtfClass = rtfText;
+                       info->rtfMajor = c;
+                       return;
+               }
+
+               /* control symbol */
+               Lookup (info, info->rtfTextBuf);        /* sets class, major, minor */
+               return;
+       }
+       /* control word */
+       while (isalpha (c))
+       {
+               if ((c = GetChar (info)) == EOF)
+                       break;
+       }
+
+       /*
+        * At this point, the control word is all collected, so the
+        * major/minor numbers are determined before the parameter
+        * (if any) is scanned.  There will be one too many characters
+        * in the buffer, though, so fix up before and restore after
+        * looking up.
+        */
+
+       if (c != EOF)
+               info->rtfTextBuf[info->rtfTextLen-1] = '\0';
+       Lookup (info, info->rtfTextBuf);        /* sets class, major, minor */
+       if (c != EOF)
+               info->rtfTextBuf[info->rtfTextLen-1] = c;
+
+       /*
+        * Should be looking at first digit of parameter if there
+        * is one, unless it's negative.  In that case, next char
+        * is '-', so need to gobble next char, and remember sign.
+        */
+
+       sign = 1;
+       if (c == '-')
+       {
+               sign = -1;
+               c = GetChar (info);
+       }
+       if (c != EOF && isdigit (c))
+       {
+               info->rtfParam = 0;
+               while (isdigit (c))     /* gobble parameter */
+               {
+                       info->rtfParam = info->rtfParam * 10 + c - '0';
+                       if ((c = GetChar (info)) == EOF)
+                               break;
+               }
+               info->rtfParam *= sign;
+       }
+       /*
+        * If control symbol delimiter was a blank, gobble it.
+        * Otherwise the character is first char of next token, so
+        * push it back for next call.  In either case, delete the
+        * delimiter from the token buffer.
+        */
+       if (c != EOF)
+       {
+               if (c != ' ')
+                       info->pushedChar = c;
+               info->rtfTextBuf[--info->rtfTextLen] = '\0';
+       }
+}
+
+
+/*
+ * Read the next character from the input.  This handles setting the
+ * current line and position-within-line variables.  Those variable are
+ * set correctly whether lines end with CR, LF, or CRLF (the last being
+ * the tricky case).
+ *
+ * bumpLine indicates whether the line number should be incremented on
+ * the *next* input character.
+ */
+
+
+static int GetChar(RTF_Info *info)
+{
+       int     c;
+       int     oldBumpLine;
+
+       TRACE("\n");
+
+       if ((c = _RTFGetChar(info)) != EOF)
+       {
+               info->rtfTextBuf[info->rtfTextLen++] = c;
+               info->rtfTextBuf[info->rtfTextLen] = '\0';
+       }
+       if (info->prevChar == EOF)
+               info->bumpLine = 1;
+       oldBumpLine = info->bumpLine;   /* non-zero if prev char was line ending */
+       info->bumpLine = 0;
+       if (c == '\r')
+               info->bumpLine = 1;
+       else if (c == '\n')
+       {
+               info->bumpLine = 1;
+               if (info->prevChar == '\r')             /* oops, previous \r wasn't */
+                       oldBumpLine = 0;        /* really a line ending */
+       }
+       ++info->rtfLinePos;
+       if (oldBumpLine)        /* were we supposed to increment the */
+       {                       /* line count on this char? */
+               ++info->rtfLineNum;
+               info->rtfLinePos = 1;
+       }
+       info->prevChar = c;
+       return (c);
+}
+
+
+/*
+ * Synthesize a token by setting the global variables to the
+ * values supplied.  Typically this is followed with a call
+ * to RTFRouteToken().
+ *
+ * If a param value other than rtfNoParam is passed, it becomes
+ * part of the token text.
+ */
+
+void RTFSetToken(RTF_Info *info, int class, int major, int minor, int param, const char *text)
+{
+       TRACE("\n");
+
+       info->rtfClass = class;
+       info->rtfMajor = major;
+       info->rtfMinor = minor;
+       info->rtfParam = param;
+       if (param == rtfNoParam)
+               (void) strcpy (info->rtfTextBuf, text);
+       else
+               sprintf (info->rtfTextBuf, "%s%d", text, param);
+       info->rtfTextLen = strlen (info->rtfTextBuf);
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ * Routines to handle mapping of RTF character sets
+ * onto standard characters.
+ *
+ * RTFStdCharCode(name)        given char name, produce numeric code
+ * RTFStdCharName(code)        given char code, return name
+ * RTFMapChar(c)       map input (RTF) char code to std code
+ * RTFSetCharSet(id)   select given charset map
+ * RTFGetCharSet()     get current charset map
+ *
+ * See ../h/README for more information about charset names and codes.
+ */
+
+
+/*
+ * Initialize charset stuff.
+ */
+
+static void CharSetInit(RTF_Info *info)
+{
+       TRACE("\n");
+
+       info->autoCharSetFlags = (rtfReadCharSet | rtfSwitchCharSet);
+       RTFFree (info->genCharSetFile);
+       info->genCharSetFile = (char *) NULL;
+       info->haveGenCharSet = 0;
+       RTFFree (info->symCharSetFile);
+       info->symCharSetFile = (char *) NULL;
+       info->haveSymCharSet = 0;
+       info->curCharSet = rtfCSGeneral;
+       info->curCharCode = info->genCharCode;
+}
+
+
+/*
+ * Specify the name of a file to be read when auto-charset-file reading is
+ * done.
+ */
+
+void RTFSetCharSetMap (RTF_Info *info, char *name, int csId)
+{
+       TRACE("\n");
+
+       if ((name = RTFStrSave (name)) == (char *) NULL)        /* make copy */
+               RTFPanic (info,"RTFSetCharSetMap: out of memory");
+       switch (csId)
+       {
+       case rtfCSGeneral:
+               RTFFree (info->genCharSetFile); /* free any previous value */
+               info->genCharSetFile = name;
+               break;
+       case rtfCSSymbol:
+               RTFFree (info->symCharSetFile); /* free any previous value */
+               info->symCharSetFile = name;
+               break;
+       }
+}
+
+
+/*
+ * Do auto-charset-file reading.
+ * will always use the ansi charset no mater what the value
+ * of the rtfTextBuf is.
+ *
+ * TODO: add support for other charset in the future.
+ *
+ */
+
+static void ReadCharSetMaps(RTF_Info *info)
+{
+       char    buf[rtfBufSiz];
+
+       TRACE("\n");
+
+       if (info->genCharSetFile != (char *) NULL)
+               (void) strcpy (buf, info->genCharSetFile);
+       else
+               sprintf (buf, "%s-gen", &info->rtfTextBuf[1]);
+       if (RTFReadCharSetMap (info, rtfCSGeneral) == 0)
+               RTFPanic (info,"ReadCharSetMaps: Cannot read charset map %s", buf);
+       if (info->symCharSetFile != (char *) NULL)
+            (void) strcpy (buf, info->symCharSetFile);
+       else
+               sprintf (buf, "%s-sym", &info->rtfTextBuf[1]);
+       if (RTFReadCharSetMap (info, rtfCSSymbol) == 0)
+               RTFPanic (info,"ReadCharSetMaps: Cannot read charset map %s", buf);
+}
+
+
+
+/*
+ * Convert a CharSetMap (character_name, character) into
+ * this form : array[character_ident] = character;
+ */
+
+int RTFReadCharSetMap(RTF_Info *info, int csId)
+{
+        int    *stdCodeArray;
+        unsigned int i;
+
+       TRACE("\n");
+
+       switch (csId)
+       {
+       default:
+               return (0);     /* illegal charset id */
+       case rtfCSGeneral:
+
+               info->haveGenCharSet = 1;
+               stdCodeArray = info->genCharCode;
+               for (i = 0; i < charSetSize; i++)
+               {
+                   stdCodeArray[i] = rtfSC_nothing;
+               }
+
+               for ( i = 0 ; i< sizeof(ansi_gen)/(sizeof(int));i+=2)
+               {
+                   stdCodeArray[ ansi_gen[i+1] ] = ansi_gen[i];
+               }
+               break;
+
+       case rtfCSSymbol:
+
+               info->haveSymCharSet = 1;
+               stdCodeArray = info->symCharCode;
+               for (i = 0; i < charSetSize; i++)
+               {
+                   stdCodeArray[i] = rtfSC_nothing;
+               }
+
+               for ( i = 0 ; i< sizeof(ansi_sym)/(sizeof(int));i+=2)
+               {
+                   stdCodeArray[ ansi_sym[i+1] ] = ansi_sym[i];
+               }
+               break;
+       }
+
+       return (1);
+}
+
+
+/*
+ * Given a standard character name (a string), find its code (a number).
+ * Return -1 if name is unknown.
+ */
+
+int RTFStdCharCode(RTF_Info *info, const char *name)
+{
+       int     i;
+
+       TRACE("\n");
+
+       for (i = 0; i < rtfSC_MaxChar; i++)
+       {
+               if (strcmp (name, stdCharName[i]) == 0)
+                       return (i);
+       }
+       return (-1);
+}
+
+
+/*
+ * Given a standard character code (a number), find its name (a string).
+ * Return NULL if code is unknown.
+ */
+
+const char *RTFStdCharName(RTF_Info *info, int code)
+{
+       if (code < 0 || code >= rtfSC_MaxChar)
+               return ((char *) NULL);
+       return (stdCharName[code]);
+}
+
+
+/*
+ * Given an RTF input character code, find standard character code.
+ * The translator should read the appropriate charset maps when it finds a
+ * charset control.  However, the file might not contain one.  In this
+ * case, no map will be available.  When the first attempt is made to
+ * map a character under these circumstances, RTFMapChar() assumes ANSI
+ * and reads the map as necessary.
+ */
+
+int RTFMapChar(RTF_Info *info, int c)
+{
+       TRACE("\n");
+
+       switch (info->curCharSet)
+       {
+       case rtfCSGeneral:
+               if (!info->haveGenCharSet)
+               {
+                       if (RTFReadCharSetMap (info, rtfCSGeneral) == 0)
+                               RTFPanic (info,"RTFMapChar: cannot read ansi-gen");
+               }
+               break;
+       case rtfCSSymbol:
+               if (!info->haveSymCharSet)
+               {
+                       if (RTFReadCharSetMap (info, rtfCSSymbol) == 0)
+                               RTFPanic (info,"RTFMapChar: cannot read ansi-sym");
+               }
+               break;
+       }
+       if (c < 0 || c >= charSetSize)
+               return (rtfSC_nothing);
+       return (info->curCharCode[c]);
+}
+
+
+/*
+ * Set the current character set.  If csId is illegal, uses general charset.
+ */
+
+void RTFSetCharSet(RTF_Info *info, int csId)
+{
+       TRACE("\n");
+
+       switch (csId)
+       {
+       default:                /* use general if csId unknown */
+       case rtfCSGeneral:
+               info->curCharCode = info->genCharCode;
+               info->curCharSet = csId;
+               break;
+       case rtfCSSymbol:
+               info->curCharCode = info->symCharCode;
+               info->curCharSet = csId;
+               break;
+       }
+}
+
+
+int RTFGetCharSet(RTF_Info *info)
+{
+       return (info->curCharSet);
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ * Special destination readers.  They gobble the destination so the
+ * writer doesn't have to deal with them.  That's wrong for any
+ * translator that wants to process any of these itself.  In that
+ * case, these readers should be overridden by installing a different
+ * destination callback.
+ *
+ * NOTE: The last token read by each of these reader will be the
+ * destination's terminating '}', which will then be the current token.
+ * That '}' token is passed to RTFRouteToken() - the writer has already
+ * seen the '{' that began the destination group, and may have pushed a
+ * state; it also needs to know at the end of the group that a state
+ * should be popped.
+ *
+ * It's important that rtf.h and the control token lookup table list
+ * as many symbols as possible, because these destination readers
+ * unfortunately make strict assumptions about the input they expect,
+ * and a token of class rtfUnknown will throw them off easily.
+ */
+
+
+/*
+ * Read { \fonttbl ... } destination.  Old font tables don't have
+ * braces around each table entry; try to adjust for that.
+ */
+
+static void ReadFontTbl(RTF_Info *info)
+{
+       RTFFont         *fp = NULL;
+       char            buf[rtfBufSiz], *bp;
+       int             old = -1;
+       const char      *fn = "ReadFontTbl";
+
+       TRACE("\n");
+
+       for (;;)
+       {
+               (void) RTFGetToken (info);
+               if (RTFCheckCM (info, rtfGroup, rtfEndGroup))
+                       break;
+               if (old < 0)            /* first entry - determine tbl type */
+               {
+                       if (RTFCheckCMM (info, rtfControl, rtfCharAttr, rtfFontNum))
+                               old = 1;        /* no brace */
+                       else if (RTFCheckCM (info, rtfGroup, rtfBeginGroup))
+                               old = 0;        /* brace */
+                       else                    /* can't tell! */
+                               RTFPanic (info, "%s: Cannot determine format", fn);
+               }
+               if (old == 0)           /* need to find "{" here */
+               {
+                       if (!RTFCheckCM (info, rtfGroup, rtfBeginGroup))
+                               RTFPanic (info, "%s: missing \"{\"", fn);
+                       (void) RTFGetToken (info);      /* yes, skip to next token */
+               }
+               if ((fp = New (RTFFont)) == (RTFFont *) NULL)
+                       RTFPanic (info, "%s: cannot allocate font entry", fn);
+
+               fp->rtfNextFont = info->fontList;
+               info->fontList = fp;
+
+               fp->rtfFName = (char *) NULL;
+               fp->rtfFAltName = (char *) NULL;
+               fp->rtfFNum = -1;
+               fp->rtfFFamily = 0;
+               fp->rtfFCharSet = 0;
+               fp->rtfFPitch = 0;
+               fp->rtfFType = 0;
+               fp->rtfFCodePage = 0;
+
+               while (info->rtfClass != rtfEOF
+                      && !RTFCheckCM (info, rtfText, ';')
+                      && !RTFCheckCM (info, rtfGroup, rtfEndGroup))
+               {
+                       if (info->rtfClass == rtfControl)
+                       {
+                               switch (info->rtfMajor)
+                               {
+                               default:
+                                       /* ignore token but announce it */
+                                       RTFMsg (info,"%s: unknown token \"%s\"\n",
+                                                       fn, info->rtfTextBuf);
+                                        break;
+                               case rtfFontFamily:
+                                       fp->rtfFFamily = info->rtfMinor;
+                                       break;
+                               case rtfCharAttr:
+                                       switch (info->rtfMinor)
+                                       {
+                                       default:
+                                               break;  /* ignore unknown? */
+                                       case rtfFontNum:
+                                               fp->rtfFNum = info->rtfParam;
+                                               break;
+                                       }
+                                       break;
+                               case rtfFontAttr:
+                                       switch (info->rtfMinor)
+                                       {
+                                       default:
+                                               break;  /* ignore unknown? */
+                                       case rtfFontCharSet:
+                                               fp->rtfFCharSet = info->rtfParam;
+                                               break;
+                                       case rtfFontPitch:
+                                               fp->rtfFPitch = info->rtfParam;
+                                               break;
+                                       case rtfFontCodePage:
+                                               fp->rtfFCodePage = info->rtfParam;
+                                               break;
+                                       case rtfFTypeNil:
+                                       case rtfFTypeTrueType:
+                                               fp->rtfFType = info->rtfParam;
+                                               break;
+                                       }
+                                       break;
+                               }
+                       }
+                       else if (RTFCheckCM (info, rtfGroup, rtfBeginGroup))    /* dest */
+                       {
+                               RTFSkipGroup (info);    /* ignore for now */
+                       }
+                       else if (info->rtfClass == rtfText)     /* font name */
+                       {
+                               bp = buf;
+                                while (info->rtfClass == rtfText
+                                        && !RTFCheckCM (info, rtfText, ';'))
+                               {
+                                       *bp++ = info->rtfMajor;
+                                       (void) RTFGetToken (info);
+                               }
+
+                               /* FIX: in some cases the <fontinfo> isn't finished with a semi-column */
+                               if(RTFCheckCM (info, rtfGroup, rtfEndGroup))
+                               {
+                                 RTFUngetToken (info);
+                               }
+                               *bp = '\0';
+                               fp->rtfFName = RTFStrSave (buf);
+                               if (fp->rtfFName == (char *) NULL)
+                                       RTFPanic (info, "%s: cannot allocate font name", fn);
+                               /* already have next token; don't read one */
+                               /* at bottom of loop */
+                               continue;
+                       }
+                       else
+                       {
+                               /* ignore token but announce it */
+                               RTFMsg (info, "%s: unknown token \"%s\"\n",
+                                                       fn,info->rtfTextBuf);
+                       }
+                       (void) RTFGetToken (info);
+               }
+               if (old == 0)   /* need to see "}" here */
+               {
+                       (void) RTFGetToken (info);
+                       if (!RTFCheckCM (info, rtfGroup, rtfEndGroup))
+                               RTFPanic (info, "%s: missing \"}\"", fn);
+               }
+       }
+       if (fp->rtfFNum == -1)
+               RTFPanic (info,"%s: missing font number", fn);
+/*
+ * Could check other pieces of structure here, too, I suppose.
+ */
+       RTFRouteToken (info);   /* feed "}" back to router */
+}
+
+
+/*
+ * The color table entries have color values of -1 if
+ * the default color should be used for the entry (only
+ * a semi-colon is given in the definition, no color values).
+ * There will be a problem if a partial entry (1 or 2 but
+ * not 3 color values) is given.  The possibility is ignored
+ * here.
+ */
+
+static void ReadColorTbl(RTF_Info *info)
+{
+       RTFColor        *cp;
+       int             cnum = 0;
+       const char      *fn = "ReadColorTbl";
+
+       TRACE("\n");
+
+       for (;;)
+       {
+               (void) RTFGetToken (info);
+               if (RTFCheckCM (info, rtfGroup, rtfEndGroup))
+                       break;
+               if ((cp = New (RTFColor)) == (RTFColor *) NULL)
+                       RTFPanic (info,"%s: cannot allocate color entry", fn);
+               cp->rtfCNum = cnum++;
+               cp->rtfCRed = cp->rtfCGreen = cp->rtfCBlue = -1;
+               cp->rtfNextColor = info->colorList;
+               info->colorList = cp;
+               while (RTFCheckCM (info, rtfControl, rtfColorName))
+               {
+                       switch (info->rtfMinor)
+                       {
+                       case rtfRed:    cp->rtfCRed = info->rtfParam; break;
+                       case rtfGreen:  cp->rtfCGreen = info->rtfParam; break;
+                       case rtfBlue:   cp->rtfCBlue = info->rtfParam; break;
+                       }
+                       RTFGetToken (info);
+               }
+               if (!RTFCheckCM (info, rtfText, (int) ';'))
+                       RTFPanic (info,"%s: malformed entry", fn);
+       }
+       RTFRouteToken (info);   /* feed "}" back to router */
+}
+
+
+/*
+ * The "Normal" style definition doesn't contain any style number,
+ * all others do.  Normal style is given style rtfNormalStyleNum.
+ */
+
+static void ReadStyleSheet(RTF_Info *info)
+{
+       RTFStyle        *sp;
+       RTFStyleElt     *sep, *sepLast;
+       char            buf[rtfBufSiz], *bp;
+       const char      *fn = "ReadStyleSheet";
+
+       TRACE("\n");
+
+       for (;;)
+       {
+               (void) RTFGetToken (info);
+               if (RTFCheckCM (info, rtfGroup, rtfEndGroup))
+                       break;
+               if ((sp = New (RTFStyle)) == (RTFStyle *) NULL)
+                       RTFPanic (info,"%s: cannot allocate stylesheet entry", fn);
+               sp->rtfSName = (char *) NULL;
+               sp->rtfSNum = -1;
+               sp->rtfSType = rtfParStyle;
+               sp->rtfSAdditive = 0;
+               sp->rtfSBasedOn = rtfNoStyleNum;
+               sp->rtfSNextPar = -1;
+               sp->rtfSSEList = sepLast = (RTFStyleElt *) NULL;
+               sp->rtfNextStyle = info->styleList;
+               sp->rtfExpanding = 0;
+               info->styleList = sp;
+               if (!RTFCheckCM (info, rtfGroup, rtfBeginGroup))
+                       RTFPanic (info,"%s: missing \"{\"", fn);
+               for (;;)
+               {
+                       (void) RTFGetToken (info);
+                       if (info->rtfClass == rtfEOF
+                               || RTFCheckCM (info, rtfText, ';'))
+                               break;
+                       if (info->rtfClass == rtfControl)
+                       {
+                               if (RTFCheckMM (info, rtfSpecialChar, rtfOptDest))
+                                       continue;       /* ignore "\*" */
+                               if (RTFCheckMM (info, rtfParAttr, rtfStyleNum))
+                               {
+                                       sp->rtfSNum = info->rtfParam;
+                                       sp->rtfSType = rtfParStyle;
+                                       continue;
+                               }
+                               if (RTFCheckMM (info, rtfCharAttr, rtfCharStyleNum))
+                               {
+                                       sp->rtfSNum = info->rtfParam;
+                                       sp->rtfSType = rtfCharStyle;
+                                       continue;
+                               }
+                               if (RTFCheckMM (info, rtfSectAttr, rtfSectStyleNum))
+                               {
+                                       sp->rtfSNum = info->rtfParam;
+                                       sp->rtfSType = rtfSectStyle;
+                                       continue;
+                               }
+                               if (RTFCheckMM (info, rtfStyleAttr, rtfBasedOn))
+                               {
+                                       sp->rtfSBasedOn = info->rtfParam;
+                                       continue;
+                               }
+                               if (RTFCheckMM (info, rtfStyleAttr, rtfAdditive))
+                               {
+                                       sp->rtfSAdditive = 1;
+                                       continue;
+                               }
+                               if (RTFCheckMM (info, rtfStyleAttr, rtfNext))
+                               {
+                                       sp->rtfSNextPar = info->rtfParam;
+                                       continue;
+                               }
+                               if ((sep = New (RTFStyleElt)) == (RTFStyleElt *) NULL)
+                                       RTFPanic (info,"%s: cannot allocate style element", fn);
+                               sep->rtfSEClass = info->rtfClass;
+                               sep->rtfSEMajor = info->rtfMajor;
+                               sep->rtfSEMinor = info->rtfMinor;
+                               sep->rtfSEParam = info->rtfParam;
+                               if ((sep->rtfSEText = RTFStrSave (info->rtfTextBuf))
+                                                               == (char *) NULL)
+                                       RTFPanic (info,"%s: cannot allocate style element text", fn);
+                               if (sepLast == (RTFStyleElt *) NULL)
+                                       sp->rtfSSEList = sep;   /* first element */
+                               else                            /* add to end */
+                                       sepLast->rtfNextSE = sep;
+                               sep->rtfNextSE = (RTFStyleElt *) NULL;
+                               sepLast = sep;
+                       }
+                       else if (RTFCheckCM (info, rtfGroup, rtfBeginGroup))
+                       {
+                               /*
+                                * This passes over "{\*\keycode ... }, among
+                                * other things. A temporary (perhaps) hack.
+                                */
+                               RTFSkipGroup (info);
+                               continue;
+                       }
+                       else if (info->rtfClass == rtfText)     /* style name */
+                       {
+                               bp = buf;
+                               while (info->rtfClass == rtfText)
+                               {
+                                       if (info->rtfMajor == ';')
+                                       {
+                                               /* put back for "for" loop */
+                                               (void) RTFUngetToken (info);
+                                               break;
+                                       }
+                                       *bp++ = info->rtfMajor;
+                                       (void) RTFGetToken (info);
+                               }
+                               *bp = '\0';
+                               if ((sp->rtfSName = RTFStrSave (buf)) == (char *) NULL)
+                                       RTFPanic (info, "%s: cannot allocate style name", fn);
+                       }
+                       else            /* unrecognized */
+                       {
+                               /* ignore token but announce it */
+                               RTFMsg (info, "%s: unknown token \"%s\"\n",
+                                                       fn, info->rtfTextBuf);
+                       }
+               }
+               (void) RTFGetToken (info);
+               if (!RTFCheckCM (info, rtfGroup, rtfEndGroup))
+                       RTFPanic (info, "%s: missing \"}\"", fn);
+
+               /*
+                * Check over the style structure.  A name is a must.
+                * If no style number was specified, check whether it's the
+                * Normal style (in which case it's given style number
+                * rtfNormalStyleNum).  Note that some "normal" style names
+                * just begin with "Normal" and can have other stuff following,
+                * e.g., "Normal,Times 10 point".  Ugh.
+                *
+                * Some German RTF writers use "Standard" instead of "Normal".
+                */
+               if (sp->rtfSName == (char *) NULL)
+                       RTFPanic (info,"%s: missing style name", fn);
+               if (sp->rtfSNum < 0)
+               {
+                       if (strncmp (buf, "Normal", 6) != 0
+                               && strncmp (buf, "Standard", 8) != 0)
+                               RTFPanic (info,"%s: missing style number", fn);
+                       sp->rtfSNum = rtfNormalStyleNum;
+               }
+               if (sp->rtfSNextPar == -1)      /* if \snext not given, */
+                       sp->rtfSNextPar = sp->rtfSNum;  /* next is itself */
+       }
+       RTFRouteToken (info);   /* feed "}" back to router */
+}
+
+
+static void ReadInfoGroup(RTF_Info *info)
+{
+       RTFSkipGroup (info);
+       RTFRouteToken (info);   /* feed "}" back to router */
+}
+
+
+static void ReadPictGroup(RTF_Info *info)
+{
+       RTFSkipGroup (info);
+       RTFRouteToken (info);   /* feed "}" back to router */
+}
+
+
+static void ReadObjGroup(RTF_Info *info)
+{
+       RTFSkipGroup (info);
+       RTFRouteToken (info);   /* feed "}" back to router */
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ * Routines to return pieces of stylesheet, or font or color tables.
+ * References to style 0 are mapped onto the Normal style.
+ */
+
+
+RTFStyle *RTFGetStyle(RTF_Info *info, int num)
+{
+       RTFStyle        *s;
+
+       if (num == -1)
+               return (info->styleList);
+       for (s = info->styleList; s != (RTFStyle *) NULL; s = s->rtfNextStyle)
+       {
+               if (s->rtfSNum == num)
+                       break;
+       }
+       return (s);             /* NULL if not found */
+}
+
+
+RTFFont *RTFGetFont(RTF_Info *info, int num)
+{
+       RTFFont *f;
+
+       if (num == -1)
+               return (info->fontList);
+       for (f = info->fontList; f != (RTFFont *) NULL; f = f->rtfNextFont)
+       {
+               if (f->rtfFNum == num)
+                       break;
+       }
+       return (f);             /* NULL if not found */
+}
+
+
+RTFColor *RTFGetColor(RTF_Info *info, int num)
+{
+       RTFColor        *c;
+
+       if (num == -1)
+               return (info->colorList);
+       for (c = info->colorList; c != (RTFColor *) NULL; c = c->rtfNextColor)
+       {
+               if (c->rtfCNum == num)
+                       break;
+       }
+       return (c);             /* NULL if not found */
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+
+/*
+ * Expand style n, if there is such a style.
+ */
+
+void RTFExpandStyle(RTF_Info *info, int n)
+{
+       RTFStyle        *s;
+       RTFStyleElt     *se;
+
+       TRACE("\n");
+
+       if (n == -1 || (s = RTFGetStyle (info, n)) == (RTFStyle *) NULL)
+               return;
+       if (s->rtfExpanding != 0)
+               RTFPanic (info,"Style expansion loop, style %d", n);
+       s->rtfExpanding = 1;    /* set expansion flag for loop detection */
+       /*
+        * Expand "based-on" style (unless it's the same as the current
+        * style -- Normal style usually gives itself as its own based-on
+        * style).  Based-on style expansion is done by synthesizing
+        * the token that the writer needs to see in order to trigger
+        * another style expansion, and feeding to token back through
+        * the router so the writer sees it.
+        */
+       if (n != s->rtfSBasedOn)
+       {
+               RTFSetToken (info, rtfControl, rtfParAttr, rtfStyleNum,
+                                                       s->rtfSBasedOn, "\\s");
+               RTFRouteToken (info);
+       }
+       /*
+        * Now route the tokens unique to this style.  RTFSetToken()
+        * isn't used because it would add the param value to the end
+        * of the token text, which already has it in.
+        */
+       for (se = s->rtfSSEList; se != (RTFStyleElt *) NULL; se = se->rtfNextSE)
+       {
+               info->rtfClass = se->rtfSEClass;
+               info->rtfMajor = se->rtfSEMajor;
+               info->rtfMinor = se->rtfSEMinor;
+               info->rtfParam = se->rtfSEParam;
+               (void) strcpy (info->rtfTextBuf, se->rtfSEText);
+               info->rtfTextLen = strlen (info->rtfTextBuf);
+               RTFRouteToken (info);
+       }
+       s->rtfExpanding = 0;    /* done - clear expansion flag */
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ * Control symbol lookup routines
+ */
+
+
+typedef struct RTFKey  RTFKey;
+
+struct RTFKey
+{
+       int        rtfKMajor;   /* major number */
+       int        rtfKMinor;   /* minor number */
+       const char *rtfKStr;    /* symbol name */
+       int        rtfKHash;    /* symbol name hash value */
+};
+
+/*
+ * A minor number of -1 means the token has no minor number
+ * (all valid minor numbers are >= 0).
+ */
+
+static RTFKey  rtfKey[] =
+{
+       /*
+        * Special characters
+        */
+
+       { rtfSpecialChar,       rtfIIntVersion,         "vern",         0 },
+       { rtfSpecialChar,       rtfICreateTime,         "creatim",      0 },
+       { rtfSpecialChar,       rtfIRevisionTime,       "revtim",       0 },
+       { rtfSpecialChar,       rtfIPrintTime,          "printim",      0 },
+       { rtfSpecialChar,       rtfIBackupTime,         "buptim",       0 },
+       { rtfSpecialChar,       rtfIEditTime,           "edmins",       0 },
+       { rtfSpecialChar,       rtfIYear,               "yr",           0 },
+       { rtfSpecialChar,       rtfIMonth,              "mo",           0 },
+       { rtfSpecialChar,       rtfIDay,                "dy",           0 },
+       { rtfSpecialChar,       rtfIHour,               "hr",           0 },
+       { rtfSpecialChar,       rtfIMinute,             "min",          0 },
+       { rtfSpecialChar,       rtfISecond,             "sec",          0 },
+       { rtfSpecialChar,       rtfINPages,             "nofpages",     0 },
+       { rtfSpecialChar,       rtfINWords,             "nofwords",     0 },
+       { rtfSpecialChar,       rtfINChars,             "nofchars",     0 },
+       { rtfSpecialChar,       rtfIIntID,              "id",           0 },
+
+       { rtfSpecialChar,       rtfCurHeadDate,         "chdate",       0 },
+       { rtfSpecialChar,       rtfCurHeadDateLong,     "chdpl",        0 },
+       { rtfSpecialChar,       rtfCurHeadDateAbbrev,   "chdpa",        0 },
+       { rtfSpecialChar,       rtfCurHeadTime,         "chtime",       0 },
+       { rtfSpecialChar,       rtfCurHeadPage,         "chpgn",        0 },
+       { rtfSpecialChar,       rtfSectNum,             "sectnum",      0 },
+       { rtfSpecialChar,       rtfCurFNote,            "chftn",        0 },
+       { rtfSpecialChar,       rtfCurAnnotRef,         "chatn",        0 },
+       { rtfSpecialChar,       rtfFNoteSep,            "chftnsep",     0 },
+       { rtfSpecialChar,       rtfFNoteCont,           "chftnsepc",    0 },
+       { rtfSpecialChar,       rtfCell,                "cell",         0 },
+       { rtfSpecialChar,       rtfRow,                 "row",          0 },
+       { rtfSpecialChar,       rtfPar,                 "par",          0 },
+       /* newline and carriage return are synonyms for */
+       /* \par when they are preceded by a \ character */
+       { rtfSpecialChar,       rtfPar,                 "\n",           0 },
+       { rtfSpecialChar,       rtfPar,                 "\r",           0 },
+       { rtfSpecialChar,       rtfSect,                "sect",         0 },
+       { rtfSpecialChar,       rtfPage,                "page",         0 },
+       { rtfSpecialChar,       rtfColumn,              "column",       0 },
+       { rtfSpecialChar,       rtfLine,                "line",         0 },
+       { rtfSpecialChar,       rtfSoftPage,            "softpage",     0 },
+       { rtfSpecialChar,       rtfSoftColumn,          "softcol",      0 },
+       { rtfSpecialChar,       rtfSoftLine,            "softline",     0 },
+       { rtfSpecialChar,       rtfSoftLineHt,          "softlheight",  0 },
+       { rtfSpecialChar,       rtfTab,                 "tab",          0 },
+       { rtfSpecialChar,       rtfEmDash,              "emdash",       0 },
+       { rtfSpecialChar,       rtfEnDash,              "endash",       0 },
+       { rtfSpecialChar,       rtfEmSpace,             "emspace",      0 },
+       { rtfSpecialChar,       rtfEnSpace,             "enspace",      0 },
+       { rtfSpecialChar,       rtfBullet,              "bullet",       0 },
+       { rtfSpecialChar,       rtfLQuote,              "lquote",       0 },
+       { rtfSpecialChar,       rtfRQuote,              "rquote",       0 },
+       { rtfSpecialChar,       rtfLDblQuote,           "ldblquote",    0 },
+       { rtfSpecialChar,       rtfRDblQuote,           "rdblquote",    0 },
+       { rtfSpecialChar,       rtfFormula,             "|",            0 },
+       { rtfSpecialChar,       rtfNoBrkSpace,          "~",            0 },
+       { rtfSpecialChar,       rtfNoReqHyphen,         "-",            0 },
+       { rtfSpecialChar,       rtfNoBrkHyphen,         "_",            0 },
+       { rtfSpecialChar,       rtfOptDest,             "*",            0 },
+       { rtfSpecialChar,       rtfLTRMark,             "ltrmark",      0 },
+       { rtfSpecialChar,       rtfRTLMark,             "rtlmark",      0 },
+       { rtfSpecialChar,       rtfNoWidthJoiner,       "zwj",          0 },
+       { rtfSpecialChar,       rtfNoWidthNonJoiner,    "zwnj",         0 },
+       /* is this valid? */
+       { rtfSpecialChar,       rtfCurHeadPict,         "chpict",       0 },
+
+       /*
+        * Character formatting attributes
+        */
+
+       { rtfCharAttr,  rtfPlain,               "plain",        0 },
+       { rtfCharAttr,  rtfBold,                "b",            0 },
+       { rtfCharAttr,  rtfAllCaps,             "caps",         0 },
+       { rtfCharAttr,  rtfDeleted,             "deleted",      0 },
+       { rtfCharAttr,  rtfSubScript,           "dn",           0 },
+       { rtfCharAttr,  rtfSubScrShrink,        "sub",          0 },
+       { rtfCharAttr,  rtfNoSuperSub,          "nosupersub",   0 },
+       { rtfCharAttr,  rtfExpand,              "expnd",        0 },
+       { rtfCharAttr,  rtfExpandTwips,         "expndtw",      0 },
+       { rtfCharAttr,  rtfKerning,             "kerning",      0 },
+       { rtfCharAttr,  rtfFontNum,             "f",            0 },
+       { rtfCharAttr,  rtfFontSize,            "fs",           0 },
+       { rtfCharAttr,  rtfItalic,              "i",            0 },
+       { rtfCharAttr,  rtfOutline,             "outl",         0 },
+       { rtfCharAttr,  rtfRevised,             "revised",      0 },
+       { rtfCharAttr,  rtfRevAuthor,           "revauth",      0 },
+       { rtfCharAttr,  rtfRevDTTM,             "revdttm",      0 },
+       { rtfCharAttr,  rtfSmallCaps,           "scaps",        0 },
+       { rtfCharAttr,  rtfShadow,              "shad",         0 },
+       { rtfCharAttr,  rtfStrikeThru,          "strike",       0 },
+       { rtfCharAttr,  rtfUnderline,           "ul",           0 },
+       { rtfCharAttr,  rtfDotUnderline,        "uld",          0 },
+       { rtfCharAttr,  rtfDbUnderline,         "uldb",         0 },
+       { rtfCharAttr,  rtfNoUnderline,         "ulnone",       0 },
+       { rtfCharAttr,  rtfWordUnderline,       "ulw",          0 },
+       { rtfCharAttr,  rtfSuperScript,         "up",           0 },
+       { rtfCharAttr,  rtfSuperScrShrink,      "super",        0 },
+       { rtfCharAttr,  rtfInvisible,           "v",            0 },
+       { rtfCharAttr,  rtfForeColor,           "cf",           0 },
+       { rtfCharAttr,  rtfBackColor,           "cb",           0 },
+       { rtfCharAttr,  rtfRTLChar,             "rtlch",        0 },
+       { rtfCharAttr,  rtfLTRChar,             "ltrch",        0 },
+       { rtfCharAttr,  rtfCharStyleNum,        "cs",           0 },
+       { rtfCharAttr,  rtfCharCharSet,         "cchs",         0 },
+       { rtfCharAttr,  rtfLanguage,            "lang",         0 },
+       /* this has disappeared from spec 1.2 */
+       { rtfCharAttr,  rtfGray,                "gray",         0 },
+
+       /*
+        * Paragraph formatting attributes
+        */
+
+       { rtfParAttr,   rtfParDef,              "pard",         0 },
+       { rtfParAttr,   rtfStyleNum,            "s",            0 },
+       { rtfParAttr,   rtfHyphenate,           "hyphpar",      0 },
+       { rtfParAttr,   rtfInTable,             "intbl",        0 },
+       { rtfParAttr,   rtfKeep,                "keep",         0 },
+       { rtfParAttr,   rtfNoWidowControl,      "nowidctlpar",  0 },
+       { rtfParAttr,   rtfKeepNext,            "keepn",        0 },
+       { rtfParAttr,   rtfOutlineLevel,        "level",        0 },
+       { rtfParAttr,   rtfNoLineNum,           "noline",       0 },
+       { rtfParAttr,   rtfPBBefore,            "pagebb",       0 },
+       { rtfParAttr,   rtfSideBySide,          "sbys",         0 },
+       { rtfParAttr,   rtfQuadLeft,            "ql",           0 },
+       { rtfParAttr,   rtfQuadRight,           "qr",           0 },
+       { rtfParAttr,   rtfQuadJust,            "qj",           0 },
+       { rtfParAttr,   rtfQuadCenter,          "qc",           0 },
+       { rtfParAttr,   rtfFirstIndent,         "fi",           0 },
+       { rtfParAttr,   rtfLeftIndent,          "li",           0 },
+       { rtfParAttr,   rtfRightIndent,         "ri",           0 },
+       { rtfParAttr,   rtfSpaceBefore,         "sb",           0 },
+       { rtfParAttr,   rtfSpaceAfter,          "sa",           0 },
+       { rtfParAttr,   rtfSpaceBetween,        "sl",           0 },
+       { rtfParAttr,   rtfSpaceMultiply,       "slmult",       0 },
+
+       { rtfParAttr,   rtfSubDocument,         "subdocument",  0 },
+
+       { rtfParAttr,   rtfRTLPar,              "rtlpar",       0 },
+       { rtfParAttr,   rtfLTRPar,              "ltrpar",       0 },
+
+       { rtfParAttr,   rtfTabPos,              "tx",           0 },
+       /*
+        * FrameMaker writes \tql (to mean left-justified tab, apparently)
+        * although it's not in the spec.  It's also redundant, since lj
+        * tabs are the default.
+        */
+       { rtfParAttr,   rtfTabLeft,             "tql",          0 },
+       { rtfParAttr,   rtfTabRight,            "tqr",          0 },
+       { rtfParAttr,   rtfTabCenter,           "tqc",          0 },
+       { rtfParAttr,   rtfTabDecimal,          "tqdec",        0 },
+       { rtfParAttr,   rtfTabBar,              "tb",           0 },
+       { rtfParAttr,   rtfLeaderDot,           "tldot",        0 },
+       { rtfParAttr,   rtfLeaderHyphen,        "tlhyph",       0 },
+       { rtfParAttr,   rtfLeaderUnder,         "tlul",         0 },
+       { rtfParAttr,   rtfLeaderThick,         "tlth",         0 },
+       { rtfParAttr,   rtfLeaderEqual,         "tleq",         0 },
+
+       { rtfParAttr,   rtfParLevel,            "pnlvl",        0 },
+       { rtfParAttr,   rtfParBullet,           "pnlvlblt",     0 },
+       { rtfParAttr,   rtfParSimple,           "pnlvlbody",    0 },
+       { rtfParAttr,   rtfParNumCont,          "pnlvlcont",    0 },
+       { rtfParAttr,   rtfParNumOnce,          "pnnumonce",    0 },
+       { rtfParAttr,   rtfParNumAcross,        "pnacross",     0 },
+       { rtfParAttr,   rtfParHangIndent,       "pnhang",       0 },
+       { rtfParAttr,   rtfParNumRestart,       "pnrestart",    0 },
+       { rtfParAttr,   rtfParNumCardinal,      "pncard",       0 },
+       { rtfParAttr,   rtfParNumDecimal,       "pndec",        0 },
+       { rtfParAttr,   rtfParNumULetter,       "pnucltr",      0 },
+       { rtfParAttr,   rtfParNumURoman,        "pnucrm",       0 },
+       { rtfParAttr,   rtfParNumLLetter,       "pnlcltr",      0 },
+       { rtfParAttr,   rtfParNumLRoman,        "pnlcrm",       0 },
+       { rtfParAttr,   rtfParNumOrdinal,       "pnord",        0 },
+       { rtfParAttr,   rtfParNumOrdinalText,   "pnordt",       0 },
+       { rtfParAttr,   rtfParNumBold,          "pnb",          0 },
+       { rtfParAttr,   rtfParNumItalic,        "pni",          0 },
+       { rtfParAttr,   rtfParNumAllCaps,       "pncaps",       0 },
+       { rtfParAttr,   rtfParNumSmallCaps,     "pnscaps",      0 },
+       { rtfParAttr,   rtfParNumUnder,         "pnul",         0 },
+       { rtfParAttr,   rtfParNumDotUnder,      "pnuld",        0 },
+       { rtfParAttr,   rtfParNumDbUnder,       "pnuldb",       0 },
+       { rtfParAttr,   rtfParNumNoUnder,       "pnulnone",     0 },
+       { rtfParAttr,   rtfParNumWordUnder,     "pnulw",        0 },
+       { rtfParAttr,   rtfParNumStrikethru,    "pnstrike",     0 },
+       { rtfParAttr,   rtfParNumForeColor,     "pncf",         0 },
+       { rtfParAttr,   rtfParNumFont,          "pnf",          0 },
+       { rtfParAttr,   rtfParNumFontSize,      "pnfs",         0 },
+       { rtfParAttr,   rtfParNumIndent,        "pnindent",     0 },
+       { rtfParAttr,   rtfParNumSpacing,       "pnsp",         0 },
+       { rtfParAttr,   rtfParNumInclPrev,      "pnprev",       0 },
+       { rtfParAttr,   rtfParNumCenter,        "pnqc",         0 },
+       { rtfParAttr,   rtfParNumLeft,          "pnql",         0 },
+       { rtfParAttr,   rtfParNumRight,         "pnqr",         0 },
+       { rtfParAttr,   rtfParNumStartAt,       "pnstart",      0 },
+
+       { rtfParAttr,   rtfBorderTop,           "brdrt",        0 },
+       { rtfParAttr,   rtfBorderBottom,        "brdrb",        0 },
+       { rtfParAttr,   rtfBorderLeft,          "brdrl",        0 },
+       { rtfParAttr,   rtfBorderRight,         "brdrr",        0 },
+       { rtfParAttr,   rtfBorderBetween,       "brdrbtw",      0 },
+       { rtfParAttr,   rtfBorderBar,           "brdrbar",      0 },
+       { rtfParAttr,   rtfBorderBox,           "box",          0 },
+       { rtfParAttr,   rtfBorderSingle,        "brdrs",        0 },
+       { rtfParAttr,   rtfBorderThick,         "brdrth",       0 },
+       { rtfParAttr,   rtfBorderShadow,        "brdrsh",       0 },
+       { rtfParAttr,   rtfBorderDouble,        "brdrdb",       0 },
+       { rtfParAttr,   rtfBorderDot,           "brdrdot",      0 },
+       { rtfParAttr,   rtfBorderDot,           "brdrdash",     0 },
+       { rtfParAttr,   rtfBorderHair,          "brdrhair",     0 },
+       { rtfParAttr,   rtfBorderWidth,         "brdrw",        0 },
+       { rtfParAttr,   rtfBorderColor,         "brdrcf",       0 },
+       { rtfParAttr,   rtfBorderSpace,         "brsp",         0 },
+
+       { rtfParAttr,   rtfShading,             "shading",      0 },
+       { rtfParAttr,   rtfBgPatH,              "bghoriz",      0 },
+       { rtfParAttr,   rtfBgPatV,              "bgvert",       0 },
+       { rtfParAttr,   rtfFwdDiagBgPat,        "bgfdiag",      0 },
+       { rtfParAttr,   rtfBwdDiagBgPat,        "bgbdiag",      0 },
+       { rtfParAttr,   rtfHatchBgPat,          "bgcross",      0 },
+       { rtfParAttr,   rtfDiagHatchBgPat,      "bgdcross",     0 },
+       { rtfParAttr,   rtfDarkBgPatH,          "bgdkhoriz",    0 },
+       { rtfParAttr,   rtfDarkBgPatV,          "bgdkvert",     0 },
+       { rtfParAttr,   rtfFwdDarkBgPat,        "bgdkfdiag",    0 },
+       { rtfParAttr,   rtfBwdDarkBgPat,        "bgdkbdiag",    0 },
+       { rtfParAttr,   rtfDarkHatchBgPat,      "bgdkcross",    0 },
+       { rtfParAttr,   rtfDarkDiagHatchBgPat,  "bgdkdcross",   0 },
+       { rtfParAttr,   rtfBgPatLineColor,      "cfpat",        0 },
+       { rtfParAttr,   rtfBgPatColor,          "cbpat",        0 },
+
+       /*
+        * Section formatting attributes
+        */
+
+       { rtfSectAttr,  rtfSectDef,             "sectd",        0 },
+       { rtfSectAttr,  rtfENoteHere,           "endnhere",     0 },
+       { rtfSectAttr,  rtfPrtBinFirst,         "binfsxn",      0 },
+       { rtfSectAttr,  rtfPrtBin,              "binsxn",       0 },
+       { rtfSectAttr,  rtfSectStyleNum,        "ds",           0 },
+
+       { rtfSectAttr,  rtfNoBreak,             "sbknone",      0 },
+       { rtfSectAttr,  rtfColBreak,            "sbkcol",       0 },
+       { rtfSectAttr,  rtfPageBreak,           "sbkpage",      0 },
+       { rtfSectAttr,  rtfEvenBreak,           "sbkeven",      0 },
+       { rtfSectAttr,  rtfOddBreak,            "sbkodd",       0 },
+
+       { rtfSectAttr,  rtfColumns,             "cols",         0 },
+       { rtfSectAttr,  rtfColumnSpace,         "colsx",        0 },
+       { rtfSectAttr,  rtfColumnNumber,        "colno",        0 },
+       { rtfSectAttr,  rtfColumnSpRight,       "colsr",        0 },
+       { rtfSectAttr,  rtfColumnWidth,         "colw",         0 },
+       { rtfSectAttr,  rtfColumnLine,          "linebetcol",   0 },
+
+       { rtfSectAttr,  rtfLineModulus,         "linemod",      0 },
+       { rtfSectAttr,  rtfLineDist,            "linex",        0 },
+       { rtfSectAttr,  rtfLineStarts,          "linestarts",   0 },
+       { rtfSectAttr,  rtfLineRestart,         "linerestart",  0 },
+       { rtfSectAttr,  rtfLineRestartPg,       "lineppage",    0 },
+       { rtfSectAttr,  rtfLineCont,            "linecont",     0 },
+
+       { rtfSectAttr,  rtfSectPageWid,         "pgwsxn",       0 },
+       { rtfSectAttr,  rtfSectPageHt,          "pghsxn",       0 },
+       { rtfSectAttr,  rtfSectMarginLeft,      "marglsxn",     0 },
+       { rtfSectAttr,  rtfSectMarginRight,     "margrsxn",     0 },
+       { rtfSectAttr,  rtfSectMarginTop,       "margtsxn",     0 },
+       { rtfSectAttr,  rtfSectMarginBottom,    "margbsxn",     0 },
+       { rtfSectAttr,  rtfSectMarginGutter,    "guttersxn",    0 },
+       { rtfSectAttr,  rtfSectLandscape,       "lndscpsxn",    0 },
+       { rtfSectAttr,  rtfTitleSpecial,        "titlepg",      0 },
+       { rtfSectAttr,  rtfHeaderY,             "headery",      0 },
+       { rtfSectAttr,  rtfFooterY,             "footery",      0 },
+
+       { rtfSectAttr,  rtfPageStarts,          "pgnstarts",    0 },
+       { rtfSectAttr,  rtfPageCont,            "pgncont",      0 },
+       { rtfSectAttr,  rtfPageRestart,         "pgnrestart",   0 },
+       { rtfSectAttr,  rtfPageNumRight,        "pgnx",         0 },
+       { rtfSectAttr,  rtfPageNumTop,          "pgny",         0 },
+       { rtfSectAttr,  rtfPageDecimal,         "pgndec",       0 },
+       { rtfSectAttr,  rtfPageURoman,          "pgnucrm",      0 },
+       { rtfSectAttr,  rtfPageLRoman,          "pgnlcrm",      0 },
+       { rtfSectAttr,  rtfPageULetter,         "pgnucltr",     0 },
+       { rtfSectAttr,  rtfPageLLetter,         "pgnlcltr",     0 },
+       { rtfSectAttr,  rtfPageNumHyphSep,      "pgnhnsh",      0 },
+       { rtfSectAttr,  rtfPageNumSpaceSep,     "pgnhnsp",      0 },
+       { rtfSectAttr,  rtfPageNumColonSep,     "pgnhnsc",      0 },
+       { rtfSectAttr,  rtfPageNumEmdashSep,    "pgnhnsm",      0 },
+       { rtfSectAttr,  rtfPageNumEndashSep,    "pgnhnsn",      0 },
+
+       { rtfSectAttr,  rtfTopVAlign,           "vertalt",      0 },
+       /* misspelled as "vertal" in specification 1.0 */
+       { rtfSectAttr,  rtfBottomVAlign,        "vertalb",      0 },
+       { rtfSectAttr,  rtfCenterVAlign,        "vertalc",      0 },
+       { rtfSectAttr,  rtfJustVAlign,          "vertalj",      0 },
+
+       { rtfSectAttr,  rtfRTLSect,             "rtlsect",      0 },
+       { rtfSectAttr,  rtfLTRSect,             "ltrsect",      0 },
+
+       /* I've seen these in an old spec, but not in real files... */
+       /*rtfSectAttr,  rtfNoBreak,             "nobreak",      0,*/
+       /*rtfSectAttr,  rtfColBreak,            "colbreak",     0,*/
+       /*rtfSectAttr,  rtfPageBreak,           "pagebreak",    0,*/
+       /*rtfSectAttr,  rtfEvenBreak,           "evenbreak",    0,*/
+       /*rtfSectAttr,  rtfOddBreak,            "oddbreak",     0,*/
+
+       /*
+        * Document formatting attributes
+        */
+
+       { rtfDocAttr,   rtfDefTab,              "deftab",       0 },
+       { rtfDocAttr,   rtfHyphHotZone,         "hyphhotz",     0 },
+       { rtfDocAttr,   rtfHyphConsecLines,     "hyphconsec",   0 },
+       { rtfDocAttr,   rtfHyphCaps,            "hyphcaps",     0 },
+       { rtfDocAttr,   rtfHyphAuto,            "hyphauto",     0 },
+       { rtfDocAttr,   rtfLineStart,           "linestart",    0 },
+       { rtfDocAttr,   rtfFracWidth,           "fracwidth",    0 },
+       /* \makeback was given in old version of spec, it's now */
+       /* listed as \makebackup */
+       { rtfDocAttr,   rtfMakeBackup,          "makeback",     0 },
+       { rtfDocAttr,   rtfMakeBackup,          "makebackup",   0 },
+       { rtfDocAttr,   rtfRTFDefault,          "defformat",    0 },
+       { rtfDocAttr,   rtfPSOverlay,           "psover",       0 },
+       { rtfDocAttr,   rtfDocTemplate,         "doctemp",      0 },
+       { rtfDocAttr,   rtfDefLanguage,         "deflang",      0 },
+
+       { rtfDocAttr,   rtfFENoteType,          "fet",          0 },
+       { rtfDocAttr,   rtfFNoteEndSect,        "endnotes",     0 },
+       { rtfDocAttr,   rtfFNoteEndDoc,         "enddoc",       0 },
+       { rtfDocAttr,   rtfFNoteText,           "ftntj",        0 },
+       { rtfDocAttr,   rtfFNoteBottom,         "ftnbj",        0 },
+       { rtfDocAttr,   rtfENoteEndSect,        "aendnotes",    0 },
+       { rtfDocAttr,   rtfENoteEndDoc,         "aenddoc",      0 },
+       { rtfDocAttr,   rtfENoteText,           "aftntj",       0 },
+       { rtfDocAttr,   rtfENoteBottom,         "aftnbj",       0 },
+       { rtfDocAttr,   rtfFNoteStart,          "ftnstart",     0 },
+       { rtfDocAttr,   rtfENoteStart,          "aftnstart",    0 },
+       { rtfDocAttr,   rtfFNoteRestartPage,    "ftnrstpg",     0 },
+       { rtfDocAttr,   rtfFNoteRestart,        "ftnrestart",   0 },
+       { rtfDocAttr,   rtfFNoteRestartCont,    "ftnrstcont",   0 },
+       { rtfDocAttr,   rtfENoteRestart,        "aftnrestart",  0 },
+       { rtfDocAttr,   rtfENoteRestartCont,    "aftnrstcont",  0 },
+       { rtfDocAttr,   rtfFNoteNumArabic,      "ftnnar",       0 },
+       { rtfDocAttr,   rtfFNoteNumLLetter,     "ftnnalc",      0 },
+       { rtfDocAttr,   rtfFNoteNumULetter,     "ftnnauc",      0 },
+       { rtfDocAttr,   rtfFNoteNumLRoman,      "ftnnrlc",      0 },
+       { rtfDocAttr,   rtfFNoteNumURoman,      "ftnnruc",      0 },
+       { rtfDocAttr,   rtfFNoteNumChicago,     "ftnnchi",      0 },
+       { rtfDocAttr,   rtfENoteNumArabic,      "aftnnar",      0 },
+       { rtfDocAttr,   rtfENoteNumLLetter,     "aftnnalc",     0 },
+       { rtfDocAttr,   rtfENoteNumULetter,     "aftnnauc",     0 },
+       { rtfDocAttr,   rtfENoteNumLRoman,      "aftnnrlc",     0 },
+       { rtfDocAttr,   rtfENoteNumURoman,      "aftnnruc",     0 },
+       { rtfDocAttr,   rtfENoteNumChicago,     "aftnnchi",     0 },
+
+       { rtfDocAttr,   rtfPaperWidth,          "paperw",       0 },
+       { rtfDocAttr,   rtfPaperHeight,         "paperh",       0 },
+       { rtfDocAttr,   rtfPaperSize,           "psz",          0 },
+       { rtfDocAttr,   rtfLeftMargin,          "margl",        0 },
+       { rtfDocAttr,   rtfRightMargin,         "margr",        0 },
+       { rtfDocAttr,   rtfTopMargin,           "margt",        0 },
+       { rtfDocAttr,   rtfBottomMargin,        "margb",        0 },
+       { rtfDocAttr,   rtfFacingPage,          "facingp",      0 },
+       { rtfDocAttr,   rtfGutterWid,           "gutter",       0 },
+       { rtfDocAttr,   rtfMirrorMargin,        "margmirror",   0 },
+       { rtfDocAttr,   rtfLandscape,           "landscape",    0 },
+       { rtfDocAttr,   rtfPageStart,           "pgnstart",     0 },
+       { rtfDocAttr,   rtfWidowCtrl,           "widowctrl",    0 },
+
+       { rtfDocAttr,   rtfLinkStyles,          "linkstyles",   0 },
+
+       { rtfDocAttr,   rtfNoAutoTabIndent,     "notabind",     0 },
+       { rtfDocAttr,   rtfWrapSpaces,          "wraptrsp",     0 },
+       { rtfDocAttr,   rtfPrintColorsBlack,    "prcolbl",      0 },
+       { rtfDocAttr,   rtfNoExtraSpaceRL,      "noextrasprl",  0 },
+       { rtfDocAttr,   rtfNoColumnBalance,     "nocolbal",     0 },
+       { rtfDocAttr,   rtfCvtMailMergeQuote,   "cvmme",        0 },
+       { rtfDocAttr,   rtfSuppressTopSpace,    "sprstsp",      0 },
+       { rtfDocAttr,   rtfSuppressPreParSpace, "sprsspbf",     0 },
+       { rtfDocAttr,   rtfCombineTblBorders,   "otblrul",      0 },
+       { rtfDocAttr,   rtfTranspMetafiles,     "transmf",      0 },
+       { rtfDocAttr,   rtfSwapBorders,         "swpbdr",       0 },
+       { rtfDocAttr,   rtfShowHardBreaks,      "brkfrm",       0 },
+
+       { rtfDocAttr,   rtfFormProtected,       "formprot",     0 },
+       { rtfDocAttr,   rtfAllProtected,        "allprot",      0 },
+       { rtfDocAttr,   rtfFormShading,         "formshade",    0 },
+       { rtfDocAttr,   rtfFormDisplay,         "formdisp",     0 },
+       { rtfDocAttr,   rtfPrintData,           "printdata",    0 },
+
+       { rtfDocAttr,   rtfRevProtected,        "revprot",      0 },
+       { rtfDocAttr,   rtfRevisions,           "revisions",    0 },
+       { rtfDocAttr,   rtfRevDisplay,          "revprop",      0 },
+       { rtfDocAttr,   rtfRevBar,              "revbar",       0 },
+
+       { rtfDocAttr,   rtfAnnotProtected,      "annotprot",    0 },
+
+       { rtfDocAttr,   rtfRTLDoc,              "rtldoc",       0 },
+       { rtfDocAttr,   rtfLTRDoc,              "ltrdoc",       0 },
+
+       /*
+        * Style attributes
+        */
+
+       { rtfStyleAttr, rtfAdditive,            "additive",     0 },
+       { rtfStyleAttr, rtfBasedOn,             "sbasedon",     0 },
+       { rtfStyleAttr, rtfNext,                "snext",        0 },
+
+       /*
+        * Picture attributes
+        */
+
+       { rtfPictAttr,  rtfMacQD,               "macpict",      0 },
+       { rtfPictAttr,  rtfPMMetafile,          "pmmetafile",   0 },
+       { rtfPictAttr,  rtfWinMetafile,         "wmetafile",    0 },
+       { rtfPictAttr,  rtfDevIndBitmap,        "dibitmap",     0 },
+       { rtfPictAttr,  rtfWinBitmap,           "wbitmap",      0 },
+       { rtfPictAttr,  rtfPixelBits,           "wbmbitspixel", 0 },
+       { rtfPictAttr,  rtfBitmapPlanes,        "wbmplanes",    0 },
+       { rtfPictAttr,  rtfBitmapWid,           "wbmwidthbytes", 0 },
+
+       { rtfPictAttr,  rtfPicWid,              "picw",         0 },
+       { rtfPictAttr,  rtfPicHt,               "pich",         0 },
+       { rtfPictAttr,  rtfPicGoalWid,          "picwgoal",     0 },
+       { rtfPictAttr,  rtfPicGoalHt,           "pichgoal",     0 },
+       /* these two aren't in the spec, but some writers emit them */
+       { rtfPictAttr,  rtfPicGoalWid,          "picwGoal",     0 },
+       { rtfPictAttr,  rtfPicGoalHt,           "pichGoal",     0 },
+       { rtfPictAttr,  rtfPicScaleX,           "picscalex",    0 },
+       { rtfPictAttr,  rtfPicScaleY,           "picscaley",    0 },
+       { rtfPictAttr,  rtfPicScaled,           "picscaled",    0 },
+       { rtfPictAttr,  rtfPicCropTop,          "piccropt",     0 },
+       { rtfPictAttr,  rtfPicCropBottom,       "piccropb",     0 },
+       { rtfPictAttr,  rtfPicCropLeft,         "piccropl",     0 },
+       { rtfPictAttr,  rtfPicCropRight,        "piccropr",     0 },
+
+       { rtfPictAttr,  rtfPicMFHasBitmap,      "picbmp",       0 },
+       { rtfPictAttr,  rtfPicMFBitsPerPixel,   "picbpp",       0 },
+
+       { rtfPictAttr,  rtfPicBinary,           "bin",          0 },
+
+       /*
+        * NeXT graphic attributes
+        */
+
+       { rtfNeXTGrAttr,        rtfNeXTGWidth,          "width",        0 },
+       { rtfNeXTGrAttr,        rtfNeXTGHeight,         "height",       0 },
+
+       /*
+        * Destinations
+        */
+
+       { rtfDestination,       rtfFontTbl,             "fonttbl",      0 },
+       { rtfDestination,       rtfFontAltName,         "falt",         0 },
+       { rtfDestination,       rtfEmbeddedFont,        "fonteb",       0 },
+       { rtfDestination,       rtfFontFile,            "fontfile",     0 },
+       { rtfDestination,       rtfFileTbl,             "filetbl",      0 },
+       { rtfDestination,       rtfFileInfo,            "file",         0 },
+       { rtfDestination,       rtfColorTbl,            "colortbl",     0 },
+       { rtfDestination,       rtfStyleSheet,          "stylesheet",   0 },
+       { rtfDestination,       rtfKeyCode,             "keycode",      0 },
+       { rtfDestination,       rtfRevisionTbl,         "revtbl",       0 },
+       { rtfDestination,       rtfInfo,                "info",         0 },
+       { rtfDestination,       rtfITitle,              "title",        0 },
+       { rtfDestination,       rtfISubject,            "subject",      0 },
+       { rtfDestination,       rtfIAuthor,             "author",       0 },
+       { rtfDestination,       rtfIOperator,           "operator",     0 },
+       { rtfDestination,       rtfIKeywords,           "keywords",     0 },
+       { rtfDestination,       rtfIComment,            "comment",      0 },
+       { rtfDestination,       rtfIVersion,            "version",      0 },
+       { rtfDestination,       rtfIDoccomm,            "doccomm",      0 },
+       /* \verscomm may not exist -- was seen in earlier spec version */
+       { rtfDestination,       rtfIVerscomm,           "verscomm",     0 },
+       { rtfDestination,       rtfNextFile,            "nextfile",     0 },
+       { rtfDestination,       rtfTemplate,            "template",     0 },
+       { rtfDestination,       rtfFNSep,               "ftnsep",       0 },
+       { rtfDestination,       rtfFNContSep,           "ftnsepc",      0 },
+       { rtfDestination,       rtfFNContNotice,        "ftncn",        0 },
+       { rtfDestination,       rtfENSep,               "aftnsep",      0 },
+       { rtfDestination,       rtfENContSep,           "aftnsepc",     0 },
+       { rtfDestination,       rtfENContNotice,        "aftncn",       0 },
+       { rtfDestination,       rtfPageNumLevel,        "pgnhn",        0 },
+       { rtfDestination,       rtfParNumLevelStyle,    "pnseclvl",     0 },
+       { rtfDestination,       rtfHeader,              "header",       0 },
+       { rtfDestination,       rtfFooter,              "footer",       0 },
+       { rtfDestination,       rtfHeaderLeft,          "headerl",      0 },
+       { rtfDestination,       rtfHeaderRight,         "headerr",      0 },
+       { rtfDestination,       rtfHeaderFirst,         "headerf",      0 },
+       { rtfDestination,       rtfFooterLeft,          "footerl",      0 },
+       { rtfDestination,       rtfFooterRight,         "footerr",      0 },
+       { rtfDestination,       rtfFooterFirst,         "footerf",      0 },
+       { rtfDestination,       rtfParNumText,          "pntext",       0 },
+       { rtfDestination,       rtfParNumbering,        "pn",           0 },
+       { rtfDestination,       rtfParNumTextAfter,     "pntexta",      0 },
+       { rtfDestination,       rtfParNumTextBefore,    "pntextb",      0 },
+       { rtfDestination,       rtfBookmarkStart,       "bkmkstart",    0 },
+       { rtfDestination,       rtfBookmarkEnd,         "bkmkend",      0 },
+       { rtfDestination,       rtfPict,                "pict",         0 },
+       { rtfDestination,       rtfObject,              "object",       0 },
+       { rtfDestination,       rtfObjClass,            "objclass",     0 },
+       { rtfDestination,       rtfObjName,             "objname",      0 },
+       { rtfObjAttr,   rtfObjTime,             "objtime",      0 },
+       { rtfDestination,       rtfObjData,             "objdata",      0 },
+       { rtfDestination,       rtfObjAlias,            "objalias",     0 },
+       { rtfDestination,       rtfObjSection,          "objsect",      0 },
+       /* objitem and objtopic aren't documented in the spec! */
+       { rtfDestination,       rtfObjItem,             "objitem",      0 },
+       { rtfDestination,       rtfObjTopic,            "objtopic",     0 },
+       { rtfDestination,       rtfObjResult,           "result",       0 },
+       { rtfDestination,       rtfDrawObject,          "do",           0 },
+       { rtfDestination,       rtfFootnote,            "footnote",     0 },
+       { rtfDestination,       rtfAnnotRefStart,       "atrfstart",    0 },
+       { rtfDestination,       rtfAnnotRefEnd,         "atrfend",      0 },
+       { rtfDestination,       rtfAnnotID,             "atnid",        0 },
+       { rtfDestination,       rtfAnnotAuthor,         "atnauthor",    0 },
+       { rtfDestination,       rtfAnnotation,          "annotation",   0 },
+       { rtfDestination,       rtfAnnotRef,            "atnref",       0 },
+       { rtfDestination,       rtfAnnotTime,           "atntime",      0 },
+       { rtfDestination,       rtfAnnotIcon,           "atnicn",       0 },
+       { rtfDestination,       rtfField,               "field",        0 },
+       { rtfDestination,       rtfFieldInst,           "fldinst",      0 },
+       { rtfDestination,       rtfFieldResult,         "fldrslt",      0 },
+       { rtfDestination,       rtfDataField,           "datafield",    0 },
+       { rtfDestination,       rtfIndex,               "xe",           0 },
+       { rtfDestination,       rtfIndexText,           "txe",          0 },
+       { rtfDestination,       rtfIndexRange,          "rxe",          0 },
+       { rtfDestination,       rtfTOC,                 "tc",           0 },
+       { rtfDestination,       rtfNeXTGraphic,         "NeXTGraphic",  0 },
+
+       /*
+        * Font families
+        */
+
+       { rtfFontFamily,        rtfFFNil,               "fnil",         0 },
+       { rtfFontFamily,        rtfFFRoman,             "froman",       0 },
+       { rtfFontFamily,        rtfFFSwiss,             "fswiss",       0 },
+       { rtfFontFamily,        rtfFFModern,            "fmodern",      0 },
+       { rtfFontFamily,        rtfFFScript,            "fscript",      0 },
+       { rtfFontFamily,        rtfFFDecor,             "fdecor",       0 },
+       { rtfFontFamily,        rtfFFTech,              "ftech",        0 },
+       { rtfFontFamily,        rtfFFBidirectional,     "fbidi",        0 },
+
+       /*
+        * Font attributes
+        */
+
+       { rtfFontAttr,  rtfFontCharSet,         "fcharset",     0 },
+       { rtfFontAttr,  rtfFontPitch,           "fprq",         0 },
+       { rtfFontAttr,  rtfFontCodePage,        "cpg",          0 },
+       { rtfFontAttr,  rtfFTypeNil,            "ftnil",        0 },
+       { rtfFontAttr,  rtfFTypeTrueType,       "fttruetype",   0 },
+
+       /*
+        * File table attributes
+        */
+
+       { rtfFileAttr,  rtfFileNum,             "fid",          0 },
+       { rtfFileAttr,  rtfFileRelPath,         "frelative",    0 },
+       { rtfFileAttr,  rtfFileOSNum,           "fosnum",       0 },
+
+       /*
+        * File sources
+        */
+
+       { rtfFileSource,        rtfSrcMacintosh,        "fvalidmac",    0 },
+       { rtfFileSource,        rtfSrcDOS,              "fvaliddos",    0 },
+       { rtfFileSource,        rtfSrcNTFS,             "fvalidntfs",   0 },
+       { rtfFileSource,        rtfSrcHPFS,             "fvalidhpfs",   0 },
+       { rtfFileSource,        rtfSrcNetwork,          "fnetwork",     0 },
+
+       /*
+        * Color names
+        */
+
+       { rtfColorName, rtfRed,                 "red",          0 },
+       { rtfColorName, rtfGreen,               "green",        0 },
+       { rtfColorName, rtfBlue,                "blue",         0 },
+
+       /*
+        * Charset names
+        */
+
+       { rtfCharSet,   rtfMacCharSet,          "mac",          0 },
+       { rtfCharSet,   rtfAnsiCharSet,         "ansi",         0 },
+       { rtfCharSet,   rtfPcCharSet,           "pc",           0 },
+       { rtfCharSet,   rtfPcaCharSet,          "pca",          0 },
+
+       /*
+        * Table attributes
+        */
+
+       { rtfTblAttr,   rtfRowDef,              "trowd",        0 },
+       { rtfTblAttr,   rtfRowGapH,             "trgaph",       0 },
+       { rtfTblAttr,   rtfCellPos,             "cellx",        0 },
+       { rtfTblAttr,   rtfMergeRngFirst,       "clmgf",        0 },
+       { rtfTblAttr,   rtfMergePrevious,       "clmrg",        0 },
+
+       { rtfTblAttr,   rtfRowLeft,             "trql",         0 },
+       { rtfTblAttr,   rtfRowRight,            "trqr",         0 },
+       { rtfTblAttr,   rtfRowCenter,           "trqc",         0 },
+       { rtfTblAttr,   rtfRowLeftEdge,         "trleft",       0 },
+       { rtfTblAttr,   rtfRowHt,               "trrh",         0 },
+       { rtfTblAttr,   rtfRowHeader,           "trhdr",        0 },
+       { rtfTblAttr,   rtfRowKeep,             "trkeep",       0 },
+
+       { rtfTblAttr,   rtfRTLRow,              "rtlrow",       0 },
+       { rtfTblAttr,   rtfLTRRow,              "ltrrow",       0 },
+
+       { rtfTblAttr,   rtfRowBordTop,          "trbrdrt",      0 },
+       { rtfTblAttr,   rtfRowBordLeft,         "trbrdrl",      0 },
+       { rtfTblAttr,   rtfRowBordBottom,       "trbrdrb",      0 },
+       { rtfTblAttr,   rtfRowBordRight,        "trbrdrr",      0 },
+       { rtfTblAttr,   rtfRowBordHoriz,        "trbrdrh",      0 },
+       { rtfTblAttr,   rtfRowBordVert,         "trbrdrv",      0 },
+
+       { rtfTblAttr,   rtfCellBordBottom,      "clbrdrb",      0 },
+       { rtfTblAttr,   rtfCellBordTop,         "clbrdrt",      0 },
+       { rtfTblAttr,   rtfCellBordLeft,        "clbrdrl",      0 },
+       { rtfTblAttr,   rtfCellBordRight,       "clbrdrr",      0 },
+
+       { rtfTblAttr,   rtfCellShading,         "clshdng",      0 },
+       { rtfTblAttr,   rtfCellBgPatH,          "clbghoriz",    0 },
+       { rtfTblAttr,   rtfCellBgPatV,          "clbgvert",     0 },
+       { rtfTblAttr,   rtfCellFwdDiagBgPat,    "clbgfdiag",    0 },
+       { rtfTblAttr,   rtfCellBwdDiagBgPat,    "clbgbdiag",    0 },
+       { rtfTblAttr,   rtfCellHatchBgPat,      "clbgcross",    0 },
+       { rtfTblAttr,   rtfCellDiagHatchBgPat,  "clbgdcross",   0 },
+       /*
+        * The spec lists "clbgdkhor", but the corresponding non-cell
+        * control is "bgdkhoriz".  At any rate Macintosh Word seems
+        * to accept both "clbgdkhor" and "clbgdkhoriz".
+        */
+       { rtfTblAttr,   rtfCellDarkBgPatH,      "clbgdkhoriz",  0 },
+       { rtfTblAttr,   rtfCellDarkBgPatH,      "clbgdkhor",    0 },
+       { rtfTblAttr,   rtfCellDarkBgPatV,      "clbgdkvert",   0 },
+       { rtfTblAttr,   rtfCellFwdDarkBgPat,    "clbgdkfdiag",  0 },
+       { rtfTblAttr,   rtfCellBwdDarkBgPat,    "clbgdkbdiag",  0 },
+       { rtfTblAttr,   rtfCellDarkHatchBgPat,  "clbgdkcross",  0 },
+       { rtfTblAttr,   rtfCellDarkDiagHatchBgPat, "clbgdkdcross",      0 },
+       { rtfTblAttr,   rtfCellBgPatLineColor, "clcfpat",       0 },
+       { rtfTblAttr,   rtfCellBgPatColor,      "clcbpat",      0 },
+
+       /*
+        * Field attributes
+        */
+
+       { rtfFieldAttr, rtfFieldDirty,          "flddirty",     0 },
+       { rtfFieldAttr, rtfFieldEdited,         "fldedit",      0 },
+       { rtfFieldAttr, rtfFieldLocked,         "fldlock",      0 },
+       { rtfFieldAttr, rtfFieldPrivate,        "fldpriv",      0 },
+       { rtfFieldAttr, rtfFieldAlt,            "fldalt",       0 },
+
+       /*
+        * Positioning attributes
+        */
+
+       { rtfPosAttr,   rtfAbsWid,              "absw",         0 },
+       { rtfPosAttr,   rtfAbsHt,               "absh",         0 },
+
+       { rtfPosAttr,   rtfRPosMargH,           "phmrg",        0 },
+       { rtfPosAttr,   rtfRPosPageH,           "phpg",         0 },
+       { rtfPosAttr,   rtfRPosColH,            "phcol",        0 },
+       { rtfPosAttr,   rtfPosX,                "posx",         0 },
+       { rtfPosAttr,   rtfPosNegX,             "posnegx",      0 },
+       { rtfPosAttr,   rtfPosXCenter,          "posxc",        0 },
+       { rtfPosAttr,   rtfPosXInside,          "posxi",        0 },
+       { rtfPosAttr,   rtfPosXOutSide,         "posxo",        0 },
+       { rtfPosAttr,   rtfPosXRight,           "posxr",        0 },
+       { rtfPosAttr,   rtfPosXLeft,            "posxl",        0 },
+
+       { rtfPosAttr,   rtfRPosMargV,           "pvmrg",        0 },
+       { rtfPosAttr,   rtfRPosPageV,           "pvpg",         0 },
+       { rtfPosAttr,   rtfRPosParaV,           "pvpara",       0 },
+       { rtfPosAttr,   rtfPosY,                "posy",         0 },
+       { rtfPosAttr,   rtfPosNegY,             "posnegy",      0 },
+       { rtfPosAttr,   rtfPosYInline,          "posyil",       0 },
+       { rtfPosAttr,   rtfPosYTop,             "posyt",        0 },
+       { rtfPosAttr,   rtfPosYCenter,          "posyc",        0 },
+       { rtfPosAttr,   rtfPosYBottom,          "posyb",        0 },
+
+       { rtfPosAttr,   rtfNoWrap,              "nowrap",       0 },
+       { rtfPosAttr,   rtfDistFromTextAll,     "dxfrtext",     0 },
+       { rtfPosAttr,   rtfDistFromTextX,       "dfrmtxtx",     0 },
+       { rtfPosAttr,   rtfDistFromTextY,       "dfrmtxty",     0 },
+       /* \dyfrtext no longer exists in spec 1.2, apparently */
+       /* replaced by \dfrmtextx and \dfrmtexty. */
+       { rtfPosAttr,   rtfTextDistY,           "dyfrtext",     0 },
+
+       { rtfPosAttr,   rtfDropCapLines,        "dropcapli",    0 },
+       { rtfPosAttr,   rtfDropCapType,         "dropcapt",     0 },
+
+       /*
+        * Object controls
+        */
+
+       { rtfObjAttr,   rtfObjEmb,              "objemb",       0 },
+       { rtfObjAttr,   rtfObjLink,             "objlink",      0 },
+       { rtfObjAttr,   rtfObjAutoLink,         "objautlink",   0 },
+       { rtfObjAttr,   rtfObjSubscriber,       "objsub",       0 },
+       { rtfObjAttr,   rtfObjPublisher,        "objpub",       0 },
+       { rtfObjAttr,   rtfObjICEmb,            "objicemb",     0 },
+
+       { rtfObjAttr,   rtfObjLinkSelf,         "linkself",     0 },
+       { rtfObjAttr,   rtfObjLock,             "objupdate",    0 },
+       { rtfObjAttr,   rtfObjUpdate,           "objlock",      0 },
+
+       { rtfObjAttr,   rtfObjHt,               "objh",         0 },
+       { rtfObjAttr,   rtfObjWid,              "objw",         0 },
+       { rtfObjAttr,   rtfObjSetSize,          "objsetsize",   0 },
+       { rtfObjAttr,   rtfObjAlign,            "objalign",     0 },
+       { rtfObjAttr,   rtfObjTransposeY,       "objtransy",    0 },
+       { rtfObjAttr,   rtfObjCropTop,          "objcropt",     0 },
+       { rtfObjAttr,   rtfObjCropBottom,       "objcropb",     0 },
+       { rtfObjAttr,   rtfObjCropLeft,         "objcropl",     0 },
+       { rtfObjAttr,   rtfObjCropRight,        "objcropr",     0 },
+       { rtfObjAttr,   rtfObjScaleX,           "objscalex",    0 },
+       { rtfObjAttr,   rtfObjScaleY,           "objscaley",    0 },
+
+       { rtfObjAttr,   rtfObjResRTF,           "rsltrtf",      0 },
+       { rtfObjAttr,   rtfObjResPict,          "rsltpict",     0 },
+       { rtfObjAttr,   rtfObjResBitmap,        "rsltbmp",      0 },
+       { rtfObjAttr,   rtfObjResText,          "rslttxt",      0 },
+       { rtfObjAttr,   rtfObjResMerge,         "rsltmerge",    0 },
+
+       { rtfObjAttr,   rtfObjBookmarkPubObj,   "bkmkpub",      0 },
+       { rtfObjAttr,   rtfObjPubAutoUpdate,    "pubauto",      0 },
+
+       /*
+        * Associated character formatting attributes
+        */
+
+       { rtfACharAttr, rtfACBold,              "ab",           0 },
+       { rtfACharAttr, rtfACAllCaps,           "caps",         0 },
+       { rtfACharAttr, rtfACForeColor,         "acf",          0 },
+       { rtfACharAttr, rtfACSubScript,         "adn",          0 },
+       { rtfACharAttr, rtfACExpand,            "aexpnd",       0 },
+       { rtfACharAttr, rtfACFontNum,           "af",           0 },
+       { rtfACharAttr, rtfACFontSize,          "afs",          0 },
+       { rtfACharAttr, rtfACItalic,            "ai",           0 },
+       { rtfACharAttr, rtfACLanguage,          "alang",        0 },
+       { rtfACharAttr, rtfACOutline,           "aoutl",        0 },
+       { rtfACharAttr, rtfACSmallCaps,         "ascaps",       0 },
+       { rtfACharAttr, rtfACShadow,            "ashad",        0 },
+       { rtfACharAttr, rtfACStrikeThru,        "astrike",      0 },
+       { rtfACharAttr, rtfACUnderline,         "aul",          0 },
+       { rtfACharAttr, rtfACDotUnderline,      "auld",         0 },
+       { rtfACharAttr, rtfACDbUnderline,       "auldb",        0 },
+       { rtfACharAttr, rtfACNoUnderline,       "aulnone",      0 },
+       { rtfACharAttr, rtfACWordUnderline,     "aulw",         0 },
+       { rtfACharAttr, rtfACSuperScript,       "aup",          0 },
+
+       /*
+        * Footnote attributes
+        */
+
+       { rtfFNoteAttr, rtfFNAlt,               "ftnalt",       0 },
+
+       /*
+        * Key code attributes
+        */
+
+       { rtfKeyCodeAttr,       rtfAltKey,              "alt",          0 },
+       { rtfKeyCodeAttr,       rtfShiftKey,            "shift",        0 },
+       { rtfKeyCodeAttr,       rtfControlKey,          "ctrl",         0 },
+       { rtfKeyCodeAttr,       rtfFunctionKey,         "fn",           0 },
+
+       /*
+        * Bookmark attributes
+        */
+
+       { rtfBookmarkAttr, rtfBookmarkFirstCol, "bkmkcolf",     0 },
+       { rtfBookmarkAttr, rtfBookmarkLastCol,  "bkmkcoll",     0 },
+
+       /*
+        * Index entry attributes
+        */
+
+       { rtfIndexAttr, rtfIndexNumber,         "xef",          0 },
+       { rtfIndexAttr, rtfIndexBold,           "bxe",          0 },
+       { rtfIndexAttr, rtfIndexItalic,         "ixe",          0 },
+
+       /*
+        * Table of contents attributes
+        */
+
+       { rtfTOCAttr,   rtfTOCType,             "tcf",          0 },
+       { rtfTOCAttr,   rtfTOCLevel,            "tcl",          0 },
+
+       /*
+        * Drawing object attributes
+        */
+
+       { rtfDrawAttr,  rtfDrawLock,            "dolock",       0 },
+       { rtfDrawAttr,  rtfDrawPageRelX,        "doxpage",      0 },
+       { rtfDrawAttr,  rtfDrawColumnRelX,      "dobxcolumn",   0 },
+       { rtfDrawAttr,  rtfDrawMarginRelX,      "dobxmargin",   0 },
+       { rtfDrawAttr,  rtfDrawPageRelY,        "dobypage",     0 },
+       { rtfDrawAttr,  rtfDrawColumnRelY,      "dobycolumn",   0 },
+       { rtfDrawAttr,  rtfDrawMarginRelY,      "dobymargin",   0 },
+       { rtfDrawAttr,  rtfDrawHeight,          "dobhgt",       0 },
+
+       { rtfDrawAttr,  rtfDrawBeginGroup,      "dpgroup",      0 },
+       { rtfDrawAttr,  rtfDrawGroupCount,      "dpcount",      0 },
+       { rtfDrawAttr,  rtfDrawEndGroup,        "dpendgroup",   0 },
+       { rtfDrawAttr,  rtfDrawArc,             "dparc",        0 },
+       { rtfDrawAttr,  rtfDrawCallout,         "dpcallout",    0 },
+       { rtfDrawAttr,  rtfDrawEllipse,         "dpellipse",    0 },
+       { rtfDrawAttr,  rtfDrawLine,            "dpline",       0 },
+       { rtfDrawAttr,  rtfDrawPolygon,         "dppolygon",    0 },
+       { rtfDrawAttr,  rtfDrawPolyLine,        "dppolyline",   0 },
+       { rtfDrawAttr,  rtfDrawRect,            "dprect",       0 },
+       { rtfDrawAttr,  rtfDrawTextBox,         "dptxbx",       0 },
+
+       { rtfDrawAttr,  rtfDrawOffsetX,         "dpx",          0 },
+       { rtfDrawAttr,  rtfDrawSizeX,           "dpxsize",      0 },
+       { rtfDrawAttr,  rtfDrawOffsetY,         "dpy",          0 },
+       { rtfDrawAttr,  rtfDrawSizeY,           "dpysize",      0 },
+
+       { rtfDrawAttr,  rtfCOAngle,             "dpcoa",        0 },
+       { rtfDrawAttr,  rtfCOAccentBar,         "dpcoaccent",   0 },
+       { rtfDrawAttr,  rtfCOBestFit,           "dpcobestfit",  0 },
+       { rtfDrawAttr,  rtfCOBorder,            "dpcoborder",   0 },
+       { rtfDrawAttr,  rtfCOAttachAbsDist,     "dpcodabs",     0 },
+       { rtfDrawAttr,  rtfCOAttachBottom,      "dpcodbottom",  0 },
+       { rtfDrawAttr,  rtfCOAttachCenter,      "dpcodcenter",  0 },
+       { rtfDrawAttr,  rtfCOAttachTop,         "dpcodtop",     0 },
+       { rtfDrawAttr,  rtfCOLength,            "dpcolength",   0 },
+       { rtfDrawAttr,  rtfCONegXQuadrant,      "dpcominusx",   0 },
+       { rtfDrawAttr,  rtfCONegYQuadrant,      "dpcominusy",   0 },
+       { rtfDrawAttr,  rtfCOOffset,            "dpcooffset",   0 },
+       { rtfDrawAttr,  rtfCOAttachSmart,       "dpcosmarta",   0 },
+       { rtfDrawAttr,  rtfCODoubleLine,        "dpcotdouble",  0 },
+       { rtfDrawAttr,  rtfCORightAngle,        "dpcotright",   0 },
+       { rtfDrawAttr,  rtfCOSingleLine,        "dpcotsingle",  0 },
+       { rtfDrawAttr,  rtfCOTripleLine,        "dpcottriple",  0 },
+
+       { rtfDrawAttr,  rtfDrawTextBoxMargin,   "dptxbxmar",    0 },
+       { rtfDrawAttr,  rtfDrawTextBoxText,     "dptxbxtext",   0 },
+       { rtfDrawAttr,  rtfDrawRoundRect,       "dproundr",     0 },
+
+       { rtfDrawAttr,  rtfDrawPointX,          "dpptx",        0 },
+       { rtfDrawAttr,  rtfDrawPointY,          "dppty",        0 },
+       { rtfDrawAttr,  rtfDrawPolyCount,       "dppolycount",  0 },
+
+       { rtfDrawAttr,  rtfDrawArcFlipX,        "dparcflipx",   0 },
+       { rtfDrawAttr,  rtfDrawArcFlipY,        "dparcflipy",   0 },
+
+       { rtfDrawAttr,  rtfDrawLineBlue,        "dplinecob",    0 },
+       { rtfDrawAttr,  rtfDrawLineGreen,       "dplinecog",    0 },
+       { rtfDrawAttr,  rtfDrawLineRed,         "dplinecor",    0 },
+       { rtfDrawAttr,  rtfDrawLinePalette,     "dplinepal",    0 },
+       { rtfDrawAttr,  rtfDrawLineDashDot,     "dplinedado",   0 },
+       { rtfDrawAttr,  rtfDrawLineDashDotDot,  "dplinedadodo", 0 },
+       { rtfDrawAttr,  rtfDrawLineDash,        "dplinedash",   0 },
+       { rtfDrawAttr,  rtfDrawLineDot,         "dplinedot",    0 },
+       { rtfDrawAttr,  rtfDrawLineGray,        "dplinegray",   0 },
+       { rtfDrawAttr,  rtfDrawLineHollow,      "dplinehollow", 0 },
+       { rtfDrawAttr,  rtfDrawLineSolid,       "dplinesolid",  0 },
+       { rtfDrawAttr,  rtfDrawLineWidth,       "dplinew",      0 },
+
+       { rtfDrawAttr,  rtfDrawHollowEndArrow,  "dpaendhol",    0 },
+       { rtfDrawAttr,  rtfDrawEndArrowLength,  "dpaendl",      0 },
+       { rtfDrawAttr,  rtfDrawSolidEndArrow,   "dpaendsol",    0 },
+       { rtfDrawAttr,  rtfDrawEndArrowWidth,   "dpaendw",      0 },
+       { rtfDrawAttr,  rtfDrawHollowStartArrow,"dpastarthol",  0 },
+       { rtfDrawAttr,  rtfDrawStartArrowLength,"dpastartl",    0 },
+       { rtfDrawAttr,  rtfDrawSolidStartArrow, "dpastartsol",  0 },
+       { rtfDrawAttr,  rtfDrawStartArrowWidth, "dpastartw",    0 },
+
+       { rtfDrawAttr,  rtfDrawBgFillBlue,      "dpfillbgcb",   0 },
+       { rtfDrawAttr,  rtfDrawBgFillGreen,     "dpfillbgcg",   0 },
+       { rtfDrawAttr,  rtfDrawBgFillRed,       "dpfillbgcr",   0 },
+       { rtfDrawAttr,  rtfDrawBgFillPalette,   "dpfillbgpal",  0 },
+       { rtfDrawAttr,  rtfDrawBgFillGray,      "dpfillbggray", 0 },
+       { rtfDrawAttr,  rtfDrawFgFillBlue,      "dpfillfgcb",   0 },
+       { rtfDrawAttr,  rtfDrawFgFillGreen,     "dpfillfgcg",   0 },
+       { rtfDrawAttr,  rtfDrawFgFillRed,       "dpfillfgcr",   0 },
+       { rtfDrawAttr,  rtfDrawFgFillPalette,   "dpfillfgpal",  0 },
+       { rtfDrawAttr,  rtfDrawFgFillGray,      "dpfillfggray", 0 },
+       { rtfDrawAttr,  rtfDrawFillPatIndex,    "dpfillpat",    0 },
+
+       { rtfDrawAttr,  rtfDrawShadow,          "dpshadow",     0 },
+       { rtfDrawAttr,  rtfDrawShadowXOffset,   "dpshadx",      0 },
+       { rtfDrawAttr,  rtfDrawShadowYOffset,   "dpshady",      0 },
+
+       { rtfVersion,   -1,                     "rtf",          0 },
+       { rtfDefFont,   -1,                     "deff",         0 },
+
+       { 0,            -1,                     (char *) NULL,  0 }
+};
+
+
+/*
+ * Initialize lookup table hash values.  Only need to do this once.
+ */
+
+static void LookupInit(void)
+{
+       static int      inited = 0;
+       RTFKey  *rp;
+
+       if (inited == 0)
+       {
+               for (rp = rtfKey; rp->rtfKStr != (char *) NULL; rp++)
+                       rp->rtfKHash = Hash ((char*)rp->rtfKStr);
+               ++inited;
+       }
+}
+
+
+/*
+ * Determine major and minor number of control token.  If it's
+ * not found, the class turns into rtfUnknown.
+ */
+
+static void Lookup(RTF_Info *info, char *s)
+{
+       RTFKey  *rp;
+       int     hash;
+
+       TRACE("\n");
+       ++s;                    /* skip over the leading \ character */
+       hash = Hash (s);
+       for (rp = rtfKey; rp->rtfKStr != (char *) NULL; rp++)
+       {
+               if (hash == rp->rtfKHash && strcmp (s, rp->rtfKStr) == 0)
+               {
+                       info->rtfClass = rtfControl;
+                       info->rtfMajor = rp->rtfKMajor;
+                       info->rtfMinor = rp->rtfKMinor;
+                       return;
+               }
+       }
+       info->rtfClass = rtfUnknown;
+}
+
+
+/*
+ * Compute hash value of symbol
+ */
+
+static int Hash(char *s)
+{
+       char    c;
+       int     val = 0;
+
+       while ((c = *s++) != '\0')
+               val += (int) c;
+       return (val);
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ * Memory allocation routines
+ */
+
+
+/*
+ * Return pointer to block of size bytes, or NULL if there's
+ * not enough memory available.
+ *
+ * This is called through RTFAlloc(), a define which coerces the
+ * argument to int.  This avoids the persistent problem of allocation
+ * failing under THINK C when a long is passed.
+ */
+
+char *_RTFAlloc(int size)
+{
+       return HeapAlloc(me_heap, 0, size);
+}
+
+
+/*
+ * Saves a string on the heap and returns a pointer to it.
+ */
+
+
+char *RTFStrSave(char *s)
+{
+       char    *p;
+
+       if ((p = RTFAlloc ((int) (strlen (s) + 1))) == (char *) NULL)
+               return ((char *) NULL);
+       return (strcpy (p, s));
+}
+
+
+void RTFFree(char *p)
+{
+        HeapFree(me_heap, 0, p);
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+
+/*
+ * Token comparison routines
+ */
+
+int RTFCheckCM(RTF_Info *info, int class, int major)
+{
+       return (info->rtfClass == class && info->rtfMajor == major);
+}
+
+
+int RTFCheckCMM(RTF_Info *info, int class, int major, int minor)
+{
+       return (info->rtfClass == class && info->rtfMajor == major && info->rtfMinor == minor);
+}
+
+
+int RTFCheckMM(RTF_Info *info, int major, int minor)
+{
+       return (info->rtfMajor == major && info->rtfMinor == minor);
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+
+int RTFCharToHex(char c)
+{
+       if (isupper (c))
+               c = tolower (c);
+       if (isdigit (c))
+               return (c - '0');       /* '0'..'9' */
+       return (c - 'a' + 10);          /* 'a'..'f' */
+}
+
+
+int RTFHexToChar(int i)
+{
+       if (i < 10)
+               return (i + '0');
+       return (i - 10 + 'a');
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ * RTFReadOutputMap() -- Read output translation map
+ */
+
+/*
+ * Read in an array describing the relation between the standard character set
+ * and an RTF translator's corresponding output sequences.  Each line consists
+ * of a standard character name and the output sequence for that character.
+ *
+ * outMap is an array of strings into which the sequences should be placed.
+ * It should be declared like this in the calling program:
+ *
+ *     char *outMap[rtfSC_MaxChar];
+ *
+ * reinit should be non-zero if outMap should be initialized
+ * zero otherwise.
+ *
+ */
+
+int RTFReadOutputMap(RTF_Info *info, char *outMap[], int reinit)
+{
+       unsigned int  i;
+       int  stdCode;
+
+       if (reinit)
+       {
+               for (i = 0; i < rtfSC_MaxChar; i++)
+               {
+                       outMap[i] = (char *) NULL;
+               }
+       }
+
+       for (i=0 ;i< sizeof(text_map)/sizeof(char*); i+=2)
+       {
+               const char *name = text_map[i];
+               const char *seq  = text_map[i+1];
+               stdCode = RTFStdCharCode( info, name );
+               outMap[stdCode] = (char*)seq;
+       }
+
+       return (1);
+}
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ * Open a library file.
+ */
+
+
+void RTFSetOpenLibFileProc(RTF_Info *info, FILE        *(*proc)())
+{
+       info->libFileOpen = proc;
+}
+
+
+FILE *RTFOpenLibFile (RTF_Info *info, char *file, char *mode)
+{
+       if (info->libFileOpen == NULL)
+               return ((FILE *) NULL);
+       return ((*info->libFileOpen) (file, mode));
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ * Print message.  Default is to send message to stderr
+ * but this may be overridden with RTFSetMsgProc().
+ *
+ * Message should include linefeeds as necessary.  If the default
+ * function is overridden, the overriding function may want to
+ * map linefeeds to another line ending character or sequence if
+ * the host system doesn't use linefeeds.
+ */
+
+
+void RTFMsg (RTF_Info *info, const char *fmt, ...)
+{
+       char    buf[rtfBufSiz];
+
+       va_list args;
+       va_start (args,fmt);
+       vsprintf (buf, fmt, args);
+       va_end (args);
+       MESSAGE( "%s", buf);
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+
+/*
+ * Process termination.  Print error message and exit.  Also prints
+ * current token, and current input line number and position within
+ * line if any input has been read from the current file.  (No input
+ * has been read if prevChar is EOF).
+ */
+
+static void DefaultPanicProc(RTF_Info *info, char *s)
+{
+       MESSAGE( "%s", s);
+       /*exit (1);*/
+}
+
+
+
+void RTFPanic(RTF_Info *info, const char *fmt, ...)
+{
+       char    buf[rtfBufSiz];
+
+       va_list args;
+       va_start (args,fmt);
+       vsprintf (buf, fmt, args);
+       va_end (args);
+       (void) strcat (buf, "\n");
+       if (info->prevChar != EOF && info->rtfTextBuf != (char *) NULL)
+       {
+               sprintf (buf + strlen (buf),
+                       "Last token read was \"%s\" near line %ld, position %d.\n",
+                       info->rtfTextBuf, info->rtfLineNum, info->rtfLinePos);
+       }
+       DefaultPanicProc(info, buf);
+}
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ * originally from RTF tools' text-writer.c
+ *
+ * text-writer -- RTF-to-text translation writer code.
+ *
+ * Read RTF input, write text of document (text extraction).
+ */
+
+static void    TextClass (RTF_Info *info);
+static void    ControlClass (RTF_Info *info);
+static void    Destination (RTF_Info *info);
+static void    SpecialChar (RTF_Info *info);
+static void    PutStdChar (RTF_Info *info, int stdCode);
+static void    PutLitChar (RTF_Info *info, int c);
+static void    PutLitStr (RTF_Info *info, char *s);
+
+/*
+ * Initialize the writer.
+ */
+
+void
+WriterInit (RTF_Info *info )
+{
+       RTFReadOutputMap (info, info->outMap,1);
+}
+
+
+int
+BeginFile (RTF_Info *info )
+{
+       /* install class callbacks */
+
+       RTFSetClassCallback (info, rtfText, TextClass);
+       RTFSetClassCallback (info, rtfControl, ControlClass);
+
+       return (1);
+}
+
+
+/*
+ * Write out a character.  rtfMajor contains the input character, rtfMinor
+ * contains the corresponding standard character code.
+ *
+ * If the input character isn't in the charset map, try to print some
+ * representation of it.
+ */
+
+static void
+TextClass (RTF_Info *info)
+{
+       char    buf[rtfBufSiz];
+
+       TRACE("\n");
+
+       if (info->rtfFormat == SF_TEXT)
+               PutLitChar (info, info->rtfMajor);
+       else if (info->rtfMinor != rtfSC_nothing)
+               PutStdChar (info, info->rtfMinor);
+       else
+       {
+               if (info->rtfMajor < 128)       /* in ASCII range */
+                       sprintf (buf, "[[%c]]", info->rtfMajor);
+               else
+                       sprintf (buf, "[[\\'%02x]]", info->rtfMajor);
+               PutLitStr (info, buf);
+       }
+}
+
+
+static void
+ControlClass (RTF_Info *info)
+{
+       TRACE("\n");
+
+       switch (info->rtfMajor)
+       {
+       case rtfDestination:
+               Destination (info);
+               break;
+       case rtfSpecialChar:
+               SpecialChar (info);
+               break;
+       }
+}
+
+
+/*
+ * This function notices destinations that should be ignored
+ * and skips to their ends.  This keeps, for instance, picture
+ * data from being considered as plain text.
+ */
+
+static void
+Destination (RTF_Info *info)
+{
+       TRACE("\n");
+
+       switch (info->rtfMinor)
+       {
+       case rtfPict:
+       case rtfFNContSep:
+       case rtfFNContNotice:
+       case rtfInfo:
+       case rtfIndexRange:
+       case rtfITitle:
+       case rtfISubject:
+       case rtfIAuthor:
+       case rtfIOperator:
+       case rtfIKeywords:
+       case rtfIComment:
+       case rtfIVersion:
+       case rtfIDoccomm:
+               RTFSkipGroup (info);
+               break;
+       }
+}
+
+
+/*
+ * The reason these use the rtfSC_xxx thingies instead of just writing
+ * out ' ', '-', '"', etc., is so that the mapping for these characters
+ * can be controlled by the text-map file.
+ */
+
+void SpecialChar (RTF_Info *info)
+{
+
+       TRACE("\n");
+
+       switch (info->rtfMinor)
+       {
+       case rtfPage:
+       case rtfSect:
+       case rtfRow:
+       case rtfLine:
+       case rtfPar:
+               PutLitChar (info, '\n');
+               break;
+       case rtfCell:
+               PutStdChar (info, rtfSC_space); /* make sure cells are separated */
+               break;
+       case rtfNoBrkSpace:
+               PutStdChar (info, rtfSC_nobrkspace);
+               break;
+       case rtfTab:
+               PutLitChar (info, '\t');
+               break;
+       case rtfNoBrkHyphen:
+               PutStdChar (info, rtfSC_nobrkhyphen);
+               break;
+       case rtfBullet:
+               PutStdChar (info, rtfSC_bullet);
+               break;
+       case rtfEmDash:
+               PutStdChar (info, rtfSC_emdash);
+               break;
+       case rtfEnDash:
+               PutStdChar (info, rtfSC_endash);
+               break;
+       case rtfLQuote:
+               PutStdChar (info, rtfSC_quoteleft);
+               break;
+       case rtfRQuote:
+               PutStdChar (info, rtfSC_quoteright);
+               break;
+       case rtfLDblQuote:
+               PutStdChar (info, rtfSC_quotedblleft);
+               break;
+       case rtfRDblQuote:
+               PutStdChar (info, rtfSC_quotedblright);
+               break;
+       }
+}
+
+
+/*
+ * Eventually this should keep track of the destination of the
+ * current state and only write text when in the initial state.
+ *
+ * If the output sequence is unspecified in the output map, write
+ * the character's standard name instead.  This makes map deficiencies
+ * obvious and provides incentive to fix it. :-)
+ */
+
+void PutStdChar (RTF_Info *info, int stdCode)
+{
+
+       char    *oStr = (char *) NULL;
+       char    buf[rtfBufSiz];
+
+/*     if (stdCode == rtfSC_nothing)
+               RTFPanic ("Unknown character code, logic error\n");
+*/
+       TRACE("\n");
+
+       oStr = info->outMap[stdCode];
+       if (oStr == (char *) NULL)      /* no output sequence in map */
+       {
+               sprintf (buf, "[[%s]]", RTFStdCharName (info, stdCode));
+               oStr = buf;
+       }
+       PutLitStr (info, oStr);
+}
+
+void PutLitChar (RTF_Info *info, int c)
+{
+       if( info->dwOutputCount >= ( sizeof info->OutputBuffer - 1 ) )
+               RTFFlushOutputBuffer( info );
+       info->OutputBuffer[info->dwOutputCount++] = c;
+}
+
+void RTFFlushOutputBuffer( RTF_Info *info )
+{
+       info->OutputBuffer[info->dwOutputCount] = 0;
+       SendMessageA( info->hwndEdit, EM_REPLACESEL, FALSE, (LPARAM) info->OutputBuffer );
+       info->dwOutputCount = 0;
+}
+
+static void PutLitStr (RTF_Info *info, char *str )
+{
+       int len = strlen( str );
+
+       if( ( len + info->dwOutputCount + 1 ) > sizeof info->OutputBuffer )
+               RTFFlushOutputBuffer( info );
+       if( ( len + 1 ) >= sizeof info->OutputBuffer )
+       {
+               SendMessageA( info->hwndEdit, EM_REPLACESEL, FALSE, (LPARAM) str );
+               return;
+       }
+       strcpy( &info->OutputBuffer[info->dwOutputCount], str );
+       info->dwOutputCount += len;
+}
diff --git a/reactos/lib/riched20/riched20.spec b/reactos/lib/riched20/riched20.spec
new file mode 100644 (file)
index 0000000..aa71eec
--- /dev/null
@@ -0,0 +1,9 @@
+2 extern IID_IRichEditOle
+3 extern IID_IRichEditOleCallback
+4 stdcall CreateTextServices(ptr ptr ptr)
+5 extern IID_ITextServices
+6 extern IID_ITextHost
+7 extern IID_ITextHost2
+8 stdcall REExtendedRegisterClass()
+9 stdcall RichEdit10ANSIWndProc(ptr long long long)
+10 stdcall RichEditANSIWndProc(ptr long long long)
diff --git a/reactos/lib/riched20/richole.c b/reactos/lib/riched20/richole.c
new file mode 100644 (file)
index 0000000..1c9e450
--- /dev/null
@@ -0,0 +1,266 @@
+/*
+ * RichEdit GUIDs and OLE interface
+ *
+ * Copyright 2004 by Krzysztof Foltman
+ * Copyright 2004 Aric Stewart
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <stdarg.h>
+
+#define NONAMELESSUNION
+#define NONAMELESSSTRUCT
+#define COBJMACROS
+
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "ole2.h"
+#include "richole.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(richedit);
+
+typedef struct IRichEditOleImpl {
+    IRichEditOleVtbl *lpVtbl;
+    DWORD ref;
+} IRichEditOleImpl;
+
+/* there is no way to be consistent across different sets of headers - mingw, Wine, Win32 SDK*/
+
+/* FIXME: the next 6 lines should be in textserv.h */
+#define TEXTSERV_GUID(name, l, w1, w2, b1, b2) \
+  GUID name = { l, w1, w2, {b1, b2, 0x00, 0xaa, 0x00, 0x6c, 0xad, 0xc5}}
+
+TEXTSERV_GUID(IID_ITextServices, 0x8d33f740, 0xcf58, 0x11ce, 0xa8, 0x9d);
+TEXTSERV_GUID(IID_ITextHost, 0xc5bdd8d0, 0xd26e, 0x11ce, 0xa8, 0x9e);
+TEXTSERV_GUID(IID_ITextHost2, 0xc5bdd8d0, 0xd26e, 0x11ce, 0xa8, 0x9e);
+
+static HRESULT WINAPI
+IRichEditOle_fnQueryInterface(IRichEditOle *me, REFIID riid, LPVOID *ppvObj)
+{
+    IRichEditOleImpl *This = (IRichEditOleImpl *)me;
+
+    TRACE("%p %s\n", This, debugstr_guid(riid) );
+
+    if (IsEqualGUID(riid, &IID_IUnknown) ||
+        IsEqualGUID(riid, &IID_IRichEditOle))
+    {
+        IRichEditOle_AddRef(me);
+        *ppvObj = (LPVOID) This;
+        return S_OK;
+    }
+    return E_NOINTERFACE;   
+}
+
+static ULONG WINAPI
+IRichEditOle_fnAddRef(IRichEditOle *me)
+{
+    IRichEditOleImpl *This = (IRichEditOleImpl *)me;
+    ULONG ref = InterlockedIncrement( &This->ref );
+
+    TRACE("%p ref = %lu\n", This, ref);
+
+    return ref;
+}
+
+static ULONG WINAPI
+IRichEditOle_fnRelease(IRichEditOle *me)
+{
+    IRichEditOleImpl *This = (IRichEditOleImpl *)me;
+    ULONG ref = InterlockedDecrement(&This->ref);
+
+    TRACE ("%p ref=%lu\n", This, ref);
+
+    if (!ref)
+    {
+        TRACE ("Destroying %p\n", This);
+        HeapFree(GetProcessHeap(),0,This);
+    }
+    return ref;
+}
+
+static HRESULT WINAPI
+IRichEditOle_fnActivateAs(IRichEditOle *me, REFCLSID rclsid, REFCLSID rclsidAs)
+{
+    IRichEditOleImpl *This = (IRichEditOleImpl *)me;
+    FIXME("stub %p\n",This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IRichEditOle_fnContextSensitiveHelp(IRichEditOle *me, BOOL fEnterMode)
+{
+    IRichEditOleImpl *This = (IRichEditOleImpl *)me;
+    FIXME("stub %p\n",This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IRichEditOle_fnConvertObject(IRichEditOle *me, LONG iob,
+               REFCLSID rclsidNew, LPCSTR lpstrUserTypeNew)
+{
+    IRichEditOleImpl *This = (IRichEditOleImpl *)me;
+    FIXME("stub %p\n",This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IRichEditOle_fnGetClientSite(IRichEditOle *me,
+               LPOLECLIENTSITE *lplpolesite)
+{
+    IRichEditOleImpl *This = (IRichEditOleImpl *)me;
+    FIXME("stub %p\n",This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IRichEditOle_fnGetClipboardData(IRichEditOle *me, CHARRANGE *lpchrg,
+               DWORD reco, LPDATAOBJECT *lplpdataobj)
+{
+    IRichEditOleImpl *This = (IRichEditOleImpl *)me;
+    FIXME("stub %p\n",This);
+    return E_NOTIMPL;
+}
+
+static LONG WINAPI IRichEditOle_fnGetLinkCount(IRichEditOle *me)
+{
+    IRichEditOleImpl *This = (IRichEditOleImpl *)me;
+    FIXME("stub %p\n",This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IRichEditOle_fnGetObject(IRichEditOle *me, LONG iob,
+               REOBJECT *lpreobject, DWORD dwFlags)
+{
+    IRichEditOleImpl *This = (IRichEditOleImpl *)me;
+    FIXME("stub %p\n",This);
+    return E_NOTIMPL;
+}
+
+static LONG WINAPI
+IRichEditOle_fnGetObjectCount(IRichEditOle *me)
+{
+    IRichEditOleImpl *This = (IRichEditOleImpl *)me;
+    FIXME("stub %p\n",This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IRichEditOle_fnHandsOffStorage(IRichEditOle *me, LONG iob)
+{
+    IRichEditOleImpl *This = (IRichEditOleImpl *)me;
+    FIXME("stub %p\n",This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IRichEditOle_fnImportDataObject(IRichEditOle *me, LPDATAOBJECT lpdataobj,
+               CLIPFORMAT cf, HGLOBAL hMetaPict)
+{
+    IRichEditOleImpl *This = (IRichEditOleImpl *)me;
+    FIXME("stub %p\n",This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IRichEditOle_fnInPlaceDeactivate(IRichEditOle *me)
+{
+    IRichEditOleImpl *This = (IRichEditOleImpl *)me;
+    FIXME("stub %p\n",This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IRichEditOle_fnInsertObject(IRichEditOle *me, REOBJECT *lpreobject)
+{
+    IRichEditOleImpl *This = (IRichEditOleImpl *)me;
+    FIXME("stub %p\n",This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI IRichEditOle_fnSaveCompleted(IRichEditOle *me, LONG iob,
+               LPSTORAGE lpstg)
+{
+    IRichEditOleImpl *This = (IRichEditOleImpl *)me;
+    FIXME("stub %p\n",This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IRichEditOle_fnSetDvaspect(IRichEditOle *me, LONG iob, DWORD dvaspect)
+{
+    IRichEditOleImpl *This = (IRichEditOleImpl *)me;
+    FIXME("stub %p\n",This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI IRichEditOle_fnSetHostNames(IRichEditOle *me,
+               LPCSTR lpstrContainerApp, LPCSTR lpstrContainerObj)
+{
+    IRichEditOleImpl *This = (IRichEditOleImpl *)me;
+    FIXME("stub %p\n",This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IRichEditOle_fnSetLinkAvailable(IRichEditOle *me, LONG iob, BOOL fAvailable)
+{
+    IRichEditOleImpl *This = (IRichEditOleImpl *)me;
+    FIXME("stub %p\n",This);
+    return E_NOTIMPL;
+}
+
+static IRichEditOleVtbl revt = {
+    IRichEditOle_fnQueryInterface,
+    IRichEditOle_fnAddRef,
+    IRichEditOle_fnRelease,
+    IRichEditOle_fnGetClientSite,
+    IRichEditOle_fnGetObjectCount,
+    IRichEditOle_fnGetLinkCount,
+    IRichEditOle_fnGetObject,
+    IRichEditOle_fnInsertObject,
+    IRichEditOle_fnConvertObject,
+    IRichEditOle_fnActivateAs,
+    IRichEditOle_fnSetHostNames,
+    IRichEditOle_fnSetLinkAvailable,
+    IRichEditOle_fnSetDvaspect,
+    IRichEditOle_fnHandsOffStorage,
+    IRichEditOle_fnSaveCompleted,
+    IRichEditOle_fnInPlaceDeactivate,
+    IRichEditOle_fnContextSensitiveHelp,
+    IRichEditOle_fnGetClipboardData,
+    IRichEditOle_fnImportDataObject
+};
+
+LRESULT CreateIRichEditOle(LPVOID *ppObj)
+{
+    IRichEditOleImpl *reo;
+
+    reo = HeapAlloc(GetProcessHeap(), 0, sizeof(IRichEditOleImpl));
+    if (!reo)
+        return 0;
+
+    reo->lpVtbl = &revt;
+    reo->ref = 1;
+    TRACE("Created %p\n",reo);
+    *ppObj = (LPVOID) reo;
+
+    return 1;
+}
diff --git a/reactos/lib/riched20/row.c b/reactos/lib/riched20/row.c
new file mode 100644 (file)
index 0000000..1e4e208
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * RichEdit - Operations on rows of text (rows are recreated during
+ * wrapping and are used for displaying the document, they don't keep any
+ * true document content; delete all rows, rewrap all paragraphs and 
+ * you get them back).
+ * 
+ * Copyright 2004 by Krzysztof Foltman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */ 
+
+
+#include "editor.h"
+
+ME_DisplayItem *ME_FindRowStart(ME_Context *c, ME_DisplayItem *item, 
+                                int nRelPos) {
+  ME_DisplayItem *para = ME_GetParagraph(item);
+  ME_MustBeWrapped(c, para);
+  if(nRelPos>=0) { /* if this or preceding row */
+    while(nRelPos<=0) {
+      ME_DisplayItem *item2 = ME_FindItemBack(item, diStartRowOrParagraph);
+      if (item2->type == diParagraph)
+      {
+        if (item2->member.para.prev_para == NULL)
+          return item;
+        /* if skipping to the preceding paragraph, ensure it's wrapped */
+        ME_MustBeWrapped(c, item2->member.para.prev_para);
+        item = item2;
+        continue;
+      }
+      else if (item2->type == diStartRow)
+      {
+        nRelPos++;
+        if (nRelPos>0)
+          return item;
+        item = item2;
+        continue;
+      }
+      assert(0 == "bug in FindItemBack(item, diStartRowOrParagraph)");
+      item = item2;
+    }
+    return item;
+  }
+  while(nRelPos>0) { /* if one of the next rows */
+    ME_DisplayItem *item2 = ME_FindItemFwd(item, diStartRowOrParagraph);
+    if (!item2)
+      return item;
+    if (item2->type == diParagraph)
+    {
+      if (item2->member.para.next_para == NULL)
+        return item;
+      continue;
+    }
+    item = item2;
+    nRelPos--;
+  }
+  return item;
+}
+
+/* I'm sure these functions would simplify some code in caret ops etc,
+ * I just didn't remember them when I wrote that code
+ */ 
+
+ME_DisplayItem *ME_RowStart(ME_DisplayItem *item) {
+  return ME_FindItemBackOrHere(item, diStartRow);
+}
+
+ME_DisplayItem *ME_RowEnd(ME_DisplayItem *item) {
+  ME_DisplayItem *item2 = ME_FindItemFwd(item, diStartRowOrParagraphOrEnd);
+  if (!item2) return NULL;
+  return ME_FindItemBack(item, diRun);
+}
diff --git a/reactos/lib/riched20/rtf.h b/reactos/lib/riched20/rtf.h
new file mode 100644 (file)
index 0000000..2704ae0
--- /dev/null
@@ -0,0 +1,1570 @@
+#ifndef _RTF
+#define _RTF
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "richedit.h"
+
+
+/* The following defines are automatically generated.  Do not edit. */
+
+
+/* These must be sequential beginning from zero */
+
+#define rtfSC_nothing  0
+#define rtfSC_space    1
+#define rtfSC_exclam   2
+#define rtfSC_quotedbl 3
+#define rtfSC_numbersign       4
+#define rtfSC_dollar   5
+#define rtfSC_percent  6
+#define rtfSC_ampersand        7
+#define rtfSC_quoteright       8
+#define rtfSC_parenleft        9
+#define rtfSC_parenright       10
+#define rtfSC_asterisk 11
+#define rtfSC_plus     12
+#define rtfSC_comma    13
+#define rtfSC_hyphen   14
+#define rtfSC_period   15
+#define rtfSC_slash    16
+#define rtfSC_zero     17
+#define rtfSC_one      18
+#define rtfSC_two      19
+#define rtfSC_three    20
+#define rtfSC_four     21
+#define rtfSC_five     22
+#define rtfSC_six      23
+#define rtfSC_seven    24
+#define rtfSC_eight    25
+#define rtfSC_nine     26
+#define rtfSC_colon    27
+#define rtfSC_semicolon        28
+#define rtfSC_less     29
+#define rtfSC_equal    30
+#define rtfSC_greater  31
+#define rtfSC_question 32
+#define rtfSC_at       33
+#define rtfSC_A        34
+#define rtfSC_B        35
+#define rtfSC_C        36
+#define rtfSC_D        37
+#define rtfSC_E        38
+#define rtfSC_F        39
+#define rtfSC_G        40
+#define rtfSC_H        41
+#define rtfSC_I        42
+#define rtfSC_J        43
+#define rtfSC_K        44
+#define rtfSC_L        45
+#define rtfSC_M        46
+#define rtfSC_N        47
+#define rtfSC_O        48
+#define rtfSC_P        49
+#define rtfSC_Q        50
+#define rtfSC_R        51
+#define rtfSC_S        52
+#define rtfSC_T        53
+#define rtfSC_U        54
+#define rtfSC_V        55
+#define rtfSC_W        56
+#define rtfSC_X        57
+#define rtfSC_Y        58
+#define rtfSC_Z        59
+#define rtfSC_bracketleft      60
+#define rtfSC_backslash        61
+#define rtfSC_bracketright     62
+#define rtfSC_asciicircum      63
+#define rtfSC_underscore       64
+#define rtfSC_quoteleft        65
+#define rtfSC_a        66
+#define rtfSC_b        67
+#define rtfSC_c        68
+#define rtfSC_d        69
+#define rtfSC_e        70
+#define rtfSC_f        71
+#define rtfSC_g        72
+#define rtfSC_h        73
+#define rtfSC_i        74
+#define rtfSC_j        75
+#define rtfSC_k        76
+#define rtfSC_l        77
+#define rtfSC_m        78
+#define rtfSC_n        79
+#define rtfSC_o        80
+#define rtfSC_p        81
+#define rtfSC_q        82
+#define rtfSC_r        83
+#define rtfSC_s        84
+#define rtfSC_t        85
+#define rtfSC_u        86
+#define rtfSC_v        87
+#define rtfSC_w        88
+#define rtfSC_x        89
+#define rtfSC_y        90
+#define rtfSC_z        91
+#define rtfSC_braceleft        92
+#define rtfSC_bar      93
+#define rtfSC_braceright       94
+#define rtfSC_asciitilde       95
+#define rtfSC_exclamdown       96
+#define rtfSC_cent     97
+#define rtfSC_sterling 98
+#define rtfSC_fraction 99
+#define rtfSC_yen      100
+#define rtfSC_florin   101
+#define rtfSC_section  102
+#define rtfSC_currency 103
+#define rtfSC_quotedblleft     104
+#define rtfSC_guillemotleft    105
+#define rtfSC_guilsinglleft    106
+#define rtfSC_guilsinglright   107
+#define rtfSC_fi       108
+#define rtfSC_fl       109
+#define rtfSC_endash   110
+#define rtfSC_dagger   111
+#define rtfSC_daggerdbl        112
+#define rtfSC_periodcentered   113
+#define rtfSC_paragraph        114
+#define rtfSC_bullet   115
+#define rtfSC_quotesinglbase   116
+#define rtfSC_quotedblbase     117
+#define rtfSC_quotedblright    118
+#define rtfSC_guillemotright   119
+#define rtfSC_ellipsis 120
+#define rtfSC_perthousand      121
+#define rtfSC_questiondown     122
+#define rtfSC_grave    123
+#define rtfSC_acute    124
+#define rtfSC_circumflex       125
+#define rtfSC_tilde    126
+#define rtfSC_macron   127
+#define rtfSC_breve    128
+#define rtfSC_dotaccent        129
+#define rtfSC_dieresis 130
+#define rtfSC_ring     131
+#define rtfSC_cedilla  132
+#define rtfSC_hungarumlaut     133
+#define rtfSC_ogonek   134
+#define rtfSC_caron    135
+#define rtfSC_emdash   136
+#define rtfSC_AE       137
+#define rtfSC_ordfeminine      138
+#define rtfSC_Lslash   139
+#define rtfSC_Oslash   140
+#define rtfSC_OE       141
+#define rtfSC_ordmasculine     142
+#define rtfSC_ae       143
+#define rtfSC_dotlessi 144
+#define rtfSC_lslash   145
+#define rtfSC_oslash   146
+#define rtfSC_oe       147
+#define rtfSC_germandbls       148
+#define rtfSC_Aacute   149
+#define rtfSC_Acircumflex      150
+#define rtfSC_Adieresis        151
+#define rtfSC_Agrave   152
+#define rtfSC_Aring    153
+#define rtfSC_Atilde   154
+#define rtfSC_Ccedilla 155
+#define rtfSC_Eacute   156
+#define rtfSC_Ecircumflex      157
+#define rtfSC_Edieresis        158
+#define rtfSC_Egrave   159
+#define rtfSC_Eth      160
+#define rtfSC_Iacute   161
+#define rtfSC_Icircumflex      162
+#define rtfSC_Idieresis        163
+#define rtfSC_Igrave   164
+#define rtfSC_Ntilde   165
+#define rtfSC_Oacute   166
+#define rtfSC_Ocircumflex      167
+#define rtfSC_Odieresis        168
+#define rtfSC_Ograve   169
+#define rtfSC_Otilde   170
+#define rtfSC_Scaron   171
+#define rtfSC_Thorn    172
+#define rtfSC_Uacute   173
+#define rtfSC_Ucircumflex      174
+#define rtfSC_Udieresis        175
+#define rtfSC_Ugrave   176
+#define rtfSC_Yacute   177
+#define rtfSC_Ydieresis        178
+#define rtfSC_aacute   179
+#define rtfSC_acircumflex      180
+#define rtfSC_adieresis        181
+#define rtfSC_agrave   182
+#define rtfSC_aring    183
+#define rtfSC_atilde   184
+#define rtfSC_brokenbar        185
+#define rtfSC_ccedilla 186
+#define rtfSC_copyright        187
+#define rtfSC_degree   188
+#define rtfSC_divide   189
+#define rtfSC_eacute   190
+#define rtfSC_ecircumflex      191
+#define rtfSC_edieresis        192
+#define rtfSC_egrave   193
+#define rtfSC_eth      194
+#define rtfSC_iacute   195
+#define rtfSC_icircumflex      196
+#define rtfSC_idieresis        197
+#define rtfSC_igrave   198
+#define rtfSC_logicalnot       199
+#define rtfSC_minus    200
+#define rtfSC_multiply 201
+#define rtfSC_ntilde   202
+#define rtfSC_oacute   203
+#define rtfSC_ocircumflex      204
+#define rtfSC_odieresis        205
+#define rtfSC_ograve   206
+#define rtfSC_onehalf  207
+#define rtfSC_onequarter       208
+#define rtfSC_onesuperior      209
+#define rtfSC_otilde   210
+#define rtfSC_plusminus        211
+#define rtfSC_registered       212
+#define rtfSC_thorn    213
+#define rtfSC_threequarters    214
+#define rtfSC_threesuperior    215
+#define rtfSC_trademark        216
+#define rtfSC_twosuperior      217
+#define rtfSC_uacute   218
+#define rtfSC_ucircumflex      219
+#define rtfSC_udieresis        220
+#define rtfSC_ugrave   221
+#define rtfSC_yacute   222
+#define rtfSC_ydieresis        223
+#define rtfSC_Alpha    224
+#define rtfSC_Beta     225
+#define rtfSC_Chi      226
+#define rtfSC_Delta    227
+#define rtfSC_Epsilon  228
+#define rtfSC_Phi      229
+#define rtfSC_Gamma    230
+#define rtfSC_Eta      231
+#define rtfSC_Iota     232
+#define rtfSC_Kappa    233
+#define rtfSC_Lambda   234
+#define rtfSC_Mu       235
+#define rtfSC_Nu       236
+#define rtfSC_Omicron  237
+#define rtfSC_Pi       238
+#define rtfSC_Theta    239
+#define rtfSC_Rho      240
+#define rtfSC_Sigma    241
+#define rtfSC_Tau      242
+#define rtfSC_Upsilon  243
+#define rtfSC_varUpsilon       244
+#define rtfSC_Omega    245
+#define rtfSC_Xi       246
+#define rtfSC_Psi      247
+#define rtfSC_Zeta     248
+#define rtfSC_alpha    249
+#define rtfSC_beta     250
+#define rtfSC_chi      251
+#define rtfSC_delta    252
+#define rtfSC_epsilon  253
+#define rtfSC_phi      254
+#define rtfSC_varphi   255
+#define rtfSC_gamma    256
+#define rtfSC_eta      257
+#define rtfSC_iota     258
+#define rtfSC_kappa    259
+#define rtfSC_lambda   260
+#define rtfSC_mu       261
+#define rtfSC_nu       262
+#define rtfSC_omicron  263
+#define rtfSC_pi       264
+#define rtfSC_varpi    265
+#define rtfSC_theta    266
+#define rtfSC_vartheta 267
+#define rtfSC_rho      268
+#define rtfSC_sigma    269
+#define rtfSC_varsigma 270
+#define rtfSC_tau      271
+#define rtfSC_upsilon  272
+#define rtfSC_omega    273
+#define rtfSC_xi       274
+#define rtfSC_psi      275
+#define rtfSC_zeta     276
+#define rtfSC_nobrkspace       277
+#define rtfSC_nobrkhyphen      278
+#define rtfSC_lessequal        279
+#define rtfSC_greaterequal     280
+#define rtfSC_infinity 281
+#define rtfSC_integral 282
+#define rtfSC_notequal 283
+#define rtfSC_radical  284
+#define rtfSC_radicalex        285
+#define rtfSC_approxequal      286
+#define rtfSC_apple    287
+#define rtfSC_partialdiff      288
+#define rtfSC_opthyphen        289
+#define rtfSC_formula  290
+#define rtfSC_lozenge  291
+#define rtfSC_universal        292
+#define rtfSC_existential      293
+#define rtfSC_suchthat 294
+#define rtfSC_congruent        295
+#define rtfSC_therefore        296
+#define rtfSC_perpendicular    297
+#define rtfSC_minute   298
+#define rtfSC_club     299
+#define rtfSC_diamond  300
+#define rtfSC_heart    301
+#define rtfSC_spade    302
+#define rtfSC_arrowboth        303
+#define rtfSC_arrowleft        304
+#define rtfSC_arrowup  305
+#define rtfSC_arrowright       306
+#define rtfSC_arrowdown        307
+#define rtfSC_second   308
+#define rtfSC_proportional     309
+#define rtfSC_equivalence      310
+#define rtfSC_arrowvertex      311
+#define rtfSC_arrowhorizex     312
+#define rtfSC_carriagereturn   313
+#define rtfSC_aleph    314
+#define rtfSC_Ifraktur 315
+#define rtfSC_Rfraktur 316
+#define rtfSC_weierstrass      317
+#define rtfSC_circlemultiply   318
+#define rtfSC_circleplus       319
+#define rtfSC_emptyset 320
+#define rtfSC_intersection     321
+#define rtfSC_union    322
+#define rtfSC_propersuperset   323
+#define rtfSC_reflexsuperset   324
+#define rtfSC_notsubset        325
+#define rtfSC_propersubset     326
+#define rtfSC_reflexsubset     327
+#define rtfSC_element  328
+#define rtfSC_notelement       329
+#define rtfSC_angle    330
+#define rtfSC_gradient 331
+#define rtfSC_product  332
+#define rtfSC_logicaland       333
+#define rtfSC_logicalor        334
+#define rtfSC_arrowdblboth     335
+#define rtfSC_arrowdblleft     336
+#define rtfSC_arrowdblup       337
+#define rtfSC_arrowdblright    338
+#define rtfSC_arrowdbldown     339
+#define rtfSC_angleleft        340
+#define rtfSC_registersans     341
+#define rtfSC_copyrightsans    342
+#define rtfSC_trademarksans    343
+#define rtfSC_angleright       344
+#define rtfSC_mathplus 345
+#define rtfSC_mathminus        346
+#define rtfSC_mathasterisk     347
+#define rtfSC_mathnumbersign   348
+#define rtfSC_dotmath  349
+#define rtfSC_mathequal        350
+#define rtfSC_mathtilde        351
+
+#define rtfSC_MaxChar  352
+/*
+ * rtf.h - RTF document processing stuff.  Release 1.10.
+ */
+
+
+/*
+ * Twentieths of a point (twips) per inch (Many RTF measurements
+ * are in twips per inch (tpi) units).  Assumes 72 points/inch.
+ */
+
+# define       rtfTpi          1440
+
+/*
+ * RTF buffer size (avoids BUFSIZ, which differs across systems)
+ */
+
+# define       rtfBufSiz       1024
+
+/*
+ * Tokens are associated with up to three classification numbers:
+ *
+ * Class number: Broadest (least detailed) breakdown.  For programs
+ *     that only care about gross token distinctions.
+ * Major/minor numbers: Within their class, tokens have a major
+ *     number, and may also have a minor number to further
+ *     distinquish tokens with the same major number.
+ *
+ *     *** Class, major and minor token numbers are all >= 0 ***
+ *
+ * Tokens that can't be classified are put in the "unknown" class.
+ * For such, the major and minor numbers are meaningless, although
+ * rtfTextBuf may be of interest then.
+ *
+ * Text tokens are a single character, and the major number indicates
+ * the character value (note: can be non-ascii, i.e., greater than 127).
+ * There is no minor number.
+ *
+ * Control symbols may have a parameter value, which will be found in
+ * rtfParam.  If no parameter was given, rtfParam = rtfNoParam.
+ *
+ * RTFGetToken() return value is the class number, but it sets all the
+ * global token vars.
+ *
+ * rtfEOF is a fake token used by the reader; the writer never sees
+ * it (except in the token reader hook, if it installs one).
+ */
+
+
+# ifdef THINK_C
+# define       rtfNoParam      (-32768)        /* 16-bit max. neg. value */
+# endif
+# ifndef rtfNoParam
+# define       rtfNoParam      (-1000000)
+# endif
+
+
+
+
+/*
+ * For some reason, the no-style number is 222
+ */
+
+# define       rtfNoStyleNum           222
+# define       rtfNormalStyleNum       0
+
+
+/*
+ * Token classes (must be zero-based and sequential)
+ */
+
+# define       rtfUnknown      0
+# define       rtfGroup        1
+# define       rtfText         2
+# define       rtfControl      3
+# define       rtfEOF          4
+# define       rtfMaxClass     5       /* highest class + 1 */
+
+/*
+ * Group class major numbers
+ */
+
+# define       rtfBeginGroup   0
+# define       rtfEndGroup     1
+
+/*
+ * Control class major and minor numbers.
+ */
+
+# define       rtfVersion      0
+
+# define       rtfDefFont      1
+
+# define       rtfCharSet      2
+# define               rtfAnsiCharSet          0
+# define               rtfMacCharSet           1
+# define               rtfPcCharSet            2
+# define               rtfPcaCharSet           3
+
+
+/* destination minor numbers should be zero-based and sequential */
+
+# define       rtfDestination  3
+# define               rtfFontTbl              0
+# define               rtfFontAltName          1       /* new in 1.10 */
+# define               rtfEmbeddedFont         2       /* new in 1.10 */
+# define               rtfFontFile             3       /* new in 1.10 */
+# define               rtfFileTbl              4       /* new in 1.10 */
+# define               rtfFileInfo             5       /* new in 1.10 */
+# define               rtfColorTbl             6
+# define               rtfStyleSheet           7
+# define               rtfKeyCode              8
+# define               rtfRevisionTbl          9       /* new in 1.10 */
+# define               rtfInfo                 10
+# define               rtfITitle               11
+# define               rtfISubject             12
+# define               rtfIAuthor              13
+# define               rtfIOperator            14
+# define               rtfIKeywords            15
+# define               rtfIComment             16
+# define               rtfIVersion             17
+# define               rtfIDoccomm             18
+# define               rtfIVerscomm            19
+# define               rtfNextFile             20      /* reclassified in 1.10 */
+# define               rtfTemplate             21      /* reclassified in 1.10 */
+# define               rtfFNSep                22
+# define               rtfFNContSep            23
+# define               rtfFNContNotice         24
+# define               rtfENSep                25      /* new in 1.10 */
+# define               rtfENContSep            26      /* new in 1.10 */
+# define               rtfENContNotice         27      /* new in 1.10 */
+# define               rtfPageNumLevel         28      /* new in 1.10 */
+# define               rtfParNumLevelStyle     29      /* new in 1.10 */
+# define               rtfHeader               30
+# define               rtfFooter               31
+# define               rtfHeaderLeft           32
+# define               rtfHeaderRight          33
+# define               rtfHeaderFirst          34
+# define               rtfFooterLeft           35
+# define               rtfFooterRight          36
+# define               rtfFooterFirst          37
+# define               rtfParNumText           38      /* new in 1.10 */
+# define               rtfParNumbering         39      /* new in 1.10 */
+# define               rtfParNumTextAfter      40      /* new in 1.10 */
+# define               rtfParNumTextBefore     41      /* new in 1.10 */
+# define               rtfBookmarkStart        42
+# define               rtfBookmarkEnd          43
+# define               rtfPict                 44
+# define               rtfObject               45
+# define               rtfObjClass             46
+# define               rtfObjName              47
+# define               rtfObjTime              48      /* new in 1.10 */
+# define               rtfObjData              49
+# define               rtfObjAlias             50
+# define               rtfObjSection           51
+# define               rtfObjResult            52
+# define               rtfObjItem              53      /* new in 1.10 */
+# define               rtfObjTopic             54      /* new in 1.10 */
+# define               rtfDrawObject           55      /* new in 1.10 */
+# define               rtfFootnote             56
+# define               rtfAnnotRefStart        57      /* new in 1.10 */
+# define               rtfAnnotRefEnd          58      /* new in 1.10 */
+# define               rtfAnnotID              59      /* reclassified in 1.10 */
+# define               rtfAnnotAuthor          60      /* new in 1.10 */
+# define               rtfAnnotation           61      /* reclassified in 1.10 */
+# define               rtfAnnotRef             62      /* new in 1.10 */
+# define               rtfAnnotTime            63      /* new in 1.10 */
+# define               rtfAnnotIcon            64      /* new in 1.10 */
+# define               rtfField                65
+# define               rtfFieldInst            66
+# define               rtfFieldResult          67
+# define               rtfDataField            68      /* new in 1.10 */
+# define               rtfIndex                69
+# define               rtfIndexText            70
+# define               rtfIndexRange           71
+# define               rtfTOC                  72
+# define               rtfNeXTGraphic          73
+# define               rtfMaxDestination       74      /* highest dest + 1 */
+
+# define       rtfFontFamily   4
+# define               rtfFFNil                0
+# define               rtfFFRoman              1
+# define               rtfFFSwiss              2
+# define               rtfFFModern             3
+# define               rtfFFScript             4
+# define               rtfFFDecor              5
+# define               rtfFFTech               6
+# define               rtfFFBidirectional      7       /* new in 1.10 */
+
+# define       rtfColorName    5
+# define               rtfRed                  0
+# define               rtfGreen                1
+# define               rtfBlue                 2
+
+# define       rtfSpecialChar  6
+       /* special chars seen in \info destination */
+# define               rtfIIntVersion          0
+# define               rtfICreateTime          1
+# define               rtfIRevisionTime        2
+# define               rtfIPrintTime           3
+# define               rtfIBackupTime          4
+# define               rtfIEditTime            5
+# define               rtfIYear                6
+# define               rtfIMonth               7
+# define               rtfIDay                 8
+# define               rtfIHour                9
+# define               rtfIMinute              10
+# define               rtfISecond              11      /* new in 1.10 */
+# define               rtfINPages              12
+# define               rtfINWords              13
+# define               rtfINChars              14
+# define               rtfIIntID               15
+       /* other special chars */
+# define               rtfCurHeadDate          16
+# define               rtfCurHeadDateLong      17
+# define               rtfCurHeadDateAbbrev    18
+# define               rtfCurHeadTime          19
+# define               rtfCurHeadPage          20
+# define               rtfSectNum              21      /* new in 1.10 */
+# define               rtfCurFNote             22
+# define               rtfCurAnnotRef          23
+# define               rtfFNoteSep             24
+# define               rtfFNoteCont            25
+# define               rtfCell                 26
+# define               rtfRow                  27
+# define               rtfPar                  28
+# define               rtfSect                 29
+# define               rtfPage                 30
+# define               rtfColumn               31
+# define               rtfLine                 32
+# define               rtfSoftPage             33      /* new in 1.10 */
+# define               rtfSoftColumn           34      /* new in 1.10 */
+# define               rtfSoftLine             35      /* new in 1.10 */
+# define               rtfSoftLineHt           36      /* new in 1.10 */
+# define               rtfTab                  37
+# define               rtfEmDash               38
+# define               rtfEnDash               39
+# define               rtfEmSpace              40      /* new in 1.10 */
+# define               rtfEnSpace              41      /* new in 1.10 */
+# define               rtfBullet               42
+# define               rtfLQuote               43
+# define               rtfRQuote               44
+# define               rtfLDblQuote            45
+# define               rtfRDblQuote            46
+# define               rtfFormula              47
+# define               rtfNoBrkSpace           49
+# define               rtfNoReqHyphen          50
+# define               rtfNoBrkHyphen          51
+# define               rtfOptDest              52
+# define               rtfLTRMark              53      /* new in 1.10 */
+# define               rtfRTLMark              54      /* new in 1.10 */
+# define               rtfNoWidthJoiner        55      /* new in 1.10 */
+# define               rtfNoWidthNonJoiner     56      /* new in 1.10 */
+# define               rtfCurHeadPict          57      /* valid? */
+/*# define             rtfCurAnnot             58*/    /* apparently not used */
+
+# define       rtfStyleAttr    7
+# define               rtfAdditive             0       /* new in 1.10 */
+# define               rtfBasedOn              1
+# define               rtfNext                 2
+
+# define       rtfDocAttr      8
+# define               rtfDefTab               0
+# define               rtfHyphHotZone          1
+# define               rtfHyphConsecLines      2       /* new in 1.10 */
+# define               rtfHyphCaps             3       /* new in 1.10 */
+# define               rtfHyphAuto             4       /* new in 1.10 */
+# define               rtfLineStart            5
+# define               rtfFracWidth            6
+# define               rtfMakeBackup           7
+# define               rtfRTFDefault           8
+# define               rtfPSOverlay            9
+# define               rtfDocTemplate          10      /* new in 1.10 */
+# define               rtfDefLanguage          11
+# define               rtfFENoteType           12      /* new in 1.10 */
+# define               rtfFNoteEndSect         13
+# define               rtfFNoteEndDoc          14
+# define               rtfFNoteText            15
+# define               rtfFNoteBottom          16
+# define               rtfENoteEndSect         17      /* new in 1.10 */
+# define               rtfENoteEndDoc          18      /* new in 1.10 */
+# define               rtfENoteText            19      /* new in 1.10 */
+# define               rtfENoteBottom          20      /* new in 1.10 */
+# define               rtfFNoteStart           21
+# define               rtfENoteStart           22      /* new in 1.10 */
+# define               rtfFNoteRestartPage     23      /* new in 1.10 */
+# define               rtfFNoteRestart         24
+# define               rtfFNoteRestartCont     25      /* new in 1.10 */
+# define               rtfENoteRestart         26      /* new in 1.10 */
+# define               rtfENoteRestartCont     27      /* new in 1.10 */
+# define               rtfFNoteNumArabic       28      /* new in 1.10 */
+# define               rtfFNoteNumLLetter      29      /* new in 1.10 */
+# define               rtfFNoteNumULetter      30      /* new in 1.10 */
+# define               rtfFNoteNumLRoman       31      /* new in 1.10 */
+# define               rtfFNoteNumURoman       32      /* new in 1.10 */
+# define               rtfFNoteNumChicago      33      /* new in 1.10 */
+# define               rtfENoteNumArabic       34      /* new in 1.10 */
+# define               rtfENoteNumLLetter      35      /* new in 1.10 */
+# define               rtfENoteNumULetter      36      /* new in 1.10 */
+# define               rtfENoteNumLRoman       37      /* new in 1.10 */
+# define               rtfENoteNumURoman       38      /* new in 1.10 */
+# define               rtfENoteNumChicago      39      /* new in 1.10 */
+# define               rtfPaperWidth           40
+# define               rtfPaperHeight          41
+# define               rtfPaperSize            42      /* new in 1.10 */
+# define               rtfLeftMargin           43
+# define               rtfRightMargin          44
+# define               rtfTopMargin            45
+# define               rtfBottomMargin         46
+# define               rtfFacingPage           47
+# define               rtfGutterWid            48
+# define               rtfMirrorMargin         49
+# define               rtfLandscape            50
+# define               rtfPageStart            51
+# define               rtfWidowCtrl            52
+# define               rtfLinkStyles           53      /* new in 1.10 */
+# define               rtfNoAutoTabIndent      54      /* new in 1.10 */
+# define               rtfWrapSpaces           55      /* new in 1.10 */
+# define               rtfPrintColorsBlack     56      /* new in 1.10 */
+# define               rtfNoExtraSpaceRL       57      /* new in 1.10 */
+# define               rtfNoColumnBalance      58      /* new in 1.10 */
+# define               rtfCvtMailMergeQuote    59      /* new in 1.10 */
+# define               rtfSuppressTopSpace     60      /* new in 1.10 */
+# define               rtfSuppressPreParSpace  61      /* new in 1.10 */
+# define               rtfCombineTblBorders    62      /* new in 1.10 */
+# define               rtfTranspMetafiles      63      /* new in 1.10 */
+# define               rtfSwapBorders          64      /* new in 1.10 */
+# define               rtfShowHardBreaks       65      /* new in 1.10 */
+# define               rtfFormProtected        66      /* new in 1.10 */
+# define               rtfAllProtected         67      /* new in 1.10 */
+# define               rtfFormShading          68      /* new in 1.10 */
+# define               rtfFormDisplay          69      /* new in 1.10 */
+# define               rtfPrintData            70      /* new in 1.10 */
+# define               rtfRevProtected         71      /* new in 1.10 */
+# define               rtfRevisions            72
+# define               rtfRevDisplay           73
+# define               rtfRevBar               74
+# define               rtfAnnotProtected       75      /* new in 1.10 */
+# define               rtfRTLDoc               76      /* new in 1.10 */
+# define               rtfLTRDoc               77      /* new in 1.10 */
+
+# define       rtfSectAttr     9
+# define               rtfSectDef              0
+# define               rtfENoteHere            1
+# define               rtfPrtBinFirst          2
+# define               rtfPrtBin               3
+# define               rtfSectStyleNum         4       /* new in 1.10 */
+# define               rtfNoBreak              5
+# define               rtfColBreak             6
+# define               rtfPageBreak            7
+# define               rtfEvenBreak            8
+# define               rtfOddBreak             9
+# define               rtfColumns              10
+# define               rtfColumnSpace          11
+# define               rtfColumnNumber         12      /* new in 1.10 */
+# define               rtfColumnSpRight        13      /* new in 1.10 */
+# define               rtfColumnWidth          14      /* new in 1.10 */
+# define               rtfColumnLine           15
+# define               rtfLineModulus          16
+# define               rtfLineDist             17
+# define               rtfLineStarts           18
+# define               rtfLineRestart          19
+# define               rtfLineRestartPg        20
+# define               rtfLineCont             21
+# define               rtfSectPageWid          22
+# define               rtfSectPageHt           23
+# define               rtfSectMarginLeft       24
+# define               rtfSectMarginRight      25
+# define               rtfSectMarginTop        26
+# define               rtfSectMarginBottom     27
+# define               rtfSectMarginGutter     28
+# define               rtfSectLandscape        29
+# define               rtfTitleSpecial         30
+# define               rtfHeaderY              31
+# define               rtfFooterY              32
+# define               rtfPageStarts           33
+# define               rtfPageCont             34
+# define               rtfPageRestart          35
+# define               rtfPageNumRight         36      /* renamed in 1.10 */
+# define               rtfPageNumTop           37
+# define               rtfPageDecimal          38
+# define               rtfPageURoman           39
+# define               rtfPageLRoman           40
+# define               rtfPageULetter          41
+# define               rtfPageLLetter          42
+# define               rtfPageNumHyphSep       43      /* new in 1.10 */
+# define               rtfPageNumSpaceSep      44      /* new in 1.10 */
+# define               rtfPageNumColonSep      45      /* new in 1.10 */
+# define               rtfPageNumEmdashSep     46      /* new in 1.10 */
+# define               rtfPageNumEndashSep     47      /* new in 1.10 */
+# define               rtfTopVAlign            48
+# define               rtfBottomVAlign         49
+# define               rtfCenterVAlign         50
+# define               rtfJustVAlign           51
+# define               rtfRTLSect              52      /* new in 1.10 */
+# define               rtfLTRSect              53      /* new in 1.10 */
+
+# define       rtfTblAttr      10
+# define               rtfRowDef               0
+# define               rtfRowGapH              1
+# define               rtfCellPos              2
+# define               rtfMergeRngFirst        3
+# define               rtfMergePrevious        4
+# define               rtfRowLeft              5
+# define               rtfRowRight             6
+# define               rtfRowCenter            7
+# define               rtfRowLeftEdge          8
+# define               rtfRowHt                9
+# define               rtfRowHeader            10      /* new in 1.10 */
+# define               rtfRowKeep              11      /* new in 1.10 */
+# define               rtfRTLRow               12      /* new in 1.10 */
+# define               rtfLTRRow               13      /* new in 1.10 */
+# define               rtfRowBordTop           14      /* new in 1.10 */
+# define               rtfRowBordLeft          15      /* new in 1.10 */
+# define               rtfRowBordBottom        16      /* new in 1.10 */
+# define               rtfRowBordRight         17      /* new in 1.10 */
+# define               rtfRowBordHoriz         18      /* new in 1.10 */
+# define               rtfRowBordVert          19      /* new in 1.10 */
+# define               rtfCellBordBottom       20
+# define               rtfCellBordTop          21
+# define               rtfCellBordLeft         22
+# define               rtfCellBordRight        23
+# define               rtfCellShading          24
+# define               rtfCellBgPatH           25
+# define               rtfCellBgPatV           26
+# define               rtfCellFwdDiagBgPat     27
+# define               rtfCellBwdDiagBgPat     28
+# define               rtfCellHatchBgPat       29
+# define               rtfCellDiagHatchBgPat   30
+# define               rtfCellDarkBgPatH       31
+# define               rtfCellDarkBgPatV       32
+# define               rtfCellFwdDarkBgPat     33
+# define               rtfCellBwdDarkBgPat     34
+# define               rtfCellDarkHatchBgPat   35
+# define               rtfCellDarkDiagHatchBgPat 36
+# define               rtfCellBgPatLineColor   37
+# define               rtfCellBgPatColor       38
+
+# define       rtfParAttr      11
+# define               rtfParDef               0
+# define               rtfStyleNum             1
+# define               rtfHyphenate            2       /* new in 1.10 */
+# define               rtfInTable              3
+# define               rtfKeep                 4
+# define               rtfNoWidowControl       5       /* new in 1.10 */
+# define               rtfKeepNext             6
+# define               rtfOutlineLevel         7       /* new in 1.10 */
+# define               rtfNoLineNum            8
+# define               rtfPBBefore             9
+# define               rtfSideBySide           10
+# define               rtfQuadLeft             11
+# define               rtfQuadRight            12
+# define               rtfQuadJust             13
+# define               rtfQuadCenter           14
+# define               rtfFirstIndent          15
+# define               rtfLeftIndent           16
+# define               rtfRightIndent          17
+# define               rtfSpaceBefore          18
+# define               rtfSpaceAfter           19
+# define               rtfSpaceBetween         20
+# define               rtfSpaceMultiply        21      /* new in 1.10 */
+# define               rtfSubDocument          22      /* new in 1.10 */
+# define               rtfRTLPar               23      /* new in 1.10 */
+# define               rtfLTRPar               24      /* new in 1.10 */
+# define               rtfTabPos               25
+# define               rtfTabLeft              26      /* new in 1.10 */
+# define               rtfTabRight             27
+# define               rtfTabCenter            28
+# define               rtfTabDecimal           29
+# define               rtfTabBar               30
+# define               rtfLeaderDot            31
+# define               rtfLeaderHyphen         32
+# define               rtfLeaderUnder          33
+# define               rtfLeaderThick          34
+# define               rtfLeaderEqual          35
+# define               rtfParLevel             36      /* new in 1.10 */
+# define               rtfParBullet            37      /* new in 1.10 */
+# define               rtfParSimple            38      /* new in 1.10 */
+# define               rtfParNumCont           39      /* new in 1.10 */
+# define               rtfParNumOnce           40      /* new in 1.10 */
+# define               rtfParNumAcross         41      /* new in 1.10 */
+# define               rtfParHangIndent        42      /* new in 1.10 */
+# define               rtfParNumRestart        43      /* new in 1.10 */
+# define               rtfParNumCardinal       44      /* new in 1.10 */
+# define               rtfParNumDecimal        45      /* new in 1.10 */
+# define               rtfParNumULetter        46      /* new in 1.10 */
+# define               rtfParNumURoman         47      /* new in 1.10 */
+# define               rtfParNumLLetter        48      /* new in 1.10 */
+# define               rtfParNumLRoman         49      /* new in 1.10 */
+# define               rtfParNumOrdinal        50      /* new in 1.10 */
+# define               rtfParNumOrdinalText    51      /* new in 1.10 */
+# define               rtfParNumBold           52      /* new in 1.10 */
+# define               rtfParNumItalic         53      /* new in 1.10 */
+# define               rtfParNumAllCaps        54      /* new in 1.10 */
+# define               rtfParNumSmallCaps      55      /* new in 1.10 */
+# define               rtfParNumUnder          56      /* new in 1.10 */
+# define               rtfParNumDotUnder       57      /* new in 1.10 */
+# define               rtfParNumDbUnder        58      /* new in 1.10 */
+# define               rtfParNumNoUnder        59      /* new in 1.10 */
+# define               rtfParNumWordUnder      60      /* new in 1.10 */
+# define               rtfParNumStrikethru     61      /* new in 1.10 */
+# define               rtfParNumForeColor      62      /* new in 1.10 */
+# define               rtfParNumFont           63      /* new in 1.10 */
+# define               rtfParNumFontSize       64      /* new in 1.10 */
+# define               rtfParNumIndent         65      /* new in 1.10 */
+# define               rtfParNumSpacing        66      /* new in 1.10 */
+# define               rtfParNumInclPrev       67      /* new in 1.10 */
+# define               rtfParNumCenter         68      /* new in 1.10 */
+# define               rtfParNumLeft           69      /* new in 1.10 */
+# define               rtfParNumRight          70      /* new in 1.10 */
+# define               rtfParNumStartAt        71      /* new in 1.10 */
+# define               rtfBorderTop            72
+# define               rtfBorderBottom         73
+# define               rtfBorderLeft           74
+# define               rtfBorderRight          75
+# define               rtfBorderBetween        76
+# define               rtfBorderBar            77
+# define               rtfBorderBox            78
+# define               rtfBorderSingle         79
+# define               rtfBorderThick          80
+# define               rtfBorderShadow         81
+# define               rtfBorderDouble         82
+# define               rtfBorderDot            83
+# define               rtfBorderDash           84      /* new in 1.10 */
+# define               rtfBorderHair           85
+# define               rtfBorderWidth          86
+# define               rtfBorderColor          87
+# define               rtfBorderSpace          88
+# define               rtfShading              89
+# define               rtfBgPatH               90
+# define               rtfBgPatV               91
+# define               rtfFwdDiagBgPat         92
+# define               rtfBwdDiagBgPat         93
+# define               rtfHatchBgPat           94
+# define               rtfDiagHatchBgPat       95
+# define               rtfDarkBgPatH           96
+# define               rtfDarkBgPatV           97
+# define               rtfFwdDarkBgPat         98
+# define               rtfBwdDarkBgPat         99
+# define               rtfDarkHatchBgPat       100
+# define               rtfDarkDiagHatchBgPat   101
+# define               rtfBgPatLineColor       102
+# define               rtfBgPatColor           103
+
+# define       rtfCharAttr     12
+# define               rtfPlain                0
+# define               rtfBold                 1
+# define               rtfAllCaps              2
+# define               rtfDeleted              3
+# define               rtfSubScript            4
+# define               rtfSubScrShrink         5       /* new in 1.10 */
+# define               rtfNoSuperSub           6       /* new in 1.10 */
+# define               rtfExpand               7
+# define               rtfExpandTwips          8       /* new in 1.10 */
+# define               rtfKerning              9       /* new in 1.10 */
+# define               rtfFontNum              10
+# define               rtfFontSize             11
+# define               rtfItalic               12
+# define               rtfOutline              13
+# define               rtfRevised              14
+# define               rtfRevAuthor            15      /* new in 1.10 */
+# define               rtfRevDTTM              16      /* new in 1.10 */
+# define               rtfSmallCaps            17
+# define               rtfShadow               18
+# define               rtfStrikeThru           19
+# define               rtfUnderline            20
+# define               rtfDotUnderline         21      /* renamed in 1.10 */
+# define               rtfDbUnderline          22
+# define               rtfNoUnderline          23
+# define               rtfWordUnderline        24      /* renamed in 1.10 */
+# define               rtfSuperScript          25
+# define               rtfSuperScrShrink       26      /* new in 1.10 */
+# define               rtfInvisible            27
+# define               rtfForeColor            28
+# define               rtfBackColor            29
+# define               rtfRTLChar              30      /* new in 1.10 */
+# define               rtfLTRChar              31      /* new in 1.10 */
+# define               rtfCharStyleNum         32      /* new in 1.10 */
+# define               rtfCharCharSet          33      /* new in 1.10 */
+# define               rtfLanguage             34
+# define               rtfGray                 35
+
+# define       rtfPictAttr     13
+# define               rtfMacQD                0
+# define               rtfPMMetafile           1
+# define               rtfWinMetafile          2
+# define               rtfDevIndBitmap         3
+# define               rtfWinBitmap            4
+# define               rtfPixelBits            5
+# define               rtfBitmapPlanes         6
+# define               rtfBitmapWid            7
+# define               rtfPicWid               8
+# define               rtfPicHt                9
+# define               rtfPicGoalWid           10
+# define               rtfPicGoalHt            11
+# define               rtfPicScaleX            12
+# define               rtfPicScaleY            13
+# define               rtfPicScaled            14
+# define               rtfPicCropTop           15
+# define               rtfPicCropBottom        16
+# define               rtfPicCropLeft          17
+# define               rtfPicCropRight         18
+# define               rtfPicMFHasBitmap       19      /* new in 1.10 */
+# define               rtfPicMFBitsPerPixel    20      /* new in 1.10 */
+# define               rtfPicBinary            21
+
+# define       rtfBookmarkAttr 14
+# define               rtfBookmarkFirstCol     0
+# define               rtfBookmarkLastCol      1
+
+# define       rtfNeXTGrAttr   15
+# define               rtfNeXTGWidth           0
+# define               rtfNeXTGHeight          1
+
+# define       rtfFieldAttr    16
+# define               rtfFieldDirty           0
+# define               rtfFieldEdited          1
+# define               rtfFieldLocked          2
+# define               rtfFieldPrivate         3
+# define               rtfFieldAlt             4       /* new in 1.10 */
+
+# define       rtfTOCAttr      17
+# define               rtfTOCType              0
+# define               rtfTOCLevel             1
+
+# define       rtfPosAttr      18
+# define               rtfAbsWid               0
+# define               rtfAbsHt                1
+# define               rtfRPosMargH            2
+# define               rtfRPosPageH            3
+# define               rtfRPosColH             4
+# define               rtfPosX                 5
+# define               rtfPosNegX              6       /* new in 1.10 */
+# define               rtfPosXCenter           7
+# define               rtfPosXInside           8
+# define               rtfPosXOutSide          9
+# define               rtfPosXRight            10
+# define               rtfPosXLeft             11
+# define               rtfRPosMargV            12
+# define               rtfRPosPageV            13
+# define               rtfRPosParaV            14
+# define               rtfPosY                 15
+# define               rtfPosNegY              16      /* new in 1.10 */
+# define               rtfPosYInline           17
+# define               rtfPosYTop              18
+# define               rtfPosYCenter           19
+# define               rtfPosYBottom           20
+# define               rtfNoWrap               21
+# define               rtfDistFromTextAll      22      /* renamed in 1.10 */
+# define               rtfDistFromTextX        23      /* new in 1.10 */
+# define               rtfDistFromTextY        24      /* new in 1.10 */
+# define               rtfTextDistY            25
+# define               rtfDropCapLines         26      /* new in 1.10 */
+# define               rtfDropCapType          27      /* new in 1.10 */
+
+# define       rtfObjAttr      19
+# define               rtfObjEmb               0
+# define               rtfObjLink              1
+# define               rtfObjAutoLink          2
+# define               rtfObjSubscriber        3
+# define               rtfObjPublisher         4       /* new in 1.10 */
+# define               rtfObjICEmb             5
+# define               rtfObjLinkSelf          6
+# define               rtfObjLock              7
+# define               rtfObjUpdate            8       /* new in 1.10 */
+# define               rtfObjHt                9
+# define               rtfObjWid               10
+# define               rtfObjSetSize           11
+# define               rtfObjAlign             12      /* new in 1.10 */
+# define               rtfObjTransposeY        13
+# define               rtfObjCropTop           14
+# define               rtfObjCropBottom        15
+# define               rtfObjCropLeft          16
+# define               rtfObjCropRight         17
+# define               rtfObjScaleX            18
+# define               rtfObjScaleY            19
+# define               rtfObjResRTF            20
+# define               rtfObjResPict           21
+# define               rtfObjResBitmap         22
+# define               rtfObjResText           23
+# define               rtfObjResMerge          24
+# define               rtfObjBookmarkPubObj    25
+# define               rtfObjPubAutoUpdate     26
+
+# define       rtfFNoteAttr    20                      /* new in 1.10 */
+# define               rtfFNAlt                0       /* new in 1.10 */
+
+# define       rtfKeyCodeAttr  21                      /* new in 1.10 */
+# define               rtfAltKey               0       /* new in 1.10 */
+# define               rtfShiftKey             1       /* new in 1.10 */
+# define               rtfControlKey           2       /* new in 1.10 */
+# define               rtfFunctionKey          3       /* new in 1.10 */
+
+# define       rtfACharAttr    22                      /* new in 1.10 */
+# define               rtfACBold               0       /* new in 1.10 */
+# define               rtfACAllCaps            1       /* new in 1.10 */
+# define               rtfACForeColor          2       /* new in 1.10 */
+# define               rtfACSubScript          3       /* new in 1.10 */
+# define               rtfACExpand             4       /* new in 1.10 */
+# define               rtfACFontNum            5       /* new in 1.10 */
+# define               rtfACFontSize           6       /* new in 1.10 */
+# define               rtfACItalic             7       /* new in 1.10 */
+# define               rtfACLanguage           8       /* new in 1.10 */
+# define               rtfACOutline            9       /* new in 1.10 */
+# define               rtfACSmallCaps          10      /* new in 1.10 */
+# define               rtfACShadow             11      /* new in 1.10 */
+# define               rtfACStrikeThru         12      /* new in 1.10 */
+# define               rtfACUnderline          13      /* new in 1.10 */
+# define               rtfACDotUnderline       14      /* new in 1.10 */
+# define               rtfACDbUnderline        15      /* new in 1.10 */
+# define               rtfACNoUnderline        16      /* new in 1.10 */
+# define               rtfACWordUnderline      17      /* new in 1.10 */
+# define               rtfACSuperScript        18      /* new in 1.10 */
+
+# define       rtfFontAttr     23                      /* new in 1.10 */
+# define               rtfFontCharSet          0       /* new in 1.10 */
+# define               rtfFontPitch            1       /* new in 1.10 */
+# define               rtfFontCodePage         2       /* new in 1.10 */
+# define               rtfFTypeNil             3       /* new in 1.10 */
+# define               rtfFTypeTrueType        4       /* new in 1.10 */
+
+# define       rtfFileAttr     24                      /* new in 1.10 */
+# define               rtfFileNum              0       /* new in 1.10 */
+# define               rtfFileRelPath          1       /* new in 1.10 */
+# define               rtfFileOSNum            2       /* new in 1.10 */
+
+# define       rtfFileSource   25                      /* new in 1.10 */
+# define               rtfSrcMacintosh         0       /* new in 1.10 */
+# define               rtfSrcDOS               1       /* new in 1.10 */
+# define               rtfSrcNTFS              2       /* new in 1.10 */
+# define               rtfSrcHPFS              3       /* new in 1.10 */
+# define               rtfSrcNetwork           4       /* new in 1.10 */
+
+/*
+ * Drawing attributes
+ */
+
+# define       rtfDrawAttr     26                      /* new in 1.10 */
+# define               rtfDrawLock             0       /* new in 1.10 */
+# define               rtfDrawPageRelX         1       /* new in 1.10 */
+# define               rtfDrawColumnRelX       2       /* new in 1.10 */
+# define               rtfDrawMarginRelX       3       /* new in 1.10 */
+# define               rtfDrawPageRelY         4       /* new in 1.10 */
+# define               rtfDrawColumnRelY       5       /* new in 1.10 */
+# define               rtfDrawMarginRelY       6       /* new in 1.10 */
+# define               rtfDrawHeight           7       /* new in 1.10 */
+
+# define               rtfDrawBeginGroup       8       /* new in 1.10 */
+# define               rtfDrawGroupCount       9       /* new in 1.10 */
+# define               rtfDrawEndGroup         10      /* new in 1.10 */
+# define               rtfDrawArc              11      /* new in 1.10 */
+# define               rtfDrawCallout          12      /* new in 1.10 */
+# define               rtfDrawEllipse          13      /* new in 1.10 */
+# define               rtfDrawLine             14      /* new in 1.10 */
+# define               rtfDrawPolygon          15      /* new in 1.10 */
+# define               rtfDrawPolyLine         16      /* new in 1.10 */
+# define               rtfDrawRect             17      /* new in 1.10 */
+# define               rtfDrawTextBox          18      /* new in 1.10 */
+
+# define               rtfDrawOffsetX          19      /* new in 1.10 */
+# define               rtfDrawSizeX            20      /* new in 1.10 */
+# define               rtfDrawOffsetY          21      /* new in 1.10 */
+# define               rtfDrawSizeY            22      /* new in 1.10 */
+
+# define               rtfCOAngle              23      /* new in 1.10 */
+# define               rtfCOAccentBar          24      /* new in 1.10 */
+# define               rtfCOBestFit            25      /* new in 1.10 */
+# define               rtfCOBorder             26      /* new in 1.10 */
+# define               rtfCOAttachAbsDist      27      /* new in 1.10 */
+# define               rtfCOAttachBottom       28      /* new in 1.10 */
+# define               rtfCOAttachCenter       29      /* new in 1.10 */
+# define               rtfCOAttachTop          30      /* new in 1.10 */
+# define               rtfCOLength             31      /* new in 1.10 */
+# define               rtfCONegXQuadrant       32      /* new in 1.10 */
+# define               rtfCONegYQuadrant       33      /* new in 1.10 */
+# define               rtfCOOffset             34      /* new in 1.10 */
+# define               rtfCOAttachSmart        35      /* new in 1.10 */
+# define               rtfCODoubleLine         36      /* new in 1.10 */
+# define               rtfCORightAngle         37      /* new in 1.10 */
+# define               rtfCOSingleLine         38      /* new in 1.10 */
+# define               rtfCOTripleLine         39      /* new in 1.10 */
+
+# define               rtfDrawTextBoxMargin    40      /* new in 1.10 */
+# define               rtfDrawTextBoxText      41      /* new in 1.10 */
+# define               rtfDrawRoundRect        42      /* new in 1.10 */
+
+# define               rtfDrawPointX           43      /* new in 1.10 */
+# define               rtfDrawPointY           44      /* new in 1.10 */
+# define               rtfDrawPolyCount        45      /* new in 1.10 */
+
+# define               rtfDrawArcFlipX         46      /* new in 1.10 */
+# define               rtfDrawArcFlipY         47      /* new in 1.10 */
+
+# define               rtfDrawLineBlue         48      /* new in 1.10 */
+# define               rtfDrawLineGreen        49      /* new in 1.10 */
+# define               rtfDrawLineRed          50      /* new in 1.10 */
+# define               rtfDrawLinePalette      51      /* new in 1.10 */
+# define               rtfDrawLineDashDot      52      /* new in 1.10 */
+# define               rtfDrawLineDashDotDot   53      /* new in 1.10 */
+# define               rtfDrawLineDash         54      /* new in 1.10 */
+# define               rtfDrawLineDot          55      /* new in 1.10 */
+# define               rtfDrawLineGray         56      /* new in 1.10 */
+# define               rtfDrawLineHollow       57      /* new in 1.10 */
+# define               rtfDrawLineSolid        58      /* new in 1.10 */
+# define               rtfDrawLineWidth        59      /* new in 1.10 */
+
+# define               rtfDrawHollowEndArrow   60      /* new in 1.10 */
+# define               rtfDrawEndArrowLength   61      /* new in 1.10 */
+# define               rtfDrawSolidEndArrow    62      /* new in 1.10 */
+# define               rtfDrawEndArrowWidth    63      /* new in 1.10 */
+# define               rtfDrawHollowStartArrow 64      /* new in 1.10 */
+# define               rtfDrawStartArrowLength 65      /* new in 1.10 */
+# define               rtfDrawSolidStartArrow  66      /* new in 1.10 */
+# define               rtfDrawStartArrowWidth  67      /* new in 1.10 */
+
+# define               rtfDrawBgFillBlue       68      /* new in 1.10 */
+# define               rtfDrawBgFillGreen      69      /* new in 1.10 */
+# define               rtfDrawBgFillRed        70      /* new in 1.10 */
+# define               rtfDrawBgFillPalette    71      /* new in 1.10 */
+# define               rtfDrawBgFillGray       72      /* new in 1.10 */
+# define               rtfDrawFgFillBlue       73      /* new in 1.10 */
+# define               rtfDrawFgFillGreen      74      /* new in 1.10 */
+# define               rtfDrawFgFillRed        75      /* new in 1.10 */
+# define               rtfDrawFgFillPalette    76      /* new in 1.10 */
+# define               rtfDrawFgFillGray       77      /* new in 1.10 */
+# define               rtfDrawFillPatIndex     78      /* new in 1.10 */
+
+# define               rtfDrawShadow           79      /* new in 1.10 */
+# define               rtfDrawShadowXOffset    80      /* new in 1.10 */
+# define               rtfDrawShadowYOffset    81      /* new in 1.10 */
+
+/*
+ * index entry attributes
+ */
+
+# define       rtfIndexAttr    27                      /* new in 1.10 */
+# define               rtfIndexNumber          0       /* new in 1.10 */
+# define               rtfIndexBold            1       /* reclassified in 1.10 */
+# define               rtfIndexItalic          2       /* reclassified in 1.10 */
+
+
+/*
+ * \wmetafile argument values
+ */
+
+# define       rtfWmMmText             1
+# define       rtfWmMmLometric         2
+# define       rtfWmMmHimetric         3
+# define       rtfWmMmLoenglish        4
+# define       rtfWmMmHienglish        5
+# define       rtfWmMmTwips            6
+# define       rtfWmMmIsotropic        7
+# define       rtfWmMmAnisotropic      8
+
+/*
+ * \pmmetafile argument values
+ */
+
+# define       rtfPmPuArbitrary        4
+# define       rtfPmPuPels             8
+# define       rtfPmPuLometric         12
+# define       rtfPmPuHimetric         16
+# define       rtfPmPuLoenglish        20
+# define       rtfPmPuHienglish        24
+# define       rtfPmPuTwips            28
+
+/*
+ * \lang argument values
+ */
+
+# define       rtfLangNoLang                   0x0400
+# define       rtfLangAlbanian                 0x041c
+# define       rtfLangArabic                   0x0401
+# define       rtfLangBahasa                   0x0421
+# define       rtfLangBelgianDutch             0x0813
+# define       rtfLangBelgianFrench            0x080c
+# define       rtfLangBrazilianPortuguese      0x0416
+# define       rtfLangBulgarian                0x0402
+# define       rtfLangCatalan                  0x0403
+# define       rtfLangLatinCroatoSerbian       0x041a
+# define       rtfLangCzech                    0x0405
+# define       rtfLangDanish                   0x0406
+# define       rtfLangDutch                    0x0413
+# define       rtfLangAustralianEnglish        0x0c09
+# define       rtfLangUKEnglish                0x0809
+# define       rtfLangUSEnglish                0x0409
+# define       rtfLangFinnish                  0x040b
+# define       rtfLangFrench                   0x040c
+# define       rtfLangCanadianFrench           0x0c0c
+# define       rtfLangGerman                   0x0407
+# define       rtfLangGreek                    0x0408
+# define       rtfLangHebrew                   0x040d
+# define       rtfLangHungarian                0x040e
+# define       rtfLangIcelandic                0x040f
+# define       rtfLangItalian                  0x0410
+# define       rtfLangJapanese                 0x0411
+# define       rtfLangKorean                   0x0412
+# define       rtfLangBokmalNorwegian          0x0414
+# define       rtfLangNynorskNorwegian         0x0814
+# define       rtfLangPolish                   0x0415
+# define       rtfLangPortuguese               0x0816
+# define       rtfLangRhaetoRomanic            0x0417
+# define       rtfLangRomanian                 0x0418
+# define       rtfLangRussian                  0x0419
+# define       rtfLangCyrillicSerboCroatian    0x081a
+# define       rtfLangSimplifiedChinese        0x0804
+# define       rtfLangSlovak                   0x041b
+# define       rtfLangCastilianSpanish         0x040a
+# define       rtfLangMexicanSpanish           0x080a
+# define       rtfLangSwedish                  0x041d
+# define       rtfLangSwissFrench              0x100c
+# define       rtfLangSwissGerman              0x0807
+# define       rtfLangSwissItalian             0x0810
+# define       rtfLangThai                     0x041e
+# define       rtfLangTraditionalChinese       0x0404
+# define       rtfLangTurkish                  0x041f
+# define       rtfLangUrdu                     0x0420
+
+/*
+ * CharSet indices
+ */
+
+# define       rtfCSGeneral    0       /* general (default) charset */
+# define       rtfCSSymbol     1       /* symbol charset */
+
+/*
+ * Flags for auto-charset-processing.  Both are on by default.
+ */
+
+# define       rtfReadCharSet          0x01    /* auto-read charset files */
+# define       rtfSwitchCharSet        0x02    /* auto-switch charset maps */
+
+/*
+ * Style types
+ */
+
+# define       rtfParStyle     0       /* the default */
+# define       rtfCharStyle    1
+# define       rtfSectStyle    2
+
+/*
+ * RTF font, color and style structures.  Used for font table,
+ * color table, and stylesheet processing.
+ */
+
+typedef struct RTFFont         RTFFont;
+typedef struct RTFColor                RTFColor;
+typedef struct RTFStyle                RTFStyle;
+typedef struct RTFStyleElt     RTFStyleElt;
+
+
+struct RTFFont
+{
+       char    *rtfFName;              /* font name */
+       char    *rtfFAltName;           /* font alternate name */
+       int     rtfFNum;                /* font number */
+       int     rtfFFamily;             /* font family */
+       int     rtfFCharSet;            /* font charset */
+       int     rtfFPitch;              /* font pitch */
+       int     rtfFType;               /* font type */
+       int     rtfFCodePage;           /* font code page */
+       RTFFont *rtfNextFont;           /* next font in list */
+};
+
+
+/*
+ * Color values are -1 if the default color for the the color
+ * number should be used.  The default color is writer-dependent.
+ */
+
+struct RTFColor
+{
+       int             rtfCNum;        /* color number */
+       int             rtfCRed;        /* red value */
+       int             rtfCGreen;      /* green value */
+       int             rtfCBlue;       /* blue value */
+       RTFColor        *rtfNextColor;  /* next color in list */
+};
+
+
+struct RTFStyle
+{
+       char            *rtfSName;      /* style name */
+       int             rtfSType;       /* style type */
+       int             rtfSAdditive;   /* whether or not style is additive */
+       int             rtfSNum;        /* style number */
+       int             rtfSBasedOn;    /* style this one's based on */
+       int             rtfSNextPar;    /* style next paragraph style */
+       RTFStyleElt     *rtfSSEList;    /* list of style words */
+       int             rtfExpanding;   /* non-zero = being expanded */
+       RTFStyle        *rtfNextStyle;  /* next style in style list */
+};
+
+
+struct RTFStyleElt
+{
+       int             rtfSEClass;     /* token class */
+       int             rtfSEMajor;     /* token major number */
+       int             rtfSEMinor;     /* token minor number */
+       int             rtfSEParam;     /* control symbol parameter */
+       char            *rtfSEText;     /* text of symbol */
+       RTFStyleElt     *rtfNextSE;     /* next element in style */
+};
+
+
+/*
+ * Return pointer to new element of type t, or NULL
+ * if no memory available.
+ */
+
+# define        New(t)  ((t *) RTFAlloc ((int) sizeof (t)))
+
+/* maximum number of character values representable in a byte */
+
+# define        charSetSize             256
+
+/* charset stack size */
+
+# define        maxCSStack              10
+
+
+struct _RTF_Info;
+typedef struct _RTF_Info RTF_Info;
+
+typedef        void (*RTFFuncPtr) (RTF_Info *);                /* generic function pointer */
+
+struct _RTF_Info {
+    /*
+     * Public variables (listed in rtf.h)
+     */
+
+    /*
+     * Information pertaining to last token read by RTFToken.  The
+     * text is exactly as it occurs in the input file, e.g., "\{"
+     * will be found in rtfTextBuf as "\{", even though it means "{".
+     * These variables are also set when styles are reprocessed.
+     */
+
+    int        rtfClass;
+    int        rtfMajor;
+    int        rtfMinor;
+    int        rtfParam;
+    int rtfFormat;
+    char *rtfTextBuf;
+    int        rtfTextLen;
+
+    long rtfLineNum;
+    int        rtfLinePos;
+
+
+    /*
+     * Private stuff
+     */
+
+    int        pushedChar;     /* pushback char if read too far */
+
+    int        pushedClass;    /* pushed token info for RTFUngetToken() */
+    int        pushedMajor;
+    int        pushedMinor;
+    int        pushedParam;
+    char *pushedTextBuf;
+
+    int        prevChar;
+    int        bumpLine;
+
+    RTFFont    *fontList;      /* these lists MUST be */
+    RTFColor   *colorList;     /* initialized to NULL */
+    RTFStyle   *styleList;
+
+    char *inputName;
+    char *outputName;
+
+    EDITSTREAM editstream;
+    char InputBuffer[0x1000];
+    DWORD dwInputSize;
+    DWORD dwInputUsed;
+
+    /* edit window to output to */
+    HWND hwndEdit;
+
+    /*
+     * These arrays are used to map RTF input character values onto the standard
+     * character names represented by the values.  Input character values are
+     * used as indices into the arrays to produce standard character codes.
+     */
+
+
+    char *genCharSetFile ;
+    int        genCharCode[charSetSize];       /* general */
+    int        haveGenCharSet;
+
+    char *symCharSetFile;
+    int        symCharCode[charSetSize];       /* symbol */
+    int        haveSymCharSet;
+
+    int        curCharSet;
+    int        *curCharCode;
+
+    /*
+     * By default, the reader is configured to handle charset mapping invisibly,
+     * including reading the charset files and switching charset maps as necessary
+     * for Symbol font.
+     */
+
+    int        autoCharSetFlags;
+
+    /*
+     * Stack for keeping track of charset map on group begin/end.  This is
+     * necessary because group termination reverts the font to the previous
+     * value, which may implicitly change it.
+     */
+
+    int        csStack[maxCSStack];
+    int        csTop;
+
+    RTFFuncPtr       ccb[rtfMaxClass];               /* class callbacks */
+
+    RTFFuncPtr       dcb[rtfMaxDestination]; /* destination callbacks */
+
+    RTFFuncPtr       readHook;
+
+    RTFFuncPtr       panicProc;
+
+    FILE     *(*libFileOpen) ();
+
+    char     *outMap[rtfSC_MaxChar];
+
+    DWORD    dwOutputCount;
+    char     OutputBuffer[0x1000];
+};
+
+
+/*
+ * Public RTF reader routines
+ */
+
+void           RTFInit (RTF_Info *);
+void           RTFSetInputName (RTF_Info *, char *);
+char           *RTFGetInputName (RTF_Info *);
+void           RTFSetOutputName (RTF_Info *, char *);
+char           *RTFGetOutputName (RTF_Info *);
+void           RTFSetClassCallback (RTF_Info *, int, RTFFuncPtr);
+RTFFuncPtr     RTFGetClassCallback (RTF_Info *, int);
+void           RTFSetDestinationCallback (RTF_Info *, int, RTFFuncPtr);
+RTFFuncPtr     RTFGetDestinationCallback (RTF_Info *, int);
+void           RTFRead (RTF_Info *);
+int            RTFGetToken (RTF_Info *);       /* writer should rarely need this */
+void           RTFUngetToken (RTF_Info *);
+int            RTFPeekToken (RTF_Info *);
+void           RTFSetToken (RTF_Info *, int, int, int, int, const char *);
+void           RTFSetReadHook (RTF_Info *, RTFFuncPtr);
+RTFFuncPtr     RTFGetReadHook (RTF_Info *);
+void           RTFRouteToken (RTF_Info *);
+void           RTFSkipGroup (RTF_Info *);
+void           RTFExpandStyle (RTF_Info *, int);
+int            RTFCheckCM (RTF_Info *, int, int);
+int            RTFCheckCMM (RTF_Info *, int, int, int);
+int            RTFCheckMM (RTF_Info *, int, int);
+RTFFont                *RTFGetFont (RTF_Info *, int);
+RTFColor       *RTFGetColor (RTF_Info *, int);
+RTFStyle       *RTFGetStyle (RTF_Info *, int);
+# define       RTFAlloc(size)  _RTFAlloc ((int) size)
+char           *_RTFAlloc (int);
+char           *RTFStrSave (char *);
+void           RTFFree (char *);
+int            RTFCharToHex ( char);
+int            RTFHexToChar ( int );
+void           RTFSetMsgProc ( RTFFuncPtr );
+void           RTFSetPanicProc ( RTF_Info *, RTFFuncPtr);
+
+/*
+ * The following messing around is used to allow RTFMsg() and RTFPanic()
+ * to be variable-argument functions that are declared publicly but
+ * without generating prototype-mismatch errors on systems that have
+ * stdarg.h.
+ */
+
+void   RTFMsg (RTF_Info *, const char *fmt, ...);
+void   RTFPanic (RTF_Info *, const char *fmt, ...);
+
+int            RTFReadOutputMap ( RTF_Info *, char *[], int);
+int            RTFReadCharSetMap ( RTF_Info *, int);
+void           RTFSetCharSetMap ( RTF_Info *, char *, int);
+int            RTFStdCharCode ( RTF_Info *, const char *);
+const char     *RTFStdCharName ( RTF_Info *, int);
+int            RTFMapChar ( RTF_Info *, int);
+int            RTFGetCharSet( RTF_Info * );
+void           RTFSetCharSet( RTF_Info *, int);
+
+void   RTFSetOpenLibFileProc ( RTF_Info *, FILE *(*)());
+FILE   *RTFOpenLibFile ( RTF_Info *, char *, char *);
+
+void   RTFFlushOutputBuffer( RTF_Info *info );
+void   RTFSetEditStream(RTF_Info *, EDITSTREAM *es);
+
+void   WriterInit (RTF_Info *);
+int    BeginFile (RTF_Info *);
+
+#endif
diff --git a/reactos/lib/riched20/run.c b/reactos/lib/riched20/run.c
new file mode 100644 (file)
index 0000000..9e0ef76
--- /dev/null
@@ -0,0 +1,672 @@
+/*
+ * RichEdit - operations on runs (diRun, rectangular pieces of paragraphs).
+ * Splitting/joining runs. Adjusting offsets after deleting/adding content.
+ * Character/pixel conversions.
+ *
+ * Copyright 2004 by Krzysztof Foltman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "editor.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(richedit);
+
+int ME_CanJoinRuns(ME_Run *run1, ME_Run *run2)
+{
+  if ((run1->nFlags | run2->nFlags) & (MERF_ENDPARA | MERF_GRAPHICS))
+    return 0;
+  if (run1->style != run2->style)
+    return 0;
+  if ((run1->nFlags & MERF_STYLEFLAGS) != (run2->nFlags & MERF_STYLEFLAGS))
+    return 0;
+  return 1;
+}
+
+void ME_SkipAndPropagateCharOffset(ME_DisplayItem *p, int shift)
+{
+  p = ME_FindItemFwd(p, diRunOrParagraphOrEnd);
+  assert(p);
+  ME_PropagateCharOffset(p, shift);
+}
+
+void ME_PropagateCharOffset(ME_DisplayItem *p, int shift)
+{
+  if (p->type == diRun) /* propagate in all runs in this para */
+  {
+    TRACE("PropagateCharOffset(%s, %d)\n", debugstr_w(p->member.run.strText->szData), shift);
+    do {
+      p->member.run.nCharOfs += shift;
+      assert(p->member.run.nCharOfs >= 0);
+      p = ME_FindItemFwd(p, diRunOrParagraphOrEnd);
+    } while(p->type == diRun);
+  }
+  if (p->type == diParagraph) /* propagate in all next paras */
+  {
+    do {
+      p->member.para.nCharOfs += shift;
+      assert(p->member.para.nCharOfs >= 0);
+      p = p->member.para.next_para;
+    } while(p->type == diParagraph);
+  }
+  if (p->type == diTextEnd)
+  {
+    p->member.para.nCharOfs += shift;
+    assert(p->member.para.nCharOfs >= 0);
+  }
+}
+
+void ME_CheckCharOffsets(ME_TextEditor *editor)
+{
+  ME_DisplayItem *p = editor->pBuffer->pFirst;
+  int ofs = 0, ofsp = 0;
+  if(TRACE_ON(richedit))
+  {
+    TRACE("---\n");
+    ME_DumpDocument(editor->pBuffer);
+  }
+  do {
+    p = ME_FindItemFwd(p, diRunOrParagraphOrEnd);
+    switch(p->type) {
+      case diTextEnd:
+        TRACE("tend, real ofsp = %d, counted = %d\n", p->member.para.nCharOfs, ofsp+ofs);
+        assert(ofsp+ofs == p->member.para.nCharOfs);
+        return;
+      case diParagraph:
+        TRACE("para, real ofsp = %d, counted = %d\n", p->member.para.nCharOfs, ofsp+ofs);
+        assert(ofsp+ofs == p->member.para.nCharOfs);
+        ofsp = p->member.para.nCharOfs;
+        ofs = 0;
+        break;
+      case diRun:
+        TRACE("run, real ofs = %d (+ofsp = %d), counted = %d, len = %d, txt = \"%s\", flags=%08x, fx&mask = %08lx\n", 
+          p->member.run.nCharOfs, p->member.run.nCharOfs+ofsp, ofsp+ofs, 
+          p->member.run.strText->nLen, debugstr_w(p->member.run.strText->szData),
+          p->member.run.nFlags,
+          p->member.run.style->fmt.dwMask & p->member.run.style->fmt.dwEffects);
+        assert(ofs == p->member.run.nCharOfs);
+        ofs += ME_StrLen(p->member.run.strText);
+        break;
+      default:
+        assert(0);
+    }
+  } while(1);
+}
+
+int ME_CharOfsFromRunOfs(ME_TextEditor *editor, ME_DisplayItem *pRun, int nOfs)
+{
+  ME_DisplayItem *pPara;
+  
+  assert(pRun->type == diRun);
+  assert(pRun->member.run.nCharOfs != -1);
+
+  pPara = ME_FindItemBack(pRun, diParagraph);
+  assert(pPara);
+  assert(pPara->type==diParagraph);
+  return pPara->member.para.nCharOfs + pRun->member.run.nCharOfs 
+    + ME_VPosToPos(pRun->member.run.strText, nOfs);
+}
+
+void ME_CursorFromCharOfs(ME_TextEditor *editor, int nCharOfs, ME_Cursor *pCursor)
+{
+  ME_RunOfsFromCharOfs(editor, nCharOfs, &pCursor->pRun, &pCursor->nOffset);
+}
+
+void ME_RunOfsFromCharOfs(ME_TextEditor *editor, int nCharOfs, ME_DisplayItem **ppRun, int *pOfs)
+{
+  ME_DisplayItem *pPara;
+  int nParaOfs;
+  
+  pPara = editor->pBuffer->pFirst->member.para.next_para;
+  assert(pPara);
+  assert(ppRun);
+  assert(pOfs);
+  while (pPara->type == diParagraph)
+  {
+    nParaOfs = pPara->member.para.nCharOfs;
+    assert(nCharOfs >= nParaOfs);
+    
+    if (nCharOfs < pPara->member.para.next_para->member.para.nCharOfs)
+    {
+      *ppRun = ME_FindItemFwd(pPara, diRun);
+      assert(*ppRun);      
+      while (!((*ppRun)->member.run.nFlags & MERF_ENDPARA))
+      {
+        ME_DisplayItem *pNext = ME_FindItemFwd(*ppRun, diRun);
+        assert(pNext);
+        assert(pNext->type == diRun);
+        if (nCharOfs < nParaOfs + pNext->member.run.nCharOfs) {
+          *pOfs = ME_PosToVPos((*ppRun)->member.run.strText, 
+            nCharOfs - nParaOfs - (*ppRun)->member.run.nCharOfs);
+          return;
+        }
+        *ppRun = pNext;
+      }
+      if (nCharOfs == nParaOfs + (*ppRun)->member.run.nCharOfs) {
+        *pOfs = 0;
+        return;
+      }        
+    }
+    pPara = pPara->member.para.next_para;
+  }
+  *ppRun = ME_FindItemBack(editor->pBuffer->pLast, diRun);
+  *pOfs = 0;  
+  assert((*ppRun)->member.run.nFlags & MERF_ENDPARA);
+}
+
+void ME_JoinRuns(ME_TextEditor *editor, ME_DisplayItem *p)
+{
+  ME_DisplayItem *pNext = p->next;
+  int i;
+  assert(p->type == diRun && pNext->type == diRun);
+  assert(p->member.run.nCharOfs != -1);
+  ME_GetParagraph(p)->member.para.nFlags |= MEPF_REWRAP;
+
+  for (i=0; i<editor->nCursors; i++) {
+    if (editor->pCursors[i].pRun == pNext) {
+      editor->pCursors[i].pRun = p;
+      editor->pCursors[i].nOffset += ME_StrVLen(p->member.run.strText);
+    }
+  }
+  
+  ME_AppendString(p->member.run.strText, pNext->member.run.strText);
+  ME_Remove(pNext);
+  ME_DestroyDisplayItem(pNext);
+  ME_UpdateRunFlags(editor, &p->member.run);
+  if(TRACE_ON(richedit))
+  {
+    TRACE("Before check after join\n");
+    ME_CheckCharOffsets(editor);
+    TRACE("After check after join\n");
+  }
+}
+
+ME_DisplayItem *ME_SplitRun(ME_Context *c, ME_DisplayItem *item, int nVChar)
+{
+  ME_TextEditor *editor = c->editor;
+  ME_DisplayItem *item2 = NULL;
+  ME_Run *run, *run2;
+  
+  assert(item->member.run.nCharOfs != -1);
+  if(TRACE_ON(richedit))
+  {
+    TRACE("Before check before split\n");
+    ME_CheckCharOffsets(editor);
+    TRACE("After check before split\n");
+  }
+
+  run = &item->member.run;
+
+  TRACE("Before split: %s(%ld, %ld)\n", debugstr_w(run->strText->szData),
+        run->pt.x, run->pt.y);
+
+  item2 = ME_SplitRunSimple(editor, item, nVChar);
+  
+  run2 = &item2->member.run;
+  
+  ME_CalcRunExtent(c, run);
+  ME_CalcRunExtent(c, run2);
+    
+  run2->pt.x = run->pt.x+run->nWidth;
+  run2->pt.y = run->pt.y;
+  
+  if(TRACE_ON(richedit))
+  {
+    TRACE("Before check after split\n");
+    ME_CheckCharOffsets(editor);
+    TRACE("After check after split\n");
+    TRACE("After split: %s(%ld, %ld), %s(%ld, %ld)\n", 
+      debugstr_w(run->strText->szData), run->pt.x, run->pt.y,
+      debugstr_w(run2->strText->szData), run2->pt.x, run2->pt.y);
+  }
+
+  return item2;
+}
+  
+/* split a run starting from voffset */
+ME_DisplayItem *ME_SplitRunSimple(ME_TextEditor *editor, ME_DisplayItem *item, int nVChar)
+{
+  ME_Run *run = &item->member.run;
+  ME_DisplayItem *item2;
+  ME_Run *run2;
+  int i;
+  assert(nVChar > 0 && nVChar < ME_StrVLen(run->strText));
+  assert(item->type == diRun);
+  assert(!(item->member.run.nFlags & MERF_GRAPHICS));
+  assert(item->member.run.nCharOfs != -1);
+
+  item2 = ME_MakeRun(run->style, 
+      ME_VSplitString(run->strText, nVChar), run->nFlags&MERF_SPLITMASK);
+  
+  item2->member.run.nCharOfs = item->member.run.nCharOfs+
+    ME_VPosToPos(item->member.run.strText, nVChar);
+
+  run2 = &item2->member.run;
+  ME_InsertBefore(item->next, item2);
+  
+  ME_UpdateRunFlags(editor, run);
+  ME_UpdateRunFlags(editor, run2);
+  for (i=0; i<editor->nCursors; i++) {
+    if (editor->pCursors[i].pRun == item && 
+        editor->pCursors[i].nOffset >= nVChar) {
+      assert(item2->type == diRun);
+      editor->pCursors[i].pRun = item2;
+      editor->pCursors[i].nOffset -= nVChar;
+    }
+  }
+  ME_GetParagraph(item)->member.para.nFlags |= MEPF_REWRAP;
+  return item2;
+}
+
+/* split the start and final whitespace into separate runs */
+/* returns the last run added */
+/*
+ME_DisplayItem *ME_SplitFurther(ME_TextEditor *editor, ME_DisplayItem *item)
+{
+  int i, nVLen, nChanged;
+  assert(item->type == diRun);
+  assert(!(item->member.run.nFlags & MERF_GRAPHICS));
+  return item;
+}
+*/
+
+ME_DisplayItem *ME_MakeRun(ME_Style *s, ME_String *strData, int nFlags)
+{
+  ME_DisplayItem *item = ME_MakeDI(diRun);
+  item->member.run.style = s;
+  item->member.run.strText = strData;
+  item->member.run.nFlags = nFlags;
+  item->member.run.nCharOfs = -1;
+  ME_AddRefStyle(s);
+  return item;
+}
+
+ME_DisplayItem *ME_InsertRun(ME_TextEditor *editor, int nCharOfs, ME_DisplayItem *pItem)
+{
+  ME_Cursor tmp;
+  ME_DisplayItem *pDI;
+  ME_UndoItem *pUI;
+  
+  assert(pItem->type == diRun || pItem->type == diUndoInsertRun);
+  
+  pUI = ME_AddUndoItem(editor, diUndoDeleteRun, NULL);
+  pUI->nStart = nCharOfs;
+  pUI->nLen = pItem->member.run.strText->nLen;
+  ME_CursorFromCharOfs(editor, nCharOfs, &tmp);
+  if (tmp.nOffset) {
+    tmp.pRun = ME_SplitRunSimple(editor, tmp.pRun, tmp.nOffset);
+    tmp.nOffset = 0;
+  }
+  pDI = ME_MakeRun(pItem->member.run.style, ME_StrDup(pItem->member.run.strText), pItem->member.run.nFlags);
+  pDI->member.run.nCharOfs = tmp.pRun->member.run.nCharOfs;
+  ME_InsertBefore(tmp.pRun, pDI);
+  TRACE("Shift length:%d\n", pDI->member.run.strText->nLen);
+  ME_PropagateCharOffset(tmp.pRun, pDI->member.run.strText->nLen);
+  ME_GetParagraph(tmp.pRun)->member.para.nFlags |= MEPF_REWRAP;
+  
+  return pDI;
+}
+
+static inline int ME_IsWSpace(WCHAR ch)
+{
+  return ch <= ' ';
+}
+
+void ME_UpdateRunFlags(ME_TextEditor *editor, ME_Run *run)
+{
+  assert(run->nCharOfs != -1);
+  if (ME_IsSplitable(run->strText))
+    run->nFlags |= MERF_SPLITTABLE;
+  else
+    run->nFlags &= ~MERF_SPLITTABLE;
+    
+  if (!(run->nFlags & MERF_GRAPHICS)) {
+    if (ME_IsWhitespaces(run->strText))
+      run->nFlags |= MERF_WHITESPACE | MERF_STARTWHITE | MERF_ENDWHITE;
+    else
+    {
+      run->nFlags &= ~MERF_WHITESPACE;
+    
+      if (ME_IsWSpace(ME_GetCharFwd(run->strText,0)))
+        run->nFlags |= MERF_STARTWHITE;
+      else
+        run->nFlags &= ~MERF_STARTWHITE;
+    
+      if (ME_IsWSpace(ME_GetCharBack(run->strText,0)))
+        run->nFlags |= MERF_ENDWHITE;
+      else
+        run->nFlags &= ~MERF_ENDWHITE;
+    }
+  }
+  else
+    run->nFlags &= ~(MERF_WHITESPACE | MERF_STARTWHITE | MERF_ENDWHITE);
+}
+
+void ME_GetGraphicsSize(ME_TextEditor *editor, ME_Run *run, SIZE *pSize)
+{
+  assert(run->nFlags & MERF_GRAPHICS);
+  pSize->cx = 64;
+  pSize->cy = 64;
+}
+
+int ME_CharFromPoint(ME_TextEditor *editor, int cx, ME_Run *run)
+{
+  int fit = 0;
+  HGDIOBJ hOldFont;
+  HDC hDC;
+  SIZE sz;
+  if (!run->strText->nLen)
+    return 0;
+
+  if (run->nFlags & MERF_GRAPHICS)
+  {
+    SIZE sz;
+    ME_GetGraphicsSize(editor, run, &sz);
+    if (cx < sz.cx)
+      return 0;
+    return 1;
+  }
+  hDC = GetDC(editor->hWnd);
+  hOldFont = ME_SelectStyleFont(editor, hDC, run->style);
+  GetTextExtentExPointW(hDC, run->strText->szData, run->strText->nLen, 
+    cx, &fit, NULL, &sz);
+  ME_UnselectStyleFont(editor, hDC, run->style, hOldFont);  
+  ReleaseDC(editor->hWnd, hDC);
+  return fit;
+}
+
+int ME_CharFromPointCursor(ME_TextEditor *editor, int cx, ME_Run *run)
+{
+  int fit = 0, fit1 = 0;
+  HGDIOBJ hOldFont;
+  HDC hDC;
+  SIZE sz, sz2, sz3;
+  if (!run->strText->nLen)
+    return 0;
+
+  if (run->nFlags & MERF_GRAPHICS)
+  {
+    SIZE sz;
+    ME_GetGraphicsSize(editor, run, &sz);
+    if (cx < sz.cx/2)
+      return 0;
+    return 1;
+  }
+
+  hDC = GetDC(editor->hWnd);
+  hOldFont = ME_SelectStyleFont(editor, hDC, run->style);
+  GetTextExtentExPointW(hDC, run->strText->szData, run->strText->nLen, 
+    cx, &fit, NULL, &sz);
+  if (fit != run->strText->nLen)
+  {
+    int chars = 1;
+    
+    GetTextExtentPoint32W(hDC, run->strText->szData, fit, &sz2);
+    fit1 = ME_StrRelPos(run->strText, fit, &chars);
+    GetTextExtentPoint32W(hDC, run->strText->szData, fit1, &sz3);
+    if (cx >= (sz2.cx+sz3.cx)/2)
+      fit = fit1;
+  }
+  ME_UnselectStyleFont(editor, hDC, run->style, hOldFont);  
+  ReleaseDC(editor->hWnd, hDC);
+  return fit;
+}
+
+int ME_PointFromChar(ME_TextEditor *editor, ME_Run *pRun, int nOffset)
+{
+  SIZE size;
+  HDC hDC = GetDC(editor->hWnd);
+  HGDIOBJ hOldFont;
+  
+  if (pRun->nFlags & MERF_GRAPHICS)
+  {
+    if (!nOffset) return 0;
+    ME_GetGraphicsSize(editor, pRun, &size);
+    return 1;
+  }
+  hOldFont = ME_SelectStyleFont(editor, hDC, pRun->style);
+  GetTextExtentPoint32W(hDC, pRun->strText->szData, nOffset, &size);
+  ME_UnselectStyleFont(editor, hDC, pRun->style, hOldFont);  
+  ReleaseDC(editor->hWnd, hDC);
+  return size.cx;
+}
+
+void ME_GetTextExtent(ME_Context *c, LPCWSTR szText, int nChars, ME_Style *s, 
+  SIZE *size)
+{
+  HDC hDC = c->hDC;
+  HGDIOBJ hOldFont;
+  hOldFont = ME_SelectStyleFont(c->editor, hDC, s);
+  GetTextExtentPoint32W(hDC, szText, nChars, size);
+  ME_UnselectStyleFont(c->editor, hDC, s, hOldFont);  
+}
+
+SIZE ME_GetRunSize(ME_Context *c, ME_Run *run, int nLen)
+{
+  SIZE size;
+  int nMaxLen = ME_StrVLen(run->strText);
+
+  if (nLen>nMaxLen)
+    nLen = nMaxLen;
+    
+  if (run->nFlags & MERF_GRAPHICS)
+  {
+    ME_GetGraphicsSize(c->editor, run, &size);
+    return size;
+  }
+
+  ME_GetTextExtent(c, run->strText->szData, nLen, run->style, &size);
+
+  return size;
+}
+
+void ME_CalcRunExtent(ME_Context *c, ME_Run *run)
+{
+  SIZE size;
+  int nEnd = ME_StrVLen(run->strText);
+  
+  if (run->nFlags & MERF_GRAPHICS) {
+    ME_GetGraphicsSize(c->editor, run, &size);
+    run->nWidth = size.cx;
+    run->nAscent = size.cy;
+    run->nDescent = 0;
+    return;
+  }
+  ME_GetTextExtent(c, run->strText->szData, nEnd, run->style, &size);
+  run->nWidth = size.cx;
+  run->nAscent = run->style->tm.tmAscent;
+  run->nDescent = run->style->tm.tmDescent;
+}
+
+void ME_MustBeWrapped(ME_Context *c, ME_DisplayItem *para)
+{
+  assert(para->type == diParagraph);
+  /* FIXME */
+}
+
+void ME_SetSelectionCharFormat(ME_TextEditor *editor, CHARFORMAT2W *pFmt)
+{
+  int nFrom, nTo;
+  ME_GetSelection(editor, &nFrom, &nTo);
+  if (nFrom == nTo)
+  {
+    ME_Style *s;
+    if (!editor->pBuffer->pCharStyle)
+      editor->pBuffer->pCharStyle = ME_GetInsertStyle(editor, 0);
+    s = ME_ApplyStyle(editor->pBuffer->pCharStyle, pFmt);
+    ME_ReleaseStyle(editor->pBuffer->pCharStyle);
+    editor->pBuffer->pCharStyle = s;
+  }
+  else
+    ME_SetCharFormat(editor, nFrom, nTo-nFrom, pFmt);
+}
+
+void ME_SetCharFormat(ME_TextEditor *editor, int nOfs, int nChars, CHARFORMAT2W *pFmt)
+{
+  ME_Cursor tmp, tmp2;
+  ME_DisplayItem *para;
+  
+  ME_CursorFromCharOfs(editor, nOfs, &tmp);
+  if (tmp.nOffset)
+    tmp.pRun = ME_SplitRunSimple(editor, tmp.pRun, tmp.nOffset);
+
+  ME_CursorFromCharOfs(editor, nOfs+nChars, &tmp2);
+  if (tmp2.nOffset)
+    tmp2.pRun = ME_SplitRunSimple(editor, tmp2.pRun, tmp2.nOffset);
+
+  para = ME_GetParagraph(tmp.pRun);
+  para->member.para.nFlags |= MEPF_REWRAP;
+    
+  while(tmp.pRun != tmp2.pRun)
+  {
+    ME_UndoItem *undo = NULL;
+    ME_Style *new_style = ME_ApplyStyle(tmp.pRun->member.run.style, pFmt);
+    /* ME_DumpStyle(new_style); */
+    undo = ME_AddUndoItem(editor, diUndoSetCharFormat, NULL);
+    if (undo) {
+      undo->nStart = tmp.pRun->member.run.nCharOfs+para->member.para.nCharOfs;
+      undo->nLen = tmp.pRun->member.run.strText->nLen;
+      undo->di.member.ustyle = tmp.pRun->member.run.style;
+      /* we'd have to addref undo..ustyle and release tmp...style
+         but they'd cancel each other out so we can do nothing instead */
+    }
+    else
+      ME_ReleaseStyle(tmp.pRun->member.run.style);
+    tmp.pRun->member.run.style = new_style;
+    tmp.pRun = ME_FindItemFwd(tmp.pRun, diRunOrParagraph);
+    if (tmp.pRun->type == diParagraph)
+    {
+      para = tmp.pRun;
+      tmp.pRun = ME_FindItemFwd(tmp.pRun, diRun);
+      if (tmp.pRun != tmp2.pRun)
+        para->member.para.nFlags |= MEPF_REWRAP;
+    }
+    assert(tmp.pRun);
+  }
+}
+
+void ME_SetDefaultCharFormat(ME_TextEditor *editor, CHARFORMAT2W *mod)
+{
+  ME_Style *style; 
+  ME_UndoItem *undo;
+  
+  assert(mod->cbSize == sizeof(CHARFORMAT2W));
+  undo = ME_AddUndoItem(editor, diUndoSetDefaultCharFormat, NULL);
+  if (undo) {
+    undo->nStart = -1;
+    undo->nLen = -1;
+    undo->di.member.ustyle = editor->pBuffer->pDefaultStyle;
+    ME_AddRefStyle(undo->di.member.ustyle);
+  }
+  style = ME_ApplyStyle(editor->pBuffer->pDefaultStyle, mod);
+  editor->pBuffer->pDefaultStyle->fmt = style->fmt;
+  editor->pBuffer->pDefaultStyle->tm = style->tm;
+  ME_ReleaseStyle(style);
+  ME_MarkAllForWrapping(editor);
+  /*  pcf = editor->pBuffer->pDefaultStyle->fmt; */
+}
+
+void ME_GetRunCharFormat(ME_TextEditor *editor, ME_DisplayItem *run, CHARFORMAT2W *pFmt)
+{
+  ME_CopyCharFormat(pFmt, &run->member.run.style->fmt);
+}
+
+void ME_GetDefaultCharFormat(ME_TextEditor *editor, CHARFORMAT2W *pFmt)
+{
+  int nFrom, nTo;
+  ME_GetSelection(editor, &nFrom, &nTo);
+  ME_CopyCharFormat(pFmt, &editor->pBuffer->pDefaultStyle->fmt);
+}
+
+void ME_GetSelectionCharFormat(ME_TextEditor *editor, CHARFORMAT2W *pFmt)
+{
+  int nFrom, nTo;
+  ME_GetSelection(editor, &nFrom, &nTo);
+  if (nFrom == nTo && editor->pBuffer->pCharStyle)
+  {
+    ME_CopyCharFormat(pFmt, &editor->pBuffer->pCharStyle->fmt);
+    return;
+  }
+  ME_GetCharFormat(editor, nFrom, nTo, pFmt);
+}
+
+void ME_GetCharFormat(ME_TextEditor *editor, int nFrom, int nTo, CHARFORMAT2W *pFmt)
+{
+  ME_DisplayItem *run, *run_end;
+  int nOffset, nOffset2;
+  CHARFORMAT2W tmp;
+  
+  if (nTo>nFrom) /* selection consists of chars from nFrom up to nTo-1 */
+    nTo--;
+  
+  ME_RunOfsFromCharOfs(editor, nFrom, &run, &nOffset);
+  if (nFrom == nTo) /* special case - if selection is empty, take previous char's formatting */
+  {
+    if (!nOffset)
+    {
+      ME_DisplayItem *tmp_run = ME_FindItemBack(run, diRunOrParagraph);
+      if (tmp_run->type == diRun) {
+        ME_GetRunCharFormat(editor, tmp_run, pFmt);
+        return;
+      }
+    }
+    ME_GetRunCharFormat(editor, run, pFmt);
+    return;
+  }
+  ME_RunOfsFromCharOfs(editor, nTo, &run_end, &nOffset2);
+  
+  ME_GetRunCharFormat(editor, run, pFmt);
+  
+  if (run == run_end) return;
+  
+  do {
+    /* FIXME add more style feature comparisons */
+    int nAttribs = CFM_SIZE | CFM_FACE | CFM_COLOR;
+    int nEffects = CFM_BOLD | CFM_ITALIC | CFM_UNDERLINE;
+
+    run = ME_FindItemFwd(run, diRun);
+    
+    ZeroMemory(&tmp, sizeof(tmp));
+    tmp.cbSize = sizeof(tmp);
+    ME_GetRunCharFormat(editor, run, &tmp);
+    
+    assert((tmp.dwMask & nAttribs) == nAttribs);
+    assert((tmp.dwMask & nEffects) == nEffects);
+    /* reset flags that differ */
+
+    if (pFmt->yHeight != tmp.yHeight)
+      pFmt->dwMask &= ~CFM_SIZE;
+    if (pFmt->dwMask & CFM_FACE)
+    {
+      if (!(tmp.dwMask & CFM_FACE))
+        pFmt->dwMask &= ~CFM_FACE;
+      else if (lstrcmpW(pFmt->szFaceName, tmp.szFaceName))
+        pFmt->dwMask &= ~CFM_FACE;
+    }
+    if (pFmt->yHeight != tmp.yHeight)
+      pFmt->dwMask &= ~CFM_SIZE;
+    if (pFmt->dwMask & CFM_COLOR)
+    {
+      if (!((pFmt->dwEffects&CFE_AUTOCOLOR) & (tmp.dwEffects&CFE_AUTOCOLOR)))
+      {
+        if (pFmt->crTextColor != tmp.crTextColor)
+          pFmt->dwMask &= ~CFM_COLOR;
+      }
+    }
+      
+    pFmt->dwMask &= ~((pFmt->dwEffects ^ tmp.dwEffects) & nEffects);
+    
+  } while(run != run_end);
+}
diff --git a/reactos/lib/riched20/string.c b/reactos/lib/riched20/string.c
new file mode 100644 (file)
index 0000000..c18fa1d
--- /dev/null
@@ -0,0 +1,318 @@
+/*
+ * RichEdit - string operations
+ *
+ * Copyright 2004 by Krzysztof Foltman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "editor.h"     
+
+WINE_DEFAULT_DEBUG_CHANNEL(richedit);
+
+int ME_GetOptimalBuffer(int nLen)
+{
+  return ((2*nLen+1)+128)&~63;
+}
+
+ME_String *ME_MakeString(LPCWSTR szText)
+{
+  ME_String *s = ALLOC_OBJ(ME_String);
+  s->nLen = lstrlenW(szText);
+  s->nBuffer = ME_GetOptimalBuffer(s->nLen+1);
+  s->szData = ALLOC_N_OBJ(WCHAR, s->nBuffer);
+  lstrcpyW(s->szData, szText);
+  return s;
+}
+
+ME_String *ME_MakeStringN(LPCWSTR szText, int nMaxChars)
+{
+  ME_String *s = ALLOC_OBJ(ME_String);
+  int i;
+  for (i=0; i<nMaxChars && szText[i]; i++)
+    ;
+  s->nLen = i;
+  s->nBuffer = ME_GetOptimalBuffer(s->nLen+1);
+  s->szData = ALLOC_N_OBJ(WCHAR, s->nBuffer);
+  lstrcpynW(s->szData, szText, s->nLen+1);
+  return s;
+}
+
+ME_String *ME_StrDup(ME_String *s)
+{
+  return ME_MakeStringN(s->szData, s->nLen);
+}
+
+void ME_DestroyString(ME_String *s)
+{
+  FREE_OBJ(s->szData);
+  FREE_OBJ(s);
+}
+
+void ME_AppendString(ME_String *s1, ME_String *s2)
+{
+  if (s1->nLen+s2->nLen+1 <= s1->nBuffer) {
+    lstrcpyW(s1->szData+s1->nLen, s2->szData);
+    s1->nLen += s2->nLen;
+  }
+  else
+  {
+    WCHAR *buf;
+    s1->nBuffer = ME_GetOptimalBuffer(s1->nLen+s2->nLen+1);
+
+    buf = ALLOC_N_OBJ(WCHAR, s1->nBuffer); 
+    lstrcpyW(buf, s1->szData);
+    lstrcpyW(buf+s1->nLen, s2->szData);
+    FREE_OBJ(s1->szData);
+    s1->szData = buf;
+    s1->nLen += s2->nLen;
+  }
+}
+
+ME_String *ME_ConcatString(ME_String *s1, ME_String *s2)
+{
+  ME_String *s = ALLOC_OBJ(ME_String);
+  s->nLen = s1->nLen+s2->nLen;
+  s->nBuffer = ME_GetOptimalBuffer(s1->nLen+s2->nLen+1);
+  s->szData = ALLOC_N_OBJ(WCHAR, s->nBuffer);
+  lstrcpyW(s->szData, s1->szData);
+  lstrcpyW(s->szData+s1->nLen, s2->szData);
+  return s;  
+}
+
+ME_String *ME_VSplitString(ME_String *orig, int charidx)
+{
+  ME_String *s;
+
+  /*if (charidx<0) charidx = 0;
+  if (charidx>orig->nLen) charidx = orig->nLen;
+  */
+  assert(charidx>=0);
+  assert(charidx<=orig->nLen);
+
+  s = ME_MakeString(orig->szData+charidx);
+  orig->nLen = charidx;
+  orig->szData[charidx] = L'\0';
+  return s;
+}
+
+int ME_IsWhitespaces(ME_String *s)
+{
+  /* FIXME multibyte */
+  WCHAR *pos = s->szData;
+  while(*pos++ == ' ')
+    ;
+  pos--;
+  if (*pos)
+    return 0;
+  else
+    return 1;
+}
+
+int ME_IsSplitable(ME_String *s)
+{
+  /* FIXME multibyte */
+  WCHAR *pos = s->szData;
+  WCHAR ch;
+  while(*pos++ == L' ')
+    ;
+  pos--;
+  while((ch = *pos++) != 0)
+  {
+    if (ch == L' ')
+      return 1;
+  }
+  return 0;
+}
+
+/* FIXME multibyte */
+/*
+int ME_CalcSkipChars(ME_String *s)
+{
+  int cnt = 0;
+  while(cnt < s->nLen && s->szData[s->nLen-1-cnt]==' ')
+    cnt++;
+  return cnt;
+}
+*/
+
+int ME_StrLen(ME_String *s) { 
+  return s->nLen;
+}
+
+int ME_StrVLen(ME_String *s) {
+  return s->nLen;
+}
+
+/* FIXME we use widechars, not multibytes, inside, no need for complex logic anymore */
+int ME_StrRelPos(ME_String *s, int nVChar, int *pRelChars)
+{
+  TRACE("%s,%d,&%d\n", debugstr_w(s->szData), nVChar, *pRelChars);
+
+  assert(*pRelChars);
+  if (!*pRelChars) return nVChar;
+  
+  if (*pRelChars>0)
+  {
+    while(nVChar<s->nLen && *pRelChars>0)
+    {
+      nVChar++;
+      (*pRelChars)--;
+    }
+    return nVChar;
+  }
+
+  while(nVChar>0 && *pRelChars<0)
+  {
+    nVChar--;
+    (*pRelChars)++;
+  }
+  return nVChar;
+}
+
+int ME_StrRelPos2(ME_String *s, int nVChar, int nRelChars)
+{
+  return ME_StrRelPos(s, nVChar, &nRelChars);
+}
+
+int ME_VPosToPos(ME_String *s, int nVPos)
+{
+  return nVPos;
+  /*
+  int i = 0, len = 0;
+  if (!nVPos)
+    return 0;
+  while (i < s->nLen)
+  {
+    if (i == nVPos)
+      return len;
+    if (s->szData[i]=='\\') i++;
+    i++;
+    len++;
+  }
+  return len;
+  */
+}
+
+int ME_PosToVPos(ME_String *s, int nPos)
+{
+  if (!nPos)
+    return 0;
+  return ME_StrRelPos2(s, 0, nPos);
+}
+
+void ME_StrDeleteV(ME_String *s, int nVChar, int nChars)
+{
+  int end_ofs;
+  
+  assert(nVChar >=0 && nVChar <= s->nLen);
+  assert(nChars >= 0);
+  assert(nVChar+nChars <= s->nLen);
+  
+  end_ofs = ME_StrRelPos2(s, nVChar, nChars);
+  assert(end_ofs <= s->nLen);
+  memmove(s->szData+nVChar, s->szData+end_ofs, 2*(s->nLen+1-end_ofs));
+  s->nLen -= (end_ofs - nVChar);
+}
+
+int ME_GetCharFwd(ME_String *s, int nPos)
+{
+  int nVPos = 0;
+  
+  assert(nPos < ME_StrLen(s));
+  if (nPos)
+    nVPos = ME_StrRelPos2(s, nVPos, nPos);
+  
+  if (nVPos < s->nLen)
+    return s->szData[nVPos];
+  return -1;
+}
+
+int ME_GetCharBack(ME_String *s, int nPos)
+{
+  int nVPos = ME_StrVLen(s);
+  
+  assert(nPos < ME_StrLen(s));
+  if (nPos)
+    nVPos = ME_StrRelPos2(s, nVPos, -nPos);
+  
+  if (nVPos < s->nLen)
+    return s->szData[nVPos];
+  return -1;
+}
+
+int ME_FindNonWhitespaceV(ME_String *s, int nVChar) {
+  int i;
+  for (i = nVChar; isspace(s->szData[i]) && i<s->nLen; i++)
+    ;
+    
+  return i;
+}
+
+/* note: returns offset of the first trailing whitespace */
+int ME_ReverseFindNonWhitespaceV(ME_String *s, int nVChar) {
+  int i;
+  for (i = nVChar; i>0 && isspace(s->szData[i-1]); i--)
+    ;
+    
+  return i;
+}
+
+/* note: returns offset of the first trailing nonwhitespace */
+int ME_ReverseFindWhitespaceV(ME_String *s, int nVChar) {
+  int i;
+  for (i = nVChar; i>0 && !isspace(s->szData[i-1]); i--)
+    ;
+    
+  return i;
+}
+
+LPWSTR ME_ToUnicode(HWND hWnd, LPVOID psz)
+{
+  if (IsWindowUnicode(hWnd))
+    return (LPWSTR)psz;
+  else {
+    WCHAR *tmp;
+    int nChars = MultiByteToWideChar(CP_ACP, 0, (char *)psz, -1, NULL, 0);
+    if((tmp = ALLOC_N_OBJ(WCHAR, nChars)) != NULL)
+      MultiByteToWideChar(CP_ACP, 0, (char *)psz, -1, tmp, nChars);
+    return tmp;
+  }
+}
+
+void ME_EndToUnicode(HWND hWnd, LPVOID psz)
+{
+  if (IsWindowUnicode(hWnd))
+    FREE_OBJ(psz);
+}
+
+LPSTR ME_ToAnsi(HWND hWnd, LPVOID psz)
+{
+  if (!IsWindowUnicode(hWnd))
+    return (LPSTR)psz;
+  else {
+    char *tmp;
+    int nChars = WideCharToMultiByte(CP_ACP, 0, (WCHAR *)psz, -1, NULL, 0, NULL, NULL);
+    if((tmp = ALLOC_N_OBJ(char, nChars)) != NULL)
+      WideCharToMultiByte(CP_ACP, 0, (WCHAR *)psz, -1, tmp, nChars, NULL, NULL);
+    return tmp;
+  }
+}
+
+void ME_EndToAnsi(HWND hWnd, LPVOID psz)
+{
+  if (!IsWindowUnicode(hWnd))
+    FREE_OBJ(psz);
+}
diff --git a/reactos/lib/riched20/style.c b/reactos/lib/riched20/style.c
new file mode 100644 (file)
index 0000000..b2be737
--- /dev/null
@@ -0,0 +1,443 @@
+/*
+ * RichEdit style management functions
+ *
+ * Copyright 2004 by Krzysztof Foltman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "editor.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(richedit);
+
+static int all_refs = 0;
+
+CHARFORMAT2W *ME_ToCF2W(CHARFORMAT2W *to, CHARFORMAT2W *from)
+{
+  if (from->cbSize == sizeof(CHARFORMATA))
+  {
+    CHARFORMATA *f = (CHARFORMATA *)from;
+    CopyMemory(to, f, sizeof(*f)-sizeof(f->szFaceName));
+    to->cbSize = sizeof(CHARFORMAT2W);
+    if (f->dwMask & CFM_FACE) {
+      MultiByteToWideChar(0, 0, f->szFaceName, -1, to->szFaceName, sizeof(to->szFaceName)/sizeof(WCHAR));
+    }
+    return to;
+  }
+  if (from->cbSize == sizeof(CHARFORMATW))
+  {
+    CHARFORMATW *f = (CHARFORMATW *)from;
+    CopyMemory(to, f, sizeof(*f));
+    /* theoretically, we don't need to zero the remaining memory */
+    ZeroMemory(((CHARFORMATW *)to)+1, sizeof(CHARFORMAT2W)-sizeof(CHARFORMATW));
+    to->cbSize = sizeof(CHARFORMAT2W);
+    return to;
+  }
+  if (from->cbSize == sizeof(CHARFORMAT2A))
+  {
+    CHARFORMATA *f = (CHARFORMATA *)from;
+    /* copy the A structure without face name */
+    CopyMemory(to, f, sizeof(CHARFORMATA)-sizeof(f->szFaceName));
+    /* convert face name */
+    if (f->dwMask & CFM_FACE)
+      MultiByteToWideChar(0, 0, f->szFaceName, -1, to->szFaceName, sizeof(to->szFaceName));
+    /* copy the rest of the 2A structure to 2W */
+    CopyMemory(1+((CHARFORMATW *)from), f+1, sizeof(CHARFORMAT2A)-sizeof(CHARFORMATA));
+    to->cbSize = sizeof(CHARFORMAT2W);
+    return to;
+  }
+
+  assert(from->cbSize >= sizeof(CHARFORMAT2W));  
+  return from;
+}
+
+void ME_CopyToCF2W(CHARFORMAT2W *to, CHARFORMAT2W *from)
+{
+  if (ME_ToCF2W(to, from) == from)
+    CopyMemory(to, from, sizeof(*from));
+}
+
+CHARFORMAT2W *ME_ToCFAny(CHARFORMAT2W *to, CHARFORMAT2W *from)
+{
+  assert(from->cbSize == sizeof(CHARFORMAT2W));
+  if (to->cbSize == sizeof(CHARFORMATA))
+  {
+    CHARFORMATA *t = (CHARFORMATA *)to;
+    CopyMemory(t, from, sizeof(*t)-sizeof(t->szFaceName));
+    WideCharToMultiByte(0, 0, from->szFaceName, -1, t->szFaceName, sizeof(t->szFaceName), 0, 0);
+    t->cbSize = sizeof(*t); /* it was overwritten by CopyMemory */
+    return to;
+  }
+  if (to->cbSize == sizeof(CHARFORMATW))
+  {
+    CHARFORMATW *t = (CHARFORMATW *)to;
+    CopyMemory(t, from, sizeof(*t));
+    t->cbSize = sizeof(*t); /* it was overwritten by CopyMemory */
+    return to;
+  }
+  if (to->cbSize == sizeof(CHARFORMAT2A))
+  {
+    CHARFORMAT2A *t = (CHARFORMAT2A *)to;
+    /* copy the A structure without face name */
+    CopyMemory(t, from, sizeof(CHARFORMATA)-sizeof(t->szFaceName));
+    /* convert face name */
+    WideCharToMultiByte(0, 0, from->szFaceName, -1, t->szFaceName, sizeof(t->szFaceName), 0, 0);
+    /* copy the rest of the 2A structure to 2W */
+    CopyMemory(&t->wWeight, &from->wWeight, sizeof(CHARFORMAT2A)-sizeof(CHARFORMATA));
+    t->cbSize = sizeof(*t); /* it was overwritten by CopyMemory */
+    return to;
+  }
+  assert(to->cbSize >= sizeof(CHARFORMAT2W));  
+  return from;
+}
+
+void ME_CopyToCFAny(CHARFORMAT2W *to, CHARFORMAT2W *from)
+{
+  if (ME_ToCFAny(to, from) == from)
+    CopyMemory(to, from, to->cbSize);
+}
+
+ME_Style *ME_MakeStyle(CHARFORMAT2W *style) {
+  CHARFORMAT2W styledata;
+  ME_Style *s = ALLOC_OBJ(ME_Style);
+  
+  style = ME_ToCF2W(&styledata, style);
+  memset(s, 0, sizeof(ME_Style));
+  if (style->cbSize <= sizeof(CHARFORMAT2W))
+    CopyMemory(&s->fmt, style, style->cbSize);
+  else
+    CopyMemory(&s->fmt, style, sizeof(CHARFORMAT2W));
+  s->fmt.cbSize = sizeof(CHARFORMAT2W);
+
+  s->nSequence = -2;
+  s->nRefs = 1;
+  s->hFont = NULL;
+  all_refs++;
+  return s;
+}
+
+#define COPY_STYLE_ITEM(mask, member) \
+  if (style->dwMask & mask) { \
+    s->fmt.dwMask |= mask;\
+    s->fmt.member = style->member;\
+  }
+
+#define COPY_STYLE_ITEM_MEMCPY(mask, member) \
+  if (style->dwMask & mask) { \
+    s->fmt.dwMask |= mask;\
+    CopyMemory(s->fmt.member, style->member, sizeof(style->member));\
+  }
+  
+void ME_InitCharFormat2W(CHARFORMAT2W *pFmt)
+{
+  ZeroMemory(pFmt, sizeof(CHARFORMAT2W));
+  pFmt->cbSize = sizeof(CHARFORMAT2W);
+}
+
+ME_Style *ME_ApplyStyle(ME_Style *sSrc, CHARFORMAT2W *style)
+{
+  CHARFORMAT2W styledata;
+  ME_Style *s = ME_MakeStyle(&sSrc->fmt);
+  style = ME_ToCF2W(&styledata, style);
+  COPY_STYLE_ITEM(CFM_ANIMATION, bAnimation);
+  COPY_STYLE_ITEM(CFM_BACKCOLOR, crBackColor);
+  COPY_STYLE_ITEM(CFM_CHARSET, bCharSet);
+  COPY_STYLE_ITEM(CFM_COLOR, crTextColor);
+  COPY_STYLE_ITEM_MEMCPY(CFM_FACE, szFaceName);
+  COPY_STYLE_ITEM(CFM_KERNING, wKerning);
+  COPY_STYLE_ITEM(CFM_LCID, lcid);
+  COPY_STYLE_ITEM(CFM_OFFSET, yOffset);
+  COPY_STYLE_ITEM(CFM_REVAUTHOR, bRevAuthor);
+  COPY_STYLE_ITEM(CFM_SIZE, yHeight);
+  COPY_STYLE_ITEM(CFM_SPACING, sSpacing);
+  COPY_STYLE_ITEM(CFM_STYLE, sStyle);
+  COPY_STYLE_ITEM(CFM_UNDERLINETYPE, bUnderlineType);
+  COPY_STYLE_ITEM(CFM_WEIGHT, wWeight);
+  
+  s->fmt.dwEffects &= ~(style->dwMask);
+  s->fmt.dwEffects |= style->dwEffects & style->dwMask;
+  s->fmt.dwMask |= style->dwMask;
+  if (style->dwMask & CFM_COLOR)
+  {
+    if (style->dwEffects & CFE_AUTOCOLOR)
+      s->fmt.dwEffects |= CFE_AUTOCOLOR;
+    else
+      s->fmt.dwEffects &= ~CFE_AUTOCOLOR;
+  }
+  return s;
+}
+
+void ME_CopyCharFormat(CHARFORMAT2W *pDest, CHARFORMAT2W *pSrc)
+{
+  /* using this with non-2W structs is forbidden */
+  assert(pSrc->cbSize == sizeof(CHARFORMAT2W));
+  assert(pDest->cbSize == sizeof(CHARFORMAT2W));
+  CopyMemory(pDest, pSrc, sizeof(CHARFORMAT2W));
+}
+
+static void ME_DumpStyleEffect(char **p, const char *name, CHARFORMAT2W *fmt, int mask)
+{
+  *p += sprintf(*p, "%-22s%s\n", name, (fmt->dwMask & mask) ? ((fmt->dwEffects & mask) ? "YES" : "no") : "N/A");
+}
+
+void ME_DumpStyle(ME_Style *s)
+{
+  char buf[2048];
+  ME_DumpStyleToBuf(&s->fmt, buf);
+  TRACE("%s\n", buf);
+}
+
+void ME_DumpStyleToBuf(CHARFORMAT2W *pFmt, char buf[2048])
+{
+  /* FIXME only CHARFORMAT styles implemented */
+  /* this function sucks, doesn't check for buffer overruns but it's "good enough" as for debug code */
+  char *p;
+  p = buf;
+  p += sprintf(p, "Font face:            ");
+  if (pFmt->dwMask & CFM_FACE) {
+    WCHAR *q = pFmt->szFaceName;
+    while(*q) {
+      *p++ = (*q > 255) ? '?' : *q;
+      q++;      
+    }       
+  } else
+    p += sprintf(p, "N/A");
+
+  if (pFmt->dwMask & CFM_SIZE)
+    p += sprintf(p, "\nFont size:            %d\n", (int)pFmt->yHeight);
+  else
+    p += sprintf(p, "\nFont size:            N/A\n");
+    
+  if (pFmt->dwMask & CFM_OFFSET)
+    p += sprintf(p, "Char offset:          %d\n", (int)pFmt->yOffset);
+  else
+    p += sprintf(p, "Char offset:          N/A\n");
+
+  if (pFmt->dwMask & CFM_CHARSET)
+    p += sprintf(p, "Font charset:         %d\n", (int)pFmt->bCharSet);
+  else
+    p += sprintf(p, "Font charset:         N/A\n");
+    
+  /* I'm assuming CFM_xxx and CFE_xxx are the same values, fortunately it IS true wrt used flags*/
+  ME_DumpStyleEffect(&p, "Font bold:", pFmt, CFM_BOLD);
+  ME_DumpStyleEffect(&p, "Font italic:", pFmt, CFM_ITALIC);
+  ME_DumpStyleEffect(&p, "Font underline:", pFmt, CFM_UNDERLINE);
+  ME_DumpStyleEffect(&p, "Font strikeout:", pFmt, CFM_STRIKEOUT);
+  p += sprintf(p, "Text color:           ");
+  if (pFmt->dwMask & CFM_COLOR)
+  {
+    if (pFmt->dwEffects & CFE_AUTOCOLOR)
+      p += sprintf(p, "auto\n");
+    else
+      p += sprintf(p, "%06x\n", (int)pFmt->crTextColor);
+  }
+  else
+    p += sprintf(p, "N/A\n");
+  ME_DumpStyleEffect(&p, "Text protected:", pFmt, CFM_PROTECTED);
+}
+
+void ME_LogFontFromStyle(HDC hDC, LOGFONTW *lf, ME_Style *s)
+{
+  int rx, ry;
+  rx = GetDeviceCaps(hDC, LOGPIXELSX);
+  ry = GetDeviceCaps(hDC, LOGPIXELSY);
+  ZeroMemory(lf, sizeof(LOGFONTW));
+  lstrcpyW(lf->lfFaceName, s->fmt.szFaceName);
+  lf->lfHeight = -s->fmt.yHeight*ry/1440;
+  lf->lfWeight = 400;
+  if (s->fmt.dwEffects & s->fmt.dwMask & CFM_BOLD)
+    lf->lfWeight = 700;
+  if (s->fmt.dwEffects & s->fmt.dwMask & CFM_WEIGHT)
+    lf->lfWeight = s->fmt.wWeight;
+  if (s->fmt.dwEffects & s->fmt.dwMask & CFM_ITALIC)
+    lf->lfItalic = 1;
+  if (s->fmt.dwEffects & s->fmt.dwMask & CFM_UNDERLINE)
+    lf->lfUnderline = 1;
+  if (s->fmt.dwEffects & s->fmt.dwMask & CFM_STRIKEOUT)
+    lf->lfStrikeOut = 1;
+/*lf.lfQuality = PROOF_QUALITY; */
+  lf->lfPitchAndFamily = s->fmt.bPitchAndFamily;
+  lf->lfCharSet = s->fmt.bCharSet;
+}
+
+
+BOOL ME_IsFontEqual(LOGFONTW *p1, LOGFONTW *p2)
+{
+  if (memcmp(p1, p2, sizeof(LOGFONTW)-sizeof(p1->lfFaceName)))
+    return FALSE;
+  if (lstrcmpW(p1->lfFaceName, p2->lfFaceName))
+    return FALSE;
+  return TRUE;
+}
+
+HFONT ME_SelectStyleFont(ME_TextEditor *editor, HDC hDC, ME_Style *s)
+{
+  HFONT hOldFont;
+  LOGFONTW lf;
+  int i, nEmpty, nAge = 0x7FFFFFFF;
+  ME_FontCacheItem *item;
+  assert(hDC);
+  assert(s);
+  
+  ME_LogFontFromStyle(hDC, &lf, s);
+  
+  for (i=0; i<HFONT_CACHE_SIZE; i++)
+    editor->pFontCache[i].nAge++;
+  for (i=0, nEmpty=-1, nAge=0; i<HFONT_CACHE_SIZE; i++)
+  {
+    item = &editor->pFontCache[i];
+    if (!item->nRefs)
+    {
+      if (item->nAge > nAge)
+        nEmpty = i, nAge = item->nAge;
+    }
+    if (ME_IsFontEqual(&item->lfSpecs, &lf))
+      break;
+  }
+  if (i < HFONT_CACHE_SIZE) /* found */
+  {
+    item = &editor->pFontCache[i];
+    TRACE("font reused %d\n", i);
+
+    s->hFont = item->hFont;
+    item->nRefs++;
+  }
+  else
+  {
+    item = &editor->pFontCache[nEmpty]; /* this legal even when nEmpty == -1, as we don't dereference it */
+
+    assert(nEmpty != -1); /* otherwise we leak cache entries or get too many fonts at once*/
+    if (item->hFont) {
+      TRACE("font deleted %d\n", nEmpty);
+      DeleteObject(item->hFont);
+      item->hFont = NULL;
+    }
+    s->hFont = CreateFontIndirectW(&lf);
+    assert(s->hFont);
+    TRACE("font created %d\n", nEmpty);
+    item->hFont = s->hFont;
+    item->nRefs = 1;
+    memcpy(&item->lfSpecs, &lf, sizeof(LOGFONTW));
+  }
+  hOldFont = SelectObject(hDC, s->hFont);
+  /* should be cached too, maybe ? */
+  GetTextMetricsW(hDC, &s->tm);
+  return hOldFont;
+}
+
+void ME_UnselectStyleFont(ME_TextEditor *editor, HDC hDC, ME_Style *s, HFONT hOldFont)
+{
+  int i;
+  
+  assert(hDC);
+  assert(s);
+  SelectObject(hDC, hOldFont);
+  for (i=0; i<HFONT_CACHE_SIZE; i++)
+  {
+    ME_FontCacheItem *pItem = &editor->pFontCache[i];
+    if (pItem->hFont == s->hFont && pItem->nRefs > 0)
+    {
+      pItem->nRefs--;
+      pItem->nAge = 0;
+      s->hFont = NULL;
+      return;
+    }
+  }
+  assert(0 == "UnselectStyleFont without SelectStyleFont");
+}
+
+void ME_DestroyStyle(ME_Style *s) {
+  if (s->hFont)
+  {
+    DeleteObject(s->hFont);
+    s->hFont = NULL;
+  }
+  FREE_OBJ(s);
+}
+
+void ME_AddRefStyle(ME_Style *s)
+{
+  assert(s->nRefs>0); /* style with 0 references isn't supposed to exist */
+  s->nRefs++;
+  all_refs++;
+}
+
+void ME_ReleaseStyle(ME_Style *s)
+{
+  s->nRefs--;
+  all_refs--;
+  if (s->nRefs==0)
+    TRACE("destroy style %p, total refs=%d\n", s, all_refs);
+  else
+    TRACE("release style %p, new refs=%d, total refs=%d\n", s, s->nRefs, all_refs);
+  if (!all_refs) FIXME("all style references freed (good!)\n");
+  assert(s->nRefs>=0);
+  if (!s->nRefs)
+    ME_DestroyStyle(s);
+}
+
+ME_Style *ME_GetInsertStyle(ME_TextEditor *editor, int nCursor) {
+  if (ME_IsSelection(editor))
+  {
+    ME_Cursor c;
+    int from, to;
+    
+    ME_GetSelection(editor, &from, &to);
+    ME_CursorFromCharOfs(editor, from, &c);
+    ME_AddRefStyle(c.pRun->member.run.style);
+    return c.pRun->member.run.style;
+  }
+  if (editor->pBuffer->pCharStyle) {
+    ME_AddRefStyle(editor->pBuffer->pCharStyle);
+    return editor->pBuffer->pCharStyle;
+  }
+  else
+  {
+    ME_Cursor *pCursor = &editor->pCursors[nCursor];
+    ME_DisplayItem *pRunItem = pCursor->pRun;
+    ME_DisplayItem *pPrevItem = NULL;
+    if (pCursor->nOffset) {
+      ME_Run *pRun = &pRunItem->member.run;
+      ME_AddRefStyle(pRun->style);
+      return pRun->style;
+    }
+    pPrevItem = ME_FindItemBack(pRunItem, diRunOrParagraph);
+    if (pPrevItem->type == diRun)
+    {
+      ME_AddRefStyle(pPrevItem->member.run.style);
+      return pPrevItem->member.run.style;
+    }
+    else
+    {
+      ME_AddRefStyle(pRunItem->member.run.style);
+      return pRunItem->member.run.style;
+    }
+  }
+}
+
+void ME_SaveTempStyle(ME_TextEditor *editor)
+{
+  ME_Style *old_style = editor->pBuffer->pCharStyle;
+  editor->pBuffer->pCharStyle = ME_GetInsertStyle(editor, 0);
+  if (old_style)
+    ME_ReleaseStyle(old_style);
+}
+
+void ME_ClearTempStyle(ME_TextEditor *editor)
+{
+  if (!editor->pBuffer->pCharStyle) return;
+  ME_ReleaseStyle(editor->pBuffer->pCharStyle);
+  editor->pBuffer->pCharStyle = NULL;
+}
diff --git a/reactos/lib/riched20/undo.c b/reactos/lib/riched20/undo.c
new file mode 100644 (file)
index 0000000..e95edc1
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+ * RichEdit - functions dealing with editor object
+ *
+ * Copyright 2004 by Krzysztof Foltman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "editor.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(richedit);
+
+void ME_EmptyUndoStack(ME_TextEditor *editor)
+{
+  ME_DisplayItem *p, *pNext;
+  
+  TRACE("Emptying undo stack\n");
+
+  p = editor->pUndoStack;
+  editor->pUndoStack = NULL;
+  while(p) {
+    pNext = p->next;
+    ME_DestroyDisplayItem(p);    
+    p = pNext;
+  } 
+  p = editor->pRedoStack;
+  editor->pRedoStack = NULL;
+  while(p) {
+    pNext = p->next;
+    ME_DestroyDisplayItem(p);    
+    p = pNext;
+  } 
+}
+
+ME_UndoItem *ME_AddUndoItem(ME_TextEditor *editor, ME_DIType type, ME_DisplayItem *pdi) {
+  if (editor->nUndoMode == umIgnore)
+    return NULL;
+  else
+  {
+    ME_DisplayItem *pItem = (ME_DisplayItem *)ALLOC_OBJ(ME_UndoItem);
+    switch(type)
+    {
+    case diUndoEndTransaction:
+      break;
+    case diUndoSetParagraphFormat:
+      assert(pdi);
+      CopyMemory(&pItem->member.para, &pdi->member.para, sizeof(ME_Paragraph));
+      pItem->member.para.pFmt = ALLOC_OBJ(PARAFORMAT2);
+      CopyMemory(pItem->member.para.pFmt, pdi->member.para.pFmt, sizeof(PARAFORMAT2));
+      break;
+    case diUndoInsertRun:
+      assert(pdi);
+      CopyMemory(&pItem->member.run, &pdi->member.run, sizeof(ME_Run));
+      pItem->member.run.strText = ME_StrDup(pItem->member.run.strText);
+      ME_AddRefStyle(pItem->member.run.style);
+      break;
+    case diUndoSetCharFormat:
+    case diUndoSetDefaultCharFormat:
+      break;
+    case diUndoDeleteRun:
+    case diUndoJoinParagraphs:
+      break;
+    case diUndoSplitParagraph:
+      pItem->member.para.pFmt = ALLOC_OBJ(PARAFORMAT2);
+      pItem->member.para.pFmt->cbSize = sizeof(PARAFORMAT2);
+      pItem->member.para.pFmt->dwMask = 0;
+      break;
+    default:
+      assert(0 == "AddUndoItem, unsupported item type");
+      return NULL;
+    }
+    pItem->type = type;
+    pItem->prev = NULL;
+    if (editor->nUndoMode == umAddToUndo || editor->nUndoMode == umAddBackToUndo)
+    {
+      if (editor->nUndoMode == umAddToUndo)
+        TRACE("Pushing id=%s to undo stack, deleting redo stack\n", ME_GetDITypeName(type));
+      else
+        TRACE("Pushing id=%s to undo stack\n", ME_GetDITypeName(type));
+      pItem->next = editor->pUndoStack;
+      if (editor->pUndoStack)
+        editor->pUndoStack->prev = pItem;
+      editor->pUndoStack = pItem;
+      /* any new operation (not redo) clears the redo stack */
+      if (editor->nUndoMode == umAddToUndo) {
+        ME_DisplayItem *p = editor->pRedoStack;
+        while(p)
+        {
+          ME_DisplayItem *pp = p->next;
+          ME_DestroyDisplayItem(p);
+          p = pp;
+        }
+        editor->pRedoStack = NULL;
+      }
+    }
+    else if (editor->nUndoMode == umAddToRedo)
+    {
+      TRACE("Pushing id=%s to redo stack\n", ME_GetDITypeName(type));
+      pItem->next = editor->pRedoStack;
+      if (editor->pRedoStack)
+        editor->pRedoStack->prev = pItem;
+      editor->pRedoStack = pItem;
+    }
+    else
+      assert(0);
+    return (ME_UndoItem *)pItem;
+  }
+}
+
+void ME_CommitUndo(ME_TextEditor *editor) {
+  assert(editor->nUndoMode == umAddToUndo);
+  
+  /* no transactions, no need to commit */
+  if (!editor->pUndoStack)
+    return;
+
+  /* no need to commit empty transactions */
+  if (editor->pUndoStack->type == diUndoEndTransaction)
+    return;
+    
+  ME_AddUndoItem(editor, diUndoEndTransaction, NULL);
+  ME_SendSelChange(editor);
+  editor->nModifyStep++;
+}
+
+void ME_PlayUndoItem(ME_TextEditor *editor, ME_DisplayItem *pItem)
+{
+  ME_UndoItem *pUItem = (ME_UndoItem *)pItem;
+
+  TRACE("Playing undo/redo item, id=%s\n", ME_GetDITypeName(pItem->type));
+
+  switch(pItem->type)
+  {
+  case diUndoEndTransaction:
+    assert(0);
+  case diUndoSetParagraphFormat:
+  {
+    ME_Cursor tmp;
+    ME_CursorFromCharOfs(editor, pItem->member.para.nCharOfs, &tmp);
+    ME_SetParaFormat(editor, ME_FindItemBack(tmp.pRun, diParagraph), pItem->member.para.pFmt);
+    break;
+  }
+  case diUndoSetCharFormat:
+  {
+    ME_SetCharFormat(editor, pUItem->nStart, pUItem->nLen, &pItem->member.ustyle->fmt);
+    break;
+  }
+  case diUndoSetDefaultCharFormat:
+  {
+    ME_SetDefaultCharFormat(editor, &pItem->member.ustyle->fmt);
+    break;
+  }
+  case diUndoInsertRun:
+  {
+    ME_InsertRun(editor, pItem->member.run.nCharOfs, pItem);
+    break;
+  }
+  case diUndoDeleteRun:
+  {
+    ME_InternalDeleteText(editor, pUItem->nStart, pUItem->nLen);
+    break;
+  }
+  case diUndoJoinParagraphs:
+  {
+    ME_Cursor tmp;
+    ME_CursorFromCharOfs(editor, pUItem->nStart, &tmp);
+    /* the only thing that's needed is paragraph offset, so no need to split runs */
+    ME_JoinParagraphs(editor, ME_GetParagraph(tmp.pRun));
+    break;
+  }
+  case diUndoSplitParagraph:
+  {
+    ME_Cursor tmp;
+    ME_DisplayItem *new_para;
+    ME_CursorFromCharOfs(editor, pUItem->nStart, &tmp);
+    if (tmp.nOffset)
+      tmp.pRun = ME_SplitRunSimple(editor, tmp.pRun, tmp.nOffset);
+    new_para = ME_SplitParagraph(editor, tmp.pRun, tmp.pRun->member.run.style);
+    assert(pItem->member.para.pFmt->cbSize == sizeof(PARAFORMAT2));
+    CopyMemory(new_para->member.para.pFmt, pItem->member.para.pFmt, sizeof(PARAFORMAT2));
+    break;
+  }
+  default:
+    assert(0 == "PlayUndoItem, unexpected type");
+  }
+}
+
+void ME_Undo(ME_TextEditor *editor) {
+  ME_DisplayItem *p;
+  ME_UndoMode nMode = editor->nUndoMode;
+  
+  assert(nMode == umAddToUndo || nMode == umIgnore);
+  
+  /* no undo items ? */
+  if (!editor->pUndoStack)
+    return;
+    
+  /* watch out for uncommited transactions ! */
+  assert(editor->pUndoStack->type == diUndoEndTransaction);
+  
+  editor->nUndoMode = umAddToRedo;
+  p = editor->pUndoStack->next;
+  ME_DestroyDisplayItem(editor->pUndoStack);
+  do {
+    ME_DisplayItem *pp = p;
+    ME_PlayUndoItem(editor, p);
+    p = p->next;
+    ME_DestroyDisplayItem(pp);
+  } while(p && p->type != diUndoEndTransaction);
+  ME_AddUndoItem(editor, diUndoEndTransaction, NULL);
+  editor->pUndoStack = p;
+  if (p)
+    p->prev = NULL;
+  editor->nUndoMode = nMode;
+  editor->nModifyStep--;
+  ME_UpdateRepaint(editor);
+}
+
+void ME_Redo(ME_TextEditor *editor) {
+  ME_DisplayItem *p;
+  ME_UndoMode nMode = editor->nUndoMode;
+  
+  assert(nMode == umAddToUndo || nMode == umIgnore);
+  
+  /* no redo items ? */
+  if (!editor->pRedoStack)
+    return;
+    
+  /* watch out for uncommited transactions ! */
+  assert(editor->pRedoStack->type == diUndoEndTransaction);
+  
+  editor->nUndoMode = umAddBackToUndo;
+  p = editor->pRedoStack->next;
+  ME_DestroyDisplayItem(editor->pRedoStack);
+  do {
+    ME_DisplayItem *pp = p;
+    ME_PlayUndoItem(editor, p);
+    p = p->next;
+    ME_DestroyDisplayItem(pp);
+  } while(p && p->type != diUndoEndTransaction);
+  ME_AddUndoItem(editor, diUndoEndTransaction, NULL);
+  editor->pRedoStack = p;
+  if (p)
+    p->prev = NULL;
+  editor->nUndoMode = nMode;
+  editor->nModifyStep++;
+  ME_UpdateRepaint(editor);
+}
diff --git a/reactos/lib/riched20/wrap.c b/reactos/lib/riched20/wrap.c
new file mode 100644 (file)
index 0000000..683b659
--- /dev/null
@@ -0,0 +1,449 @@
+/*
+ * RichEdit - Paragraph wrapping. Don't try to understand it. You've been
+ * warned !
+ *
+ * Copyright 2004 by Krzysztof Foltman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#include "editor.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(richedit);
+
+/*
+ * Unsolved problems:
+ *  
+ * - center and right align in WordPad omits all spaces at the start, we don't
+ * - objects/images are not handled yet
+ * - no tabs 
+ */ 
+ME_DisplayItem *ME_MakeRow(int height, int baseline, int width)
+{
+  ME_DisplayItem *item = ME_MakeDI(diStartRow);
+  
+  item->member.row.nHeight = height;
+  item->member.row.nBaseline = baseline;
+  item->member.row.nWidth = width;
+  return item;
+}
+
+void ME_BeginRow(ME_WrapContext *wc)
+{
+  wc->pRowStart = NULL;
+  wc->bOverflown = FALSE;
+  wc->pLastSplittableRun = NULL;
+  wc->nAvailWidth = wc->nTotalWidth - (wc->nRow ? wc->nLeftMargin : wc->nFirstMargin) - wc->nRightMargin;
+  wc->pt.x = 0;
+}  
+
+void ME_InsertRowStart(ME_WrapContext *wc, ME_DisplayItem *pEnd)
+{
+  ME_DisplayItem *p, *row, *para;
+  int ascent = 0, descent = 0, width=0, shift = 0, align = 0;
+  /* wrap text */
+  para = ME_GetParagraph(wc->pRowStart);
+  for (p = wc->pRowStart; p!=pEnd; p = p->next)
+  {
+    /* ENDPARA run shouldn't affect row height, except if it's the only run in the paragraph */
+    if (p->type==diRun && ((p==wc->pRowStart) || !(p->member.run.nFlags & MERF_ENDPARA))) { /* FIXME add more run types */
+      if (p->member.run.nAscent>ascent)
+        ascent = p->member.run.nAscent;
+      if (p->member.run.nDescent>descent)
+        descent = p->member.run.nDescent;
+      if (!(p->member.run.nFlags & (MERF_ENDPARA|MERF_SKIPPED)))
+        width += p->member.run.nWidth;
+    }
+  }
+  row = ME_MakeRow(ascent+descent, ascent, width);
+  row->member.row.nYPos = wc->pt.y;
+  row->member.row.nLMargin = (!wc->nRow ? wc->nFirstMargin : wc->nLeftMargin);
+  row->member.row.nRMargin = wc->nRightMargin;
+  assert(para->member.para.pFmt->dwMask & PFM_ALIGNMENT);
+  align = para->member.para.pFmt->wAlignment;
+  if (align == PFA_CENTER)
+    shift = (wc->nAvailWidth-width)/2;
+  if (align == PFA_RIGHT)
+    shift = wc->nAvailWidth-width;
+  for (p = wc->pRowStart; p!=pEnd; p = p->next)
+  {
+    if (p->type==diRun) { /* FIXME add more run types */
+      p->member.run.pt.x += row->member.row.nLMargin+shift;
+    }
+  }
+  ME_InsertBefore(wc->pRowStart, row);
+  wc->nRow++;
+  wc->pt.y += ascent+descent;
+  ME_BeginRow(wc);
+}
+
+void ME_WrapEndParagraph(ME_WrapContext *wc, ME_DisplayItem *p)
+{
+  if (wc->pRowStart)
+    ME_InsertRowStart(wc, p->next);
+    
+  /*
+  p = p->member.para.prev_para->next;
+  while(p) {
+    if (p->type == diParagraph || p->type == diTextEnd)
+      return;
+    if (p->type == diRun)
+    {
+      ME_Run *run = &p->member.run;
+      TRACE("%s - (%d, %d)\n", debugstr_w(run->strText->szData), run->pt.x, run->pt.y);
+    }
+    p = p->next;
+  }
+  */
+}  
+
+void ME_WrapSizeRun(ME_WrapContext *wc, ME_DisplayItem *p)
+{
+  /* FIXME compose style (out of character and paragraph styles) here */
+  
+  ME_UpdateRunFlags(wc->context->editor, &p->member.run);
+  
+  ME_CalcRunExtent(wc->context, &p->member.run);
+}
+
+ME_DisplayItem *ME_MaximizeSplit(ME_WrapContext *wc, ME_DisplayItem *p, int i)
+{
+  ME_DisplayItem *pp, *piter = p;
+  int j;
+  if (!i)
+    return NULL;
+  j = ME_ReverseFindNonWhitespaceV(p->member.run.strText, i);
+  if (j>0) {
+    pp = ME_SplitRun(wc->context, piter, j);
+    wc->pt.x += piter->member.run.nWidth;
+    return pp;
+  }
+  else
+  {
+    pp = piter;
+    /* omit all spaces before split point */
+    while(piter != wc->pRowStart)
+    {
+      piter = ME_FindItemBack(piter, diRun);
+      if (piter->member.run.nFlags & MERF_WHITESPACE) 
+      {
+        pp = piter;
+        continue;
+      }
+      if (piter->member.run.nFlags & MERF_ENDWHITE)
+      {
+        j = ME_ReverseFindNonWhitespaceV(piter->member.run.strText, i);
+        pp = ME_SplitRun(wc->context, piter, i);
+        wc->pt = pp->member.run.pt;
+        return pp;
+      }
+      /* this run is the end of spaces, so the run edge is a good point to split */
+      wc->pt = pp->member.run.pt;
+      wc->bOverflown = TRUE;
+      TRACE("Split point is: %s|%s\n", debugstr_w(piter->member.run.strText->szData), debugstr_w(pp->member.run.strText->szData));
+      return pp;
+    }
+    wc->pt = piter->member.run.pt;
+    return piter;
+  }
+}
+
+ME_DisplayItem *ME_SplitByBacktracking(ME_WrapContext *wc, ME_DisplayItem *p, int loc)
+{
+  ME_DisplayItem *piter = p, *pp;
+  int i, idesp, len;
+  ME_Run *run = &p->member.run;
+  
+  idesp = i = ME_CharFromPoint(wc->context->editor, loc, run);
+  len = ME_StrVLen(run->strText);
+  assert(len>0);
+  assert(i<len);
+  if (i) {
+    /* don't split words */
+    i = ME_ReverseFindWhitespaceV(run->strText, i);
+    pp = ME_MaximizeSplit(wc, p, i);
+    if (pp)
+      return pp;
+  }
+  TRACE("Must backtrack to split at: %s\n", debugstr_w(p->member.run.strText->szData));
+  if (wc->pLastSplittableRun)
+  {
+    if (wc->pLastSplittableRun->member.run.nFlags & MERF_GRAPHICS)
+    {
+      wc->pt = wc->ptLastSplittableRun;
+      return wc->pLastSplittableRun;
+    }
+    else if (wc->pLastSplittableRun->member.run.nFlags & MERF_SPLITTABLE)
+    {
+      /* the following two lines are just to check if we forgot to call UpdateRunFlags earlier,
+         they serve no other purpose */
+      ME_UpdateRunFlags(wc->context->editor, run);
+      assert((wc->pLastSplittableRun->member.run.nFlags & MERF_SPLITTABLE));
+      
+      piter = wc->pLastSplittableRun;
+      run = &piter->member.run;
+      len = ME_StrVLen(run->strText);
+      /* don't split words */
+      i = ME_ReverseFindWhitespaceV(run->strText, len);
+      if (i == len)
+        i = ME_ReverseFindNonWhitespaceV(run->strText, len);
+      if (i) {        
+        ME_DisplayItem *piter2 = ME_SplitRun(wc->context, piter, i);
+        wc->pt = piter2->member.run.pt;
+        return piter2;
+      }
+      /* splittable = must have whitespaces */
+      assert(0 == "Splittable, but no whitespaces");
+    }
+    else
+    {
+      /* restart from the first run beginning with spaces */
+      wc->pt = wc->ptLastSplittableRun;
+      return wc->pLastSplittableRun;
+    }
+  }
+  TRACE("Backtracking failed, trying desperate: %s\n", debugstr_w(p->member.run.strText->szData));
+  /* OK, no better idea, so assume we MAY split words if we can split at all*/
+  if (idesp)
+    return ME_SplitRun(wc->context, piter, idesp);
+  else
+  if (wc->pRowStart && piter != wc->pRowStart)
+  {
+    /* don't need to break current run, because it's possible to split
+       before this run */
+    wc->bOverflown = TRUE;
+    return piter;
+  }
+  else
+  {
+    /* split point inside first character - no choice but split after that char */
+    int chars = 1;
+    int pos2 = ME_StrRelPos(run->strText, 0, &chars);
+    if (pos2 != len) {
+      /* the run is more than 1 char, so we may split */
+      return ME_SplitRun(wc->context, piter, pos2);
+    }
+    /* the run is one char, can't split it */
+    return piter;
+  }  
+}
+
+ME_DisplayItem *ME_WrapHandleRun(ME_WrapContext *wc, ME_DisplayItem *p)
+{
+  ME_DisplayItem *pp;
+  ME_Run *run;
+  int len;
+
+  assert(p->type == diRun);  
+  if (!wc->pRowStart)
+    wc->pRowStart = p;
+  ME_WrapSizeRun(wc, p);
+  run = &p->member.run;
+  run->pt.x = wc->pt.x;
+  run->pt.y = wc->pt.y;
+  len = ME_StrVLen(run->strText);  
+  
+  if (wc->bOverflown) /* just skipping final whitespaces */
+  {    
+    if (run->nFlags & MERF_WHITESPACE) {
+      p->member.run.nFlags |= MERF_SKIPPED;
+      /* wc->pt.x += run->nWidth; */
+      /* skip runs consisting of only whitespaces */
+      return p->next;
+    }
+    
+    if (run->nFlags & MERF_STARTWHITE) {
+      /* try to split the run at the first non-white char */
+      int black;
+      black = ME_FindNonWhitespaceV(run->strText, 0);
+      if (black) {
+        wc->bOverflown = FALSE;
+        pp = ME_SplitRun(wc->context, p, black);
+        p->member.run.nFlags |= MERF_SKIPPED;
+/*
+        run->pt = wc->pt;
+        wc->pt.x += run->nWidth;
+        */
+        ME_InsertRowStart(wc, pp);
+        return pp;
+      }
+    }
+    /* black run: the row goes from pRowStart to the previous run */
+    ME_InsertRowStart(wc, p);
+    return p;
+  }
+  /* we're not at the end of the row */
+  /* will current run fit? */
+  if (wc->pt.x + run->nWidth > wc->nAvailWidth)
+  {
+    int loc = wc->nAvailWidth - wc->pt.x;    
+    /* total white run ? */
+    if (run->nFlags & MERF_WHITESPACE) {
+      /* let the overflow logic handle it */
+      wc->bOverflown = TRUE;
+      return p;
+    }
+    /* graphics - we can split before */
+    if (run->nFlags & MERF_GRAPHICS) {
+      wc->bOverflown = TRUE;
+      return p;
+    }
+    /* can we separate out the last spaces ? (to use overflow logic later) */
+    if (run->nFlags & MERF_ENDWHITE)
+    {
+      /* we aren't sure if it's *really* necessary, it's a good start however */
+      int black = ME_ReverseFindNonWhitespaceV(run->strText, len);
+      ME_SplitRun(wc->context, p, black);
+      /* handle both parts again */
+      return p;
+    }
+    /* determine the split point by backtracking */
+    pp = ME_SplitByBacktracking(wc, p, loc);
+    if (pp == wc->pRowStart)
+    {
+      /* we had only spaces so far, entire content can be omitted */
+      wc->pt.x = 0;
+      return p->next;
+    }
+    if (p != pp) /* found a suitable split point */
+    {
+      wc->bOverflown = TRUE;
+      return pp;
+    }
+    /* we detected that it's best to split on start of this run */
+    if (wc->bOverflown)
+      return pp;
+    ERR("failure!\n");
+    /* not found anything - writing over margins is the only option left */
+  }
+  if ((run->nFlags & (MERF_SPLITTABLE | MERF_STARTWHITE)) 
+    || ((run->nFlags & MERF_GRAPHICS) && (p != wc->pRowStart)))
+  {
+    wc->pLastSplittableRun = p;
+    wc->ptLastSplittableRun = wc->pt;
+  }
+  wc->pt.x += run->nWidth;
+  return p->next;
+}
+  
+void ME_WrapTextParagraph(ME_Context *c, ME_DisplayItem *tp) {
+  ME_DisplayItem *p;
+  ME_WrapContext wc;
+
+  assert(tp->type == diParagraph);  
+  if (!(tp->member.para.nFlags & MEPF_REWRAP)) {
+    return;
+  }
+  ME_PrepareParagraphForWrapping(c, tp);
+  
+  wc.context = c;
+/*   wc.para_style = tp->member.para.style; */
+  wc.style = NULL;
+  wc.nFirstMargin = tp->member.para.nFirstMargin;
+  wc.nLeftMargin = tp->member.para.nLeftMargin;
+  wc.nRightMargin = tp->member.para.nRightMargin;
+  wc.nRow = 0;
+  wc.pt.x = 0;
+  wc.pt.y = 0;
+  wc.nTotalWidth = c->rcView.right - c->rcView.left;
+  wc.nAvailWidth = wc.nTotalWidth - wc.nFirstMargin - wc.nRightMargin;
+  wc.pRowStart = NULL;
+  
+  ME_BeginRow(&wc);
+  for (p = tp->next; p!=tp->member.para.next_para; ) {
+    assert(p->type != diStartRow);
+    if (p->type == diRun) {
+      p = ME_WrapHandleRun(&wc, p);
+      continue;
+    }
+    p = p->next;
+  }
+  ME_WrapEndParagraph(&wc, p);
+  tp->member.para.nFlags &= ~MEPF_REWRAP;
+  tp->member.para.nHeight = wc.pt.y;
+}
+
+
+void ME_PrepareParagraphForWrapping(ME_Context *c, ME_DisplayItem *tp) {
+  ME_DisplayItem *p;
+  /* remove all items that will be reinserted by paragraph wrapper anyway */
+  for (p = tp->next; p!=tp->member.para.next_para; p = p->next) {
+    switch(p->type) {
+      case diStartRow:
+        p = p->prev;
+        ME_Remove(p->next);
+        break;
+      default:
+        break;
+    }
+  }
+  /* join runs that can be joined, set up flags */
+  for (p = tp->next; p!=tp->member.para.next_para; p = p->next) {
+    int changed = 0;
+    switch(p->type) {
+      case diStartRow: assert(0); break; /* should have deleted it */
+      case diRun:
+        while (p->next->type == diRun) { /* FIXME */
+          if (ME_CanJoinRuns(&p->member.run, &p->next->member.run)) {
+            ME_JoinRuns(c->editor, p);
+            changed = 1;
+          }
+          else
+            break;
+        }
+        p->member.run.nFlags &= ~MERF_CALCBYWRAP;
+        break;
+      default:
+        break;
+    }
+  }
+}
+
+void ME_WrapMarkedParagraphs(ME_TextEditor *editor) {
+  HWND hWnd = editor->hWnd;
+  HDC hDC = GetDC(hWnd);
+  ME_DisplayItem *item;
+  ME_Context c;
+  
+  ME_InitContext(&c, editor, hDC);
+  c.pt.x = 0;
+  c.pt.y = 0;
+  item = editor->pBuffer->pFirst->next;
+  while(item != editor->pBuffer->pLast) {
+    BOOL bRedraw = FALSE;
+    
+    assert(item->type == diParagraph);
+    if ((item->member.para.nFlags & MEPF_REWRAP)
+     || (item->member.para.nYPos != c.pt.y))
+      bRedraw = TRUE;
+    item->member.para.nYPos = c.pt.y;
+    
+    ME_WrapTextParagraph(&c, item);
+
+    if (bRedraw)
+      item->member.para.nFlags |= MEPF_REPAINT;
+
+    c.pt.y += item->member.para.nHeight;
+    item = item->member.para.next_para;
+  }
+  editor->sizeWindow.cx = c.rcView.right-c.rcView.left;
+  editor->sizeWindow.cy = c.rcView.bottom-c.rcView.top;
+  editor->nTotalLength = c.pt.y;
+  
+  ME_DestroyContext(&c);
+  ReleaseDC(hWnd, hDC);
+}
index b569949..1e1d312 100644 (file)
@@ -81,6 +81,9 @@ DEFINE_GUID(FMTID_SummaryInformation,0xF29F85E0,0x4FF9,0x1068,0xAB,0x91,0x08,0x0
 DEFINE_GUID(FMTID_DocSummaryInformation,0xD5CDD502,0x2E9C,0x101B,0x93,0x97,0x08,0x00,0x2B,0x2C,0xF9,0xAE);
 DEFINE_GUID(FMTID_UserDefinedProperties,0xD5CDD505,0x2E9C,0x101B,0x93,0x97,0x08,0x00,0x2B,0x2C,0xF9,0xAE);
 
+DEFINE_GUID(IID_IRichEditOle,0x00020D00,0,0,0xC0,0,0,0,0,0,0,0x46);
+DEFINE_GUID(IID_IRichEditOleCallback,0x00020D03,0,0,0xC0,0,0,0,0,0,0,0x46);
+
 DEFINE_OLEGUID(IID_StdOle,0x00020430,0,0);
 
 DEFINE_GUID(CLSID_StdFont,0x0be35203,0x8f91,0x11ce,0x9d,0xe3,0x00,0xaa,0x00,0x4b,0xb8,0x51);
index 580b511..b1c2ab4 100644 (file)
@@ -29,8 +29,26 @@ extern "C" {
 #define CFM_FACE       0x20000000
 #define CFM_OFFSET     0x10000000
 #define CFM_CHARSET    0x08000000
+#define CFM_BACKCOLOR  0x04000000
+#define CFM_LCID       0x02000000
+#define CFM_UNDERLINETYPE      0x00800000
+#define CFM_WEIGHT     0x00400000
+#define CFM_SPACING    0x00200000
+#define CFM_KERNING    0x00100000
+#define CFM_STYLE      0x00080000
+#define CFM_ANIMATION  0x00040000
 #define CFM_SUBSCRIPT  0x00030000
 #define CFM_SUPERSCRIPT        0x00030000
+#define CFM_REVAUTHOR  0x00008000
+#define CFM_REVISED    0x00004000
+#define CFM_DISABLED   0x00002000
+#define CFM_IMPRINT    0x00001000
+#define CFM_EMBOSS     0x00000800
+#define CFM_SHADOW     0x00000400
+#define CFM_OUTLINE    0x00000200
+#define CFM_HIDDEN     0x00000100
+#define CFM_ALLCAPS    0x00000080
+#define CFM_SMALLCAPS  0x00000040
 #define CFM_EFFECTS    (CFM_BOLD | CFM_ITALIC | CFM_UNDERLINE | CFM_COLOR | CFM_STRIKEOUT | CFE_PROTECTED | CFM_LINK)
 #define CFE_BOLD       1
 #define CFE_ITALIC     2
@@ -38,6 +56,7 @@ extern "C" {
 #define CFE_STRIKEOUT  8
 #define CFE_PROTECTED  16
 #define CFE_AUTOCOLOR  0x40000000
+#define CFE_AUTOBACKCOLOR      0x04000000
 #define CFE_SUBSCRIPT  0x00010000
 #define CFE_SUPERSCRIPT        0x00020000
 #define IMF_FORCENONE  1