Index: trunk/src/bldprogs/scmrw.cpp
===================================================================
--- trunk/src/bldprogs/scmrw.cpp	(revision 69211)
+++ trunk/src/bldprogs/scmrw.cpp	(revision 69215)
@@ -77,4 +77,7 @@
     /** The comment style (neede for C/C++). */
     SCMCOMMENTSTYLE     enmCommentStyle;        /**< input */
+
+    /** Copy of the contributed-by line if present. */
+    char               *pszContributedBy;
 
     /** @name Common info
@@ -900,5 +903,37 @@
 
     /*
-     * Since the license statement is typically prefaced by a copyright line.
+     * Look for a 'contributed by' line, this comes first.
+     */
+    const char *pchContributedBy = NULL;
+    size_t      cchContributedBy = 0;
+    size_t      cBlankLinesAfterContributedBy = 0;
+    if (    pState->pszContributedBy == NULL
+        && (   pState->iLineCopyright == UINT32_MAX
+            || pState->iLineLicense == UINT32_MAX)
+        && cchBody > sizeof("Contributed by")
+        && RTStrNICmp(pszBody, RT_STR_TUPLE("contributed by")) == 0)
+    {
+        const char *pszNextLine = (const char *)memchr(pszBody, '\n', cchBody);
+        if (pszNextLine)
+        {
+            pchContributedBy = pszBody;
+            cchContributedBy = pszNextLine - pszBody;
+
+            /* Skip the copyright line and any blank lines following it. */
+            cchBody -= cchContributedBy + 1;
+            pszBody  = pszNextLine + 1;
+            iLine   += 1;
+            while (*pszBody == '\n')
+            {
+                pszBody++;
+                cchBody--;
+                iLine++;
+                cBlankLinesAfterContributedBy++;
+            }
+        }
+    }
+
+    /*
+     * Look for the copyright line.
      */
     bool     fFoundCopyright = false;
@@ -1037,4 +1072,15 @@
             }
 
+            if (pchContributedBy)
+            {
+                pState->pszContributedBy = RTStrDupN(pchContributedBy, cchContributedBy);
+                if (cBlankLinesAfterContributedBy != 1)
+                {
+                    ScmVerbose(pState->pState, 1, "* %u blank lines between contributed by and copyright, should be 1\n",
+                               cBlankLinesAfterContributedBy);
+                    pState->fWellFormedCopyright = false;
+                }
+            }
+
             fFoundCopyright = true;
             ScmVerbose(pState->pState, 2, "oracle copyright %u-%u: up-to-date=%RTbool well-formed=%RTbool\n",
@@ -1061,5 +1107,5 @@
 
     /*
-     * Now try match against the license texts if we haven't already found it.
+     * Look for the license text.
      */
     if (pState->iLineLicense == UINT32_MAX)
@@ -1181,4 +1227,6 @@
         /*.enmCommentStyle = */         enmCommentStyle,
 
+        /*.pszContributedBy = */        NULL,
+
         /*.iLineComment = */            UINT32_MAX,
         /*.cLinesComment = */           0,
@@ -1228,5 +1276,12 @@
         && RT_SUCCESS(pState->rc))
     {
-        if (Info.iLineCopyright == UINT32_MAX)
+        if (pSettings->fExternalCopyright)
+        {
+            if (Info.iLineCopyright != UINT32_MAX)
+                ScmError(pState, VERR_NOT_FOUND,
+                         "Marked as external copyright only, but found non-external copyright statement at line %u!\n",
+                         Info.iLineCopyright + 1);
+        }
+        else if (Info.iLineCopyright == UINT32_MAX)
             ScmError(pState, VERR_NOT_FOUND, "Missing copyright!\n");
         else if (Info.iLineLicense == UINT32_MAX)
@@ -1266,4 +1321,16 @@
                         ScmStreamPutLine(pOut, g_aCopyrightCommentStart[enmCommentStyle].psz,
                                          g_aCopyrightCommentStart[enmCommentStyle].cch, enmEol);
+
+                        /* Contributed by someone? */
+                        if (Info.pszContributedBy)
+                        {
+                            ScmStreamWrite(pOut, g_aCopyrightCommentPrefix[enmCommentStyle].psz,
+                                           g_aCopyrightCommentPrefix[enmCommentStyle].cch);
+                            ScmStreamWrite(pOut, Info.pszContributedBy, strlen(Info.pszContributedBy));
+                            ScmStreamPutEol(pOut, enmEol);
+
+                            ScmStreamPutLine(pOut, g_aCopyrightCommentEmpty[enmCommentStyle].psz,
+                                             g_aCopyrightCommentEmpty[enmCommentStyle].cch, enmEol);
+                        }
 
                         /* Write the copyright comment line. */
@@ -1327,6 +1394,11 @@
                     }
                     if (RT_FAILURE(rc))
+                    {
+                        RTStrFree(Info.pszContributedBy);
                         return false;
-                }
+                    }
+                } /* for each source line */
+
+                RTStrFree(Info.pszContributedBy);
                 return true;
             }
@@ -1336,4 +1408,5 @@
         ScmError(pState, rc,  "ScmEnumerateComments: %Rrc\n", rc);
     NOREF(pState); NOREF(pOut);
+    RTStrFree(Info.pszContributedBy);
     return false;
 }
