• 0 Posts
  • 104 Comments
Joined 2 years ago
cake
Cake day: July 24th, 2023

help-circle







  • Auf dem Arduino kannst du keine Dateien lesen, es sei den du willst die über serial senden, deshalb musst du die Werte in dein Programm kompilieren.

    will eher ungerne den User in einer C-Header Datei rum spielen lassen

    Dann lass deine user deine config schreiben und generiere eine header Datei daraus.
    Ich habe mal meine C-Kenntnisse raus gekramt.

    #include <stdio.h>
    #include <stdbool.h>
    #include <string.h>
    #include <stdlib.h>
    #include <stddef.h>
    
    #define BUFFER_LEN 1024
    #define MIN_STRONG_SIZE 16
    #define IN_FILE_DEFAULT "config.txt"
    #define OUT_FILE_DEFAULT "config.h"
    
    typedef struct String {
    	size_t length;
    	size_t size;
    	char content[];
    } String;
    
    typedef struct Variable {
    	String* name;
    	int intPart;
    	int fracPart;
    	bool isNegative;
    	bool hasFraction;
    } Variable;
    
    FILE* outFile;
    
    void storeVariable(Variable variable) {
    	fprintf(outFile, "#define VAR_%s ", variable.name->content);
    	if (variable.isNegative)
    		fprintf(outFile, "-");
    	fprintf(outFile, "%d", variable.intPart);
    	if (variable.hasFraction)
    		fprintf(outFile, ".%d", variable.fracPart);
    	fprintf(outFile, "\n");
    	free(variable.name);
    }
    
    String* newString(size_t size) {
    	if (size < MIN_STRONG_SIZE) {
    		size = MIN_STRONG_SIZE;
    	}
    	String* string = calloc(1, sizeof(String) + size);
    	if (string == NULL) {
    		fprintf(stderr, "allocation error");
    		exit(3);
    	}
    	string->size = size;
    	return string;
    }
    
    String* appendToString(String* string, char c) {
    	if (string == NULL) {
    		fprintf(stderr, "null pointer error");
    		exit(4);
    	}
    	if (string->length+1 >= string->size) {
    		string->size *= 2;
    		string = realloc(string, sizeof(String) + string->size);
    		if (string == NULL) {
    			fprintf(stderr, "allocation error");
    			exit(3);
    		}
    	}
    	string->content[string->length] = c;
    	string->content[string->length+1] = '\0';
    	string->length++;
    	return string;
    }
    
    
    typedef enum ParseMode {
    	VAR_NAME_START = 0,
    	VAR_NAME,
    	INTEGER_START,
    	INTEGER,
    	FRACTION,
    } ParseMode;
    
    void handleChar(char c);
    
    int main(int argc, char** argv) {
    	char* confFileName = IN_FILE_DEFAULT;
    	char* headerFileName = OUT_FILE_DEFAULT;
    	if (argc > 1) {
    		if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0) {
    			printf("usage: %s config_file output_file\n", argv[0]);
    			printf("if no files get specified, the defaults are: %s %s\n", IN_FILE_DEFAULT, OUT_FILE_DEFAULT);
    			return 0;
    		}
    		confFileName = argv[1];
    	}
    	if (argc > 2) {
    		headerFileName = argv[2];
    	}
    
    	FILE* file = fopen(confFileName, "r");
    	if (file == NULL) {
    		fprintf(stderr, "can't open input file %s", confFileName);
    		return 1;
    	}
    	outFile = fopen(headerFileName, "w");
    	if (outFile == NULL) {
    		fprintf(stderr, "can't open output file %s", headerFileName);
    		return 1;
    	}
    
    	char buffer[BUFFER_LEN];
    	unsigned long amountRead = fread(buffer, 1, BUFFER_LEN, file);
    	while (amountRead > 0) {
    		for (int i = 0; i < amountRead; i++) {
    			handleChar(buffer[i]);
    		}
    		amountRead = fread(buffer, 1, BUFFER_LEN, file);
    	}
    	handleChar('\n');
    	fclose(file);
    	fclose(outFile);
    	return 0;
    }
    
    ParseMode mode;
    Variable state = {0};
    
    void handleChar(char c) {
    	if (c == ' ') {
    		return;
    	}
    	switch (mode) {
    		case VAR_NAME_START:
    			if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z')) {
    				state.name = newString(20);
    				state.name = appendToString(state.name, c);
    				mode = VAR_NAME;
    			} else {
    				fprintf(stderr, "error on '%c': variable names must start with a letter", c);
    				exit(2);
    			}
    			break;
    		case VAR_NAME:
    			if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || (c == '_')) {
    				state.name = appendToString(state.name, c);
    			} else if (c == '=') {
    				mode = INTEGER;
    			} else {
    				fprintf(stderr, "name error on '%c': variable names consist of alphanumeric characters and underscores", c);
    				exit(2);
    			}
    			break;
    		case INTEGER_START:
    			if (c == '-') {
    				state.isNegative = true;
    				state.intPart = 0;
    			} else if ('0' <= c && c <= '9') {
    				state.intPart = c - '0';
    			} else {
    				fprintf(stderr, "number error on '%c': expected digit or '-'", c);
    				exit(2);
    			}
    			break;
    		case INTEGER:
    			if ('0' <= c && c <= '9') {
    				state.intPart = state.intPart * 10 + c - '0';
    			} else if (c == '\n') {
    				mode = VAR_NAME_START;
    				storeVariable(state);
    				Variable empty = {0};
    				state = empty;
    			} else if (c == '.') {
    				mode = FRACTION;
    				state.hasFraction = true;
    			} else {
    				fprintf(stderr, "number error on '%c':  expected digit or '.'", c);
    				exit(2);
    			}
    			break;
    		case FRACTION:
    			if ('0' <= c && c <= '9') {
    				state.intPart = state.intPart * 10 + c - '0';
    			} else if (c == '\n') {
    				mode = VAR_NAME_START;
    				storeVariable(state);
    				Variable empty = {0};
    				state = empty;
    			} else {
    				fprintf(stderr, "number error on '%c':  expected digit", c);
    				exit(2);
    			}
    			break;
    	}
    }
    

    Man sollte es wahrscheinlich in header und source aufteilen, und die strings sind vielleicht overkill, aber für ein one-of pass es schon. Wenn die variablen nach dem parsen anders verwenden willst, musst du nur storeVariable abändern.













  • the reason the bombers were in the open is due to Russian compliance with the START treaty.

    First, Russia suspended it’s participation in new START

    Second, are you sure that’s a requirement of the treaty?

    The only relevant article I could find is the following (emphasis mine):

    Article X

    1. For the purpose of ensuring verification of compliance with the provisions of this Treaty, each Party undertakes: (a) to use national technical means of verification at its disposal in a manner consistent with generally recognized principles of international law; (b) not to interfere with the national technical means of verification of the other Party operating in accordance with this Article; and © not to use concealment measures that impede verification, by national technical means of verification, of compliance with the provisions of this Treaty.
    2. The obligation not to use concealment measures includes the obligation not to use them at test ranges, including measures that result in the concealment of ICBMs, SLBMs, ICBM launchers, or the association between ICBMs or SLBMs and their launchers during testing. The obligation not to use concealment measures shall not apply to cover or concealment practices at ICBM bases or to the use of environmental shelters for strategic offensive arms.

    Looks to me like plane hangars are allowed while the tires on planes that they actually used are illegal as they don’t protect against the weather and just exist to fool bad satellite images.