--- title: "Job Jar" id: 56692 type: "computer_media" slug: "job-jar" url: "http://localhost/computer_media/job-jar/" markdown_url: "http://localhost/computer_media/job-jar.md" published_at: "2024-09-22T23:31:42+00:00" modified_at: "2026-04-03T07:59:00+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2024/09/JOB0.png" excerpt: "A complete job-management database in BASIC that stores tasks with time estimates, picks one at random to match your free time, and even renders its own logo from ROM character data." category: - name: "Archived Media" slug: "archived-media" taxonomy: "category" url: "http://localhost/category/archived-media/" post_tag: - name: "Downloadable" slug: "downloadable" taxonomy: "post_tag" url: "http://localhost/tag/downloadable/" - name: "TS 1000" slug: "ts1000" taxonomy: "post_tag" url: "http://localhost/tag/ts1000/" - name: "UAS" slug: "uas" taxonomy: "post_tag" url: "http://localhost/tag/uas/" model: - name: "Timex/Sinclair 1000" slug: "ts-1000" taxonomy: "model" url: "http://localhost/model/ts-1000/" genre: - name: "Home" slug: "home" taxonomy: "genre" url: "http://localhost/type/home/" media_type: "Cassette" download_url: "https://archive.org/download/timex-sinclair-software-archive/Job%20Jar%20%28198x%29%28UAS%29%28TS1000%29%28US%29%28Program%29.zip" mediadate: "198x" producer_company: - id: 11418 title: "UAS" type: "company" url: "http://localhost/company/uas/" images: - url: "http://localhost/wp-content/uploads/2024/09/JOB0.png" - url: "http://localhost/wp-content/uploads/2024/09/JOB1.png" - url: "http://localhost/wp-content/uploads/2024/09/Tape-12-scaled.jpg" related_products: - id: 12986 title: "Job Jar" type: "product" url: "http://localhost/product/job-jar/" media_type_tags: "Home" --- # Job Jar This program implements a “Job Jar” task management system, allowing the user to initialise a job list, add job descriptions with time estimates, mark jobs as done (removing them from the list with an array shift), pick a random job matching available time, list all jobs, and save the program to tape. Job entries are stored in a dimensioned string array B$ with 28 characters per record: 24 characters for the description and 3 characters (positions 26–28) for a numeric time estimate. The PICK function (line 4000) implements a rudimentary time-matching and randomised selection algorithm that decrements the requested time by one each pass until a matching job is found, using RND to introduce non-determinism. The save routine at line 9550 renders a pixel-accurate bitmap of the text “JOB” by reading character ROM data via PEEK from address 7680, printing inverse or normal space characters to reconstruct each glyph on screen. *** ## Program Analysis ### Program Structure The program is organised as a menu-driven application with a central dispatcher at line 490–600 and several functional modules at higher line numbers. Shared subroutines at lines 10–70 handle common prompts (Y/N confirmation, “More?”, “Press C”, and printer copy). The main modules are: 1. **Lines 490–600**: Main menu and dispatcher 2. **Lines 1000–1050**: Initialise — dimension the job array 3. **Lines 2000–2170**: Add a job entry 4. **Lines 3000–3160**: Mark a job done and remove it 5. **Lines 4000–4260**: Pick a random job by available time 6. **Lines 5000–5050**: List all jobs 7. **Lines 9550–9680**: Save program and display logo splash screen ### Data Storage Jobs are stored in a two-dimensional string array `B$` dimensioned at line 1030 as `DIM B$(N1,28)`. Each record uses a fixed 28-character layout: | Positions | Content | | --- | --- | | 1–24 | Job description (free text) | | 25 | Unused / padding | | 26–28 | Time estimate (numeric string, right-padded with spaces) | A scratch buffer `X$` of 28 characters is dimensioned at line 2020 for each add operation, then copied wholesale into `B$(N)` at line 2140. ### Input Validation Both the ADD and PICK routines validate their numeric inputs by iterating character-by-character over the time-estimate field. The condition at lines 2070 and 4050, `IF X$(K)<"A" AND X$(K)>"."`, attempts to accept only digits (which lie between `"."` and `"A"` in the ZX81 character set). Spaces are accepted as padding after the first character (lines 2064, 4044). This validation is applied in a `FOR` loop but uses `GOTO` to skip the first character check, which skips validation for position 26 entirely — a minor anomaly that could allow a non-digit leading character. ### Job Deletion by Array Compaction When a job is marked done (line 3000 module), the array is compacted by shifting all subsequent entries down one position (lines 3070–3090), then decrementing the job counter `N` at line 3100. This is a classic in-place list deletion without pointer arithmetic, achieved purely in BASIC. ### Random Job Picker Algorithm The PICK routine (lines 4085–4260) is a two-phase search. It scans all `N` jobs for one whose time estimate string matches `X$(1 TO 3)`. If none is found and the search has not already been expanded (`X=1` at line 4130), it decrements the requested time by 1 and retries — effectively widening the search downward. Once a matching job is found (line 4110), it is selected only with probability 1/3 using `IF INT(RND*3+1)<>1` at line 4200, providing randomisation across multiple matches. The variable `X` is set to 1 at line 4090 on the assumption that the loop sets it, but there is a bug: `X` is only reset to 0 at line 4090 at the top of each retry pass, never explicitly set to 1 in the no-match path; line 4130 checks `X=1` which will never be true, so the decrement loop runs indefinitely if no match is ever found. Additionally, line 4160 contains `IF T=0 THEN LET T1=T1+1`, which increments `T1` when the counter reaches zero, but this value is never used thereafter — this appears to be dead or vestigial code. ### Character ROM Logo Renderer The save splash screen (lines 9565–9645) renders the letters “JOB” pixel-by-pixel by reading the character ROM. For each letter in `A$="JOB"`, it retrieves the ASCII code with `CODE A$(NN)` and reads 8 bytes from address `7680 + C*8 + H` via `PEEK`. Each byte is decomposed bit-by-bit by repeatedly testing against a bitmask `V` (starting at 128 and halved each iteration). Set bits are printed as inverse space characters (`"% "`) and clear bits as a block graphic (`"\@@"` = two `@` characters rendered as a light block). The three letters are spaced 7 columns apart starting at column 5, and rendered starting at row 3, producing a large pixelated title. ### Subroutine Conventions and GOSUB Usage Three shared subroutines are invoked repeatedly: - `GOSUB 10` — “CHANGE Y OR N?” prompt; sets flag `F=1` for Y, `F=0` for N - `GOSUB 30` — “MORE Y OR N?” prompt; falls through to line 14 of subroutine 10 - `GOSUB 40` — “PRESS C TO CONTINUE” prompt - `GOSUB 60` — “COPY Y OR N?” prompt with optional `COPY` to printer Subroutine 30 at line 34 jumps directly into the body of subroutine 10 at line 14, sharing its Y/N polling loop and `RETURN` — a deliberate code-reuse technique via fall-through. ### Key BASIC Idioms - Inverse-video text in messages (e.g. `"%B%A%D% %E%S%T%I%M%A%T%E"`) uses the ZX81 inverse character escape to highlight error notices. - `RAND 0` at line 490 seeds the random number generator to a fixed value, ensuring reproducible picks each session start. - `SLOW` / `FAST` mode switching is used around the display-intensive logo renderer and the main menu to balance display quality versus computation speed. - The copy subroutine at line 62 uses a double-poll pattern (`IF INKEY$<>"" THEN GOTO 62` followed by `IF INKEY$="" THEN GOTO 64`) to wait for a key release then a new keypress, debouncing the input. ## Source Code ``` 10 LET F=0 12 PRINT AT 21,0;"CHANGE Y OR N" 14 IF INKEY$="Y" THEN GOTO 20 16 IF INKEY$="N" THEN GOTO 22 18 GOTO 14 20 LET F=1 22 PRINT AT 21,0;" " 24 RETURN 30 LET F=0 32 PRINT AT 21,0;"MORE Y OR N" 34 GOTO 14 40 PRINT AT 21,0;"PRESS C TO CONTINUE" 42 IF INKEY$="C" THEN GOTO 22 44 GOTO 42 60 PRINT AT 21,0;"COPY Y OR N?" 62 IF INKEY$<>"" THEN GOTO 62 64 IF INKEY$="" THEN GOTO 64 66 IF INKEY$="N" THEN RETURN 68 IF INKEY$="Y" THEN COPY 70 GOTO 62 490 RAND 0 500 CLS 510 SLOW 520 PRINT "I=INITIAL, A=ADD, D=DONE" 530 PRINT "P=PICK, L=LIST, S=SAVE" 540 IF INKEY$="I" THEN GOTO 1000 550 IF INKEY$="A" THEN GOTO 2000 560 IF INKEY$="D" THEN GOTO 3000 570 IF INKEY$="P" THEN GOTO 4000 580 IF INKEY$="L" THEN GOTO 5000 590 IF INKEY$="S" THEN GOTO 9550 600 GOTO 540 1000 CLS 1010 PRINT "INPUT NUMBER OF JOBS" 1020 INPUT N1 1030 DIM B$(N1,28) 1040 LET N=0 1050 GOTO 500 2000 CLS 2002 IF N<>N1 THEN GOTO 2008 2004 PRINT "% NO MORE ROOM IN FILE% " 2006 PAUSE 100 2007 GOTO 500 2008 CLS 2009 PRINT " NUMBER OF JOBS=";N 2010 PRINT AT 1,0;" INPUT DESCRIPTION FOR JOB ";N+1 2020 DIM X$(28) 2030 INPUT X$(1 TO 24) 2035 PRINT AT 2,0;"*";X$(1 TO 24) 2040 PRINT AT 3,0;" HOURS FOR JOB ";N+1;"="; 2050 INPUT X$(26 TO 28) 2060 FOR K=26 TO 28 2062 IF K=26 THEN GOTO 2070 2064 IF X$(K)=" " THEN GOTO 2100 2070 IF X$(K)<"A" AND X$(K)>"." THEN GOTO 2100 2080 PRINT "%B%A%D% %E%S%T%I%M%A%T%E" 2090 GOTO 2040 2100 NEXT K 2105 PRINT X$(26 TO 28);" " 2110 GOSUB 10 2120 IF F=1 THEN GOTO 2008 2130 LET N=N+1 2140 LET B$(N)=X$ 2150 GOSUB 30 2160 IF F=1 THEN GOTO 2000 2170 GOTO 500 3000 CLS 3010 PRINT "I HAVE COMPLETED NO. "; 3020 INPUT I 3030 IF I>N THEN GOTO 3000 3035 PRINT I 3040 PRINT B$(I) 3050 GOSUB 10 3060 IF F=1 THEN GOTO 3010 3070 FOR J=I TO N-1 3080 LET B$(J)=B$(J+1) 3090 NEXT J 3100 LET N=N-1 3110 GOSUB 30 3120 IF F=0 THEN GOTO 500 3130 IF N<>0 THEN GOTO 3000 3140 PRINT "%N%O% %M%O%R%E% %J%O%B%S" 3150 PAUSE 100 3160 GOTO 500 4000 CLS 4005 DIM X$(3) 4010 IF N=0 THEN GOTO 3140 4020 PRINT "INPUT AVAILABLE TIME" 4030 INPUT X$(1 TO 3) 4040 FOR K=1 TO 3 4042 IF K=1 THEN GOTO 4050 4044 IF X$(K)=" " THEN GOTO 4080 4050 IF X$(K)<"A" AND X$(K)>"." THEN GOTO 4080 4060 PRINT "%B%A%D% %I%N%P%U%T" 4065 PAUSE 100 4070 GOTO 4000 4080 NEXT K 4085 FAST 4090 LET X=0 4100 FOR K=1 TO N 4110 IF B$(K,26 TO 28)=X$(1 TO 3) THEN GOTO 4200 4120 NEXT K 4130 IF X=1 THEN GOTO 4090 4140 LET T=VAL X$(1 TO 3) 4145 LET T1=T 4150 LET T=T-1 4160 IF T=0 THEN LET T1=T1+1 4170 LET X$(1 TO 3)=STR$ T 4180 GOTO 4090 4200 IF INT (RND*3+1)<>1 THEN GOTO 4090 4210 CLS 4215 SLOW 4220 PRINT "%J%O%B% %I%S:" 4230 PRINT B$(K) 4240 PRINT 4250 GOSUB 40 4260 GOTO 500 5000 CLS 5010 FOR K=1 TO N 5020 PRINT K;TAB 4;B$(K) 5030 NEXT K 5040 GOSUB 60 5050 GOTO 500 9550 CLS 9551 SAVE "JO%B" 9555 LET A$="JOB" 9560 FAST 9565 LET NN=0 9570 FOR L=5 TO 19 STEP 7 9575 LET NN=NN+1 9580 LET C=CODE A$(NN) 9585 FOR H=0 TO 7 9590 LET P=PEEK (7680+C*8+H) 9595 LET V=128 9600 FOR G=0 TO 7 9605 IF P