A lightweight “browser” implementation in C that models basic tab management and navigation history using linked lists and stacks. This README explains the overall architecture, data structures, and each function in detail to help you understand, maintain, and extend the code.
- Introduction
- Data Structures
- Initialization Functions
- Tab Management Functions
- Navigation Functions
- I/O and Parsing
- Memory Management
- Main Program Flow
- Building and Running
This project simulates a minimal browser environment. It supports:
- Multiple tabs in a circular doubly-linked list.
- Backward/forward page navigation in each tab using two stacks.
- Opening, closing, switching, and listing tabs.
- Loading pages by ID from an input file.
- Printing current tab status and full navigation history.
Designed for clarity and teaching of linked lists and stack-based history, it can be extended to support bookmarking, tab grouping, or persistent storage.
typedef struct page {
int ID; // Unique page identifier (0 = implicit home page)
char url[50]; // URL string
char *description; // Dynamically allocated description
} page;
typedef struct node {
struct node *next; // Next stack node
page *holded_page;// Pointer to page stored in this node
} node;
typedef struct stack {
node *top; // Top of the stack
int len; // Number of elements
} stack;
typedef struct tab {
int ID; // Tab identifier
page *currentPage; // Currently displayed page
stack *backwardStack; // History backward stack
stack *forwardStack; // History forward stack
} tab;
typedef struct tab_node {
struct tab_node *next; // Next tab_node in circular list
struct tab_node *prev; // Previous tab_node in circular list
tab *holded_tab; // Pointer to the tab data
} tab_node;
typedef struct tabsList {
tab_node *sentinel; // Sentinel node for circular list
int len; // Number of open tabs
} tabsList;
typedef struct browser {
tab *current; // Currently active tab
tabsList list; // All open tabs
} browser;Prints a standard “403 Forbidden” message to the given output file when an invalid operation is attempted.
Returns 1 if there are no tabs open (i.e., len == 0), or 0 otherwise.
Allocates and returns a new page struct for the implicit “home” page:
- ID: 0
- URL:
"https://acs.pub.ro/" - description: dynamically allocated string
"Computer Science"
Allocates and initializes two empty stack objects on the given tab:
backwardStackforwardStack
Each stack’stoppointer is set toNULLand length to 0.
Sets up the browser’s initial state:
- Creates the implicit home tab (
ID = 0) with its page and stacks. - Allocates the circular list’s sentinel node.
- Inserts the home tab into the list so that
sentinel->nextandsentinel->prevboth point to it. - Sets
Chrome_x->currentto the home tab, andlist.len = 1.
Opens a new tab:
- Increments
*max_tabsand assigns the new tab its ID. - Creates a fresh implicit page and empty stacks.
- Inserts a new
tab_nodejust before the sentinel in the circular list. - Sets
Chrome_x->currentto the newly created tab and updateslist.len.
Closes the currently active tab:
- If the tab’s ID is 0, writes a “403 Forbidden” error and returns.
- Otherwise, relinks the neighbors in the circular list to remove the current node.
- Frees the tab’s stacks and implicit page (if any), then the tab struct.
- Updates
Chrome_x->currentto the tab on the immediate left.
Switches to a specific tab by ID:
- Parses the target ID from
operation. - If it matches
current->ID, does nothing. - Otherwise, searches the list; if found, updates
Chrome_x->current. - If not found, writes “403 Forbidden” to
out_file.
Navigate among tabs in circular fashion:
NEXTmovescurrentto the tab on its right (wrapping around after the last).PREVmoves to the tab on its left (wrapping to the last if at the first).
Outputs two lines:
- Tab IDs: space-separated IDs starting from the current tab and wrapping around once.
- Current Page Description: the
descriptionstring ofcurrent->currentPage.
Pushes the given page pointer onto the top of stack_push, updating its len.
Removes and returns the top page pointer from stack_pop. Returns NULL if the stack is empty.
Iterates from the top node down, printing each stored page’s url on its own line.
Returns 1 if check_stack->top is NULL, or 0 otherwise.
Loads a page by ID into the current tab:
- Parses the target page ID.
- Searches
page_vectorfor a matchingID. - If found:
- Pushes the existing
currentPageontobackwardStack. - Clears
forwardStack. - Sets
currentPageto the new page.
- Pushes the existing
- If not found, writes “403 Forbidden.”
Move through the current tab’s history:
- BACKWARD: if
backwardStackis non-empty, pushescurrentPageontoforwardStack, pops frombackwardStack, and makes it the new current. Otherwise, error. - FORWARD: similarly moves one step forward, swapping stacks.
Prints the full history for a given tab ID:
- Parses the tab ID.
- Locates the matching
tab_node. - If found:
- Prints forward-stack URLs (top to bottom).
- Prints the current page’s URL.
- Prints backward-stack URLs (top to bottom).
- Otherwise, writes “403 Forbidden.”
Reads tema1.in:
- Integer
page_count. - For each page: reads
ID,url, anddescriptionline. - Integer
operation_count. - Reads each operation line into a dynamically allocated string array.
PERFORM_OPERATIONS(char **operation_vector, browser *Chrome_x, int *operation_count, int *page_count, page *page_vector, FILE *out_file, int *max_tabs)
Loops through each operation string:
- Determines its type by matching against known keywords (
NEW_TAB,PAGE, etc.). - Calls the corresponding function with parsed arguments.
Frees the description string and the page struct itself.
Walks and frees all nodes in the stack, freeing any implicit pages (ID 0). If absolute_free is 1, also frees the stack struct.
Frees both stacks and any implicit current page, then the tab struct.
Iterates and frees every tab_node in the circular list (calls FREE_TAB), then frees the sentinel node and resets browser fields.
int main() {
browser Chrome;
tabsList initList = { NULL, 0 };
page page_vector[50];
char **operation_vector;
int page_count = 0, operation_count = 0, max_tabs = 0;
FILE *out_file = fopen("tema1.out", "w");
INIT_BROWSER(&Chrome);
PARSE_INPUT(page_vector, &operation_vector, &page_count, &operation_count);
PERFORM_OPERATIONS(operation_vector, &Chrome, &operation_count,
&page_count, page_vector, out_file, &max_tabs);
fclose(out_file);
FREE_BROWSER(&Chrome);
for (int i = 0; i < operation_count; i++) {
free(operation_vector[i]);
}
free(operation_vector);
for (int i = 0; i < page_count; i++) {
free(page_vector[i].description);
}
return 0;
}Use the following Makefile targets to build, clean, run, and test the simulator:
build:
gcc ./main.c -o tema1 -Wall -Wextra -g
clean:
rm -f ./tema1*
run:
./tema1
test:
./checker.sh