diff options
| author | Joseph Hunkeler <jhunkeler@users.noreply.github.com> | 2024-08-08 12:45:05 -0400 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-08-08 12:45:05 -0400 | 
| commit | c9579598c5a1b49f7fe8e353623175bf8f3cc236 (patch) | |
| tree | cf7ef75a4bea7b16713a172d17b82a0c1ad9904b /src | |
| parent | 99edcf7b998a1ac83b75ef3cc117c5b91c874782 (diff) | |
| download | stasis-c9579598c5a1b49f7fe8e353623175bf8f3cc236.tar.gz | |
Return of the INI refactor (#20)
* Continuation of #19
* Fixes always_update_base_environment override bug added by PR #19
* Finish type hinting implementation
* ini_getval_* functions now able to affect rendering mode using INI_READ_RAW and INI_READ_RENDER
* Created pointers to deeply nested structures to increase readability
* Output from ini_write() is more consistent, with fewer errant spaces and line feeds
* Fixes accidental regression in #19. INIVAL_TYPE_STR_ARRAY never produced an array of pointers to char. This needs to be corrected in the future. i.e. It has always generated a new-line delimited string, not a StrList, or array.
* Fix strlist_append_tokenize
* original pointer is no longer modified
* token strings are stripped of leading space before appending to the list
* Use defines instead of magic numbers
* delivery_init: add render_mode argument
* test_conda: Add render mode
* test_ini: Add render mode
* Only add conda packages and wheels to the image
* docker images are saved to the packages directory and will be consumed by the image if present.
* Render template variables after bootstrapping the delivery
Diffstat (limited to 'src')
| -rw-r--r-- | src/delivery.c | 146 | ||||
| -rw-r--r-- | src/ini.c | 211 | ||||
| -rw-r--r-- | src/stasis_main.c | 2 | ||||
| -rw-r--r-- | src/strlist.c | 5 | ||||
| -rw-r--r-- | src/utils.c | 2 | 
5 files changed, 196 insertions, 170 deletions
| diff --git a/src/delivery.c b/src/delivery.c index 1b16f39..ce6e804 100644 --- a/src/delivery.c +++ b/src/delivery.c @@ -343,7 +343,7 @@ int delivery_init_platform(struct Delivery *ctx) {      return 0;  } -static int populate_mission_ini(struct Delivery **ctx) { +static int populate_mission_ini(struct Delivery **ctx, int render_mode) {      int err = 0;      struct INIFILE *ini; @@ -370,13 +370,13 @@ static int populate_mission_ini(struct Delivery **ctx) {      }      (*ctx)->_stasis_ini_fp.mission_path = strdup(missionfile); -    (*ctx)->rules.release_fmt = ini_getval_str(ini, "meta", "release_fmt", &err); +    (*ctx)->rules.release_fmt = ini_getval_str(ini, "meta", "release_fmt", render_mode, &err);      // Used for setting artifactory build info -    (*ctx)->rules.build_name_fmt = ini_getval_str(ini, "meta", "build_name_fmt", &err); +    (*ctx)->rules.build_name_fmt = ini_getval_str(ini, "meta", "build_name_fmt", render_mode, &err);      // Used for setting artifactory build info -    (*ctx)->rules.build_number_fmt = ini_getval_str(ini, "meta", "build_number_fmt", &err); +    (*ctx)->rules.build_number_fmt = ini_getval_str(ini, "meta", "build_number_fmt", render_mode, &err);      return 0;  } @@ -432,7 +432,7 @@ void validate_delivery_ini(struct INIFILE *ini) {      }  } -static int populate_delivery_ini(struct Delivery *ctx) { +static int populate_delivery_ini(struct Delivery *ctx, int render_mode) {      union INIVal val;      struct INIFILE *ini = ctx->_stasis_ini_fp.delivery;      struct INIData *rtdata; @@ -451,34 +451,34 @@ static int populate_delivery_ini(struct Delivery *ctx) {      ctx->runtime.environ = rt;      int err = 0; -    ctx->meta.mission = ini_getval_str(ini, "meta", "mission", &err); +    ctx->meta.mission = ini_getval_str(ini, "meta", "mission", render_mode, &err);      if (!strcasecmp(ctx->meta.mission, "hst")) { -        ctx->meta.codename = ini_getval_str(ini, "meta", "codename", &err); +        ctx->meta.codename = ini_getval_str(ini, "meta", "codename", render_mode, &err);      } else {          ctx->meta.codename = NULL;      } -    ctx->meta.version = ini_getval_str(ini, "meta", "version", &err); -    ctx->meta.name = ini_getval_str(ini, "meta", "name", &err); -    ctx->meta.rc = ini_getval_int(ini, "meta", "rc", &err); -    ctx->meta.final = ini_getval_bool(ini, "meta", "final", &err); -    ctx->meta.based_on = ini_getval_str(ini, "meta", "based_on", &err); +    ctx->meta.version = ini_getval_str(ini, "meta", "version", render_mode, &err); +    ctx->meta.name = ini_getval_str(ini, "meta", "name", render_mode, &err); +    ctx->meta.rc = ini_getval_int(ini, "meta", "rc", render_mode, &err); +    ctx->meta.final = ini_getval_bool(ini, "meta", "final", render_mode, &err); +    ctx->meta.based_on = ini_getval_str(ini, "meta", "based_on", render_mode, &err);      if (!ctx->meta.python) { -        ctx->meta.python = ini_getval_str(ini, "meta", "python", &err); +        ctx->meta.python = ini_getval_str(ini, "meta", "python", render_mode, &err);          guard_free(ctx->meta.python_compact);          ctx->meta.python_compact = to_short_version(ctx->meta.python);      } else {          ini_setval(&ini, INI_SETVAL_REPLACE, "meta", "python", ctx->meta.python);      } -    ctx->conda.installer_name = ini_getval_str(ini, "conda", "installer_name", &err); -    ctx->conda.installer_version = ini_getval_str(ini, "conda", "installer_version", &err); -    ctx->conda.installer_platform = ini_getval_str(ini, "conda", "installer_platform", &err); -    ctx->conda.installer_arch = ini_getval_str(ini, "conda", "installer_arch", &err); -    ctx->conda.installer_baseurl = ini_getval_str(ini, "conda", "installer_baseurl", &err); -    ctx->conda.conda_packages = ini_getval_strlist(ini, "conda", "conda_packages", " "LINE_SEP, &err); +    ctx->conda.installer_name = ini_getval_str(ini, "conda", "installer_name", render_mode, &err); +    ctx->conda.installer_version = ini_getval_str(ini, "conda", "installer_version", render_mode, &err); +    ctx->conda.installer_platform = ini_getval_str(ini, "conda", "installer_platform", render_mode, &err); +    ctx->conda.installer_arch = ini_getval_str(ini, "conda", "installer_arch", render_mode, &err); +    ctx->conda.installer_baseurl = ini_getval_str(ini, "conda", "installer_baseurl", render_mode, &err); +    ctx->conda.conda_packages = ini_getval_strlist(ini, "conda", "conda_packages", " "LINE_SEP, render_mode, &err);      if (ctx->conda.conda_packages->data && ctx->conda.conda_packages->data[0] && strpbrk(ctx->conda.conda_packages->data[0], " \t")) {          normalize_space(ctx->conda.conda_packages->data[0]); @@ -487,7 +487,7 @@ static int populate_delivery_ini(struct Delivery *ctx) {          ini_setval(&ini, INI_SETVAL_REPLACE, "conda", "conda_packages", pip_packages_replacement);          guard_free(pip_packages_replacement);          guard_strlist_free(&ctx->conda.conda_packages); -        ctx->conda.conda_packages = ini_getval_strlist(ini, "conda", "conda_packages", LINE_SEP, &err); +        ctx->conda.conda_packages = ini_getval_strlist(ini, "conda", "conda_packages", LINE_SEP, render_mode, &err);      }      for (size_t i = 0; i < strlist_count(ctx->conda.conda_packages); i++) { @@ -497,7 +497,7 @@ static int populate_delivery_ini(struct Delivery *ctx) {          }      } -    ctx->conda.pip_packages = ini_getval_strlist(ini, "conda", "pip_packages", LINE_SEP, &err); +    ctx->conda.pip_packages = ini_getval_strlist(ini, "conda", "pip_packages", LINE_SEP, render_mode, &err);      if (ctx->conda.pip_packages->data && ctx->conda.pip_packages->data[0] && strpbrk(ctx->conda.pip_packages->data[0], " \t")) {          normalize_space(ctx->conda.pip_packages->data[0]);          replace_text(ctx->conda.pip_packages->data[0], " ", LINE_SEP, 0); @@ -505,7 +505,7 @@ static int populate_delivery_ini(struct Delivery *ctx) {          ini_setval(&ini, INI_SETVAL_REPLACE, "conda", "pip_packages", pip_packages_replacement);          guard_free(pip_packages_replacement);          guard_strlist_free(&ctx->conda.pip_packages); -        ctx->conda.pip_packages = ini_getval_strlist(ini, "conda", "pip_packages", LINE_SEP, &err); +        ctx->conda.pip_packages = ini_getval_strlist(ini, "conda", "pip_packages", LINE_SEP, render_mode, &err);      }      for (size_t i = 0; i < strlist_count(ctx->conda.pip_packages); i++) { @@ -516,7 +516,7 @@ static int populate_delivery_ini(struct Delivery *ctx) {      }      // Delivery metadata consumed -    populate_mission_ini(&ctx); +    populate_mission_ini(&ctx, render_mode);      if (ctx->info.release_name) {          guard_free(ctx->info.release_name); @@ -556,12 +556,12 @@ static int populate_delivery_ini(struct Delivery *ctx) {              }              conv_str(&test->name, val); -            test->version = ini_getval_str(ini, section_name, "version", &err); -            test->repository = ini_getval_str(ini, section_name, "repository", &err); -            test->script = ini_getval_str(ini, section_name, "script", &err); -            test->repository_remove_tags = ini_getval_strlist(ini, section_name, "repository_remove_tags", LINE_SEP, &err); -            test->build_recipe = ini_getval_str(ini, section_name, "build_recipe", &err); -            test->runtime.environ = ini_getval_strlist(ini, section_name, "runtime", LINE_SEP, &err); +            test->version = ini_getval_str(ini, section_name, "version", render_mode, &err); +            test->repository = ini_getval_str(ini, section_name, "repository", render_mode, &err); +            test->script = ini_getval_str(ini, section_name, "script", render_mode, &err); +            test->repository_remove_tags = ini_getval_strlist(ini, section_name, "repository_remove_tags", LINE_SEP, render_mode, &err); +            test->build_recipe = ini_getval_str(ini, section_name, "build_recipe", render_mode, &err); +            test->runtime.environ = ini_getval_strlist(ini, section_name, "runtime", LINE_SEP, render_mode, &err);              z++;          }      } @@ -573,20 +573,20 @@ static int populate_delivery_ini(struct Delivery *ctx) {              struct JFrog *jfrog = &deploy->jfrog[z];              // Artifactory base configuration -            jfrog->upload_ctx.workaround_parent_only = ini_getval_bool(ini, section_name, "workaround_parent_only", &err); -            jfrog->upload_ctx.exclusions = ini_getval_str(ini, section_name, "exclusions", &err); -            jfrog->upload_ctx.explode = ini_getval_bool(ini, section_name, "explode", &err); -            jfrog->upload_ctx.recursive = ini_getval_bool(ini, section_name, "recursive", &err); -            jfrog->upload_ctx.retries = ini_getval_int(ini, section_name, "retries", &err); -            jfrog->upload_ctx.retry_wait_time = ini_getval_int(ini, section_name, "retry_wait_time", &err); -            jfrog->upload_ctx.detailed_summary = ini_getval_bool(ini, section_name, "detailed_summary", &err); -            jfrog->upload_ctx.quiet = ini_getval_bool(ini, section_name, "quiet", &err); -            jfrog->upload_ctx.regexp = ini_getval_bool(ini, section_name, "regexp", &err); -            jfrog->upload_ctx.spec = ini_getval_str(ini, section_name, "spec", &err); -            jfrog->upload_ctx.flat = ini_getval_bool(ini, section_name, "flat", &err); -            jfrog->repo = ini_getval_str(ini, section_name, "repo", &err); -            jfrog->dest = ini_getval_str(ini, section_name, "dest", &err); -            jfrog->files = ini_getval_strlist(ini, section_name, "dest", LINE_SEP, &err); +            jfrog->upload_ctx.workaround_parent_only = ini_getval_bool(ini, section_name, "workaround_parent_only", render_mode, &err); +            jfrog->upload_ctx.exclusions = ini_getval_str(ini, section_name, "exclusions", render_mode, &err); +            jfrog->upload_ctx.explode = ini_getval_bool(ini, section_name, "explode", render_mode, &err); +            jfrog->upload_ctx.recursive = ini_getval_bool(ini, section_name, "recursive", render_mode, &err); +            jfrog->upload_ctx.retries = ini_getval_int(ini, section_name, "retries", render_mode, &err); +            jfrog->upload_ctx.retry_wait_time = ini_getval_int(ini, section_name, "retry_wait_time", render_mode, &err); +            jfrog->upload_ctx.detailed_summary = ini_getval_bool(ini, section_name, "detailed_summary", render_mode, &err); +            jfrog->upload_ctx.quiet = ini_getval_bool(ini, section_name, "quiet", render_mode, &err); +            jfrog->upload_ctx.regexp = ini_getval_bool(ini, section_name, "regexp", render_mode, &err); +            jfrog->upload_ctx.spec = ini_getval_str(ini, section_name, "spec", render_mode, &err); +            jfrog->upload_ctx.flat = ini_getval_bool(ini, section_name, "flat", render_mode, &err); +            jfrog->repo = ini_getval_str(ini, section_name, "repo", render_mode, &err); +            jfrog->dest = ini_getval_str(ini, section_name, "dest", render_mode, &err); +            jfrog->files = ini_getval_strlist(ini, section_name, "files", LINE_SEP, render_mode, &err);              z++;          }      } @@ -597,44 +597,44 @@ static int populate_delivery_ini(struct Delivery *ctx) {          if (startswith(ini->section[i]->key, "deploy:docker")) {              struct Docker *docker = &deploy->docker; -            docker->registry = ini_getval_str(ini, section_name, "registry", &err); -            docker->image_compression = ini_getval_str(ini, section_name, "image_compression", &err); -            docker->test_script = ini_getval_str(ini, section_name, "test_script", &err); -            docker->build_args = ini_getval_strlist(ini, section_name, "build_args", LINE_SEP, &err); -            docker->tags = ini_getval_strlist(ini, section_name, "tags", LINE_SEP, &err); +            docker->registry = ini_getval_str(ini, section_name, "registry", render_mode, &err); +            docker->image_compression = ini_getval_str(ini, section_name, "image_compression", render_mode, &err); +            docker->test_script = ini_getval_str(ini, section_name, "test_script", render_mode, &err); +            docker->build_args = ini_getval_strlist(ini, section_name, "build_args", LINE_SEP, render_mode, &err); +            docker->tags = ini_getval_strlist(ini, section_name, "tags", LINE_SEP, render_mode, &err);          }      }      return 0;  } -static int populate_delivery_cfg(struct Delivery *ctx) { +static int populate_delivery_cfg(struct Delivery *ctx, int render_mode) {      struct INIFILE *cfg = ctx->_stasis_ini_fp.cfg;      if (!cfg) {          return -1;      }      int err = 0; -    ctx->storage.conda_staging_dir = ini_getval_str(cfg, "default", "conda_staging_dir", &err); -    ctx->storage.conda_staging_url = ini_getval_str(cfg, "default", "conda_staging_url", &err); -    ctx->storage.wheel_staging_dir = ini_getval_str(cfg, "default", "wheel_staging_dir", &err); -    ctx->storage.wheel_staging_url = ini_getval_str(cfg, "default", "wheel_staging_url", &err); -    globals.conda_fresh_start = ini_getval_bool(cfg, "default", "conda_fresh_start", &err); +    ctx->storage.conda_staging_dir = ini_getval_str(cfg, "default", "conda_staging_dir", render_mode, &err); +    ctx->storage.conda_staging_url = ini_getval_str(cfg, "default", "conda_staging_url", render_mode, &err); +    ctx->storage.wheel_staging_dir = ini_getval_str(cfg, "default", "wheel_staging_dir", render_mode, &err); +    ctx->storage.wheel_staging_url = ini_getval_str(cfg, "default", "wheel_staging_url", render_mode, &err); +    globals.conda_fresh_start = ini_getval_bool(cfg, "default", "conda_fresh_start", render_mode, &err);      if (!globals.continue_on_error) { -        globals.continue_on_error = ini_getval_bool(cfg, "default", "continue_on_error", &err); +        globals.continue_on_error = ini_getval_bool(cfg, "default", "continue_on_error", render_mode, &err);      } -    if (globals.always_update_base_environment) { -        globals.always_update_base_environment = ini_getval_bool(cfg, "default", "always_update_base_environment", &err); +    if (!globals.always_update_base_environment) { +        globals.always_update_base_environment = ini_getval_bool(cfg, "default", "always_update_base_environment", render_mode, &err);      } -    globals.conda_install_prefix = ini_getval_str(cfg, "default", "conda_install_prefix", &err); -    globals.conda_packages = ini_getval_strlist(cfg, "default", "conda_packages", LINE_SEP, &err); -    globals.pip_packages = ini_getval_strlist(cfg, "default", "pip_packages", LINE_SEP, &err); +    globals.conda_install_prefix = ini_getval_str(cfg, "default", "conda_install_prefix", render_mode, &err); +    globals.conda_packages = ini_getval_strlist(cfg, "default", "conda_packages", LINE_SEP, render_mode, &err); +    globals.pip_packages = ini_getval_strlist(cfg, "default", "pip_packages", LINE_SEP, render_mode, &err); -    globals.jfrog.jfrog_artifactory_base_url = ini_getval_str(cfg, "jfrog_cli_download", "url", &err); -    globals.jfrog.jfrog_artifactory_product = ini_getval_str(cfg, "jfrog_cli_download", "product", &err); -    globals.jfrog.cli_major_ver = ini_getval_str(cfg, "jfrog_cli_download", "version_series", &err); -    globals.jfrog.version = ini_getval_str(cfg, "jfrog_cli_download", "version", &err); -    globals.jfrog.remote_filename = ini_getval_str(cfg, "jfrog_cli_download", "filename", &err); -    globals.jfrog.url = ini_getval_str(cfg, "deploy:artifactory", "url", &err); -    globals.jfrog.repo = ini_getval_str(cfg, "deploy:artifactory", "repo", &err); +    globals.jfrog.jfrog_artifactory_base_url = ini_getval_str(cfg, "jfrog_cli_download", "url", render_mode, &err); +    globals.jfrog.jfrog_artifactory_product = ini_getval_str(cfg, "jfrog_cli_download", "product", render_mode, &err); +    globals.jfrog.cli_major_ver = ini_getval_str(cfg, "jfrog_cli_download", "version_series", render_mode, &err); +    globals.jfrog.version = ini_getval_str(cfg, "jfrog_cli_download", "version", render_mode, &err); +    globals.jfrog.remote_filename = ini_getval_str(cfg, "jfrog_cli_download", "filename", render_mode, &err); +    globals.jfrog.url = ini_getval_str(cfg, "deploy:artifactory", "url", render_mode, &err); +    globals.jfrog.repo = ini_getval_str(cfg, "deploy:artifactory", "repo", render_mode, &err);      return 0;  } @@ -661,8 +661,8 @@ int *bootstrap_build_info(struct Delivery *ctx) {      local._stasis_ini_fp.cfg = ini_open(ctx->_stasis_ini_fp.cfg_path);      local._stasis_ini_fp.delivery = ini_open(ctx->_stasis_ini_fp.delivery_path);      delivery_init_platform(&local); -    populate_delivery_cfg(&local); -    populate_delivery_ini(&local); +    populate_delivery_cfg(&local, INI_READ_RAW); +    populate_delivery_ini(&local, INI_READ_RAW);      populate_info(&local);      ctx->info.build_name = strdup(local.info.build_name);      ctx->info.build_number = strdup(local.info.build_number); @@ -674,9 +674,9 @@ int *bootstrap_build_info(struct Delivery *ctx) {      return 0;  } -int delivery_init(struct Delivery *ctx) { +int delivery_init(struct Delivery *ctx, int render_mode) {      populate_info(ctx); -    populate_delivery_cfg(ctx); +    populate_delivery_cfg(ctx, INI_READ_RENDER);      // Set artifactory URL via environment variable if possible      char *jfurl = getenv("STASIS_JF_ARTIFACTORY_URL"); @@ -718,7 +718,7 @@ int delivery_init(struct Delivery *ctx) {      // Prevent git from paginating output      setenv("GIT_PAGER", "", 1); -    populate_delivery_ini(ctx); +    populate_delivery_ini(ctx, render_mode);      if (ctx->deploy.docker.tags) {          for (size_t i = 0; i < strlist_count(ctx->deploy.docker.tags); i++) { @@ -1940,7 +1940,7 @@ int delivery_mission_render_files(struct Delivery *ctx) {          msg(STASIS_MSG_L2, "%s\n", data.src);          int err = 0; -        data.dest = ini_getval_str(cfg, section_name, "destination", &err); +        data.dest = ini_getval_str(cfg, section_name, "destination", INI_READ_RENDER, &err);          char *contents;          struct stat st; @@ -112,7 +112,7 @@ struct INIData *ini_getall(struct INIFILE *ini, char *section_name) {      return result;  } -int ini_getval(struct INIFILE *ini, char *section_name, char *key, int type, union INIVal *result) { +int ini_getval(struct INIFILE *ini, char *section_name, char *key, int type, int flags, union INIVal *result) {      char *token = NULL;      char tbuf[STASIS_BUFSIZ];      char *tbufp = tbuf; @@ -123,77 +123,83 @@ int ini_getval(struct INIFILE *ini, char *section_name, char *key, int type, uni          return -1;      } -    char *render = tpl_render(data->value); -    if (render) { -        guard_free(data->value); -        data->value = render; +    char *data_copy = strdup(data->value); +    if (flags == INI_READ_RENDER) { +        char *render = tpl_render(data_copy); +        if (render && strcmp(render, data_copy) != 0) { +            guard_free(data_copy); +            data_copy = render; +        } else { +            guard_free(render); +        }      } -    lstrip(data->value); +    lstrip(data_copy);      switch (type) {          case INIVAL_TYPE_CHAR: -            result->as_char = (char) strtol(data->value, NULL, 10); +            result->as_char = (char) strtol(data_copy, NULL, 10);              break;          case INIVAL_TYPE_UCHAR: -            result->as_uchar = (unsigned char) strtoul(data->value, NULL, 10); +            result->as_uchar = (unsigned char) strtoul(data_copy, NULL, 10);              break;          case INIVAL_TYPE_SHORT: -            result->as_short = (short) strtol(data->value, NULL, 10); +            result->as_short = (short) strtol(data_copy, NULL, 10);              break;          case INIVAL_TYPE_USHORT: -            result->as_ushort = (unsigned short) strtoul(data->value, NULL, 10); +            result->as_ushort = (unsigned short) strtoul(data_copy, NULL, 10);              break;          case INIVAL_TYPE_INT: -            result->as_int = (int) strtol(data->value, NULL, 10); +            result->as_int = (int) strtol(data_copy, NULL, 10);              break;          case INIVAL_TYPE_UINT: -            result->as_uint = (unsigned int) strtoul(data->value, NULL, 10); +            result->as_uint = (unsigned int) strtoul(data_copy, NULL, 10);              break;          case INIVAL_TYPE_LONG: -            result->as_long = (long) strtol(data->value, NULL, 10); +            result->as_long = (long) strtol(data_copy, NULL, 10);              break;          case INIVAL_TYPE_ULONG: -            result->as_ulong = (unsigned long) strtoul(data->value, NULL, 10); +            result->as_ulong = (unsigned long) strtoul(data_copy, NULL, 10);              break;          case INIVAL_TYPE_LLONG: -            result->as_llong = (long long) strtoll(data->value, NULL, 10); +            result->as_llong = (long long) strtoll(data_copy, NULL, 10);              break;          case INIVAL_TYPE_ULLONG: -            result->as_ullong = (unsigned long long) strtoull(data->value, NULL, 10); +            result->as_ullong = (unsigned long long) strtoull(data_copy, NULL, 10);              break;          case INIVAL_TYPE_DOUBLE: -            result->as_double = (double) strtod(data->value, NULL); +            result->as_double = (double) strtod(data_copy, NULL);              break;          case INIVAL_TYPE_FLOAT: -            result->as_float = (float) strtod(data->value, NULL); +            result->as_float = (float) strtod(data_copy, NULL);              break;          case INIVAL_TYPE_STR: -            result->as_char_p = strdup(data->value); +            result->as_char_p = strdup(data_copy);              if (!result->as_char_p) {                  return -1;              } -            lstrip(result->as_char_p);              break;          case INIVAL_TYPE_STR_ARRAY: -            strcpy(tbufp, data->value); -            char *value = NULL; -            size_t lines = num_chars(tbufp, '\n'); -            value = calloc(strlen(tbufp) + lines + 1, sizeof(*value)); -            if (!value) { +            strcpy(tbufp, data_copy); +            guard_free(data_copy); +            data_copy = calloc(STASIS_BUFSIZ, sizeof(*data_copy)); +            if (!data_copy) {                  return -1;              }              while ((token = strsep(&tbufp, "\n")) != NULL) { -                lstrip(token); -                strcat(value, token); -                strcat(value, "\n"); +                //lstrip(token); +                if (!isempty(token)) { +                    strcat(data_copy, token); +                    strcat(data_copy, "\n"); +                }              } -            result->as_char_p = value; +            strip(data_copy); +            result->as_char_p = strdup(data_copy);              break;          case INIVAL_TYPE_BOOL:              result->as_bool = false; -            if ((!strcmp(data->value, "true") || !strcmp(data->value, "True")) || -                    (!strcmp(data->value, "yes") || !strcmp(data->value, "Yes")) || -                    strtol(data->value, NULL, 10)) { +            if ((!strcmp(data_copy, "true") || !strcmp(data_copy, "True")) || +                    (!strcmp(data_copy, "yes") || !strcmp(data_copy, "Yes")) || +                    strtol(data_copy, NULL, 10)) {                  result->as_bool = true;              }              break; @@ -201,103 +207,104 @@ int ini_getval(struct INIFILE *ini, char *section_name, char *key, int type, uni              memset(result, 0, sizeof(*result));              break;      } +    guard_free(data_copy);      return 0;  }  #define getval_returns(t) return result.t -#define getval_setup(t) \ +#define getval_setup(t, f) \      union INIVal result; \      int state_local = 0; \ -    state_local = ini_getval(ini, section_name, key, t, &result); \ +    state_local = ini_getval(ini, section_name, key, t, f, &result); \      if (state != NULL) { \          *state = state_local; \      } -int ini_getval_int(struct INIFILE *ini, char *section_name, char *key, int *state) { -    getval_setup(INIVAL_TYPE_INT) +int ini_getval_int(struct INIFILE *ini, char *section_name, char *key, int flags, int *state) { +    getval_setup(INIVAL_TYPE_INT, flags)      getval_returns(as_int);  } -unsigned int ini_getval_uint(struct INIFILE *ini, char *section_name, char *key, int *state) { -    getval_setup(INIVAL_TYPE_UINT) +unsigned int ini_getval_uint(struct INIFILE *ini, char *section_name, char *key, int flags, int *state) { +    getval_setup(INIVAL_TYPE_UINT, flags)      getval_returns(as_uint);  } -long ini_getval_long(struct INIFILE *ini, char *section_name, char *key, int *state) { -    getval_setup(INIVAL_TYPE_LONG) +long ini_getval_long(struct INIFILE *ini, char *section_name, char *key, int flags, int *state) { +    getval_setup(INIVAL_TYPE_LONG, flags)      getval_returns(as_long);  } -unsigned long ini_getval_ulong(struct INIFILE *ini, char *section_name, char *key, int *state) { -    getval_setup(INIVAL_TYPE_ULONG) +unsigned long ini_getval_ulong(struct INIFILE *ini, char *section_name, char *key, int flags, int *state) { +    getval_setup(INIVAL_TYPE_ULONG, flags)      getval_returns(as_ulong);  } -long long ini_getval_llong(struct INIFILE *ini, char *section_name, char *key, int *state) { -    getval_setup(INIVAL_TYPE_LLONG) +long long ini_getval_llong(struct INIFILE *ini, char *section_name, char *key, int flags, int *state) { +    getval_setup(INIVAL_TYPE_LLONG, flags)      getval_returns(as_llong);  } -unsigned long long ini_getval_ullong(struct INIFILE *ini, char *section_name, char *key, int *state) { -    getval_setup(INIVAL_TYPE_ULLONG) +unsigned long long ini_getval_ullong(struct INIFILE *ini, char *section_name, char *key, int flags, int *state) { +    getval_setup(INIVAL_TYPE_ULLONG, flags)      getval_returns(as_ullong);  } -float ini_getval_float(struct INIFILE *ini, char *section_name, char *key, int *state) { -    getval_setup(INIVAL_TYPE_FLOAT) +float ini_getval_float(struct INIFILE *ini, char *section_name, char *key, int flags, int *state) { +    getval_setup(INIVAL_TYPE_FLOAT, flags)      getval_returns(as_float);  } -double ini_getval_double(struct INIFILE *ini, char *section_name, char *key, int *state) { -    getval_setup(INIVAL_TYPE_DOUBLE) +double ini_getval_double(struct INIFILE *ini, char *section_name, char *key, int flags, int *state) { +    getval_setup(INIVAL_TYPE_DOUBLE, flags)      getval_returns(as_double);  } -bool ini_getval_bool(struct INIFILE *ini, char *section_name, char *key, int *state) { -    getval_setup(INIVAL_TYPE_BOOL) +bool ini_getval_bool(struct INIFILE *ini, char *section_name, char *key, int flags, int *state) { +    getval_setup(INIVAL_TYPE_BOOL, flags)      getval_returns(as_bool);  } -short ini_getval_short(struct INIFILE *ini, char *section_name, char *key, int *state) { -    getval_setup(INIVAL_TYPE_SHORT) +short ini_getval_short(struct INIFILE *ini, char *section_name, char *key, int flags, int *state) { +    getval_setup(INIVAL_TYPE_SHORT, flags)      getval_returns(as_short);  } -unsigned short ini_getval_ushort(struct INIFILE *ini, char *section_name, char *key, int *state) { -    getval_setup(INIVAL_TYPE_USHORT) +unsigned short ini_getval_ushort(struct INIFILE *ini, char *section_name, char *key, int flags, int *state) { +    getval_setup(INIVAL_TYPE_USHORT, flags)      getval_returns(as_ushort);  } -char ini_getval_char(struct INIFILE *ini, char *section_name, char *key, int *state) { -    getval_setup(INIVAL_TYPE_CHAR) +char ini_getval_char(struct INIFILE *ini, char *section_name, char *key, int flags, int *state) { +    getval_setup(INIVAL_TYPE_CHAR, flags)      getval_returns(as_char);  } -unsigned char ini_getval_uchar(struct INIFILE *ini, char *section_name, char *key, int *state) { -    getval_setup(INIVAL_TYPE_UCHAR) +unsigned char ini_getval_uchar(struct INIFILE *ini, char *section_name, char *key, int flags, int *state) { +    getval_setup(INIVAL_TYPE_UCHAR, flags)      getval_returns(as_uchar);  } -char *ini_getval_char_p(struct INIFILE *ini, char *section_name, char *key, int *state) { -    getval_setup(INIVAL_TYPE_STR) +char *ini_getval_char_p(struct INIFILE *ini, char *section_name, char *key, int flags, int *state) { +    getval_setup(INIVAL_TYPE_STR, flags)      getval_returns(as_char_p);  } -char *ini_getval_str(struct INIFILE *ini, char *section_name, char *key, int *state) { -    return ini_getval_char_p(ini, section_name, key, state); +char *ini_getval_str(struct INIFILE *ini, char *section_name, char *key, int flags, int *state) { +    return ini_getval_char_p(ini, section_name, key, flags, state);  } -char **ini_getval_char_array_p(struct INIFILE *ini, char *section_name, char *key, int *state) { -    getval_setup(INIVAL_TYPE_STR_ARRAY) -    getval_returns(as_char_array_p); +char *ini_getval_char_array_p(struct INIFILE *ini, char *section_name, char *key, int flags, int *state) { +    getval_setup(INIVAL_TYPE_STR_ARRAY, flags) +    getval_returns(as_char_p);  } -char **ini_getval_str_array(struct INIFILE *ini, char *section_name, char *key, int *state) { -    return ini_getval_char_array_p(ini, section_name, key, state); +char *ini_getval_str_array(struct INIFILE *ini, char *section_name, char *key, int flags, int *state) { +    return ini_getval_char_array_p(ini, section_name, key, flags, state);  } -struct StrList *ini_getval_strlist(struct INIFILE *ini, char *section_name, char *key, char *tok, int *state) { -    getval_setup(INIVAL_TYPE_STR_ARRAY) +struct StrList *ini_getval_strlist(struct INIFILE *ini, char *section_name, char *key, char *tok, int flags, int *state) { +    getval_setup(INIVAL_TYPE_STR_ARRAY, flags)      struct StrList *list;      list = strlist_init();      strlist_append_tokenize(list, result.as_char_p, tok); @@ -305,7 +312,7 @@ struct StrList *ini_getval_strlist(struct INIFILE *ini, char *section_name, char      return list;  } -int ini_data_append(struct INIFILE **ini, char *section_name, char *key, char *value) { +int ini_data_append(struct INIFILE **ini, char *section_name, char *key, char *value, unsigned int hint) {      struct INISection *section = ini_section_search(ini, INI_SEARCH_EXACT, section_name);      if (section == NULL) {          return 1; @@ -324,6 +331,7 @@ int ini_data_append(struct INIFILE **ini, char *section_name, char *key, char *v              SYSERROR("Unable to allocate %zu bytes for section data", sizeof(*data[0]));              return -1;          } +        data[section->data_count]->type_hint = hint;          data[section->data_count]->key = key ? strdup(key) : strdup("");          if (!data[section->data_count]->key) {              SYSERROR("Unable to allocate data key%s", ""); @@ -361,7 +369,7 @@ int ini_setval(struct INIFILE **ini, unsigned type, char *section_name, char *ke      }      if (ini_has_key(*ini, section_name, key)) {          if (!type) { -            if (ini_data_append(ini, section_name, key, value)) { +            if (ini_data_append(ini, section_name, key, value, 0)) {                  // append failed                  return -1;              } @@ -410,30 +418,48 @@ int ini_write(struct INIFILE *ini, FILE **stream, unsigned mode) {          return -1;      }      for (size_t x = 0; x < ini->section_count; x++) { -        fprintf(*stream, "[%s]" LINE_SEP, ini->section[x]->key); +        struct INISection *section = ini->section[x]; +        char *section_name = section->key; +        fprintf(*stream, "[%s]" LINE_SEP, section_name); +          for (size_t y = 0; y < ini->section[x]->data_count; y++) { +            struct INIData *data = section->data[y];              char outvalue[STASIS_BUFSIZ]; +            char *key = data->key; +            char *value = data->value; +            unsigned *hint = &data->type_hint;              memset(outvalue, 0, sizeof(outvalue)); -            if (ini->section[x]->data[y]->value) { -                char **parts = split(ini->section[x]->data[y]->value, LINE_SEP, 0); + +            if (key && value) { +                int err = 0; +                char *xvalue = NULL; +                if (*hint == INIVAL_TYPE_STR_ARRAY) { +                    xvalue = ini_getval_str_array(ini, section_name, key, (int) mode, &err); +                    value = xvalue; +                } else { +                    xvalue = ini_getval_str(ini, section_name, key, (int) mode, &err); +                    value = xvalue; +                } +                char **parts = split(value, LINE_SEP, 0);                  size_t parts_total = 0;                  for (; parts && parts[parts_total] != NULL; parts_total++);                  for (size_t p = 0; parts && parts[p] != NULL; p++) {                      char *render = NULL;                      if (mode == INI_WRITE_PRESERVE) {                          render = tpl_render(parts[p]); -                        replace_text(render, "\n", "\n    ", 0);                      } else {                          render = parts[p];                      } -                    if (p == 0) { -                        sprintf(outvalue, "%s" LINE_SEP, render); -                    } else { -                        if (!isspace(render[0])) { -                            sprintf(outvalue + strlen(outvalue), "    %s" LINE_SEP, render); -                        } else { + +                    if (*hint == INIVAL_TYPE_STR_ARRAY) { +                        int leading_space = isspace(*render); +                        if (leading_space) {                              sprintf(outvalue + strlen(outvalue), "%s" LINE_SEP, render); +                        } else { +                            sprintf(outvalue + strlen(outvalue), "    %s" LINE_SEP, render);                          } +                    } else { +                        sprintf(outvalue + strlen(outvalue), "%s", render);                      }                      if (mode == INI_WRITE_PRESERVE) {                          guard_free(render); @@ -442,7 +468,8 @@ int ini_write(struct INIFILE *ini, FILE **stream, unsigned mode) {                  GENERIC_ARRAY_FREE(parts);                  strip(outvalue);                  strcat(outvalue, LINE_SEP); -                fprintf(*stream, "%s = %s%s", ini->section[x]->data[y]->key, ini->section[x]->data[y]->type_hint || parts_total > 1 ? LINE_SEP "    " : "", outvalue); +                fprintf(*stream, "%s = %s%s", ini->section[x]->data[y]->key, *hint == INIVAL_TYPE_STR_ARRAY ? LINE_SEP : "", outvalue); +                guard_free(value);              } else {                  fprintf(*stream, "%s = %s", ini->section[x]->data[y]->key, ini->section[x]->data[y]->value);              } @@ -487,13 +514,6 @@ void ini_free(struct INIFILE **ini) {      guard_free((*ini));  } -static void ini_data_set_hint(struct INIFILE **ini, char *section_name, char *key, int hint) { -    struct INIData *data = ini_data_get(*ini, section_name, key); -    if (data) { -        data->type_hint = hint; -    } -} -  struct INIFILE *ini_open(const char *filename) {      FILE *fp;      char line[STASIS_BUFSIZ] = {0}; @@ -519,6 +539,7 @@ struct INIFILE *ini_open(const char *filename) {          return NULL;      } +    unsigned hint = 0;      int multiline_data = 0;      int no_data = 0;      char inikey[2][255]; @@ -617,11 +638,13 @@ struct INIFILE *ini_open(const char *filename) {              }              if (isempty(value)) {                  //printf("%s is probably long raw data\n", key); -                ini_data_set_hint(&ini, current_section, key, INIVAL_TYPE_STR_ARRAY); +                //ini_data_set_hint(&ini, current_section, key, INIVAL_TYPE_STR_ARRAY); +                hint = INIVAL_TYPE_STR_ARRAY;                  multiline_data = 1;                  no_data = 1;              } else {                  //printf("%s is probably short data\n", key); +                hint = INIVAL_TYPE_STR;                  multiline_data = 0;              }              strip(value); @@ -638,10 +661,10 @@ struct INIFILE *ini_open(const char *filename) {              unquote(value);              if (!multiline_data) {                  reading_value = 0; -                ini_data_append(&ini, current_section, key, value); +                ini_data_append(&ini, current_section, key, value, hint);                  continue;              } -            ini_data_append(&ini, current_section, key, value); +            ini_data_append(&ini, current_section, key, value, hint);              reading_value = 1;          }      } diff --git a/src/stasis_main.c b/src/stasis_main.c index b6ffc1d..4c47672 100644 --- a/src/stasis_main.c +++ b/src/stasis_main.c @@ -390,7 +390,7 @@ int main(int argc, char *argv[]) {      }      msg(STASIS_MSG_L2, "Initializing delivery context\n"); -    if (delivery_init(&ctx)) { +    if (delivery_init(&ctx, INI_READ_RENDER)) {          msg(STASIS_MSG_ERROR | STASIS_MSG_L2, "Failed to initialize delivery context\n");          exit(1);      } diff --git a/src/strlist.c b/src/strlist.c index bdacb5a..d1bb926 100644 --- a/src/strlist.c +++ b/src/strlist.c @@ -174,13 +174,16 @@ void strlist_append_strlist(struct StrList *pStrList1, struct StrList *pStrList2           return;       } -     token = split(str, delim, 0); +     char *tmp = strdup(str); +     token = split(tmp, delim, 0);       if (token) {           for (size_t i = 0; token[i] != NULL; i++) { +             lstrip(token[i]);               strlist_append(&pStrList, token[i]);           }           GENERIC_ARRAY_FREE(token);       } +    guard_free(tmp);   }  /** diff --git a/src/utils.c b/src/utils.c index f721581..70430e1 100644 --- a/src/utils.c +++ b/src/utils.c @@ -645,7 +645,7 @@ int fix_tox_conf(const char *filename, char **result) {                  if (data) {                      int err = 0;                      char *key = data->key; -                    char *value = ini_getval_str(toxini, section->key, data->key, &err); +                    char *value = ini_getval_str(toxini, section->key, data->key, INI_READ_RENDER, &err);                      if (key && value) {                          if (startswith(value, "pytest") && !strstr(value, "{posargs}")) {                              strip(value); | 
