From edf108a2299a1504adc7fa5a070d116439512fa1 Mon Sep 17 00:00:00 2001
From: Marko Lindqvist <cazfi74@gmail.com>
Date: Sun, 17 Sep 2023 09:51:08 +0300
Subject: [PATCH 28/28] fcmp: Add support for multiple files_ sections

Each such section have their own baseURL.

See osdn #48613

Signed-off-by: Marko Lindqvist <cazfi74@gmail.com>
---
 doc/README.modpack_installer |  30 +++--
 tools/fcmp/download.c        | 224 +++++++++++++++++++----------------
 tools/fcmp/download.h        |   2 +-
 3 files changed, 148 insertions(+), 108 deletions(-)

diff --git a/doc/README.modpack_installer b/doc/README.modpack_installer
index b9fc889cb8..228eff2321 100644
--- a/doc/README.modpack_installer
+++ b/doc/README.modpack_installer
@@ -236,8 +236,7 @@ of the general syntax. Its filename must end in ".mpdl".
 Here is an example of a .mpdl file:
 
 [info]
-options = "+Freeciv-mpdl-Devel-3.2-2022.Jul.14"
-baseURL = "./ancients-6f88ee23de"
+options = "+Freeciv-mpdl-Devel-3.2-2023.Sep.17"
 name    = "Ancients"
 type    = "Modpack"
 version = "3.1-0"
@@ -248,7 +247,9 @@ list =
   "Ancients-tiles", "./ancients-tiles.mpdl", "Tileset", "3.1-0"
 }
 
-[files]
+[files_1]
+baseURL = "./ancients-6f88ee23de"
+
 list =
 { "src", "dest"
   "ancients/ancients.serv", "ancients.serv"
@@ -256,6 +257,17 @@ list =
   ; ...
 }
 
+[files_2]
+baseURL = "https://ancients.org/docs/"
+
+list =
+{ "src"
+  "ancients/ChangeLog"
+  "ancients/Usage"
+  ; ...
+}
+
+
 The [info] section has overall control information:
  - "options": must be exactly as shown in the example.
  - "name":
@@ -279,16 +291,20 @@ The [info] section has overall control information:
         than one of the above kinds of material
       - "Group": contains no files but only depends on other modpacks
      At the moment, only "Scenario" causes special behavior.
+
+The [files_*] sections lists the individual files comprising your modpack.
+(They must list every file individually; any files in the same directory
+on the webserver that are not listed will not be downloaded.)
+The "files_" part is mandatory. It can be followed by any identifier as long
+as each such section has a distinct name.
+
  - "baseURL":
      URL to prepend to the "src" filenames in the [files] section.
      May be relative to the .mpdl file (starting with "./"), or
      absolute (in which case the files can be on some web server
      different to where the .mpdl file lives).
 
-The [files] section lists the individual files comprising your modpack.
-(It must list every file individually; any files in the same directory
-on the webserver that are not listed will not be downloaded.)
-After the header, each line can contain two strings:
+For entries in the list, each line can contain two strings:
  - "src"
      Mandatory. Path of file on webserver, relative to "baseURL",
      and also by default installation path.
