A minimal Bible format designed for the C language.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

172 lines
4.1 KiB

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include "main.h"
  4. // Split chars and ints from string
  5. int strToInt(char *buf) {
  6. int ret = 0;
  7. for (; *buf != '\0'; buf++) {
  8. ret *= 10;
  9. ret += *buf - '0';
  10. }
  11. return ret;
  12. }
  13. // Parse BibleC index file, see format.md
  14. int biblec_parse(struct Biblec_translation *translation, char *indexLocation) {
  15. FILE *index = fopen(indexLocation, "r");
  16. if (index == NULL) {
  17. return FILE_NOT_FOUND;
  18. }
  19. // If location is never filled in, then assume text
  20. // file location is in the same folder as the index file.
  21. strcpy(translation->location, indexLocation);
  22. translation->location[strlen(indexLocation) - 1] = 't';
  23. int book = 0;
  24. char line[INDEX_MAX_LENGTH];
  25. while (fgets(line, INDEX_MAX_LENGTH, index) != NULL) {
  26. // Remove trailing breakline
  27. strtok(line, "\n");
  28. // Pointer to line content
  29. char *contents = line + 1;
  30. // Make a duplicate for manipulation
  31. char afterFirst[INDEX_MAX_LENGTH];
  32. strcpy(afterFirst, contents);
  33. // Tell the difference between # and @
  34. if (line[0] == '#') {
  35. // Copy before ':' to afterFirst
  36. int c = 0;
  37. while (*contents != ':') {
  38. afterFirst[c] = *contents;
  39. contents++;
  40. c++;
  41. }
  42. afterFirst[c] = '\0';
  43. contents++; // Increment to skip ':'
  44. if (!strcmp(afterFirst, "name")) {
  45. strcpy(translation->name, contents);
  46. } else if (!strcmp(afterFirst, "lang")) {
  47. strcpy(translation->lang, contents);
  48. } else if (!strcmp(afterFirst, "location")) {
  49. strcpy(translation->location, contents);
  50. } else if (!strcmp(afterFirst, "length")) {
  51. translation->length = strToInt(contents);
  52. }
  53. } else if (line[0] == '@') {
  54. char *bookInfo = strtok(afterFirst, " ");
  55. strcpy(translation->book[book].name, afterFirst);
  56. bookInfo = strtok(NULL, " ");
  57. translation->book[book].start = strToInt(bookInfo);
  58. bookInfo = strtok(NULL, " ");
  59. translation->book[book].length = strToInt(bookInfo);
  60. } else if (line[0] == '!') {
  61. // Loop through chapters and set them in the struct
  62. int currentChapter = 0;
  63. char *chapter = strtok(afterFirst, " ");
  64. while (chapter != NULL) {
  65. translation->book[book].chapters[currentChapter] = strToInt(chapter);
  66. chapter = strtok(NULL, " ");
  67. currentChapter++;
  68. }
  69. book++;
  70. }
  71. // Any other line start chars will be skipped
  72. }
  73. fclose(index);
  74. return 0;
  75. }
  76. int getBookID(struct Biblec_translation *translation, char *book) {
  77. int bookID = BOOK_NOT_FOUND;
  78. for (int i = 0; i < translation->length; i++) {
  79. if (!strcmp(book, translation->book[i].name)) {
  80. bookID = i;
  81. }
  82. }
  83. return bookID;
  84. }
  85. int biblec_next(struct Biblec_reader *reader) {
  86. // Reached end of requested verses
  87. if (reader->linesRead > reader->to) {
  88. return -1;
  89. }
  90. // End of file
  91. if (fgets(reader->result, VERSE_LENGTH, reader->file) == NULL) {
  92. return -1;
  93. }
  94. strtok(reader->result, "\n"); // Strip '\n'
  95. reader->linesRead++;
  96. return 0;
  97. }
  98. // Create a new reader structure
  99. int biblec_new(struct Biblec_reader *reader, struct Biblec_translation *translation,
  100. char *book, int chapter, int verse, int to) {
  101. int c;
  102. // Check book ID
  103. int bookID = getBookID(translation, book);
  104. if (bookID == BOOK_NOT_FOUND) {
  105. return BOOK_NOT_FOUND;
  106. }
  107. // Check if requested chapter is larger than book length
  108. if (translation->book[bookID].length < chapter) {
  109. return CHAPTER_TOO_BIG;
  110. }
  111. // Grab start line, and add until specified chapter is reached.
  112. int line = translation->book[bookID].start;
  113. for (c = 0; c < chapter - 1; c++) {
  114. line += translation->book[bookID].chapters[c];
  115. }
  116. // When 0 is passed for "to", grab the entire chapter.
  117. // Else, "to" refers to how many verse to
  118. // count in the struct.
  119. if (to == 0) {
  120. to = translation->book[bookID].chapters[c] - 1;
  121. } else {
  122. to -= verse;
  123. }
  124. // Add the line over to the specific verse
  125. line += verse - 1;
  126. reader->book = book;
  127. reader->chapter = chapter;
  128. reader->verse = verse;
  129. reader->to = to;
  130. reader->linesRead = 0;
  131. reader->file = fopen(translation->location, "r");
  132. if (reader->file == NULL) {
  133. return FILE_ERROR;
  134. }
  135. // Loop through until it gets to the line
  136. char verseText[VERSE_LENGTH];
  137. for (int i = 0; i != line; i++) {
  138. if (fgets(verseText, VERSE_LENGTH, reader->file) == NULL) {
  139. return FILE_ERROR;
  140. }
  141. }
  142. return 0;
  143. }