This style guide outlines the conventions and best practices to follow when working on the Cloudflare DNS management tool codebase.
- Use descriptive and consistent naming for variables, functions, and constants.
- Example:
CONFIG_FILE
,API_KEY
,load_config()
.
- Example:
- Ensure error handling is implemented for all operations that may fail (e.g., file handling, HTTP requests, memory allocation).
- Keep functions small and modular, each performing a single responsibility.
- Add comments to describe the purpose of complex logic, particularly in functions.
- Follow consistent indentation and spacing (4 spaces for indentation).
- Use constants or macros for repeated values like API URLs or file paths.
- Use
snake_case
for local variables and global variables.- Example:
fetch_response
,zone_id
- Example:
- Global variables should be prefixed with a descriptive name (e.g.,
API_KEY
).
- Use
UPPER_CASE
with underscores for constants and macros.- Example:
#define CONFIG_FILE "config.txt"
- Example:
- Use
snake_case
for function names.- Example:
load_config()
,make_request()
- Example:
- Function names should be verbs or verb phrases.
- Example:
list_zones()
,delete_record()
- Example:
-
Include Statements:
- Standard libraries: Place them at the top of the file.
- Third-party libraries: Follow standard libraries.
-
Global Variables and Constants:
- Declare global variables and constants after the include statements.
-
Helper Functions:
- Implement helper functions before the
main()
function.
- Implement helper functions before the
-
Main Function:
- The
main()
function should be concise and primarily handle argument parsing and command delegation.
- The
- Input Validation:
- Validate all input parameters before using them.
- Error Handling:
- Handle all potential errors (e.g., failed memory allocations, invalid API responses).
- Print meaningful error messages to
stderr
.
- Memory Management:
- Free all dynamically allocated memory before returning or exiting.
- Modularity:
- Keep functions focused and avoid deeply nested logic.
return_type function_name(parameters) {
// Step 1: Validate input
// Step 2: Perform the main operation
// Step 3: Handle errors and cleanup
return result;
}
- Use
make_request()
for all HTTP requests. - Always include required headers such as:
Content-Type: application/json
Authorization: Bearer <API_KEY>
- Handle HTTP responses appropriately:
- Log response errors.
- Parse JSON responses using
cJSON
.
char *response = make_request("https://api.cloudflare.com/client/v4/zones", "GET", NULL);
if (response) {
printf("API Response: %s\n", response);
free(response);
} else {
fprintf(stderr, "Error: API call failed.\n");
}
- Use
cJSON
for JSON parsing. - Check for
NULL
or invalid types before accessing JSON objects. - Always clean up JSON objects with
cJSON_Delete()
after use.
cJSON *json = cJSON_Parse(response);
if (!json) {
fprintf(stderr, "Error: Failed to parse JSON response.\n");
free(response);
return;
}
cJSON *result = cJSON_GetObjectItem(json, "result");
if (!result || !cJSON_IsArray(result)) {
fprintf(stderr, "Error: Invalid response structure.\n");
cJSON_Delete(json);
free(response);
return;
}
// Process result...
cJSON_Delete(json);
free(response);
- Reallocate Carefully:
- Use
realloc()
to expand memory safely. - Always check for
NULL
after memory allocation.
- Use
- Free Dynamically Allocated Memory:
- Free memory allocated with
malloc()
orrealloc()
.
- Free memory allocated with
- Avoid Memory Leaks:
- Ensure all dynamically allocated memory is freed before returning from functions.
struct memory chunk = {NULL, 0};
char *ptr = realloc(chunk.response, chunk.size + new_size + 1);
if (!ptr) {
fprintf(stderr, "Error: Out of memory.\n");
free(chunk.response);
return;
}
chunk.response = ptr;
- Provide clear and concise usage instructions.
- Validate the number and format of arguments.
- Map commands to specific functions based on user input.
if (argc < 2) {
printf("Usage: ./cloudflare <command> [args]\n");
return 1;
}
const char *command = argv[1];
if (strcmp(command, "list_zones") == 0) {
list_zones();
} else {
printf("Unknown command: %s\n", command);
}
- Use
printf()
for general logging andfprintf(stderr, ...)
for error messages. - Include enough information in log messages to debug issues (e.g., HTTP responses, function parameters).
- Avoid hardcoding sensitive information (e.g., API keys).
- Use a configuration file (
config.txt
).
- Use a configuration file (
- Document all new functions with comments explaining their purpose, parameters, and return values.
- Test thoroughly after changes to ensure no regressions.