--- title: "Payroll" id: 58452 type: "computer_media" slug: "payroll-4" url: "http://localhost/computer_media/payroll-4/" markdown_url: "http://localhost/computer_media/payroll-4.md" published_at: "2024-11-17T22:03:57+00:00" modified_at: "2026-04-03T07:58:02+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2024/11/Pay.jpeg" excerpt: "A complete multi-employee payroll system that encodes dollar amounts and hours as packed binary strings to squeeze maximum data into a fixed-length string array." 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: "Business" slug: "business" taxonomy: "genre" url: "http://localhost/type/business/" media_type: "Program" download_url: "https://archive.org/download/timex-sinclair-software-archive/Payroll%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/11/Pay.jpeg" - url: "http://localhost/wp-content/uploads/2024/11/Tape-15.jpg" media_type_tags: "Business" --- # Payroll This is a payroll management system that handles employee records, weekly hours input, pay stub generation, and year-to-date withholding tracking for up to 32 employees. Employee data is stored compactly in a two-dimensional string array N$(25,200), encoding numeric values such as hours, rates, and accumulated totals as raw character bytes using a three-byte binary packing scheme (lines 16–28 and 36–42) to work around the limited numeric storage of the platform. The program supports multiple withholding categories (federal tax, state tax, FICA, disability, unemployment, and other) with configurable percentage rates and a FICA dollar cap. Menu navigation uses INKEY$ scanning with CODE-based dispatch via a calculated GOTO at line 700. *** ## Program Structure The program is organised as a menu-driven application with a main dispatch loop at lines 500–700 and numbered sections at every 1000th line. The top of the file (lines 10–116) contains shared subroutines, and the menu entry point at line 500 prints a title before falling through to the menu at line 570. | Line range | Purpose | | --- | --- | | 10–14 | Subroutine: “Press Enter to continue” pause | | 16–28 | Subroutine: pack integer X into 3-char string X$ | | 36–42 | Subroutine: unpack 3-char string X$ into integer X | | 44–52 | Subroutine: input a value and store as CHR$ in N$ | | 56–66 | Subroutine: display employee list (two columns) | | 70–94 | Subroutine: print data-entry screen labels | | 100–116 | Subroutine: format and print a monetary value P with decimal alignment | | 200–440 | Subroutine: calculate and display a pay stub for employee K, week Y | | 500–703 | Startup banner and main menu with INKEY$ dispatch | | 1000–1130 | Option 1: Add a new employee | | 1520–1690 | Per-field data-entry subroutines (called via calculated GOSUB) | | 2000–2410 | Option 2: Input weekly hours for all employees | | 3000–3140 | Option 3: Print individual pay stub | | 4000–4220 | Option 4: Print weekly payroll totals | | 5000–5160 | Option 5: Print year-to-date withholding totals | | 6000–6310 | Option 6: Change employee data | | 7000–7240 | Option 7: Initialise (clear) all data | | 8000–8020 | Option 8: SAVE program to tape | | 9000–9110 | Option 9: Update tax-rate constants | | 9100–9110 | Error handler: “INITIATE FIRST” guard | ## Data Storage: Binary Packing in a String Array All employee records live in `N$(25,200)`, a 25-row × 200-character string array. Numeric values that exceed a single byte range (e.g., hourly rates in cents, year-to-date totals) are stored as 2- or 3-byte sequences using `CHR$` encoding. The pack subroutine at lines 16–28 decomposes an integer into base-65536, base-256, and remainder components, storing each as a character. The corresponding unpack subroutine (lines 36–42) reconstructs the value with `CODE` and multiplications. This avoids storing floating-point numbers (which consume 5 bytes each) and instead uses only as many characters as needed. The layout of significant byte offsets within each employee row is as follows: | Column(s) | Content | | --- | --- | | 1–10 | Last name (padded) | | 11 | Initial | | 12–13 | Hourly rate × 100 (2 bytes) | | 14–18 | Withholding % rates (1 byte each: FWT, STAX, FICA-flag, DISA, VAC) | | 19–20 | Vacation/sick deduction × 100 (2 bytes) | | W+20 | Hours for week W (packed: hours×4 + vac×32) | | 2W+70–2W+71 | Rate snapshot for week W (2 bytes) | | 177–179 | YTD gross pay × 100 (3 bytes) | | 180–198 | YTD withholdings by category (3 bytes each, 7 categories) | ## Menu Dispatch The main menu (lines 680–700) reads a keypress with `INKEY$` in a tight polling loop, validates that its `CODE` falls in the range 29–37 (keys 1–9), then executes `GOTO 1000*(CODE B$-28)`. This maps key “1” → line 1000, “2” → 2000, …, “9” → 9000 in a single calculated jump, a classic Sinclair BASIC dispatch idiom. Data-entry field subroutines during employee add/change are similarly dispatched with `GOSUB K*20+1500` (lines 1090, 6270), stepping through fields at lines 1520, 1540, 1560, 1580/1600, 1620, 1640, 1660, 1680. ## Monetary Formatting Subroutine (Lines 100–116) The formatting routine at line 100 is a pure-BASIC fixed-point formatter for currency values stored as floating-point. It rounds to two decimal places, converts via `STR$`, then applies a cascade of string-length checks to ensure exactly two digits appear after the decimal point. If the value is six or more characters (i.e., ≥ 1000.00), a comma is inserted three places from the right. Output is right-aligned to column `V+10` using `TAB`. ## Pay Calculation (Lines 200–440) The pay stub routine unpacks hours (dividing the stored byte by 4 to recover quarter-hours) and separates regular from overtime (anything above 40 hours). Base pay is `R*H`; premium overtime pay applies the employee’s overtime multiplier stored at offset 14. Withholding deductions (FWT, STAX, FICA, disability, unemployment, other) are each computed as a percentage of gross and accumulated into both weekly totals `T()` and year-to-date totals `W()`. The FICA deduction is capped by checking the running YTD total against the configured dollar limit `T`. The `Z` flag controls whether totals are accumulated (`Z=0`) or the stub is display-only (`Z=1` or `Z=2`). ## Notable Techniques and Idioms - The `INKEY$` polling loop at lines 680–700 and 2210–2230 is used without `PAUSE 0` pre-delay, relying on the loop itself for debounce. - `RUN 7015` at line 7011 during initialisation clears all variables and restarts execution mid-program, a technique used to reliably reset all arrays and variables without a separate clear routine. - The `H$()` string array (8 rows × 4 chars) stores short category labels (“GRSS”, “FWT”, “STAX”, “FICA”, “DISA”, “UNEM”, “OTAX”, “OTHR”) for reuse throughout display and input prompts, avoiding repeated string literals. - `DIM W(7)` appears twice (lines 7015 and 7050) — the second `DIM` reinitialises the array to zero after the rate-input section, which effectively doubles as a year-to-date accumulator reset. - The block-graphic characters in lines 78, 80, 82, 84 (rendered as `\ '/\.` = ▝▖ = a “%” lookalike) are used decoratively as a percent-sign substitute within labels. ## Source Code ``` 10 PRINT AT 21,0;"%T%O% %C%O%N%T%I%N%U%E% %P%R%E%S%S% %E%N%T%E%R" 12 INPUT X$ 14 RETURN 16 DIM X$(3) 18 LET X1=INT (X/65536+.001) 20 LET X$(1)=CHR$ X1 21 LET X2=X-X1*65536 23 LET X2=INT (X2/256+.001) 24 LET X$(2)=CHR$ X2 25 LET X3=INT (ABS (X-INT (X1*65536)-INT (X2*256))) 27 LET X$(3)=CHR$ X3 28 RETURN 36 LET X=CODE X$(1)*65536 37 LET X=X+CODE X$(2)*256 38 LET X=X+CODE X$(3) 42 RETURN 44 INPUT X 46 PRINT AT K+1,22;X 48 GOSUB 16 50 LET N$(F,K+10)=CHR$ X 52 RETURN 56 FOR K=1 TO F 58 LET X=K 60 IF K>12 THEN LET X=K-12 62 PRINT AT X,16*(K>12);K;TAB (4+(20*(K>12)));N$(K, TO 10);" ";N$(K,11 TO 12) 64 NEXT K 66 RETURN 70 CLS 71 PRINT AT 2,0;"1.LAST NAME=" 72 PRINT "2.INITIAL=" 76 PRINT "3.HOURLY RATE=" 78 PRINT "4.O.T( '/. HRLY RATE)=" 80 PRINT "5. '/. ";H$(2) 82 PRINT "6. '/. ";H$(3) 84 PRINT "7. '/. ";H$(8) 90 PRINT "8.VAC/SICK DAYS=" 92 PRINT "9.";H$(8) 94 RETURN 100 LET P=INT (100*P+.05)/100 101 LET Y$=" " 102 IF P=0 THEN GOTO 114 103 LET Y$=STR$ P 104 IF LEN Y$=1 THEN LET Y$=Y$+".00" 106 IF LEN Y$=2 THEN LET Y$=Y$+".0" 108 IF Y$(LEN Y$-1)="." THEN LET Y$=Y$+"0" 110 IF Y$(LEN Y$-2)<>"." THEN LET Y$=Y$+".00" 112 IF LEN Y$>6 THEN LET Y$=Y$( TO LEN Y$-6)+","+Y$(LEN Y$-5 TO LEN Y$) 114 PRINT TAB (V+10-LEN Y$);Y$ 116 RETURN 200 CLS 202 PRINT N$(K, TO 10);",";N$(K,11);TAB 24;"%W%E%E%K:";Y 204 LET X$=" "+N$(K,20+Y) 206 GOSUB 36 208 LET H=X/4 232 LET I=0 234 IF H>40 THEN LET I=H-40 236 LET H=H-I 238 LET X$=" "+N$(K,2*Y+70 TO 2*Y+71) 240 GOSUB 36 242 LET R=X/100 244 PRINT 246 LET P=R*H 247 LET G=P 248 LET V=22 250 PRINT "BASE PAY"; 251 LET J=1 252 GOSUB 100 253 PRINT "PREMIUM PAY"; 254 LET X$=" "+N$(K,14) 255 GOSUB 36 256 LET P=I*R*(1+X/100) 257 LET G=G+P 258 GOSUB 100 259 PRINT "%G%R%O%S%S% %P%A%Y"; 260 LET P=G 261 GOSUB 100 262 IF Z=0 THEN LET T(8)=T(8)+P 265 PRINT 266 PRINT H$(2); 267 LET A=15 268 LET B=180 269 LET R=G 270 GOSUB 272 271 GOTO 296 272 LET X$=" "+N$(K,A) 273 GOSUB 36 274 LET P=G*X/100 275 LET V=13 276 GOSUB 100 277 IF Z>0 THEN GOTO 293 278 LET X$=N$(K,B TO B+2) 279 GOSUB 36 280 LET X=X+P*100 282 GOSUB 16 284 LET N$(K,B TO B+2)=X$ 285 IF Z=0 THEN LET T(J)=T(J)+P 286 IF Z=0 THEN LET W(J)=W(J)+P 293 LET R=R-P 294 RETURN 296 PRINT H$(3); 297 LET J=2 298 LET A=16 300 LET B=183 302 GOSUB 272 304 PRINT H$(4); 306 LET X$=N$(K,186 TO 188) 308 GOSUB 36 309 IF X/100<>T THEN GOTO 312 310 LET P=0 311 GOTO 324 312 LET P=G*S/100 314 IF P>T-X/100 THEN LET P=T-XV100 317 LET X=X+P*100 318 GOSUB 16 319 LET N$(K,186 TO 188)=X$ 320 GOSUB 100 321 IF Z>0 THEN GOTO 324 322 LET T(3)=T(3)+P 323 LET W(3)=W(3)+P 324 LET R=R-P 326 PRINT H$(7); 327 LET J=6 328 LET A=17 330 LET B=195 332 GOSUB 272 334 PRINT H$(5); 336 LET P=G*D/100 337 LET B=189 338 LET J=4 340 GOSUB 276 342 PRINT H$(6); 344 LET P=G*U/100 346 LET B=192 348 LET J=5 350 GOSUB 276 362 PRINT H$(8); 364 LET X$=" "+N$(K,19 TO 20) 366 GOSUB 36 368 LET P=X/100 369 LET J=7 370 LET B=198 372 GOSUB 276 384 PRINT 388 PRINT "%N%E%T% %P%A%Y"; 390 LET V=22 395 LET P=R 400 GOSUB 100 402 IF Z>0 THEN GOTO 414 404 LET X$=N$(K,177 TO 179) 406 GOSUB 36 408 LET X=X+G*100 410 GOSUB 16 412 LET N$(K,177 TO 179)=X$ 414 PRINT 415 IF Z=2 THEN RETURN 416 PRINT "%Y%E%A%R% %T%O%D%A%T%E%:" 418 FOR J=1 TO 8 420 LET A=16 422 LET V=5 424 IF J>4 THEN LET A=12 426 IF J>4 THEN LET V=22 428 PRINT AT A+J,V-5;H$(J); 430 LET X$=N$(K,3*J+174 TO 3*J+176) 432 GOSUB 36 434 LET P=X/100 436 GOSUB 100 438 NEXT J 440 RETURN 500 FAST 520 PRINT " PAYROLL COPYRIGHT UAS BOX 612 HADDONFIELD,N.J.08033" 530 PRINT 540 GOTO 570 550 FAST 560 CLS 570 PRINT "%P%R%E%S%S% %N%U%M%B%E%R% %D%E%S%I%R%E%D" 580 PRINT 590 PRINT "1..ADD NAME" 600 PRINT "2..INPUT WEEKLY INFO" 610 PRINT "3..EMPLOYEE PAY STUB" 620 PRINT "4..TOTAL PAYROLL" 630 PRINT "5..TOTAL WITH-HOLDING TODATE" 640 PRINT "6..CHANGE EMPLOYEE DATA" 650 PRINT "7..INITIATE" 660 PRINT "8..SAVE" 665 PRINT "9..UPDATE CONSTANTS" 670 SLOW 680 LET B$=INKEY$ 690 IF CODE B$<29 OR CODE B$>37 THEN GOTO 680 700 GOTO 1000*(CODE B$-28) 703 LET W=0 1000 FAST 1010 CLS 1015 IF E=0 THEN GOTO 9100 1020 IF E<33 THEN GOTO 1060 1030 PRINT "%F%I%L%E% %F%U%L%L" 1040 PAUSE 100 1050 GOTO 550 1060 PRINT "%A%D%D% %N%A%M%E..FILE NUMBER=";E 1070 PRINT 1080 GOSUB 70 1081 LET F=E 1082 FOR K=1 TO 9 1085 PRINT AT K+1,22;"% ";C$(23 TO 31) 1090 GOSUB K*20+1500 1100 NEXT K 1110 LET E=E+1 1120 GOSUB 10 1130 GOTO 550 1520 INPUT N$(F, TO 10) 1522 PRINT AT K+1,22;N$(F, TO 10) 1524 RETURN 1540 INPUT N$(F,11) 1542 PRINT AT K+1,22;N$(F,11 TO 12) 1544 RETURN 1560 INPUT X 1562 PRINT AT K+1,22;X 1564 LET X=X*100 1566 GOSUB 16 1568 LET N$(F,12 TO 13)=X$(2 TO ) 1570 RETURN 1580 GOTO 1600 1600 GOSUB 44 1602 RETURN 1620 GOTO 1600 1660 GOTO 1600 1680 INPUT X 1682 PRINT AT K+1,22;X 1684 LET X=X*100 1686 GOSUB 16 1688 LET N$(F,19 TO 20)=X$(2 TO ) 1690 RETURN 2000 FAST 2002 DIM T(8) 2005 IF E=0 THEN GOTO 9100 2010 CLS 2020 PRINT "%W%E%E%K%L%Y% %I%N%F%O" 2025 PRINT 2026 PRINT "INPUT WEEK NO.=" 2030 INPUT X 2040 IF X>W THEN GOTO 2070 2050 PRINT "%A%L%R%E%A%D%Y% %E%N%T%E%R%E%D" 2060 GOTO 1040 2070 LET W=X 2080 FOR K=1 TO E-1 2090 FAST 2100 DIM X(2) 2105 CLS 2110 PRINT N$(K, TO 10);",";N$(K,11) 2120 PRINT 2130 PRINT "%I%N%P%U%T HRS(.25 PER 1/4 HR)="; 2140 INPUT X(1) 2150 PRINT X(1) 2151 LET K$="PAID VAC/SICK DAYS" 2155 PRINT 2156 PRINT K$;" TODATE:"; 2157 LET X$=" "+N$(K,18) 2158 GOSUB 36 2159 PRINT X 2160 PRINT "%I%N%P%U%T ";K$;"="; 2170 INPUT X(2) 2180 PRINT X(2) 2190 PRINT AT 21,0;"CHANGE Y OR N?" 2200 SLOW 2210 IF INKEY$="N" THEN GOTO 2270 2220 IF INKEY$="Y" THEN GOTO 2090 2230 GOTO 2210 2270 FAST 2280 CLS 2290 LET X=X(1)*4+X(2)*32 2300 GOSUB 16 2310 LET N$(K,W+20)=X$(3) 2320 LET X=X(2) 2330 GOSUB 16 2340 LET N$(K,18)=X$(3) 2350 LET N$(K,W*2+70 TO W*2+71)=N$(K,12 TO 13) 2360 LET Z=0 2370 LET Y=W 2380 GOSUB 200 2390 GOSUB 10 2400 NEXT K 2410 GOTO 550 3000 FAST 3005 IF E=0 THEN GOTO 9100 3010 CLS 3015 GOSUB 3020 3016 GOTO 3050 3020 FOR K=1 TO E-1 STEP 2 3030 PRINT CHR$ (K+156);TAB 3;N$(K, TO 10)+","+N$(K,11);TAB 16;CHR$ (K+157);TAB 20;N$(K+1, TO 10)+","+N$(K+1,11) 3040 NEXT K 3045 RETURN 3050 PRINT 3060 PRINT "%I%N%P%U%T NUMBER="; 3070 INPUT K 3080 PRINT K 3090 PRINT "%I%N%P%U%T WEEK " 3095 LET Z=1 3100 INPUT Y 3105 IF Y>W THEN GOTO 550 3110 IF Y<>W THEN LET Z=2 3120 GOSUB 200 3130 GOSUB 10 3140 GOTO 550 4000 FAST 4010 CLS 4015 IF E=0 THEN GOTO 9100 4020 PRINT "%P%A%Y%R%O%L%L% %F%O%R% %W%E%E%K%: ";W 4030 PRINT 4040 PRINT "GROSS PAY "; 4045 LET V=15 4050 LET P=T(8) 4060 GOSUB 100 4070 PRINT "%W%I%T%H%-%H%O%L%D%I%N%G%S" 4074 PRINT 4075 LET V=7 4080 FOR K=2 TO 8 4090 PRINT H$(K); 4100 LET P=T(K-1) 4110 GOSUB 100 4120 NEXT K 4210 GOSUB 10 4220 GOTO 550 5000 FAST 5010 CLS 5015 IF E=0 THEN GOTO 9100 5020 PRINT "%W%I%T%H%-%H%O%L%D%I%N%G%S% %T%O% %W%E%E%K ";W 5030 PRINT 5090 LET V=8 5100 FOR K=1 TO 7 5105 PRINT H$(K+1); 5110 LET P=W(K) 5120 PRINT AT K+1,0; 5130 GOSUB 100 5140 NEXT K 5150 GOSUB 10 5160 GOTO 550 6000 FAST 6005 IF E=0 THEN GOTO 9100 6010 CLS 6020 PRINT "%C%H%A%N%G%E% %D%A%T%A" 6025 GOSUB 3020 6030 PRINT AT 21,0;"INPUT FILE NO." 6032 INPUT Y 6050 GOSUB 70 6060 PRINT AT 2,22;N$(Y, TO 10) 6070 PRINT AT 3,22;N$(Y,11) 6110 LET X$=" "+N$(Y,12 TO 13) 6120 GOSUB 36 6130 PRINT AT 4,22;X/100 6150 FOR K=14 TO 18 6160 LET X$=" "+N$(Y,K) 6170 GOSUB 36 6180 PRINT AT K-9,22;X 6190 NEXT K 6200 LET X$=" "+N$(Y,19 TO 20) 6210 GOSUB 36 6220 PRINT AT 10,22;X/100 6230 PRINT AT 21,0;"INPUT LINE NO,OR 0 FOR END" 6240 INPUT K 6250 IF K=0 THEN GOTO 550 6260 IF K<1 OR K>10 THEN GOTO 6240 6265 PRINT AT K+1,22;"% ";C$( TO 9) 6268 PRINT AT 21,0;C$ 6269 LET F=Y 6270 GOSUB K*20+1500 6310 GOTO 6230 7000 CLS 7001 PRINT "THIS MODE CLEARS FILES %P%R%E%S%S: Y IF YOU WANT IT, N IF NOT" 7002 SLOW 7003 IF INKEY$="N" THEN GOTO 550 7004 IF INKEY$="Y" THEN GOTO 7010 7005 GOTO 7003 7010 FAST 7011 RUN 7015 7015 DIM W(7) 7020 DIM C$(32) 7030 DIM N$(25,200) 7031 DIM H$(8,4) 7032 LET H$(2)="FWT" 7033 LET H$(3)="STAX" 7034 LET H$(4)="FICA" 7035 LET H$(5)="DISA" 7036 LET H$(6)="UNEM" 7037 LET H$(7)="OTAX" 7038 LET H$(8)="OTHR" 7040 LET E=1 7041 LET H$(1)="GRSS" 7050 DIM W(7) 7060 FAST 7070 CLS 7080 PRINT H$(4);" '/. RATE="; 7090 INPUT S 7100 PRINT S 7110 PRINT H$(4);" $ LIMIT="; 7120 INPUT T 7130 PRINT T 7140 PRINT H$(5);" '/. RATE="; 7150 INPUT D 7160 PRINT D 7170 PRINT H$(6);" '/. RATE="; 7180 INPUT W 7190 PRINT W 7200 PRINT AT 21,0;"CHANGE Y OR N?" 7210 SLOW 7220 IF INKEY$="Y" THEN GOTO 7060 7230 IF INKEY$="N" THEN GOTO 550 7240 GOTO 7220 8000 CLS 8010 SAVE "PA%Y" 8020 GOTO 500 9000 FAST 9010 CLS 9020 IF E=0 THEN GOTO 9100 9030 PRINT H$(4);" '/. RATE=";S 9040 PRINT H$(4);" $ LIMIT=";T 9050 PRINT H$(5);" '/. RATE=";D 9060 PRINT H$(6);" '/. RATE=";U 9070 GOTO 7200 9100 PRINT "%I%N%I%T%I%A%T%E% %F%I%R%S%T" 9110 GOTO 1040 ```