Task 278: .H File Format

Task 278: .H File Format

1. Properties of the .H File Format Intrinsic to Its Structure

The .H file format refers to C/C++ header files, which are plain-text ASCII files used to declare shared elements like functions, variables, types, and macros for inclusion in source code via the #include directive. These files follow conventions defined by the C standard (e.g., ISO/IEC 9899) and C++ standard (e.g., ISO/IEC 14882), but lack a rigid binary structure—instead, they are line-oriented text files parsed by the C preprocessor. "Intrinsic properties" here refer to core structural elements that define their content and behavior within the C/C++ compilation ecosystem (not a separate file system, but the compilation model's dependency graph). Based on standard specifications, the key properties are:

  • Text Encoding: ASCII or UTF-8 compatible, with lines terminated by LF (line feed, ASCII 10) or CRLF (carriage return + line feed, ASCII 13+10). No binary data; maximum line length is implementation-defined but typically 509 characters (C standard recommendation).
  • Preprocessor Directives: Lines starting with # (after optional whitespace), including:
  • #include <header> or #include "header" for including other files (system or user headers).
  • #define for macro definitions (e.g., constants, functions).
  • #undef for macro undefinition.
  • Conditional compilation (#if, #ifdef, #ifndef, #else, #elif, #endif).
  • #pragma for compiler-specific directives (e.g., #pragma once for include guards).
  • Include Guards: Typically a triplet of #ifndef GUARD_NAME, #define GUARD_NAME, and #endif to prevent multiple inclusions.
  • Declarations:
  • Function prototypes (e.g., int func(int param);).
  • Extern variable declarations (e.g., extern int global_var;).
  • Type definitions: struct, union, enum, typedef.
  • Comments: /* block */ or // line (C++ only), ignored by preprocessor.
  • No Definitions: Headers should avoid executable code or full function bodies (except inline or templates in C++); violations lead to multiple definition errors.
  • File Extension Convention: Always .h (lowercase recommended for portability).
  • Self-Containment: Must compile standalone (after includes) to ensure forward declarations work.

These properties ensure modularity in C/C++ projects, where headers form a directed acyclic graph of dependencies.

3. Ghost Blog Embedded HTML JavaScript for Drag-and-Drop .H File Parsing

This is a self-contained HTML snippet with embedded JavaScript, suitable for embedding in a Ghost blog post (via the HTML card). It enables drag-and-drop of a .H file, reads it as text, parses key properties (includes, defines, function prototypes, guards), and dumps them to a <div> on screen. Parsing uses simple regex for demonstration; handles basic cases but not nested conditionals or complex syntax.

Drag & drop a .H file here

4. Python Class for .H File Handling

This Python class reads a .H file, parses and prints the properties (same as above), and supports writing a new .H file from a dict of properties. Uses re for parsing.

import re
import os

class HFileHandler:
    def __init__(self, filepath):
        self.filepath = filepath
        self.content = None
        self.properties = None

    def read_and_decode(self):
        if not os.path.exists(self.filepath) or not self.filepath.endswith('.h'):
            raise ValueError("Invalid .H file")
        with open(self.filepath, 'r') as f:
            self.content = f.read()
        self.properties = self._parse()
        self._print_properties()
        return self.properties

    def _parse(self):
        lines = self.content.split('\n')
        includes = []
        defines = []
        prototypes = []
        guards = {'has_guard': False, 'name': None}
        in_guard = False

        for idx, line in enumerate(lines):
            trimmed = line.strip()
            if trimmed.startswith('#include'):
                includes.append({'line': idx + 1, 'directive': trimmed})
            elif trimmed.startswith('#define'):
                defines.append({'line': idx + 1, 'macro': trimmed})
            elif trimmed.startswith('#ifndef') and not in_guard:
                guards['has_guard'] = True
                match = re.match(r'#ifndef\s+(\w+)', trimmed)
                if match:
                    guards['name'] = match.group(1)
                in_guard = True
            elif trimmed.startswith('#endif') and in_guard:
                in_guard = False
            elif re.match(r'^\w+\s+\w+\s*\([^)]*\)\s*;', trimmed):
                prototypes.append({'line': idx + 1, 'proto': trimmed})

        return {
            'includes': includes,
            'defines': defines,
            'prototypes': prototypes,
            'guards': guards,
            'total_lines': len(lines)
        }

    def _print_properties(self):
        print("=== .H File Properties ===")
        print(f"Total lines: {self.properties['total_lines']}")
        print("\nIncludes:")
        for inc in self.properties['includes']:
            print(f"  Line {inc['line']}: {inc['directive']}")
        print("\nDefines:")
        for defn in self.properties['defines']:
            print(f"  Line {defn['line']}: {defn['macro']}")
        print("\nPrototypes:")
        for proto in self.properties['prototypes']:
            print(f"  Line {proto['line']}: {proto['proto']}")
        print(f"\nGuards: {'Yes' if self.properties['guards']['has_guard'] else 'No'} (Name: {self.properties['guards']['name']})")

    def write(self, output_path, properties=None):
        if properties is None:
            properties = self.properties
        content = self._build_content(properties)
        with open(output_path, 'w') as f:
            f.write(content)
        print(f"Wrote .H file to {output_path}")

    def _build_content(self, props):
        content = []
        if props['guards']['has_guard']:
            content.append(f"#ifndef {props['guards']['name']}")
            content.append(f"#define {props['guards']['name']}")
        for inc in props['includes']:
            content.append(inc['directive'])
        for defn in props['defines']:
            content.append(defn['macro'])
        for proto in props['prototypes']:
            content.append(proto['proto'])
        if props['guards']['has_guard']:
            content.append("#endif")
        return '\n'.join(content) + '\n'

# Usage example:
# handler = HFileHandler('sample.h')
# handler.read_and_decode()
# handler.write('output.h')

5. Java Class for .H File Handling

This Java class reads a .H file, parses and prints properties, and writes a new one. Uses java.util.regex and BufferedReader.

import java.io.*;
import java.util.*;
import java.util.regex.Pattern;
import java.util.regex.Matcher;

public class HFileHandler {
    private String filepath;
    private String content;
    private Map<String, Object> properties;

    public HFileHandler(String filepath) {
        this.filepath = filepath;
        this.properties = new HashMap<>();
    }

    public Map<String, Object> readAndDecode() throws IOException {
        if (!filepath.endsWith(".h") || !new File(filepath).exists()) {
            throw new IllegalArgumentException("Invalid .H file");
        }
        try (BufferedReader br = new BufferedReader(new FileReader(filepath))) {
            StringBuilder sb = new StringBuilder();
            String line;
            while ((line = br.readLine()) != null) {
                sb.append(line).append("\n");
            }
            content = sb.toString();
        }
        properties = parse();
        printProperties();
        return properties;
    }

    private Map<String, Object> parse() {
        String[] lines = content.split("\n");
        List<Map<String, Object>> includes = new ArrayList<>();
        List<Map<String, Object>> defines = new ArrayList<>();
        List<Map<String, Object>> prototypes = new ArrayList<>();
        Map<String, Object> guards = new HashMap<>();
        guards.put("hasGuard", false);
        guards.put("name", null);
        boolean inGuard = false;

        Pattern protoPattern = Pattern.compile("^\\w+\\s+\\w+\\s*\\([^)]*\\)\\s*;");

        for (int idx = 0; idx < lines.length; idx++) {
            String trimmed = lines[idx].trim();
            if (trimmed.startsWith("#include")) {
                Map<String, Object> inc = new HashMap<>();
                inc.put("line", idx + 1);
                inc.put("directive", trimmed);
                includes.add(inc);
            } else if (trimmed.startsWith("#define")) {
                Map<String, Object> def = new HashMap<>();
                def.put("line", idx + 1);
                def.put("macro", trimmed);
                defines.add(def);
            } else if (trimmed.startsWith("#ifndef") && !inGuard) {
                guards.put("hasGuard", true);
                Matcher m = Pattern.compile("#ifndef\\s+(\\w+)").matcher(trimmed);
                if (m.find()) {
                    guards.put("name", m.group(1));
                }
                inGuard = true;
            } else if (trimmed.startsWith("#endif") && inGuard) {
                inGuard = false;
            } else if (protoPattern.matcher(trimmed).matches()) {
                Map<String, Object> proto = new HashMap<>();
                proto.put("line", idx + 1);
                proto.put("proto", trimmed);
                prototypes.add(proto);
            }
        }

        Map<String, Object> props = new HashMap<>();
        props.put("includes", includes);
        props.put("defines", defines);
        props.put("prototypes", prototypes);
        props.put("guards", guards);
        props.put("totalLines", lines.length);
        return props;
    }

    private void printProperties() {
        System.out.println("=== .H File Properties ===");
        System.out.println("Total lines: " + properties.get("totalLines"));
        System.out.println("\nIncludes:");
        for (Map<String, Object> inc : (List<Map<String, Object>>) properties.get("includes")) {
            System.out.println("  Line " + inc.get("line") + ": " + inc.get("directive"));
        }
        System.out.println("\nDefines:");
        for (Map<String, Object> def : (List<Map<String, Object>>) properties.get("defines")) {
            System.out.println("  Line " + def.get("line") + ": " + def.get("macro"));
        }
        System.out.println("\nPrototypes:");
        for (Map<String, Object> proto : (List<Map<String, Object>>) properties.get("prototypes")) {
            System.out.println("  Line " + proto.get("line") + ": " + proto.get("proto"));
        }
        Map<String, Object> guards = (Map<String, Object>) properties.get("guards");
        System.out.println("\nGuards: " + (guards.get("hasGuard") ? "Yes" : "No") + " (Name: " + guards.get("name") + ")");
    }

    public void write(String outputPath, Map<String, Object> customProps) throws IOException {
        Map<String, Object> props = (customProps != null) ? customProps : properties;
        StringBuilder sb = new StringBuilder();
        Map<String, Object> guards = (Map<String, Object>) props.get("guards");
        if (guards.get("hasGuard") == Boolean.TRUE) {
            sb.append("#ifndef ").append(guards.get("name")).append("\n");
            sb.append("#define ").append(guards.get("name")).append("\n");
        }
        for (Map<String, Object> inc : (List<Map<String, Object>>) props.get("includes")) {
            sb.append(inc.get("directive")).append("\n");
        }
        for (Map<String, Object> def : (List<Map<String, Object>>) props.get("defines")) {
            sb.append(def.get("macro")).append("\n");
        }
        for (Map<String, Object> proto : (List<Map<String, Object>>) props.get("prototypes")) {
            sb.append(proto.get("proto")).append("\n");
        }
        if (guards.get("hasGuard") == Boolean.TRUE) {
            sb.append("#endif\n");
        }
        try (PrintWriter pw = new PrintWriter(new FileWriter(outputPath))) {
            pw.print(sb.toString());
        }
        System.out.println("Wrote .H file to " + outputPath);
    }

    // Usage: HFileHandler handler = new HFileHandler("sample.h"); handler.readAndDecode(); handler.write("output.h", null);
}

6. JavaScript Class for .H File Handling

This Node.js-compatible class reads a .H file (using fs), parses properties, prints to console, and writes a new file. Uses regex for parsing.

const fs = require('fs');

class HFileHandler {
  constructor(filepath) {
    this.filepath = filepath;
    this.content = null;
    this.properties = null;
  }

  async readAndDecode() {
    if (!this.filepath.endsWith('.h') || !fs.existsSync(this.filepath)) {
      throw new Error('Invalid .H file');
    }
    this.content = fs.readFileSync(this.filepath, 'utf8');
    this.properties = this.parse();
    this.printProperties();
    return this.properties;
  }

  parse() {
    const lines = this.content.split('\n');
    const includes = [];
    const defines = [];
    const prototypes = [];
    const guards = { hasGuard: false, name: null };
    let inGuard = false;

    const protoRegex = /^\w+\s+\w+\s*\([^)]*\)\s*;/;

    lines.forEach((line, idx) => {
      const trimmed = line.trim();
      if (trimmed.startsWith('#include')) {
        includes.push({ line: idx + 1, directive: trimmed });
      } else if (trimmed.startsWith('#define')) {
        defines.push({ line: idx + 1, macro: trimmed });
      } else if (trimmed.startsWith('#ifndef') && !inGuard) {
        guards.hasGuard = true;
        const match = trimmed.match(/#ifndef\s+(\w+)/);
        if (match) guards.name = match[1];
        inGuard = true;
      } else if (trimmed.startsWith('#endif') && inGuard) {
        inGuard = false;
      } else if (protoRegex.test(trimmed)) {
        prototypes.push({ line: idx + 1, proto: trimmed });
      }
    });

    return {
      includes,
      defines,
      prototypes,
      guards,
      totalLines: lines.length
    };
  }

  printProperties() {
    console.log('=== .H File Properties ===');
    console.log(`Total lines: ${this.properties.totalLines}`);
    console.log('\nIncludes:');
    this.properties.includes.forEach(inc => console.log(`  Line ${inc.line}: ${inc.directive}`));
    console.log('\nDefines:');
    this.properties.defines.forEach(def => console.log(`  Line ${def.line}: ${def.macro}`));
    console.log('\nPrototypes:');
    this.properties.prototypes.forEach(proto => console.log(`  Line ${proto.line}: ${proto.proto}`));
    console.log(`\nGuards: ${this.properties.guards.hasGuard ? 'Yes' : 'No'} (Name: ${this.properties.guards.name})`);
  }

  write(outputPath, customProps = null) {
    const props = customProps || this.properties;
    let content = '';
    if (props.guards.hasGuard) {
      content += `#ifndef ${props.guards.name}\n#define ${props.guards.name}\n`;
    }
    props.includes.forEach(inc => content += `${inc.directive}\n`);
    props.defines.forEach(def => content += `${def.macro}\n`);
    props.prototypes.forEach(proto => content += `${proto.proto}\n`);
    if (props.guards.hasGuard) {
      content += '#endif\n';
    }
    fs.writeFileSync(outputPath, content);
    console.log(`Wrote .H file to ${outputPath}`);
  }
}

// Usage:
// const handler = new HFileHandler('sample.h');
// await handler.readAndDecode();
// handler.write('output.h');

7. C Struct/Class for .H File Handling

This C implementation uses a struct with functions to read, parse, print, and write .H files. Parsing is line-based with strstr and simple checks (no full regex; uses sscanf where possible). Compile with gcc -o handler handler.c.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_LINE 512
#define MAX_PROPS 100

typedef struct {
    int line;
    char directive[256];
} Prop;

typedef struct {
    Prop includes[MAX_PROPS];
    int num_includes;
    Prop defines[MAX_PROPS];
    int num_defines;
    Prop prototypes[MAX_PROPS];
    int num_prototypes;
    int has_guard;
    char guard_name[256];
    int total_lines;
} HProperties;

typedef struct {
    char filepath[256];
    char *content;
    HProperties props;
} HFileHandler;

void init_handler(HFileHandler *handler, const char *filepath) {
    strcpy(handler->filepath, filepath);
    handler->content = NULL;
    handler->props.num_includes = 0;
    handler->props.num_defines = 0;
    handler->props.num_prototypes = 0;
    handler->props.has_guard = 0;
    handler->props.total_lines = 0;
}

int read_and_decode(HFileHandler *handler) {
    FILE *fp = fopen(handler->filepath, "r");
    if (!fp || !strstr(handler->filepath, ".h")) {
        printf("Invalid .H file\n");
        return 0;
    }
    fseek(fp, 0, SEEK_END);
    long size = ftell(fp);
    rewind(fp);
    handler->content = malloc(size + 1);
    fread(handler->content, 1, size, fp);
    handler->content[size] = '\0';
    fclose(fp);
    parse_content(handler);
    print_properties(&handler->props);
    return 1;
}

void parse_content(HFileHandler *handler) {
    char *line = strtok(handler->content, "\n");
    int idx = 0;
    int in_guard = 0;
    while (line != NULL) {
        char trimmed[512];
        sscanf(line, "%511[^\n]", trimmed);
        char *p = trimmed;
        while (*p == ' ' || *p == '\t') p++;  // Trim left
        char *end = p + strlen(p) - 1;
        while (end > p && (*end == ' ' || *end == '\t' || *end == '\r')) *end-- = '\0';

        if (strncmp(p, "#include", 8) == 0) {
            if (handler->props.num_includes < MAX_PROPS) {
                handler->props.includes[handler->props.num_includes].line = idx + 1;
                strcpy(handler->props.includes[handler->props.num_includes].directive, p);
                handler->props.num_includes++;
            }
        } else if (strncmp(p, "#define", 7) == 0) {
            if (handler->props.num_defines < MAX_PROPS) {
                handler->props.defines[handler->props.num_defines].line = idx + 1;
                strcpy(handler->props.defines[handler->props.num_defines].directive, p);
                handler->props.num_defines++;
            }
        } else if (strncmp(p, "#ifndef", 7) == 0 && !in_guard) {
            handler->props.has_guard = 1;
            sscanf(p, "#ifndef %255s", handler->props.guard_name);
            in_guard = 1;
        } else if (strncmp(p, "#endif", 6) == 0 && in_guard) {
            in_guard = 0;
        } else if (strstr(p, "(") && strstr(p, ")") && strstr(p, ";") && !strstr(p, "=")) {  // Basic proto check
            if (handler->props.num_prototypes < MAX_PROPS) {
                handler->props.prototypes[handler->props.num_prototypes].line = idx + 1;
                strcpy(handler->props.prototypes[handler->props.num_prototypes].directive, p);
                handler->props.num_prototypes++;
            }
        }
        line = strtok(NULL, "\n");
        idx++;
    }
    handler->props.total_lines = idx;
}

void print_properties(HProperties *props) {
    printf("=== .H File Properties ===\n");
    printf("Total lines: %d\n", props->total_lines);
    printf("\nIncludes:\n");
    for (int i = 0; i < props->num_includes; i++) {
        printf("  Line %d: %s\n", props->includes[i].line, props->includes[i].directive);
    }
    printf("\nDefines:\n");
    for (int i = 0; i < props->num_defines; i++) {
        printf("  Line %d: %s\n", props->defines[i].line, props->defines[i].directive);
    }
    printf("\nPrototypes:\n");
    for (int i = 0; i < props->num_prototypes; i++) {
        printf("  Line %d: %s\n", props->prototypes[i].line, props->prototypes[i].directive);
    }
    printf("\nGuards: %s (Name: %s)\n", props->has_guard ? "Yes" : "No", props->guard_name);
}

void write_file(const char *output_path, HProperties *props) {
    FILE *fp = fopen(output_path, "w");
    if (!fp) return;
    if (props->has_guard) {
        fprintf(fp, "#ifndef %s\n#define %s\n", props->guard_name, props->guard_name);
    }
    for (int i = 0; i < props->num_includes; i++) {
        fprintf(fp, "%s\n", props->includes[i].directive);
    }
    for (int i = 0; i < props->num_defines; i++) {
        fprintf(fp, "%s\n", props->defines[i].directive);
    }
    for (int i = 0; i < props->num_prototypes; i++) {
        fprintf(fp, "%s\n", props->prototypes[i].directive);
    }
    if (props->has_guard) {
        fprintf(fp, "#endif\n");
    }
    fclose(fp);
    printf("Wrote .H file to %s\n", output_path);
}

/* Usage:
int main() {
    HFileHandler handler;
    init_handler(&handler, "sample.h");
    if (read_and_decode(&handler)) {
        write_file("output.h", &handler.props);
    }
    free(handler.content);
    return 0;
}
*/