Add a helper function findFruAreaLocationAndField to
updateFRUProperty

Refactoring updateFRUProperty function and created a new helper
function findFruAreaLocationAndField. Moved this function to
fru_utils.cpp as it is common for all fru-device deamons and
avoid code duplication.

This patch is created based on suggestion on the below patch.
https://gerrit.openbmc.org/c/openbmc/entity-manager/+/51555

TESTED : Built Facebook YosemiteV2 images and loaded
on the target hardware. Verified all the fru's read and write.

Signed-off-by: Kumar Thangavel <thangavel.k@hcl.com>
Change-Id: I82265e66ea5db10003e96978979250ea45c2052d
diff --git a/src/fru_device.cpp b/src/fru_device.cpp
index ed55e4a..50f1e4b 100644
--- a/src/fru_device.cpp
+++ b/src/fru_device.cpp
@@ -1108,100 +1108,20 @@
         return false;
     }
 
-    const std::vector<std::string>* fruAreaFieldNames = nullptr;
+    struct FruArea fruAreaParams{};
+    size_t fruDataIter = 0;
 
-    uint8_t fruAreaOffsetFieldValue = 0;
-    size_t offset = 0;
-    std::string areaName = propertyName.substr(0, propertyName.find('_'));
-    std::string propertyNamePrefix = areaName + "_";
-    auto it = std::find(fruAreaNames.begin(), fruAreaNames.end(), areaName);
-    if (it == fruAreaNames.end())
+    if (!findFruAreaLocationAndField(fruData, propertyName, fruAreaParams,
+                                     fruDataIter))
     {
-        std::cerr << "Can't parse area name for property " << propertyName
-                  << " \n";
-        return false;
-    }
-    fruAreas fruAreaToUpdate = static_cast<fruAreas>(it - fruAreaNames.begin());
-    fruAreaOffsetFieldValue =
-        fruData[getHeaderAreaFieldOffset(fruAreaToUpdate)];
-    switch (fruAreaToUpdate)
-    {
-        case fruAreas::fruAreaChassis:
-            offset = 3; // chassis part number offset. Skip fixed first 3 bytes
-            fruAreaFieldNames = &chassisFruAreas;
-            break;
-        case fruAreas::fruAreaBoard:
-            offset = 6; // board manufacturer offset. Skip fixed first 6 bytes
-            fruAreaFieldNames = &boardFruAreas;
-            break;
-        case fruAreas::fruAreaProduct:
-            // Manufacturer name offset. Skip fixed first 3 product fru bytes
-            // i.e. version, area length and language code
-            offset = 3;
-            fruAreaFieldNames = &productFruAreas;
-            break;
-        default:
-            std::cerr << "Don't know how to handle property " << propertyName
-                      << " \n";
-            return false;
-    }
-    if (fruAreaOffsetFieldValue == 0)
-    {
-        std::cerr << "FRU Area for " << propertyName << " not present \n";
+        std::cerr << "findFruAreaLocationAndField failed \n";
         return false;
     }
 
-    size_t fruAreaStart = fruAreaOffsetFieldValue * fruBlockSize;
-    size_t fruAreaSize = fruData[fruAreaStart + 1] * fruBlockSize;
-    size_t fruAreaEnd = fruAreaStart + fruAreaSize;
-    size_t fruDataIter = fruAreaStart + offset;
-    size_t skipToFRUUpdateField = 0;
     ssize_t fieldLength = 0;
 
-    bool found = false;
-    for (const auto& field : *fruAreaFieldNames)
-    {
-        skipToFRUUpdateField++;
-        if (propertyName == propertyNamePrefix + field)
-        {
-            found = true;
-            break;
-        }
-    }
-    if (!found)
-    {
-        std::size_t pos = propertyName.find(fruCustomFieldName);
-        if (pos == std::string::npos)
-        {
-            std::cerr << "PropertyName doesn't exist in FRU Area Vectors: "
-                      << propertyName << "\n";
-            return false;
-        }
-        std::string fieldNumStr =
-            propertyName.substr(pos + fruCustomFieldName.length());
-        size_t fieldNum = std::stoi(fieldNumStr);
-        if (fieldNum == 0)
-        {
-            std::cerr << "PropertyName not recognized: " << propertyName
-                      << "\n";
-            return false;
-        }
-        skipToFRUUpdateField += fieldNum;
-    }
-
-    for (size_t i = 1; i < skipToFRUUpdateField; i++)
-    {
-        fieldLength = getFieldLength(fruData[fruDataIter]);
-        if (fieldLength < 0)
-        {
-            break;
-        }
-        fruDataIter += 1 + fieldLength;
-    }
-    size_t fruUpdateFieldLoc = fruDataIter;
-
     // Push post update fru field bytes to a vector