diff --git a/tools/fcmp/download.c b/tools/fcmp/download.c
index 965f4305e4..cc1e13a95a 100644
--- a/tools/fcmp/download.c
+++ b/tools/fcmp/download.c
@@ -83,21 +83,18 @@ static const char *download_modpack_recursive(const char *URL,
   char local_dir[2048];
   char local_name[2048];
   int start_idx;
-  int filenbr, total_files;
+  int total_files;
   struct section_file *control;
   const char *control_capstr;
-  const char *baseURLpart;
   enum modpack_type type;
   const char *typestr;
   const char *mpname;
   const char *mpver;
-  char baseURL[2048];
-  char fileURL[2048];
   const char *src_name;
   bool partial_failure = FALSE;
   int dep;
   const char *dep_name;
-  int URL_len;
+  struct section_list *sec;
 
   if (recursion > 5) {
     return _("Recursive dependencies too deep");
@@ -182,25 +179,6 @@ static const char *download_modpack_recursive(const char *URL,
                 "%s" DIR_SEPARATOR DATASUBDIR, fcmp->inst_prefix);
   }
 
-  baseURLpart = secfile_lookup_str(control, "info.baseURL");
-
-  if (baseURLpart[0] == '.') {
-    char URLstart[start_idx];
-
-    strncpy(URLstart, URL, start_idx - 1);
-    URLstart[start_idx - 1] = '\0';
-    fc_snprintf(baseURL, sizeof(baseURL), "%s%s",
-                URLstart, baseURLpart + 1);
-  } else {
-    sz_strlcpy(baseURL, baseURLpart);
-  }
-
-  /* Remove potential ending '/' as one will get added later. */
-  URL_len = strlen(baseURL);
-  if (baseURL[URL_len - 1] == '/') {
-    baseURL[URL_len - 1] = '\0';
-  }
-
   dep = 0;
   do {
     dep_name = secfile_lookup_str_default(control, NULL,
@@ -273,117 +251,163 @@ static const char *download_modpack_recursive(const char *URL,
 
 
   total_files = 0;
-  do {
-    src_name = secfile_lookup_str_default(control, NULL,
-                                          "files.list%d.src", total_files);
+  sec = secfile_sections_by_name_prefix(control, "files_");
+
+  if (sec != NULL) {
+    size_t sec_count = section_list_size(sec);
+    size_t i;
+    int filenbr = 0;
+
+    for (i = 0; i < sec_count; i++) {
+      const char *sec_name = section_name(section_list_get(sec, i));
 
-    if (src_name != NULL) {
-      total_files++;
+      do {
+        src_name = secfile_lookup_str_default(control, NULL,
+                                              "%s.list%d.src",
+                                              sec_name, total_files);
+
+        if (src_name != NULL) {
+          total_files++;
+        }
+      } while (src_name != NULL);
     }
-  } while (src_name != NULL);
 
-  if (pbcb != NULL) {
-    /* Control file already downloaded */
-    pbcb(1, total_files + 1);
-  }
+    if (pbcb != NULL) {
+      /* Control file already downloaded */
+      pbcb(1, total_files + 1);
+    }
 
-  for (filenbr = 0; filenbr < total_files; filenbr++) {
-    const char *dest_name;
+    for (i = 0; i < sec_count; i++) {
+      const char *sec_name = section_name(section_list_get(sec, i));
+      const char *baseURLpart;
+      int URL_len;
+      char baseURL[2048];
+      int j;
+
+      baseURLpart = secfile_lookup_str(control, "%s.baseURL", sec_name);
+
+      if (baseURLpart[0] == '.') {
+        char URLstart[start_idx];
+
+        strncpy(URLstart, URL, start_idx - 1);
+        URLstart[start_idx - 1] = '\0';
+        fc_snprintf(baseURL, sizeof(baseURL), "%s%s",
+                    URLstart, baseURLpart + 1);
+      } else {
+        sz_strlcpy(baseURL, baseURLpart);
+      }
+
+      /* Remove potential ending '/' as one will get added later. */
+      URL_len = strlen(baseURL);
+      if (baseURL[URL_len - 1] == '/') {
+        baseURL[URL_len - 1] = '\0';
+      }
+
+      for (j = 0;
+           (src_name = secfile_lookup_str_default(control, NULL,
+                                                  "%s.list%d.src", sec_name, j)) != NULL;
+           j++) {
+        const char *dest_name;
 
 #ifndef DIR_SEPARATOR_IS_DEFAULT
-    char *dest_name_copy;
+        char *dest_name_copy;
 #else  /* DIR_SEPARATOR_IS_DEFAULT */
 #define dest_name_copy dest_name
 #endif /* DIR_SEPARATOR_IS_DEFAULT */
 
-    int i;
-    bool illegal_filename = FALSE;
-
-    src_name = secfile_lookup_str_default(control, NULL,
-                                          "files.list%d.src", filenbr);
+        int k;
+        bool illegal_filename = FALSE;
 
-    dest_name = secfile_lookup_str_default(control, NULL,
-                                           "files.list%d.dest", filenbr);
+        dest_name = secfile_lookup_str_default(control, NULL,
+                                               "%s.list%d.dest", sec_name, j);
 
-    if (dest_name == NULL || dest_name[0] == '\0') {
-      /* Missing dest name is ok, we just default to src_name */
-      dest_name = src_name;
-    }
+        if (dest_name == NULL || dest_name[0] == '\0') {
+          /* Missing dest name is ok, we just default to src_name */
+          dest_name = src_name;
+        }
 
 #ifndef DIR_SEPARATOR_IS_DEFAULT
-    dest_name_copy = fc_malloc(strlen(dest_name) + 1);
+        dest_name_copy = fc_malloc(strlen(dest_name) + 1);
 #endif /* DIR_SEPARATOR_IS_DEFAULT */
 
-    for (i = 0; dest_name[i] != '\0'; i++) {
-      if (dest_name[i] == '.' && dest_name[i + 1] == '.') {
-        if (mcb != NULL) {
-          char buf[2048];
+        for (k = 0; dest_name[k] != '\0'; k++) {
+          if (dest_name[k] == '.' && dest_name[k + 1] == '.') {
+            if (mcb != NULL) {
+              char buf[2048];
 
-          fc_snprintf(buf, sizeof(buf), _("Illegal path for %s"),
-                      dest_name);
-          mcb(buf);
-        }
-        partial_failure = TRUE;
-        illegal_filename = TRUE;
-      }
+              fc_snprintf(buf, sizeof(buf), _("Illegal path for %s"),
+                          dest_name);
+              mcb(buf);
+            }
+            partial_failure = TRUE;
+            illegal_filename = TRUE;
+          }
 
 #ifndef DIR_SEPARATOR_IS_DEFAULT
-      if (dest_name[i] == '/') {
-        dest_name_copy[i] = DIR_SEPARATOR_CHAR;
-      } else {
-        dest_name_copy[i] = dest_name[i];
-      }
+          if (dest_name[k] == '/') {
+            dest_name_copy[k] = DIR_SEPARATOR_CHAR;
+          } else {
+            dest_name_copy[k] = dest_name[k];
+          }
 #endif /* DIR_SEPARATOR_IS_DEFAULT */
-    }
+        }
 
 #ifndef DIR_SEPARATOR_IS_DEFAULT
-    dest_name_copy[i] = '\0';
+        dest_name_copy[k] = '\0';
 #endif /* DIR_SEPARATOR_IS_DEFAULT */
 
-    if (!illegal_filename) {
-      fc_snprintf(local_name, sizeof(local_name),
-                  "%s" DIR_SEPARATOR "%s", local_dir, dest_name_copy);
+        if (!illegal_filename) {
+          char fileURL[2048];
+
+          fc_snprintf(local_name, sizeof(local_name),
+                      "%s" DIR_SEPARATOR "%s", local_dir, dest_name_copy);
 
 #ifndef DIR_SEPARATOR_IS_DEFAULT
-      free(dest_name_copy);
+          free(dest_name_copy);
 #endif /* DIR_SEPARATOR_IS_DEFAULT */
 
-      if (!make_dir_for_file(local_name)) {
-        secfile_destroy(control);
-        return _("Cannot create required directories");
-      }
-
-      if (mcb != NULL) {
-        char buf[2048];
-
-        fc_snprintf(buf, sizeof(buf), _("Downloading %s"), src_name);
-        mcb(buf);
-      }
+          if (!make_dir_for_file(local_name)) {
+            secfile_destroy(control);
+            return _("Cannot create required directories");
+          }
+
+          if (mcb != NULL) {
+            char buf[2048];
+
+            fc_snprintf(buf, sizeof(buf), _("Downloading %s"), src_name);
+            mcb(buf);
+          }
+
+          fc_snprintf(fileURL, sizeof(fileURL), "%s/%s", baseURL, src_name);
+          log_debug("Download \"%s\" as \"%s\".", fileURL, local_name);
+          if (!netfile_download_file(fileURL, local_name, nf_cb, mcb)) {
+            if (mcb != NULL) {
+              char buf[2048];
+
+              fc_snprintf(buf, sizeof(buf), _("Failed to download %s"),
+                          src_name);
+              mcb(buf);
+            }
+            partial_failure = TRUE;
+          }
+        } else {
+#ifndef DIR_SEPARATOR_IS_DEFAULT
+          free(dest_name_copy);
+#endif /* DIR_SEPARATOR_IS_DEFAULT */
+        }
 
-      fc_snprintf(fileURL, sizeof(fileURL), "%s/%s", baseURL, src_name);
-      log_debug("Download \"%s\" as \"%s\".", fileURL, local_name);
-      if (!netfile_download_file(fileURL, local_name, nf_cb, mcb)) {
-        if (mcb != NULL) {
-          char buf[2048];
+        filenbr++;
 
-          fc_snprintf(buf, sizeof(buf), _("Failed to download %s"),
-                      src_name);
-          mcb(buf);
+        if (pbcb != NULL) {
+          /* Count download of control file also */
+          pbcb(filenbr + 1, total_files + 1);
         }
-        partial_failure = TRUE;
       }
-    } else {
-#ifndef DIR_SEPARATOR_IS_DEFAULT
-      free(dest_name_copy);
-#endif /* DIR_SEPARATOR_IS_DEFAULT */
-    }
-
-    if (pbcb != NULL) {
-      /* Count download of control file also */
-      pbcb(filenbr + 2, total_files + 1);
     }
   }
 
+  section_list_destroy(sec);
+
   if (partial_failure) {
     secfile_destroy(control);
 
diff --git a/tools/fcmp/download.h b/tools/fcmp/download.h
index c5fdcea124..973e281cf4 100644
--- a/tools/fcmp/download.h
+++ b/tools/fcmp/download.h
@@ -22,7 +22,7 @@ extern "C" {
 
 #define MODPACKDL_SUFFIX ".mpdl"
 
-#define MODPACK_CAPSTR "+Freeciv-mpdl-Devel-3.2-2022.Jul.14"
+#define MODPACK_CAPSTR "+Freeciv-mpdl-Devel-3.2-2023.Sep.17"
 #define MODLIST_CAPSTR "+Freeciv-modlist-Devel-3.2-2022.Jul.14"
 
 #define FCMP_CONTROLD ".control"
-- 
2.40.1