Index: trunk/psModules/src/config/pmConfigMask.c
===================================================================
--- trunk/psModules/src/config/pmConfigMask.c	(revision 19442)
+++ trunk/psModules/src/config/pmConfigMask.c	(revision 19870)
@@ -12,27 +12,4 @@
 // Private functions
 //////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-static psMaskType maskGet(const psMetadata *source, // Source of masks
-                          const char *masks // Mask values to get
-                          )
-{
-    psMaskType mask = 0;                // Mask value, to return
-
-    psArray *names = psStringSplitArray(masks, " ,;", false); // Array of symbolic names
-    for (int i = 0; i < names->n; i++) {
-        const char *name = names->data[i]; // Symbolic name of interest
-        bool mdok;                      // Status of MD lookup
-        psMaskType value = psMetadataLookupU8(&mdok, source, name);
-        if (!mdok) {
-            psError(PS_ERR_BAD_PARAMETER_VALUE, false, "Unable to find mask value for %s", name);
-            psFree(names);
-            return 0;
-        }
-        mask |= value;
-    }
-    psFree(names);
-
-    return mask;
-}
 
 // maskSetValues examine named mask values and set the bits for maskValue and markValue.
@@ -152,4 +129,38 @@
 }
 
+// Get a mask value by name(s)
+static psMaskType maskGet(psMetadata *source, // Source of masks
+                          const char *masks // Mask values to get
+                          )
+{
+    psMaskType mask = 0;                // Mask value, to return
+
+    psArray *names = psStringSplitArray(masks, " ,;", false); // Array of symbolic names
+    for (int i = 0; i < names->n; i++) {
+        const char *name = names->data[i]; // Symbolic name of interest
+        bool mdok;                      // Status of MD lookup
+        psMaskType value = psMetadataLookupU8(&mdok, source, name);
+        if (!mdok) {
+            // Try and generate the value if we can
+            if (strcmp(name, "MASK.VALUE") == 0 || strcmp(name, "MARK.VALUE") == 0) {
+                if (!maskSetValues(NULL, NULL, source)) {
+                    psError(PS_ERR_UNKNOWN, false, "Unable to set mask bits.");
+                    return 0;
+                }
+                value = psMetadataLookupU8(&mdok, source, name);
+                psAssert(mdok, "Should have generated mask value");
+            } else {
+                psError(PS_ERR_BAD_PARAMETER_VALUE, false, "Unable to find mask value for %s", name);
+                psFree(names);
+                return 0;
+            }
+        }
+        mask |= value;
+    }
+    psFree(names);
+
+    return mask;
+}
+
 // Remove from the header keywords starting with the provided string
 static int maskRemoveHeader(psMetadata *header, // Header from which to remove keywords
@@ -327,5 +338,6 @@
     PS_ASSERT_STRING_NON_EMPTY(masks, 0);
 
-    psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, "MASKS"); // The recipe
+    bool mdok;                          // Status of MD lookup
+    psMetadata *recipe = psMetadataLookupMetadata(&mdok, config->recipes, "MASKS"); // The recipe
     if (!recipe) {
         psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find MASKS recipe.");