-    fieldLength = getFieldLength(fruData[fruUpdateFieldLoc]);
+    fieldLength = getFieldLength(fruData[fruAreaParams.updateFieldLoc]);
     if (fieldLength < 0)
     {
         std::cerr << "Property " << propertyName << " not present \n";
@@ -1212,9 +1132,9 @@
     size_t endOfFieldsLoc = 0;
     while ((fieldLength = getFieldLength(fruData[fruDataIter])) >= 0)
     {
-        if (fruDataIter >= (fruAreaStart + fruAreaSize))
+        if (fruDataIter >= (fruAreaParams.start + fruAreaParams.size))
         {
-            fruDataIter = fruAreaStart + fruAreaSize;
+            fruDataIter = fruAreaParams.start + fruAreaParams.size;
             break;
         }
         fruDataIter += 1 + fieldLength;
@@ -1249,8 +1169,9 @@
 
     // check FRU area size
     size_t fruAreaDataSize =
-        ((fruUpdateFieldLoc - fruAreaStart + 1) + restFRUAreaFieldsData.size());
-    size_t fruAreaAvailableSize = fruAreaSize - fruAreaDataSize;
+        ((fruAreaParams.updateFieldLoc - fruAreaParams.start + 1) +
+         restFRUAreaFieldsData.size());
+    size_t fruAreaAvailableSize = fruAreaParams.size - fruAreaDataSize;
     if ((updatePropertyReqLen + 1) > fruAreaAvailableSize)
     {
 
@@ -1259,10 +1180,11 @@
         // round size to 8-byte blocks
         newFRUAreaSize =
             ((newFRUAreaSize - 1) / fruBlockSize + 1) * fruBlockSize;
-        size_t newFRUDataSize = fruData.size() + newFRUAreaSize - fruAreaSize;
+        size_t newFRUDataSize =
+            fruData.size() + newFRUAreaSize - fruAreaParams.size;
         fruData.resize(newFRUDataSize);
-        fruAreaSize = newFRUAreaSize;
-        fruAreaEnd = fruAreaStart + fruAreaSize;
+        fruAreaParams.size = newFRUAreaSize;
+        fruAreaParams.end = fruAreaParams.start + fruAreaParams.size;
 #else
         std::cerr << "FRU field length: " << updatePropertyReqLen + 1
                   << " should not be greater than available FRU area size: "
@@ -1273,21 +1195,21 @@
 
     // write new requested property field length and data
     constexpr uint8_t newTypeLenMask = 0xC0;
-    fruData[fruUpdateFieldLoc] =
+    fruData[fruAreaParams.updateFieldLoc] =
         static_cast<uint8_t>(updatePropertyReqLen | newTypeLenMask);
-    fruUpdateFieldLoc++;
+    fruAreaParams.updateFieldLoc++;
     std::copy(updatePropertyReq.begin(), updatePropertyReq.end(),
-              fruData.begin() + fruUpdateFieldLoc);
+              fruData.begin() + fruAreaParams.updateFieldLoc);
 
     // Copy remaining data to main fru area - post updated fru field vector
-    restFRUFieldsLoc = fruUpdateFieldLoc + updatePropertyReqLen;
+    restFRUFieldsLoc = fruAreaParams.updateFieldLoc + updatePropertyReqLen;
     size_t fruAreaDataEnd = restFRUFieldsLoc + restFRUAreaFieldsData.size();
     std::copy(restFRUAreaFieldsData.begin(), restFRUAreaFieldsData.end(),
               fruData.begin() + restFRUFieldsLoc);
 
     // Update final fru with new fru area length and checksum
     unsigned int nextFRUAreaNewLoc = updateFRUAreaLenAndChecksum(
-        fruData, fruAreaStart, fruAreaDataEnd, fruAreaEnd);
+        fruData, fruAreaParams.start, fruAreaDataEnd, fruAreaParams.end);
 
 #ifdef ENABLE_FRU_AREA_RESIZE
     ++nextFRUAreaNewLoc;