commit cd16d6353f0631324c1e53b304121d3f060c44d8
parent 7bdef0f2c86594d0f3bbc9af16065af4f45ed1f6
Author: Remy Noulin <loader2x@gmail.com>
Date: Sun, 20 May 2018 00:35:38 +0200
refactoring utility
morph.c | 320 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
package.yml | 18 ++++
2 files changed, 338 insertions(+)
Diffstat:
| A | morph.c | | | 320 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | package.yml | | | 18 | ++++++++++++++++++ |
2 files changed, 338 insertions(+), 0 deletions(-)
diff --git a/morph.c b/morph.c
@@ -0,0 +1,320 @@
+#!/usr/bin/env sheepy
+
+// search and replace
+// input:
+// file.txt
+// replace_configuration.txt
+// the files to process are listed in file.txt in current directory.
+// Use # to comment lines in files.txt.
+// replace_configuration.txt holds the strings to search and replace in the files listed in file.txt
+//
+// replace_configuration.txt format:
+// - line 1: separetor in line 2 and 3
+// - line 2: strings to search separeted with the characters in line 1
+// - line 3: replace strings separeted with the characters in line 1
+
+#include "libsheepyObject.h"
+#include "pcre.h"
+
+#define internal static
+
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <stdio.h>
+
+void replace();
+void replaceWithPcre(char **l, pcre *reCompiled, pcre_extra *pcreExtra, char *func_search, char *replaceWith, smallArrayt *mappingNParams);
+int MAIN(int ARGC, char** ARGV);
+
+int argc; char **argv;
+
+// get function name
+smallStringt *funcName(char *e) {
+ smallStringt *s = allocG(e);
+ smallArrayt *spl = extractG(s, "*", "(");
+ terminateG(s);
+ s = getNDupG(spl, rtSmallStringt, 0);
+ terminateG(spl);
+ return s;
+}
+
+// extract params
+smallArrayt *funcParams(char *e) {
+ smallStringt *s = allocG(e);
+ smallArrayt *spl = extractG(s, "(", ")");
+ terminateG(s);
+ s = getG(spl, rtSmallStringt, 0);
+ smallArrayt *params = splitG(s, ",");
+ terminateG(spl);
+ enumerateSmallArray(params, P, i) {
+ castS(p, P);
+ trimG(p);
+ setPG(params, i, p);
+ finishG(p);
+ }
+ return params;
+}
+
+void replace() {
+ char **replace_configuration = NULL;
+ char **search_what = NULL;
+ char **replace_with = NULL;
+ char **config = NULL;
+
+ // Steps
+ // load config
+ // create string regex
+ // compile regexes
+ // optimize the regex
+ // create regex for each search string
+ // for each file in files.txt, search and replace
+
+ printf("\nLoading config...\n");
+ printf("\n");
+
+ // load config
+ replace_configuration = readText("morph_configuration.txt");
+
+ exitFailure(replace_configuration);
+
+ search_what = split(replace_configuration[1], replace_configuration[0]);
+ replace_with = split(replace_configuration[2], replace_configuration[0]);
+
+ if (!search_what || !replace_with) {
+ printf("wrong replace_configuration.txt");
+ printf("\n");
+ XFAILURE;
+ }
+
+ createAllocateSmallArray(a);
+ createAllocateSmallArray(func_search_what);
+ createAllocateSmallArray(func_replace_with);
+
+ // create string regex
+ char **strRegex = NULL;
+ enumerate(search_what, e, i) {
+ printf("Replace: ");
+ printf("\n");
+ // char *strLCpy(char *dst, const char *src, size_t dstSize)
+ // get function name
+ pushNFreeG(func_search_what, trimG(funcName(*e)));
+ smallArrayt *params = funcParams(*e);
+ printf("%s\n", *e);
+ printf("With:");
+ printf("\n");
+ // get replace function name
+ pushNFreeG(func_replace_with, trimG(funcName(replace_with[i])));
+ // get replace params
+ smallArrayt *replace_params = funcParams(replace_with[i]);
+ // map old->new params
+ createAllocateSmallArray(param_mapping);
+ enumerateSmallArray(replace_params, P, j) {
+ enumerateSmallArray(params, RP, k) {
+ if (eqG(P, RP)) {
+ pushG(param_mapping, k);
+ }
+ finishG(RP);
+ }
+ finishG(P);
+ }
+ terminateG(replace_params);
+ // save info in array a
+ createAllocateSmallArray(mappingNParams);
+ pushNFreeG(mappingNParams, params);
+ pushNFreeG(mappingNParams, param_mapping);
+ pushNFreeG(a, mappingNParams);
+ printf("%s\n", replace_with[i]);
+ char *reg = catS("\\b", getG(func_search_what, rtChar, i), "\\b");
+ iListPushS(&strRegex, reg);
+ }
+
+ //logVarG(a);
+ //listPrintS(strRegex);
+
+ // compile regexes
+ // optimize the regex
+ size_t nSearch = lenG(func_search_what);
+ pcre **reCompiled = malloc((nSearch+1) * sizeof(pcre *));
+ reCompiled[nSearch] = NULL;
+ pcre_extra **pcreExtra = malloc((nSearch+1) * sizeof(pcre_extra *));
+ pcreExtra[nSearch] = NULL;
+
+ const char *pcreErrorStr;
+ int pcreErrorOffset;
+
+ // create regex for each search string
+ enumerate(strRegex, e, j) {
+ reCompiled[j] = pcre_compile(*e, 0, &pcreErrorStr, &pcreErrorOffset, NULL);
+ if (!reCompiled[j]) {
+ printf("ERROR: Could not study >%s<: %s", *e, pcreErrorStr);
+ printf("\n");
+ XFAILURE;
+ }
+
+ pcreExtra[j] = pcre_study(reCompiled[j], 0, &pcreErrorStr);
+ if (!pcreExtra) {
+ printf("ERROR: Could not study >%s<: %s", *e, pcreErrorStr);
+ printf("\n");
+ XFAILURE;
+ }
+ }
+
+
+ printf("\n\nProcess files...\n");
+ printf("\n");
+
+ config = readText("files.txt");
+ exitFailure(config);
+
+ // for each file in files.txt, search and replace
+ forEach(config, f) {
+ if (!isBlankS(*f)) {
+ if (*f[0] != '#') {
+ iTrimS(f);
+ char **src = readText(*f);
+ if (!src) {
+ printf("Cant read file %s", *f);
+ printf("\n");
+ continue;
+ }
+
+ // scan lines
+ forEach(src, l) {
+ range(i, nSearch) {
+ //iReplaceS_max(l, *a, func_replace_with[i]);
+ replaceWithPcre(l, reCompiled[i], pcreExtra[i], getG(func_search_what, rtChar, i), getG(func_replace_with, rtChar, i), getG(a, rtSmallArrayt, i));
+ }
+ }
+
+ bool status = writeText(*f, src);
+ //bool status = false;
+ if (status) {
+ printf("CHANGED: %s", *f);
+ printf("\n");
+ }
+ else {
+ printf("DIDNT CHANGE: %s", *f);
+ printf("\n");
+ }
+ }
+ }
+ }
+
+ listFreeManyS(replace_configuration, search_what, replace_with, config, strRegex);
+ terminateManyG(func_search_what, func_replace_with, a);
+
+ forEachType(pcre, reCompiled, e) {
+ pcre_free(*e);
+ }
+ free(reCompiled);
+
+ if (pcreExtra[0]) {
+ forEachType(pcre_extra, pcreExtra, e) {
+ #ifdef PCRE_CONFIG_JIT
+ pcre_free_study(*e);
+ #else
+ pcre_free(*e);
+ #endif
+ }
+ }
+ free(pcreExtra);
+}
+
+void replaceWithPcre(char **l, pcre *reCompiled, pcre_extra *pcreExtra, char *func_search, char *replaceWith, smallArrayt *mappingNParams) {
+ int r;
+ int subStrVec[30];
+ size_t len;
+ size_t offset = 0;;
+ int allMatch[100];
+ size_t nMatch = 0;;
+
+ len = strlen(*l);
+ r = pcre_exec(reCompiled, pcreExtra, *l, len, 0, 0, subStrVec, 30);
+
+ while ((offset < len) && (r >= 0)) {
+
+ if (r == 0) {
+ printf("But too many substrings were found to fit in subStrVec!\n");
+ r = 30/3;
+ }
+
+ for (int j=0; j < r; j++) {
+ allMatch[nMatch] = subStrVec[j*2];
+ allMatch[nMatch+1] = subStrVec[j*2+1];
+ nMatch += 2;
+ }
+
+ offset = subStrVec[1];
+ r = pcre_exec(reCompiled, pcreExtra, *l, len, offset, 0, subStrVec, 30);
+ }
+
+ if (!nMatch) {
+ return;
+ }
+
+ /* logVarG(*l); */
+ for (int i = nMatch ; i > 0 ; i-=2) {
+ /* logVarG(*l); */
+ /* logVarG(func_search); */
+ /* logVarG(mappingNParams); */
+ // split and change order
+ //puts(*l+allMatch[i-1]);
+ smallStringt *s = allocG(*l+allMatch[i-1]);
+ smallArrayt *extract = extractG(s, "(", ")");
+ terminateG(s);
+ /* logVarG(extract); */
+ if (extract) {
+ s = getG(extract, rtSmallStringt, 0);
+ /* logVarG(s); */
+ smallArrayt *spl = splitG(s, ",");
+ smallArrayt *mapping = getG(mappingNParams, rtSmallArrayt, 1);
+ createAllocateSmallArray(newPara);
+ range(p, lenG(mapping)) {
+ pushG(newPara, getG(spl, rtSmallStringt, getG(mapping, rtI64, p)));
+ }
+ smallStringt *s2 = joinG(newPara, ",");
+ prependG(s, "(");
+ appendG(s, ")");
+ prependG(s2, "(");
+ appendG(s2, ")");
+ //logVarG(s);
+ //logVarG(s2);
+ replaceG(l, ssGet(s), ssGet(s2), 0);
+ smashG(extract);
+ finishManyG(mapping, spl);
+ terminateManyG(s, s2);
+ }
+
+ // replace word
+ char *sBefore = emptySF();;
+
+ if (allMatch[i-2]) {
+ // 0 means end of string
+ sBefore = sliceS(*l, 0, allMatch[i-2]);
+ }
+
+ char *sAfter = sliceS(*l, allMatch[i-1], 0);
+ free(*l);
+ *l = catS(sBefore, replaceWith, sAfter);
+ freeManyS(sBefore, sAfter);
+}
+ finishG(mappingNParams);
+ /* logVarG(*l); */
+ }
+
+// -------------------------------------------------------------------------------------
+
+#ifndef unitTest
+// Remove main when running the unit tests
+#define MAIN main
+#endif
+int MAIN(int ARGC, char** ARGV) {
+ int dum UNUSED;
+
+ argc = ARGC; argv = ARGV;;//
+
+ replace();
+
+ XSUCCESS;
+}
diff --git a/package.yml b/package.yml
@@ -0,0 +1,18 @@
+---
+ name: morph
+ version: 0.0.1
+ description: morph command searches functions in files and replaces them with the given functions, when the parameters change order both function declaration and function calls are changed
+ bin: ./morph.c
+ lflags: -lpcre
+ repository:
+ type: git
+ url: git+https://github.com/RemyNoulin/morph.git
+ keywords:
+ - utility
+ - refactor
+ - command
+ author: Remy Noulin
+ license: MIT
+ bugs:
+ url: https://github.com/RemyNoulin/morph/issues
+ homepage: https://github.com/RemyNoulin/morph