--- title: "QLPatch" type: "article" slug: "qlpatch" url: "http://localhost/article/qlpatch/" markdown_url: "http://localhost/article/qlpatch.md" published_at: "2025-11-26T20:02:08+00:00" modified_at: "2026-06-21T23:20:55+00:00" featured_image: url: "http://localhost/wp-content/uploads/2022/04/20230809-041332.jpg" excerpt: "One of the problems I've encountered in publishing souce code in the QHJ, is the dilemma of publishing a newer version of a program (or bug fixes). I could publish the whole program but this would waste bandwidth if only a small portion of the code has been changed. Another way is to publish the…" category: - name: "QL Hacker's Journal" slug: "ql-hackers-journal" taxonomy: "category" url: "http://localhost/category/periodicals/ql-hackers-journal/" post_tag: - name: "C (programming language)" slug: "c-programming-language" taxonomy: "post_tag" url: "http://localhost/tag/c-programming-language/" - name: "Full Text" slug: "fulltext" taxonomy: "post_tag" url: "http://localhost/tag/fulltext/" - name: "QL" slug: "ql" taxonomy: "post_tag" url: "http://localhost/tag/ql/" - name: "Superbasic (programming language)" slug: "superbasic-programming-language" taxonomy: "post_tag" url: "http://localhost/tag/superbasic-programming-language/" - name: "Type-in program" slug: "type-in-program" taxonomy: "post_tag" url: "http://localhost/tag/type-in-program/" model: - name: "Sinclair QL" slug: "sinclair-ql" taxonomy: "model" url: "http://localhost/model/sinclair-ql/" indiv: - name: "Tim Swenson" slug: "tim-swenson" taxonomy: "indiv" url: "http://localhost/indiv/tim-swenson/" publication_r: id: 33686 title: "QL Hacker’s Journal" type: "periodical" url: "http://localhost/periodical/ql-hackers-journal/" authors_r: - name: "Tim Swenson" slug: "tim-swenson" taxonomy: "indiv" url: "http://localhost/indiv/tim-swenson/" issue: "7" issues_articles: - id: 61543 title: "QL Hacker’s Journal 7" type: "issue" url: "http://localhost/issue/ql-hackers-journal-7/" pubdate: "January 1992" archive_link: true --- # QLPatch One of the problems I’ve encountered in publishing souce code in the QHJ, is the dilemma of publishing a newer version of a program (or bug fixes). I could publish the whole program but this would waste bandwidth if only a small portion of the code has been changed. Another way is to publish the changes to the program and figure a way to have the user edit his version, add the changes and create a newer (second) version. In my dealings with the Unix world, I have heard of a program that does something like this, called Patch. In using Patch, the originator of the program runs the two version of the code through a file comparison utility (like Unix’s diff) and creates a diff (or delta) file. The end user takes the diff file, version 1 of the program, and runs it through Patch to create the second version. Patch uses the diff file as a guide to edit the source code. To make this work on the QL, I first needed a file comparison program. A few issues ago, I published FCOMP_C from the C Users Group. With only a few changes to FCOMP_C I was able to get a program that would work for me. I now have FCOMP2_C. Now that I could generate a diff file, I needed a version of Patch. Not having the source code to Patch, I decided to write my own version from scratch, based on the output of FCOMP2_C. Below is the result of that effort, QLPatch. This version is only written in SuperBasic. I plan to port it to C, but I prefer to develop in SuperBasic because it’s easier than C. After the source code, I have included an example of two versions of a file and the diff file for them. Take version 1 of the file, the diff file, and run them through QLPatch and see that you indeed get the second version. After this is the diff file for FCOMP_C to create FCOMP2_C. Running this and FCOMP_C though QLPatch will give you a version of FCOMP_C to use with QLPatch. If you encounter any bugs, please let me know. I do plan to use this program for the QHJ and I want it to work as advertised. ``` ** QLPatch ** By Timothy Swenson ** ** This program takes version 1 of a file, a diff file ** created by fcomp_c, and creates version 2 of the ** file. This program can be used to distribute ** changes to a program with out having to redistribute ** all of the source code. You need only distribute those ** lines needed. ** ** This program can be used for any text file, be it a C ** program, Achive program, or a text document. ** TRUE = 1 FALSE = 0 IN_FILE = 4 DIFF_FILE = 5 OUT_FILE = 6 last_insert = FALSE INPUT "Enter Souce File : ";in_file$ INPUT "Enter Diff File : ";diff_file$ INPUT "Enter Output File : ";out_file$ DELETE out_file$ OPEN #IN_FILE,in_file$ OPEN #DIFF_FILE,diff_file$ OPEN_NEW #OUT_FILE,out_file$ in_file_count = 1 REPEAT big_loop IF last_insert = FALSE THEN INPUT #DIFF_FILE,in$ IF EOF(#DIFF_FILE) THEN EXIT big_loop ELSE last_insert = FALSE ENDIF IF LEN(in$) < 13 THEN END REPEAT big_loop IF in$(1 TO 13) = "Deleted line " THEN del_line IF in$(1 to 13) = "Deleted lines" THEN del_lines IF in$(1 to 13) = "Changed line " THEN chang_line IF in$(1 to 13) = "Changed lines" THEN chang_lines IF LEN(in$) < 19 THEN END REPEAT big_loop IF in$(1 to 19) = "Inserted after line" THEN insert END REPEAT big_loop ** add rest of original file to new file REPEAT loop INPUT #IN_FILE,in_file$ IF EOF(#IN_FILE) THEN EXIT loop PRINT #OUT_FILE,in_file$ END REPEAT loop @END PRINT #OUT_FILE CLOSE #IN_FILE CLOSE #DIFF_FILE CLOSE #OUT_FILE ** Start of Functions DEFine FuNction EOS(x$) IF LEN(x$) < 3 THEN RETURN FALSE IF x$(1 to 3) = "To:" THEN RETURN TRUE IF LEN(x$) < 12 THEN RETURN FALSE IF x$(1 to 12) = "Deleted line" THEN RETURN TRUE IF x$(1 to 12) = "Changed line" THEN RETURN TRUE IF LEN(x$) < 19 THEN RETURN FALSE IF x$(1 to 19) = "Inserted after line" THEN RETURN TRUE RETURN FALSE END DEFine EOS DEFine PROCedure del_line LOCal z,x x = in$(14 to) FOR z = in_file_count TO x-1 INPUT #IN_FILE,in_file$ PRINT #OUT_FILE,in_file$ NEXT z INPUT #IN_FILE,in_file$ in_file_count = x+1 END DEFine del_line DEFine PROCedure del_lines LOCal x,y,z,temp temp = "-" INSTR in$ x = in$( 15 TO temp-1) y = in$( temp+1 TO LEN(in$)-1) FOR z = in_file_count TO x-1 INPUT #IN_FILE,in_file$ PRINT #OUT_FILE,in_file$ NEXT z FOR z = x TO y INPUT #IN_FILE,in_file$ NEXT z in_file_count = y+1 END DEFine del_lines DEFine PROCedure insert LOCal x,y,loop x = in$(21 TO) FOR y = in_file_count to x INPUT #IN_FILE,infile$ PRINT #OUT_FILE,infile$ NEXT y in_file_count = x+1 REPEAT loop INPUT #DIFF_FILE,in$ IF EOF(#DIFF_FILE) THEN GOTO @END IF EOS(in$) THEN EXIT loop IF LEN(in$) < 2 THEN PRINT #OUT_FILE,in$ ELSE PRINT #OUT_FILE,in$(2 TO) ENDIF END REPEAT loop last_insert = TRUE END DEFine insert DEFine PROCedure chang_line LOCal x,y x = in$(14 TO) FOR y = in_file_count TO x-1 INPUT #IN_FILE,infile$ PRINT #OUT_FILE,infile$ NEXT y in_file_count = x+1 INPUT #IN_FILE,infile$ INPUT #DIFF_FILE,in$ INPUT #DIFF_FILE,in$ INPUT #DIFF_FILE,in$ PRINT #OUT_FILE,in$(2 TO) END DEFine chang_line DEFine PROCedure chang_lines LOCal x,y,z,temp temp = "-" INSTR in$ x = in$( 15 TO temp-1) y = in$( temp+1 TO LEN(in$)-1) FOR z = in_file_count TO x-1 INPUT #IN_FILE,infile$ PRINT #OUT_FILE,infile$ NEXT z FOR z = x to y INPUT #IN_FILE,in$ INPUT #DIFF_FILE,in$ NEXT z INPUT #DIFF_FILE,in$ REPEAT loop INPUT #DIFF_FILE,in$ IF EOF(#DIFF_FILE) THEN GOTO @END IF EOS(IN$) THEN EXIT loop IF LEN(in$) < 2 THEN PRINT #OUT_FILE,in$ ELSE PRINT #OUT_FILE,in$(2 TO) END IF END REPEAT loop last_insert = TRUE in_file_count = y+1 END DEFine chang_lines ``` Example files: ``` Version 1 File: This is line 1 This is line 2 This is line 3 This is line 4 This is line 5 This is line 6 This is line 7 This is line 8 This is line 9 This is line 10 This is line 11 This is line 12 This is line 13 This is line 14 This is line 15 This is line 16 This is line 17 This is line 18 Version 2 File: This is line 1 This is line 3 This is line 4 add a line here This is line 5 This is line 6 add a line here add a line here This is line 7 This is a line 8 This is line 9 This is line 13 This is line 14 This is a line 15 This is a line 16 This is line 17 This is line 18 add a line here: 1 add a line here: 2 add a line here: 3 Diff File: Deleted line 2 This is line 2 Inserted after line 4: add a line here Inserted after line 6: add a line here add a line here Changed line 8 This is line 8 To: This is a line 8 Deleted lines 10-12: This is line 10 This is line 11 This is line 12 Changed lines 15-16: This is line 15 This is line 16 To: This is a line 15 This is a line 16 Inserted after line 18: add a line here: 1 add a line here: 2 add a line here: 3 ``` Diff File for FCOMP2_C: ``` (some lines wrapped for printing,so be carefull when re-typing.) Inserted after line 0: Inserted after line 13: UPDATED: 11 Nov 91 by Timothy Swenson Added changes so that output will be sent to a file. Output file will be third file arguement. Usage: CRUN "flp1_fcomp2 flp1_file_ver_1 flp1_file_ver_2 flp1_diff" Deleted line 25 Deleted line 28 Changed line 54 #include To: #include Inserted after line 69: FILE *fd; Changed lines 93-94: if(argc != 3) fatal("fcomp requires two file names."); To: if(argc != 4) fatal("fcomp requires three file names."); Inserted after line 95: if (( fd = fopen(argv[3],"w")) == NULL ) { fprintf(stderr,"Cannot open file %s.\n",argv[3]); } Changed line 107 puts("The files are identical."); To: fputs(fd,"The files are identical."); fclose(fd); Inserted after line 144: fclose(fd); Inserted after line 169: fclose(fd); Changed line 207 printf("Inserted after line %d:\n",ep->line1); To: fprintf(fd,"Inserted after line %d:\n",ep->line1); Changed line 218 printf("\nChanged "); To: fprintf(fd,"Changed "); Changed line 220 printf("\nDeleted "); To: fprintf(fd,"Deleted "); Changed line 222 printf("line %d\n",ep->line1); To: fprintf(fd,"line %d\n",ep->line1); Changed line 224 printf("lines %d-%d:\n",ep->line1,a->line1); To: fprintf(fd,"lines %d-%d:\n",ep->line1,a->line1); Changed line 228 printf(" %s",A[ep->line1-1]); To: fprintf(fd," %s",A[ep->line1-1]); Changed line 234 printf("To:\n"); To: fprintf(fd,"To:\n"); Changed line 238 printf(" %s",B[ep->line2-1]); To: fprintf(fd," %s",B[ep->line2-1]); Inserted after line 241: fprintf(fd,"\n"); Inserted after line 247: fclose(fd); Inserted after line 254: fclose(fd); ```