Я попал в ментальный блок проекта, который я делаю.Я хочу просмотреть файл и заменить все экземпляры переменных их содержимым или значением.У меня есть структура данных, которая содержит переменные, и у меня есть текстовый файл, назначенный указателю файла.
Структура данных, содержащая переменные, состоит из ключа (имя переменной) и данных (определение переменной):
// Preceeds the creation of a map to store the variable names and values
struct VarMap {
char data[1000];
char key[1000];
};
Это определение находится в заголовочном файле для моего проекта.Ниже приведен пример текстовых файлов, с которыми я имею дело:
# A Makefile to build our 'calcmarks' project
C99 = cc -std=c99
CFLAGS = -Wall -pedantic -Werror
calcmarks : calcmarks.o globals.o readmarks.o correlation.o
$(C99) $(CFLAGS) -o calcmarks \
calcmarks.o globals.o readmarks.o correlation.o -lm
calcmarks.o : calcmarks.c calcmarks.h
$(C99) $(CFLAGS) -c calcmarks.c
globals.o : globals.c calcmarks.h
$(C99) $(CFLAGS) -c globals.c
readmarks.o : readmarks.c calcmarks.h
$(C99) $(CFLAGS) -c readmarks.c
correlation.o : correlation.c calcmarks.h
$(C99) $(CFLAGS) -c correlation.c
Как вы, возможно, уже знаете из приведенного выше кода, я пишу программу, которая может реализовать небольшое подмножество программы сделать .Переменным в приведенном выше текстовом файле предшествует знак доллара «$», а имя переменной помещается в скобках «()», как в $ (C99) или $ (CFLAGS) в приведенном выше примере;хотя могут существовать и другие имена переменных.
Я уже написал часть программы для обработки этих переменных, последняя часть этой функции еще не завершена, но я надеюсь использовать ее для выполнения фактической "замены переменных":
#include "globals.h"
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdarg.h>
// Store and replace all variables used in the makefile
void processVariables(FILE* spData) {
// Initialise the counting variable buffer to hold the file line by line
varCount = 0;
char buffer[10000];
while (fgets(buffer , sizeof(buffer) , spData) != NULL) {
// Skip commented lines (preceede by hash '#')
if (buffer[0] == '#') continue;
for (int i = 0; buffer[i] != '\n' ; i++) {
if (buffer[i] == '=') {
// Increment if line with equals sign is found
varCount++;
break;
}
}
}
// Debugging print statement
printf ("varCount has counted %d equals signs.\n\n" , varCount);
// This will hold the variables
struct VarMap variables[varCount + 4];
int j = 0;
rewind(spData);
// Parse the makefile/bakefile (what is it even now) and store the variable names and assignments
while (fgets(buffer , sizeof(buffer) , spData) != NULL) {
if (buffer[0] == '#') continue;
char* p = strstr(buffer,"=");
if (p) {
*p++ = 0;
// If copy size is too small, change the final number in the function
strncpy(variables[j].key, buffer,1000);
strncpy(variables[j].data, p,1000);
j++;
}
}
// Appending the general variables to the variable array
strcpy(variables[varCount].key , "PID");
strcpy(variables[varCount].data , "getpid()");
strcpy(variables[varCount + 1].key , "PPID");
strcpy(variables[varCount + 1].data , "getppid()");
strcpy(variables[varCount + 2].key , "PWD");
strcpy(variables[varCount + 2].data , "getcwd()");
strcpy(variables[varCount + 3].key , "RAND");
strcpy(variables[varCount + 3].data , "rand()");
// Debugging print statement (All code above this point is correct)
printf("List of all variables as they stand here:\n");
for(int i = 0; i < varCount + 4; i++) {
printf("Key: %s, Value: %s\n" , variables[i].key , variables[i].data);
}
// Replacing the variables
// Go through the file and re-write it line by line, keep calling rewind(spData);
// and parse through the file until there are no more '$' signs
rewind(spData);
char copyStream[10000];
bool noDollarSigns = false;
// While there are still dollar signs in the file, indicating more variable substitution needs to occur
while (noDollarSigns == false) {
while (fgets(copyStream , sizeof(copyStream) , spData) != NULL) {
}
}
}
Как видите, последние 2 вложенных 'while's - это пространство, в котором я собирался выполнить фактическую подстановку переменных.Основные переменные, которые вы видите, - это переменные, которые программа будет подставлять в каждый обрабатываемый make-файл.
И функция main для контекста:
int main(int argc, const char * argv[]) {
char filepath[1000];
printf("Enter the filepath of the Bakefile or bakefile: ");
scanf("%s" , filepath);
FILE* spData;
spData = fopen(filepath , "r");
if (spData == NULL) {
printf ("Cannot open file.");
exit(EXIT_FAILURE);
}
processVariables(spData);
fclose(spData);
return 0;
}
Вызов mainФункция с функцией processVariables в том виде, в котором она написана, и все заголовочные файлы в актуальном состоянии, с указанным выше make-файлом, дает следующий вывод:
Enter the filepath of the Bakefile or bakefile: /Users/Admin/Documents/Makefiles/Test1.txt
varCount has counted 2 equals signs.
List of all variables as they stand here:
Key: C99 , Value: cc -std=c99
Key: CFLAGS , Value: -Wall -pedantic -Werror
Key: PID, Value: getpid()
Key: PPID, Value: getppid()
Key: PWD, Value: getcwd()
Key: RAND, Value: rand()
Первые 2 переменные относятся к рассматриваемому make-файлу, аостальные 4 являются общими и должны быть заменены на все make-файлы.
Я уже задавал здесь много вопросов о помощи по моему проекту, и все ответы до сих пор были чрезвычайно полезны - большое спасибо!
Итак, в основном:
Как мне написать код для прохождения через текстовый файл и заменить все экземпляры переменных их определениями, данными в моей структуре данных?Если такой код не должен быть записан в функции processVariables, куда этот код должен идти в моей программе?
РЕДАКТИРОВАТЬ 1: @fotang предоставил полу-полный сегмент кода,который я вставил и немного доработал, чтобы исправить тут и там.Вот новая функция processVariables с его вставленным кодом:
void processVariables(FILE* spData) {
// Initialise the counting variable buffer to hold the file line by line
varCount = 0;
char buffer[10000];
while (fgets(buffer , sizeof(buffer) , spData) != NULL) {
// Skip commented lines (preceede by hash '#')
if (buffer[0] == '#') continue;
for (int i = 0; buffer[i] != '\n' ; i++) {
if (buffer[i] == '=') {
// Increment if line with equals sign is found
varCount++;
break;
}
}
}
// Debugging print statement
printf ("varCount has counted %d equals signs.\n\n" , varCount);
// This will hold the variables
struct VarMap variables[varCount + 4];
int j = 0;
rewind(spData);
// Parse the makefile/bakefile (what is it even now bruh) and store the variable names and assignments
while (fgets(buffer , sizeof(buffer) , spData) != NULL) {
if (buffer[0] == '#') continue;
char* p = strstr(buffer , "=");
if (p) {
*p++ = 0;
// If copy size is too small, change the final number in the function
strncpy(variables[j].key, buffer,1000);
strncpy(variables[j].data, p,1000);
// Get rid of any trailing newline characters in the data
char* newline;
if ((newline = strchr(variables[j].data, '\n')) != NULL)
*newline = '\0';
j++;
}
}
// Appending the general variables to the variable array
strcpy(variables[varCount].key , "PID");
strcpy(variables[varCount].data , "getpid()");
strcpy(variables[varCount + 1].key , "PPID");
strcpy(variables[varCount + 1].data , "getppid()");
strcpy(variables[varCount + 2].key , "PWD");
strcpy(variables[varCount + 2].data , "getcwd()");
strcpy(variables[varCount + 3].key , "RAND");
strcpy(variables[varCount + 3].data , "rand()");
// Debugging print statement
printf("List of all variables as they stand here:\n");
for(int i = 0; i < varCount + 4; i++) {
printf("Key: %s, Value: %s\n" , variables[i].key , variables[i].data);
}
// Replacing the variables
// Go through the file and re-write it line by line
// parse through the file until there are no more '$' signs
FILE* outputPtr = fopen("/Users/Admin/Documents/Makefiles/Output.txt","w");
rewind(spData);
while (fgets(buffer , sizeof(buffer) , spData) != NULL) {
// Comment lines need no variable substitution so we print them as written
if (buffer[0] == '#'){
fputs(buffer,outputPtr);
continue;
}
// Copying the buffer character by character until a dollar '$' sign is reached
char* p = buffer;
while (*p) {
if (*p != '$') {
fputc(*p++ , outputPtr);
continue;
}
p++;
if(*p != '('){
fputc(*p++ , outputPtr);
continue;
}
// Get the variable name (key)
char *s = ++p;
char key[1000];
while(*s != ')') s++;
strncpy(key, p, s - p);
key[s - p] = 0;
p = s + 1;
// Fetch the contents of the variable from the structure and substitute
for(int i = 0; i < varCount + 4; i++)
if(strcmp(variables[i].key, key)){
fprintf(outputPtr, "%s", variables[i].data);
break;
}
}
}
}
Однако, если эта функция теперь вызывается на ткани со следующим текстом: (имя файла - Text1.txt)
# A Makefile to build our 'calcmarks' project
# Variable Declarations
C99 = cc -std=c99
CFLAGS = -Wall -pedantic -Werror
# Command lines
calcmarks : calcmarks.o globals.o readmarks.o correlation.o
$(C99) $(CFLAGS) -o calcmarks \
calcmarks.o globals.o readmarks.o correlation.o -lm
calcmarks.o : calcmarks.c calcmarks.h
$(C99) $(CFLAGS) -c calcmarks.c
globals.o : globals.c calcmarks.h
$(C99) $(CFLAGS) -c globals.c
readmarks.o : readmarks.c calcmarks.h
$(C99) $(CFLAGS) -c readmarks.c
correlation.o : correlation.c calcmarks.h
$(C99) $(CFLAGS) -c correlation.c
varTest:
$(PID) $(PPID) $(PWD) $(RAND)
Это следующее содержимое выходного файла:
# A Makefile to build our 'calcmarks' project
# Variable Declarations
C99 = cc -std=c99
CFLAGS = -Wall -pedantic -Werror
# Command lines
calcmarks : calcmarks.o globals.o readmarks.o correlation.o
cc -std=c99 cc -std=c99 -o calcmarks \
calcmarks.o globals.o readmarks.o correlation.o -lm
calcmarks.o : calcmarks.c calcmarks.h
cc -std=c99 cc -std=c99 -c calcmarks.c
globals.o : globals.c calcmarks.h
cc -std=c99 cc -std=c99 -c globals.c
readmarks.o : readmarks.c calcmarks.h
cc -std=c99 cc -std=c99 -c readmarks.c
correlation.o : correlation.c calcmarks.h
cc -std=c99 cc -std=c99 -c correlation.c
varTest:
cc -std=c99 cc -std=c99 cc -std=c99 cc -std=c99
Как видите, каждая переменная была заменена только содержимым первой переменной в структуре variable.
РЕДАКТИРОВАТЬ 2: Замена strcmp()
на !strcmp()
в конечном , если блок производит следующий вывод:
# A Makefile to build our 'calcmarks' project
# Variable Declarations
C99 = cc -std=c99
CFLAGS = -Wall -pedantic -Werror
# Command lines
calcmarks : calcmarks.o globals.o readmarks.o correlation.o
calcmarks.o globals.o readmarks.o correlation.o -lm
calcmarks.o : calcmarks.c calcmarks.h
globals.o : globals.c calcmarks.h
readmarks.o : readmarks.c calcmarks.h
correlation.o : correlation.c calcmarks.h
varTest:
getpid() getppid() getcwd() rand()
Как видите, на этот раз все переменные удаляются без подстановки, за исключением 4 общих добавленных переменных.