visualize the data structures in a C program
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

352 lines
12 KiB

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Struct Visualization</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<style>
:root {
--r1: pink;
--r2: blue;
--r3: magenta;
--r4: yellow;
--r5: cyan;
--r6: orange;
--r7: lime;
--r8: olive;
}
*::before,
*::after,
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html, body {
min-height: 100vh;
height: 100vh;
overscroll-behavior: none;
background: #F0EAD6;
padding-top: 10px;
direction: ltr;
font: 16px HelveticaNeue-Light,Helvetica Neue Light,Helvetica Neue,Helvetica,Arial,Lucida Grande,sans-serif;
}
.struct-info {
padding: 0 20px 20px 20px;
border-bottom: 1px solid silver;
margin-bottom: 20px;
}
.struct-info-declaration {
position: absolute;
font-family: monospace;
min-width: min-content;
max-width: 20em;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 0.9em;
transform: translateX(calc(50% - 10px));
color: black;
font-weight: normal;
}
.struct-info-declaration-name {
font: 16px HelveticaNeue-Light,Helvetica Neue Light,Helvetica Neue,Helvetica,Arial,Lucida Grande,sans-serif;
}
.struct-info-declaration-top {
top: -30px;
}
.struct-info-declaration-bottom {
bottom: -30px;
}
.struct-info-byte-row-ellipsis {
position: absolute;
right: 1em;
}
.struct-info-byte-rows {
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: flex-start;
}
.struct-info-byte-row {
display: flex;
flex-wrap: wrap;
flex-direction: row;
justify-content: flex-start;
align-items: center;
}
.struct-info-bytegroup {
margin: 2em 0;
display: flex;
flex-wrap: wrap;
flex-direction: row;
justify-content: flex-start;
align-items: center;
}
.struct-info-bytegroup:hover {
background-color: orange;
.struct-info-declaration {
font-weight: bold;
color: orange;
}
}
.struct-info-header {
font-weight: bold;
font-family: monospace;
}
.struct-info-byte {
position: relative;
display: flex;
justify-content: center;
align-items: center;
border: 1px solid black;
width: 30px;
height: 45px;
}
.struct-info-byte-alignment {
background-color: seagreen;
opacity: 0.4;
}
.struct-info-byte-first {
border-left-width: 3px;
}
.struct-info-byte-unknown {
border-left-width: 3px;
background-color: maroon;
font-weight: bold;
color: white;
}
.struct-info-byte-counted-ellipsis {
background-color: #808000;
font-weight: bold;
}
.struct-info-byte-ellipsis {
background-color: #400000;
font-weight: bold;
color: white;
}
dialog {
position: sticky;
top: 50vh;
left: 50vw;
transform: translate(-50%, -50%);
padding: 20px;
border: none;
border-radius: 3px;
background-color: #F0EAD6;
box-shadow: 10px 10px 5px 0px rgba(0,0,0,0.75);
max-width: 80vw;
max-height: 80vh;
}
input:not([type=checkbox]):not([type=radio]) {
display: block;
height: 2em;
}
p {
margin: 20px;
}
input[type=checkbox] {
width: 1.2rem;
height: 1.2rem;
}
label {
display: block;
}
label > input {
margin: 5px 15px 15px 15px;
}
.fix-missing-declaration-dialog-footer {
width: 100%;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
button {
width: 10rem;
height: 2rem;
}
.help-idk {
color: darkslategray;
font-size: 0.9rem;
}
.help-idk-container {
width: 100%;
margin-bottom: 10px;
display: flex;
flex-direction: row;
justify-content: flex-end;
align-items: center;
}
</style>
<body>
<dialog
id="fix-missing-declaration-dialog"
>
<p>What's the size and alignment of this type on your architecture?</p>
<div class="help-idk-container">
<p class="help-idk">
Help, I don't know!
</p>
</div>
<label>
It's a bitfield!
<input
type="checkbox"
/>
</label>
<label>
size (in bytes)
<input
type="number"
min="1"
value="8"
/>
</label>
<label>
alignment (in bytes)
<input
type="number"
value="8"
/>
</label>
<footer class="fix-missing-declaration-dialog-footer">
<button
onclick="fixMissingDeclDialog.close()"
>
Confirm
</button>
</footer>
</dialog>
<script defer>
const fixMissingDeclDialog = document.getElementById("fix-missing-declaration-dialog");
function createWithClasses(e, ...classes) {
const elem = document.createElement(e);
elem.classList.add(...classes);
return elem;
}
function alignForward(a, b) {
}
function renderStruct(structInfo, containingElement) {
const div = createWithClasses("div", "struct-info");
const structInfoHeader = createWithClasses("label", "struct-info-header");
structInfoHeader.innerText = `struct ${structInfo.name} - alias: ${structInfo.alias}`;
div.appendChild(structInfoHeader);
for (let i = 0; i < structInfo.declarations.length; i++) {
const decl = structInfo.declarations[i];
const position = i % 2 == 0;
const positionClass = position ? "struct-info-declaration-top" : "struct-info-declaration-bottom";
let bytesInStructSoFar = 0;
if (decl.size === -1) {
const byteGroup = createWithClasses("struct-info-bytegroup");
byteGroup.onclick = fixMissingDeclDialog.showMoodal();
const unknownByte = createWithClasses("div", "struct-info-byte", "struct-info-byte-unknown");
unknownByte.innerText = "?";
byteGroup.appendChild(unknownByte);
const declaration = createWithClasses("div", "struct-info-declaration", positionClass);
declaration.innerHTML = `${decl.type} <span class="struct-info-declaration-name">${decl.name}</span>`;
unknownByte.appendChild(declaration);
const ellipsisByte = createWithClasses("div", "struct-info-byte", "struct_info_byte_ellipsis");
ellipsisByte.innerText = "...";
byteGroup.appendChild(ellipsisByte);
div.appendChild(byteGroup);
} else {
// find if we need to align this field - pad some alignment bytes visually if we do.
const aligned = alignForward(bytesInStructSoFar, decl.align);
const needsAlign = aligned !== bytesInStructSoFar;
if (needsAlign) {
//sb_concatf("%s", "<div class='struct-info-bytegroup'>");
//for (int a = 0; a < (aligned - bytesInStructSoFar); a++) {
// sb_concatf("%s", "<div class='struct-info-byte struct-info-byte-alignment'></div>");
//}
//sb_concatf("%s", "</div>");
//bytesInStructSoFar += aligned - bytesInStructSoFar;
}
// now for the bytes representing the actual field.
//sb_concatf("%s", "<div class='struct-info-bytegroup'>");
//for (int b = 0; b < decl->size; b++) {
// if (b == 0) {
// sb_concatf(
// "<div class='struct-info-byte struct-info-byte-first'>"
// "<div class='struct-info-declaration %s'>"
// "%s <span class='struct-info-declaration-name'>%s</span>"
// "</div>"
// "</div>"
// , positionClass, decl->type, decl->name);
// } else {
// sb_concatf("%s", "<div class='struct-info-byte'></div>");
// }
//}
//bytesInStructSoFar += decl->size;
//sb_concatf("%s", "</div>"); // end bytegroup
}
//sb_concatf("%s", "</div></div>");
}
containingElement.appendChild(div);
}
function renderAllStructs() {
for (let i = 0; i < window.structs.length; i++) {
const structInfo = structs[i];
renderStruct(structInfo, document.body);
}
}
</script>
<!-- c code will place a script tag containing all of the data structures in JSON format, and terminate the body and html tags -->
<script>
window.structs = JSON.parse(`[
{"name":"Dummy","alias":"","filename":"main.c","lineNumber":78,"lineOffset":7,"size":13,"declarations":[{"type": "char*","name": "p","size": "8","align": "8","isBitfield": false},{"type": "char","name": "c","size": "1","align": "1","isBitfield": false},{"type": "int","name": "x","size": "4","align": "4","isBitfield": false}]},{"name":"Declaration","alias":"","filename":"main.c","lineNumber":162,"lineOffset":7,"size":145,"declarations":[{"type": "char","name": "type[64]","size": "64","align": "1","isBitfield": false},{"type": "char","name": "name[64]","size": "64","align": "1","isBitfield": false},{"type": "ssize_t","name": "size","size": "8","align": "8","isBitfield": false},{"type": "ssize_t","name": "align","size": "8","align": "8","isBitfield": false},{"type": "bool","name": "isBitfield","size": "1","align": "1","isBitfield": false}]},{"name":"StructInfo","alias":"","filename":"main.c","lineNumber":170,"lineOffset":7,"size":151,"declarations":[{"type": "char","name": "name[64]","size": "64","align": "1","isBitfield": false},{"type": "char","name": "alias[64]","size": "64","align": "1","isBitfield": false},{"type": "char*","name": "filename","size": "8","align": "8","isBitfield": false},{"type": "int","name": "lineNumber","size": "4","align": "4","isBitfield": false},{"type": "ssize_t","name": "size","size": "8","align": "8","isBitfield": false},{"type": "struct Declaration","name": "declarations[16]","size": "-1","align": "-1","isBitfield": false},{"type": "int","name": "numDeclarations","size": "4","align": "4","isBitfield": false}]},{"name":"Array","alias":"","filename":"main.c","lineNumber":214,"lineOffset":7,"size":16,"declarations":[{"type": "unsigned int","name": "length","size": "4","align": "4","isBitfield": false},{"type": "unsigned int","name": "capacity","size": "4","align": "4","isBitfield": false},{"type": "void*","name": "data","size": "8","align": "8","isBitfield": false}]},{"name":"TableEntry","alias":"TableEntry","filename":"table.h","lineNumber":27,"lineOffset":15,"size":23,"declarations":[{"type": "struct TableEntry*","name": "next","size": "8","align": "8","isBitfield": false},{"type": "char key","name": "TABLE_KEY_SIZE","size": "-1","align": "-1","isBitfield": false},{"type": "ssize_t","name": "size","size": "8","align": "8","isBitfield": false},{"type": "ssize_t","name": "align","size": "8","align": "8","isBitfield": false}]},{"name":"Table","alias":"Table","filename":"table.h","lineNumber":35,"lineOffset":15,"size":8,"declarations":[{"type": "TableEntry**","name": "entries","size": "8","align": "8","isBitfield": false}]},{"name":"","alias":"stb_lexer","filename":"stb_c_lexer.h","lineNumber":113,"lineOffset":0,"size":88,"declarations":[{"type": "char*","name": "input_stream","size": "8","align": "8","isBitfield": false},{"type": "char*","name": "eof","size": "8","align": "8","isBitfield": false},{"type": "char*","name": "parse_point","size": "8","align": "8","isBitfield": false},{"type": "char*","name": "string_storage","size": "8","align": "8","isBitfield": false},{"type": "int","name": "string_storage_len","size": "4","align": "4","isBitfield": false},{"type": "char*","name": "where_firstchar","size": "8","align": "8","isBitfield": false},{"type": "char*","name": "where_lastchar","size": "8","align": "8","isBitfield": false},{"type": "long","name": "token","size": "8","align": "8","isBitfield": false},{"type": "double","name": "real_number","size": "8","align": "8","isBitfield": false},{"type": "long","name": "int_number","size": "8","align": "8","isBitfield": false},{"type": "char*","name": "string","size": "8","align": "8","isBitfield": false},{"type": "int","name": "string_len","size": "4","align": "4","isBitfield": false}]},{"name":"","alias":"stb_lex_location","filename":"stb_c_lexer.h","lineNumber":134,"lineOffset":0,"size":8,"declarations":[{"type": "int","name": "line_number","size": "4","align": "4","isBitfield": false},{"type": "int","name": "line_offset","size": "4","align": "4","isBitfield": false}]}]`);renderAllStructs();
</script></body></html>