Added a bunch of stuff
This commit is contained in:
parent
244b0a7eb7
commit
01bcdabd06
Binary file not shown.
|
|
@ -0,0 +1,2 @@
|
|||
gcc -o console_example console_example.c
|
||||
gcc -o console_json -DJSON_SKIP_WHITESPACE console_json.c json.c
|
||||
Binary file not shown.
|
|
@ -0,0 +1,65 @@
|
|||
/* Example program showing how to invoke job_wizard
|
||||
* from a simple console program in order to execute a task,
|
||||
* then capture the output and print (without parsing).
|
||||
*
|
||||
* Created by Sally Goldin for SEN-210 on 15 September 2025
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
|
||||
// Open the redirect file and display the contents
|
||||
void displayOutput(char* redirectFilename)
|
||||
{
|
||||
FILE* pF = NULL;
|
||||
char* textbuffer = NULL;
|
||||
|
||||
pF = fopen(redirectFilename,"r");
|
||||
if (pF != NULL)
|
||||
{
|
||||
// get the size of the file
|
||||
fseek(pF, 0L, SEEK_END);
|
||||
int size = ftell(pF);
|
||||
rewind(pF);
|
||||
textbuffer = calloc(size + 2, sizeof(char)); // +2 for terminating 0
|
||||
if (textbuffer == NULL)
|
||||
{
|
||||
printf("Error allocating space to store results\n");
|
||||
return;
|
||||
}
|
||||
if (fread(textbuffer,sizeof(char),size,pF) != size)
|
||||
{
|
||||
printf("Error reading data from result file\n");
|
||||
return;
|
||||
}
|
||||
printf("RESULTS\n");
|
||||
printf(textbuffer);
|
||||
free(textbuffer);
|
||||
}
|
||||
}
|
||||
|
||||
/* main program executes a search with no arguments */
|
||||
int main(int argc, char* argv)
|
||||
{
|
||||
char* userEmail = "sally@cmkl.ac.th";
|
||||
char* outputFile = "output.txt";
|
||||
char jobwizardCmd[2048];
|
||||
int returnCode;
|
||||
|
||||
// Create the command to execute
|
||||
// In your real console-based UI, you probably want different functions
|
||||
// that know about the arguments for different job_wizard commands
|
||||
sprintf(jobwizardCmd,"./job_wizard -task search -email %s > %s 2>&1",userEmail,outputFile);
|
||||
// note that 2>&1 redirects both standard output and standard error to the file output.txt
|
||||
returnCode = system(jobwizardCmd);
|
||||
if (returnCode != 0)
|
||||
{
|
||||
printf("Error %d executing job_wizard command\n");
|
||||
printf("Command: |%s|\n",jobwizardCmd);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Success!\n");
|
||||
displayOutput(outputFile);
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
|
@ -0,0 +1,201 @@
|
|||
/* console_json.c
|
||||
* Example program showing how to invoke job_wizard
|
||||
* from a simple console program in order to execute a task,
|
||||
* then capture the output and parse as JSON.
|
||||
*
|
||||
* Uses https://github.com/whyisitworking/C-Simple-JSON-Parser
|
||||
*
|
||||
* Created by Sally Goldin for SEN-210 on 15 September 2025
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "json.h"
|
||||
|
||||
// structure to hold one search result, a job summary
|
||||
typedef struct
|
||||
{
|
||||
char job_id[8];
|
||||
char title[64];
|
||||
int is_open; // boolean
|
||||
char date_posted[32];
|
||||
} JOB_SUMMARY_T;
|
||||
|
||||
// Open the redirect file, reads and returns the content
|
||||
// as a null terminated text string. Note that the returned
|
||||
// string must be freed by the caller when no longer needed
|
||||
char* readOutput(char* redirectFilename)
|
||||
{
|
||||
FILE* pF = NULL;
|
||||
char* textbuffer = NULL;
|
||||
|
||||
pF = fopen(redirectFilename,"r");
|
||||
if (pF != NULL)
|
||||
{
|
||||
// get the size of the file
|
||||
fseek(pF, 0L, SEEK_END);
|
||||
int size = ftell(pF);
|
||||
rewind(pF);
|
||||
textbuffer = calloc(size+2, sizeof(char)); // +2 for 0 term
|
||||
if (textbuffer == NULL)
|
||||
{
|
||||
printf("Error allocating space to store results\n");
|
||||
return NULL;
|
||||
}
|
||||
if (fread(textbuffer,sizeof(char),size,pF) != size)
|
||||
{
|
||||
printf("Error reading data from result file\n");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return (textbuffer);
|
||||
}
|
||||
|
||||
/* parse the passed string and return the generic structure (json_element)
|
||||
* build by C-Simple-JSON-Parser.
|
||||
* Also returns a status via the integer pointer - 0 if okay, else -1
|
||||
*/
|
||||
typed(json_element) parseJsonString(char* rawJsonText, int* pStatus)
|
||||
{
|
||||
// based on example in the C-Simple-JSON-Parser repo
|
||||
typed(json_element) element;
|
||||
*pStatus = 0; // assume it will work
|
||||
|
||||
result(json_element) element_result = json_parse(rawJsonText);
|
||||
if (result_is_err(json_element)(&element_result))
|
||||
{
|
||||
typed(json_error) error = result_unwrap_err(json_element)(&element_result);
|
||||
fprintf(stderr, "Error parsing JSON: %s\n", json_error_to_string(error));
|
||||
*pStatus = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
element = result_unwrap(json_element)(&element_result);
|
||||
}
|
||||
return element;
|
||||
}
|
||||
|
||||
/* Attempts to parse the string passed as rawJsonText into
|
||||
* an array of structures that represent job summaries.
|
||||
* This is a two step process. The first, which parses the JSON,
|
||||
* will be the same for all job_wizard results. The second extracts
|
||||
* job summary information from the generic structures produced
|
||||
* by the first.
|
||||
* Returns 0 for success, -1 for error
|
||||
* If successful, also allocates and returns an array of results.
|
||||
* This array must be freed by the caller.
|
||||
* Also sets the value of pJobCount
|
||||
*/
|
||||
int parseSearchResults(char* rawJsonText, JOB_SUMMARY_T** allResults,int *pJobCount)
|
||||
{
|
||||
int status = 0;
|
||||
int i,j;
|
||||
JOB_SUMMARY_T * resultArray = NULL;
|
||||
|
||||
typed(json_element) element = parseJsonString(rawJsonText,&status);
|
||||
if (status < 0)
|
||||
{
|
||||
return status; // do we need to free the element?
|
||||
}
|
||||
// we expect an array of jobs
|
||||
typed(json_array) *arr = element.value.as_array;
|
||||
*pJobCount = arr->count;
|
||||
printf("Found %d jobs\n",*pJobCount);
|
||||
resultArray = (JOB_SUMMARY_T*) calloc(*pJobCount,sizeof(JOB_SUMMARY_T));
|
||||
if (resultArray == NULL)
|
||||
{
|
||||
printf("Error allocating job summary structures\n");
|
||||
status = -1;
|
||||
return status;
|
||||
}
|
||||
*allResults = resultArray;
|
||||
for (j=0; j < *pJobCount; j++)
|
||||
{
|
||||
typed(json_element) element = arr->elements[j];
|
||||
typed(json_object) *obj = element.value.as_object;
|
||||
for (i = 0; i < obj->count; i++)
|
||||
{
|
||||
typed(json_entry) entry = *(obj->entries[i]);
|
||||
typed(json_string) key = entry.key;
|
||||
typed(json_element_value) value = entry.element.value;
|
||||
if (strcmp(key,"job_id") == 0)
|
||||
{
|
||||
strcpy(resultArray[j].job_id,value.as_string);
|
||||
}
|
||||
else if (strcmp(key,"title") == 0)
|
||||
{
|
||||
strcpy(resultArray[j].title,value.as_string);
|
||||
}
|
||||
else if (strcmp(key,"is_open") == 0)
|
||||
{
|
||||
if (value.as_boolean)
|
||||
resultArray[j].is_open = 1;
|
||||
else
|
||||
resultArray[j].is_open = 0;
|
||||
}
|
||||
else if (strcmp(key,"date_posted") == 0)
|
||||
{
|
||||
strcpy(resultArray[j].date_posted,value.as_string);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Unrecognized object key %s\n",key);
|
||||
}
|
||||
}
|
||||
}
|
||||
json_free(&element);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Display the contents of a job structure as a line of text
|
||||
*/
|
||||
void printJobSummary(JOB_SUMMARY_T job)
|
||||
{
|
||||
printf("%6s %32s %4s %12s\n",
|
||||
job.job_id,job.title,job.is_open? "t" : "f", job.date_posted);
|
||||
}
|
||||
|
||||
/* main program executes a search with no arguments */
|
||||
int main(int argc, char* argv)
|
||||
{
|
||||
char* userEmail = "sally@cmkl.ac.th";
|
||||
char* outputFile = "output.txt";
|
||||
char jobwizardCmd[2048];
|
||||
char* resultText = NULL; // holds results, must be freed after use
|
||||
int returnCode;
|
||||
int jobCount;
|
||||
int j;
|
||||
JOB_SUMMARY_T * searchResults = NULL; // array of structs allocated for parsed JSON
|
||||
|
||||
// Create the command to execute
|
||||
// In your real console-based UI, you probably want different functions
|
||||
// that know about the arguments for different job_wizard commands
|
||||
sprintf(jobwizardCmd,"./job_wizard -task search -email %s > %s 2>&1",userEmail,outputFile);
|
||||
// note that 2>&1 redirects both standard output and standard error to the file output.txt
|
||||
returnCode = system(jobwizardCmd);
|
||||
if (returnCode != 0)
|
||||
{
|
||||
printf("Error %d executing job_wizard command\n");
|
||||
printf("Command: |%s|\n",jobwizardCmd);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Successfully ran job_wizard!\n");
|
||||
resultText = readOutput(outputFile);
|
||||
if (resultText != NULL)
|
||||
{
|
||||
returnCode = parseSearchResults(resultText,&searchResults,&jobCount);
|
||||
if (returnCode != 0)
|
||||
printf("Error parsing JSON\n");
|
||||
if (searchResults != NULL)
|
||||
{
|
||||
for (j = 0; j < jobCount; j++)
|
||||
printJobSummary(searchResults[j]);
|
||||
free(searchResults);
|
||||
}
|
||||
free(resultText);
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,163 @@
|
|||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifndef __cplusplus
|
||||
typedef unsigned int bool;
|
||||
#define true (1)
|
||||
#define false (0)
|
||||
#endif
|
||||
|
||||
#define typed(name) name##_t
|
||||
|
||||
typedef const char *typed(json_string);
|
||||
typedef bool typed(json_boolean);
|
||||
|
||||
typedef union json_number_value_u typed(json_number_value);
|
||||
typedef signed long typed(json_number_long);
|
||||
typedef double typed(json_number_double);
|
||||
typedef struct json_number_s typed(json_number);
|
||||
typedef union json_element_value_u typed(json_element_value);
|
||||
typedef struct json_element_s typed(json_element);
|
||||
typedef struct json_entry_s typed(json_entry);
|
||||
typedef struct json_object_s typed(json_object);
|
||||
typedef struct json_array_s typed(json_array);
|
||||
|
||||
#define result(name) name##_result_t
|
||||
#define result_ok(name) name##_result_ok
|
||||
#define result_err(name) name##_result_err
|
||||
#define result_is_ok(name) name##_result_is_ok
|
||||
#define result_is_err(name) name##_result_is_err
|
||||
#define result_unwrap(name) name##_result_unwrap
|
||||
#define result_unwrap_err(name) name##_result_unwrap_err
|
||||
#define result_map_err(outer_name, inner_name, value) \
|
||||
result_err(outer_name)(result_unwrap_err(inner_name)(value))
|
||||
#define result_try(outer_name, inner_name, lvalue, rvalue) \
|
||||
result(inner_name) lvalue##_result = rvalue; \
|
||||
if (result_is_err(inner_name)(&lvalue##_result)) \
|
||||
return result_map_err(outer_name, inner_name, &lvalue##_result); \
|
||||
const typed(inner_name) lvalue = result_unwrap(inner_name)(&lvalue##_result);
|
||||
#define declare_result_type(name) \
|
||||
typedef struct name##_result_s { \
|
||||
typed(json_boolean) is_ok; \
|
||||
union { \
|
||||
typed(name) value; \
|
||||
typed(json_error) err; \
|
||||
} inner; \
|
||||
} result(name); \
|
||||
result(name) result_ok(name)(typed(name)); \
|
||||
result(name) result_err(name)(typed(json_error)); \
|
||||
typed(json_boolean) result_is_ok(name)(result(name) *); \
|
||||
typed(json_boolean) result_is_err(name)(result(name) *); \
|
||||
typed(name) result_unwrap(name)(result(name) *); \
|
||||
typed(json_error) result_unwrap_err(name)(result(name) *);
|
||||
|
||||
typedef enum json_element_type_e {
|
||||
JSON_ELEMENT_TYPE_STRING = 0,
|
||||
JSON_ELEMENT_TYPE_NUMBER,
|
||||
JSON_ELEMENT_TYPE_OBJECT,
|
||||
JSON_ELEMENT_TYPE_ARRAY,
|
||||
JSON_ELEMENT_TYPE_BOOLEAN,
|
||||
JSON_ELEMENT_TYPE_NULL
|
||||
} typed(json_element_type);
|
||||
|
||||
typedef enum json_number_type_e {
|
||||
JSON_NUMBER_TYPE_LONG = 0,
|
||||
JSON_NUMBER_TYPE_DOUBLE,
|
||||
} typed(json_number_type);
|
||||
|
||||
union json_number_value_u {
|
||||
typed(json_number_long) as_long;
|
||||
typed(json_number_double) as_double;
|
||||
};
|
||||
|
||||
struct json_number_s {
|
||||
typed(json_number_type) type;
|
||||
typed(json_number_value) value;
|
||||
};
|
||||
|
||||
union json_element_value_u {
|
||||
typed(json_string) as_string;
|
||||
typed(json_number) as_number;
|
||||
typed(json_object) * as_object;
|
||||
typed(json_array) * as_array;
|
||||
typed(json_boolean) as_boolean;
|
||||
};
|
||||
|
||||
struct json_element_s {
|
||||
typed(json_element_type) type;
|
||||
typed(json_element_value) value;
|
||||
};
|
||||
|
||||
struct json_entry_s {
|
||||
typed(json_string) key;
|
||||
typed(json_element) element;
|
||||
};
|
||||
|
||||
struct json_object_s {
|
||||
typed(size) count;
|
||||
typed(json_entry) * *entries;
|
||||
};
|
||||
|
||||
struct json_array_s {
|
||||
typed(size) count;
|
||||
typed(json_element) * elements;
|
||||
};
|
||||
|
||||
typedef enum json_error_e {
|
||||
JSON_ERROR_EMPTY = 0,
|
||||
JSON_ERROR_INVALID_TYPE,
|
||||
JSON_ERROR_INVALID_KEY,
|
||||
JSON_ERROR_INVALID_VALUE
|
||||
} typed(json_error);
|
||||
|
||||
declare_result_type(json_element_type)
|
||||
declare_result_type(json_element_value)
|
||||
declare_result_type(json_element)
|
||||
declare_result_type(json_entry)
|
||||
declare_result_type(json_string)
|
||||
declare_result_type(size)
|
||||
|
||||
/**
|
||||
* @brief Parses a JSON string into a JSON element {json_element_t}
|
||||
* with a fallible `result` type
|
||||
*
|
||||
* @param json_str The raw JSON string
|
||||
* @return The parsed {json_element_t} wrapped in a `result` type
|
||||
*/
|
||||
result(json_element) json_parse(typed(json_string) json_str);
|
||||
|
||||
/**
|
||||
* @brief Tries to get the element by key. If not found, returns
|
||||
* a {JSON_ERROR_INVALID_KEY} error
|
||||
*
|
||||
* @param object The object to find the key in
|
||||
* @param key The key of the element to be found
|
||||
* @return Either a {json_element_t} or {json_error_t}
|
||||
*/
|
||||
result(json_element)
|
||||
json_object_find(typed(json_object) * object, typed(json_string) key);
|
||||
|
||||
/**
|
||||
* @brief Prints a JSON element {json_element_t} with proper
|
||||
* indentation
|
||||
*
|
||||
* @param indent The number of spaces to indent each level by
|
||||
*/
|
||||
void json_print(typed(json_element) * element, int indent);
|
||||
|
||||
/**
|
||||
* @brief Frees a JSON element {json_element_t} from memory
|
||||
*
|
||||
* @param element The JSON element {json_element_t} to free
|
||||
*/
|
||||
void json_free(typed(json_element) * element);
|
||||
|
||||
/**
|
||||
* @brief Returns a string representation of JSON error {json_error_t} type
|
||||
*
|
||||
* @param error The JSON error enum {json_error_t} type
|
||||
* @return The string representation
|
||||
*/
|
||||
typed(json_string) json_error_to_string(typed(json_error) error);
|
||||
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
JOBWIZARD_API_PORT=8889
|
||||
JOBWIZARD_DB_NAME=database/jobwizard_db
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
To import CSV files into SQLITE:
|
||||
|
||||
sqlite3 [dbname]
|
||||
.mode csv
|
||||
.import [file] [table]
|
||||
|
||||
NOTE that even though the ID columns in the job_wizard DB are flagged as
|
||||
"autoincrement", SQLITE does not really support this. So we have to provide ID
|
||||
values explicitly in the CSV files.
|
||||
|
||||
Above assumes no column headers in the file. I believe there is a way to tell
|
||||
it to skip column headers.
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
1,sally@cmkl.ac.th,Front End Developer,Design and build attractive and highly usable UIs using React/JS,0,0,0,,1,2025-06-27 13:41 +700
|
||||
2,sally@cmkl.ac.th,Back End Developer,Microservices; REST APIs; Go language; Database design and implementation,2,2,40000,,1,2025-06-27 13:45 +700
|
||||
3,joe@cmkl.ac.th,HR Director,Manage onboarding - evaluation - staff retention - staff benefits for small university,3,5,95000,,1,2025-06-27 13:50 +700
|
||||
4,mark@cmkl.ac.th,Executive Secretary,Handle day to day management tasks for university president,1,3,35000,,1,2025-07-02 13:50 +700
|
||||
5,joe@cmkl.ac.th,Student Relations Officer,Assist students with planning study; gather feedback and complaints; interface with curriculum committee,2,3,42000,,1,2025-07-02 13:50 +700
|
||||
6,sally@cmkl.ac.th,Professor,Teaching and research to support the university ,4,5,95000,,1,2025-07-02 13:50 +700
|
||||
7,joe@cmkl.ac.th,Software Project Leader,Allocate tasks to software development team; monitor progress; train new developers; report to managment,3,4,50000,,1,2025-09-15 13:50 +700
|
||||
8,joe@cmkl.ac.th,Graphics Professional,"Create graphics content including imagery, videos, slide decks; acquire photos at university events",3,2,32600,,1,2025-09-15 13:50 +700
|
||||
9,joe@cmkl.ac.th,Janitor,Cleaning and maintenance,1,0,12500,lisa@outlook.com,0,2025-09-16 13:50 +700
|
||||
10,joe@cmkl.ac.th,Driver,Part time - Drive university van on schedule rounds; occasionally chauffer university president,1,3,18500,,1,2025-09-16 13:50 +700
|
||||
11,mark@cmkl.ac.th,CEO ,Top executive for promising tech start-up; compensation includes stock options,4,4,60000,,1,2025-09-17 13:50 +700
|
||||
12,sally@cmkl.ac.th,UX Designer,Design user interfaces for in-house software; guide developers in implementation; handle usability tests,3,3,38000,jim@gmail.com,0,2025-09-17 13:45 +700
|
||||
|
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,5 @@
|
|||
1,sally@cmkl.ac.th,Sally,Goldin,“0879990088”,5,2025-06-05
|
||||
2,joe@cmkl.ac.th,Joe,Jenkins,“0329871233”,1,2025-06-22
|
||||
3,mark@cmkl.ac.th,Mark,Masters,“0770992324”,3,2025-06-26
|
||||
4,jim@gmail.com,James,Jamison,“0654329809”,2,2025-06-29
|
||||
5,lisa@outlook.com,Lisa,Roberts,“0567876666”,1,2025-09-17
|
||||
|
Binary file not shown.
|
|
@ -0,0 +1,13 @@
|
|||
# Lab 1: Introduction
|
||||
Designing a user interface for the JobWizard CMD :D
|
||||
|
||||
**Looking at...**
|
||||
- What the user will do
|
||||
- How will they do it?
|
||||
|
||||
*Try to follow the Golden Rule of UIs*
|
||||
|
||||
## FUCK JAVA AND PYTHON. DISGUSTING.
|
||||
|
||||
## Reminder
|
||||
Create account on Figma
|
||||
|
|
@ -0,0 +1 @@
|
|||
# SEN-210 - Designing User Interface
|
||||
Loading…
Reference in New Issue