#!/bin/bash # embed_web_files.sh — Convert www/ web files into C byte arrays # # Scans www/**/*.html, www/**/*.css, www/**/*.js and generates # src/embedded_web_content.c + src/embedded_web_content.h with the # file contents as C byte arrays. The sovereign:// URI scheme handler # looks up files by path via get_embedded_file(). # # Adapted from ~/lt/c-relay/embed_web_files.sh. set -e echo "[embed] Embedding web files into C byte arrays..." # Output directory for generated files OUTPUT_DIR="src" mkdir -p "$OUTPUT_DIR" # Function to convert a file to a C byte array file_to_c_array() { local input_file="$1" local array_name="$2" local output_file="$3" # Get file size local file_size=$(stat -c%s "$input_file" 2>/dev/null || stat -f%z "$input_file" 2>/dev/null || echo "0") echo "// Auto-generated from $input_file" >> "$output_file" echo "static const unsigned char ${array_name}_data[] = {" >> "$output_file" # Convert file to hex bytes hexdump -v -e '1/1 "0x%02x,"' "$input_file" >> "$output_file" echo "};" >> "$output_file" echo "static const size_t ${array_name}_size = $file_size;" >> "$output_file" echo "" >> "$output_file" } # Generate the header file HEADER_FILE="$OUTPUT_DIR/embedded_web_content.h" cat > "$HEADER_FILE" <<'EOF' // Auto-generated embedded web content header // Do not edit manually - generated by embed_web_files.sh #ifndef EMBEDDED_WEB_CONTENT_H #define EMBEDDED_WEB_CONTENT_H #include typedef struct { const char *path; /* e.g. "agents/chat.html" */ const unsigned char *data; size_t size; const char *mime_type; /* "text/html", "text/css", "application/javascript" */ } embedded_file_t; /* * Look up an embedded file by its path (e.g. "agents/chat.html"). * Returns NULL if not found. */ const embedded_file_t *get_embedded_file(const char *path); #endif /* EMBEDDED_WEB_CONTENT_H */ EOF # Generate the C file SOURCE_FILE="$OUTPUT_DIR/embedded_web_content.c" cat > "$SOURCE_FILE" <<'EOF' // Auto-generated embedded web content // Do not edit manually - generated by embed_web_files.sh #include "embedded_web_content.h" #include EOF # Process each web file and build the lookup table declare -a file_entries for file in $(find www -type f \( -name '*.html' -o -name '*.css' -o -name '*.js' -o -name '*.mjs' \) | sort); do if [ -f "$file" ]; then # Get path relative to www/ rel_path="${file#www/}" # Create C identifier from path (replace non-alphanumeric with _) c_name=$(echo "$rel_path" | sed 's/[^a-zA-Z0-9]/_/g' | sed 's/^_//') # Determine content type case "$file" in *.html) content_type="text/html" ;; *.css) content_type="text/css" ;; *.js) content_type="text/javascript" ;; *.mjs) content_type="text/javascript" ;; *) content_type="text/plain" ;; esac echo "[embed] $rel_path -> ${c_name} ($content_type)" # Generate the byte array file_to_c_array "$file" "$c_name" "$SOURCE_FILE" # Remember for the lookup table (no outer braces — the echo loop # below wraps each entry in a single set of braces) file_entries+=("\"$rel_path\", ${c_name}_data, ${c_name}_size, \"$content_type\"") fi done # Generate the lookup table echo "// File mapping" >> "$SOURCE_FILE" echo "static const embedded_file_t embedded_files[] = {" >> "$SOURCE_FILE" for entry in "${file_entries[@]}"; do echo " { $entry }," >> "$SOURCE_FILE" done echo " {NULL, NULL, 0, NULL} // Sentinel" >> "$SOURCE_FILE" echo "};" >> "$SOURCE_FILE" echo "" >> "$SOURCE_FILE" # Generate the lookup function cat >> "$SOURCE_FILE" <<'EOF' const embedded_file_t *get_embedded_file(const char *path) { if (!path) return NULL; for (int i = 0; embedded_files[i].path != NULL; i++) { if (strcmp(path, embedded_files[i].path) == 0) { return &embedded_files[i]; } } return NULL; } EOF echo "[embed] Generated $HEADER_FILE and $SOURCE_FILE" echo "[embed] Embedded ${#file_entries[@]} files"