Add the ability to append breakpoints to the save file.

llvm-svn: 282212
diff --git a/lldb/source/API/SBTarget.cpp b/lldb/source/API/SBTarget.cpp
index 54ed098..7515343 100644
--- a/lldb/source/API/SBTarget.cpp
+++ b/lldb/source/API/SBTarget.cpp
@@ -1176,7 +1176,8 @@
 }
 
 lldb::SBError SBTarget::BreakpointsWriteToFile(SBFileSpec &dest_file,
-                                               SBBreakpointList &bkpt_list) {
+                                               SBBreakpointList &bkpt_list,
+                                               bool append) {
   SBError sberr;
   TargetSP target_sp(GetSP());
   if (!target_sp) {
@@ -1187,8 +1188,8 @@
   std::lock_guard<std::recursive_mutex> guard(target_sp->GetAPIMutex());
   BreakpointIDList bp_id_list;
   bkpt_list.CopyToBreakpointIDList(bp_id_list);
-  sberr.ref() =
-      target_sp->SerializeBreakpointsToFile(dest_file.ref(), bp_id_list);
+  sberr.ref() = target_sp->SerializeBreakpointsToFile(dest_file.ref(),
+                                                      bp_id_list, append);
   return sberr;
 }
 
diff --git a/lldb/source/Commands/CommandObjectBreakpoint.cpp b/lldb/source/Commands/CommandObjectBreakpoint.cpp
index 1e90b57..cb6d1d8 100644
--- a/lldb/source/Commands/CommandObjectBreakpoint.cpp
+++ b/lldb/source/Commands/CommandObjectBreakpoint.cpp
@@ -2210,7 +2210,8 @@
 #pragma mark Write::CommandOptions
 static OptionDefinition g_breakpoint_write_options[] = {
     // clang-format off
-  { LLDB_OPT_SET_ALL, true, "file", 'f', OptionParser::eRequiredArgument, nullptr, nullptr, CommandCompletions::eDiskFileCompletion, eArgTypeFilename,    "The file into which to write the breakpoints." },
+  { LLDB_OPT_SET_ALL, true,  "file",  'f', OptionParser::eRequiredArgument, nullptr, nullptr, CommandCompletions::eDiskFileCompletion, eArgTypeFilename,    "The file into which to write the breakpoints." },
+  { LLDB_OPT_SET_ALL, false, "append",'a', OptionParser::eNoArgument,       nullptr, nullptr, 0,                                       eArgTypeNone,        "Append to saved breakpoints file if it exists."},
     // clang-format on
 };
 
@@ -2251,6 +2252,9 @@
       case 'f':
         m_filename.assign(option_arg);
         break;
+      case 'a':
+        m_append = true;
+        break;
       default:
         error.SetErrorStringWithFormat("unrecognized option '%c'",
                                        short_option);
@@ -2262,6 +2266,7 @@
 
     void OptionParsingStarting(ExecutionContext *execution_context) override {
       m_filename.clear();
+      m_append = false;
     }
 
     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
@@ -2271,6 +2276,7 @@
     // Instance variables to hold the values for command options.
 
     std::string m_filename;
+    bool m_append = false;
   };
 
 protected:
@@ -2296,7 +2302,8 @@
       }
     }
     Error error = target->SerializeBreakpointsToFile(
-        FileSpec(m_options.m_filename.c_str(), true), valid_bp_ids);
+        FileSpec(m_options.m_filename.c_str(), true), valid_bp_ids,
+        m_options.m_append);
     if (!error.Success()) {
       result.AppendErrorWithFormat("error serializing breakpoints: %s.",
                                    error.AsCString());
diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp
index d73cc84..1fcc466 100644
--- a/lldb/source/Target/Target.cpp
+++ b/lldb/source/Target/Target.cpp
@@ -796,7 +796,8 @@
 }
 
 Error Target::SerializeBreakpointsToFile(const FileSpec &file,
-                                         const BreakpointIDList &bp_ids) {
+                                         const BreakpointIDList &bp_ids,
+                                         bool append) {
   Error error;
 
   if (!file) {
@@ -805,6 +806,28 @@
   }
 
   std::string path(file.GetPath());
+  StructuredData::ObjectSP input_data_sp;
+
+  StructuredData::ArraySP break_store_sp;
+  StructuredData::Array *break_store_ptr = nullptr;
+
+  if (append) {
+    input_data_sp = StructuredData::ParseJSONFromFile(file, error);
+    if (error.Success()) {
+      break_store_ptr = input_data_sp->GetAsArray();
+      if (!break_store_ptr) {
+        error.SetErrorStringWithFormat(
+            "Tried to append to invalid input file %s", path.c_str());
+        return error;
+      }
+    }
+  }
+
+  if (!break_store_ptr) {
+    break_store_sp.reset(new StructuredData::Array());
+    break_store_ptr = break_store_sp.get();
+  }
+
   StreamFile out_file(path.c_str(),
                       File::OpenOptions::eOpenOptionTruncate |
                           File::OpenOptions::eOpenOptionWrite |
@@ -820,7 +843,6 @@
   std::unique_lock<std::recursive_mutex> lock;
   GetBreakpointList().GetListMutex(lock);
 
-  StructuredData::ArraySP break_store_sp(new StructuredData::Array());
   if (bp_ids.GetSize() == 0) {
     const BreakpointList &breakpoints = GetBreakpointList();
 
@@ -830,7 +852,7 @@
       StructuredData::ObjectSP bkpt_save_sp = bp->SerializeToStructuredData();
       // If a breakpoint can't serialize it, just ignore it for now:
       if (bkpt_save_sp)
-        break_store_sp->AddItem(bkpt_save_sp);
+        break_store_ptr->AddItem(bkpt_save_sp);
     }
   } else {
 
@@ -857,12 +879,12 @@
                                          bp_id);
           return error;
         }
-        break_store_sp->AddItem(bkpt_save_sp);
+        break_store_ptr->AddItem(bkpt_save_sp);
       }
     }
   }
 
-  break_store_sp->Dump(out_file, false);
+  break_store_ptr->Dump(out_file, false);
   out_file.PutChar('\n');
   return error;
 }