commit afe2313c5a3b621d17ab59f875f317c88445d7d2
parent 98628363cde64aef5ce5c14b4a3f92cdf0a5ccc5
Author: nibo <nibo@relim.de>
Date: Sat, 8 Feb 2025 18:05:19 +0100
Move *.c and *.h into src/ folder
Diffstat:
| M | Makefile | | | 2 | +- |
| D | chord_diagram.c | | | 741 | ------------------------------------------------------------------------------- |
| D | chord_diagram.h | | | 26 | -------------------------- |
| D | chordpro.c | | | 5474 | ------------------------------------------------------------------------------- |
| D | chordpro.h | | | 175 | ------------------------------------------------------------------------------- |
| D | config.c | | | 1065 | ------------------------------------------------------------------------------- |
| D | config.h | | | 17 | ----------------- |
| D | diagrams.h | | | 4394 | ------------------------------------------------------------------------------- |
| D | lorid.c | | | 117 | ------------------------------------------------------------------------------- |
| D | out_pdf.c | | | 2819 | ------------------------------------------------------------------------------- |
| D | out_pdf.h | | | 103 | ------------------------------------------------------------------------------- |
| D | types.h | | | 338 | ------------------------------------------------------------------------------- |
| D | util.c | | | 502 | ------------------------------------------------------------------------------- |
| D | util.h | | | 59 | ----------------------------------------------------------- |
14 files changed, 1 insertion(+), 15831 deletions(-)
diff --git a/Makefile b/Makefile
@@ -6,7 +6,7 @@ VARS = -DVERSION=\"${VERSION}\" -DCOLOR=${COLOR} -DPREFIX=\"${PREFIX}\"
CFLAGS = -std=c23 -pedantic -Wall -Wextra
LDFLAGS = -lpdfio -ltoml -lfontconfig -lgrapheme -lm
STATIC_LDFLAGS = -lpdfio -ltoml -lfontconfig -lgrapheme -lz -L/home/robin/src/libexpat/expat/lib/.libs/ -lexpat -L/home/robin/src/freetype/build/ -lfreetype -L/home/robin/src/libpng-1.6.45/.libs/ -lpng16 -L/home/robin/src/harfbuzz/build/src/ -lharfbuzz -lm
-SRC = util.c config.c chordpro.c chord_diagram.c out_pdf.c lorid.c
+SRC = src/util.c src/config.c src/chordpro.c src/chord_diagram.c src/out_pdf.c src/lorid.c
compile:
$(CC) ${CFLAGS} ${VARS} -O2 ${SRC} -o lorid ${LDFLAGS}
diff --git a/chord_diagram.c b/chord_diagram.c
@@ -1,741 +0,0 @@
-#include <string.h>
-#include <ctype.h>
-#include <pdfio.h>
-#include <pdfio-content.h>
-#include "types.h"
-#include "out_pdf.h"
-#include "util.h"
-#include "config.h"
-#include "chordpro.h"
-#include "chord_diagram.h"
-#include "diagrams.h"
-
-static bool
-text_show(
- pdfio_stream_t *stream,
- const char *text,
- double x,
- double y
-)
-{
- if (!pdfioContentSetTextRenderingMode(stream, PDFIO_TEXTRENDERING_FILL)) {
- fprintf(stderr, "pdfioContentSetTextRenderingMode failed.\n");
- return false;
- }
- if (!pdfioContentTextBegin(stream)) {
- fprintf(stderr, "pdfioContentTextBegin failed.\n");
- return false;
- }
- if (!pdfioContentTextMoveTo(stream, x, y)) {
- fprintf(stderr, "pdfioContentTextMoveTo failed.\n");
- return false;
- }
- if (!pdfioContentTextShow(stream, true, text)) {
- fprintf(stderr, "pdfioContentTextShow failed.\n");
- return false;
- }
- if (!pdfioContentTextEnd(stream)) {
- fprintf(stderr, "pdfioContentTextEnd failed.\n");
- return false;
- }
- return true;
-}
-
-static bool
-draw_rectangle(
- pdfio_stream_t *stream,
- double x,
- double y,
- double width,
- double height,
- enum TextRendering type
-)
-{
- if (!pdfioContentSetFillColorRGB(stream, 0.0, 0.0, 0.0)) {
- fprintf(stderr, "pdfioContentSetFillColorRGB failed.\n");
- return false;
- }
- if (!pdfioContentSetStrokeColorRGB(stream, 0.0, 0.0, 0.0)) {
- fprintf(stderr, "pdfioContentSetStrokeColorRGB failed.\n");
- return false;
- }
- if (!pdfioContentPathRect(stream, x, y, width, height)) {
- fprintf(stderr, "pdfioContentPathRect failed.\n");
- return false;
- }
- switch (type) {
- case FILL_AND_STROKE:
- if (!pdfioContentFillAndStroke(stream, true)) {
- fprintf(stderr, "pdfioContentFillAndStroke failed.\n");
- return false;
- }
- break;
- case FILL:
- if (!pdfioContentFill(stream, true)) {
- fprintf(stderr, "pdfioContentFill failed.\n");
- return false;
- }
- break;
- case STROKE:
- if (!pdfioContentStroke(stream)) {
- fprintf(stderr, "pdfioContentStroke failed.\n");
- return false;
- }
- break;
- }
- return true;
-}
-
-static bool
-draw_line(
- pdfio_stream_t *stream,
- double x,
- double y,
- double width,
- enum Direction direction
-)
-{
- if (!pdfioContentPathMoveTo(stream, x, y)) {
- fprintf(stderr, "pdfioContentPathMoveTo failed.\n");
- return false;
- }
- if (direction == HORIZONTAL) {
- if (!pdfioContentPathLineTo(stream, x+width, y)) {
- fprintf(stderr, "pdfioContentPathLineTo failed.\n");
- return false;
- }
- } else {
- if (!pdfioContentPathLineTo(stream, x, y+width)) {
- fprintf(stderr, "pdfioContentPathLineTo failed.\n");
- return false;
- }
- }
- if (!pdfioContentSetStrokeColorRGB(stream, 0.0, 0.0, 0.0)) {
- fprintf(stderr, "pdfioContentSetStrokeColorRGB failed.\n");
- return false;
- }
- if (!pdfioContentStroke(stream)) {
- fprintf(stderr, "pdfioContentFill failed.\n");
- return false;
- }
- return true;
-}
-
-static bool
-draw_bezier_oval_quarter(
- pdfio_stream_t *stream,
- double center_x,
- double center_y,
- double size_x,
- double size_y
-)
-{
- if (!pdfioContentPathMoveTo(stream, center_x - size_x, center_y)) {
- fprintf(stderr, "pdfioContentPathMoveTo failed.\n");
- return false;
- }
- if (!pdfioContentPathCurve(
- stream,
- center_x - size_x,
- center_y - 0.552 * size_y,
- center_x - 0.552 * size_x,
- center_y - size_y,
- center_x,
- center_y - size_y
- )) {
- fprintf(stderr, "pdfioContentPathCurve failed.\n");
- return false;
- }
- return true;
-}
-
-static bool
-draw_bezier_oval(
- pdfio_stream_t *stream,
- double center_x,
- double center_y,
- double size_x,
- double size_y
-)
-{
- if (!pdfioContentSetStrokeColorRGB(stream, 0.0, 0.0, 0.0)) {
- fprintf(stderr, "pdfioContentSetStrokeColorRGB failed.\n");
- return false;
- }
- if (!draw_bezier_oval_quarter(stream, center_x, center_y, -size_x, size_y)) {
- fprintf(stderr, "draw_bezier_oval_quarter failed.");
- return false;
- }
- if (!draw_bezier_oval_quarter(stream, center_x, center_y, size_x, size_y)) {
- fprintf(stderr, "draw_bezier_oval_quarter failed.");
- return false;
- }
- if (!draw_bezier_oval_quarter(stream, center_x, center_y, size_x, -size_y)) {
- fprintf(stderr, "draw_bezier_oval_quarter failed.");
- return false;
- }
- if (!draw_bezier_oval_quarter(stream, center_x, center_y, -size_x, -size_y)) {
- fprintf(stderr, "draw_bezier_oval_quarter failed.");
- return false;
- }
- if (!pdfioContentStroke(stream)) {
- fprintf(stderr, "pdfioContentStroke failed.\n");
- return false;
- }
- return true;
-}
-
-static bool
-draw_bezier_circle(
- pdfio_stream_t *stream,
- double center_x,
- double center_y,
- double size
-)
-{
- if (!pdfioContentSetLineWidth(stream, size * 0.4)) {
- fprintf(stderr, "pdfioContentSetLineWidth failed.\n");
- return false;
- }
- if (!draw_bezier_oval(stream, center_x, center_y, size, size)) {
- fprintf(stderr, "draw_bezier_oval failed.");
- return false;
- }
- return true;
-}
-
-static bool
-draw_x(pdfio_stream_t *stream, double x, double y, double size)
-{
- if (!pdfioContentSetLineWidth(stream, size * 0.4)) {
- fprintf(stderr, "pdfioContentSetLineWidth failed.\n");
- return false;
- }
- if (!pdfioContentSetStrokeColorRGB(stream, 0.0, 0.0, 0.0)) {
- fprintf(stderr, "pdfioContentSetStrokeColorRGB failed.\n");
- return false;
- }
- if (!pdfioContentPathMoveTo(stream, x - size, y - size)) {
- fprintf(stderr, "pdfioContentPathMoveTo failed.\n");
- return false;
- }
- if (!pdfioContentPathLineTo(stream, x + size, y + size)) {
- fprintf(stderr, "pdfioContentPathLineTo failed.\n");
- return false;
- }
- if (!pdfioContentStroke(stream)) {
- fprintf(stderr, "pdfioContentFill failed.\n");
- return false;
- }
- if (!pdfioContentPathMoveTo(stream, x - size, y + size)) {
- fprintf(stderr, "pdfioContentPathMoveTo failed.\n");
- return false;
- }
- if (!pdfioContentPathLineTo(stream, x + size, y - size)) {
- fprintf(stderr, "pdfioContentPathLineTo failed.\n");
- return false;
- }
- if (!pdfioContentStroke(stream)) {
- fprintf(stderr, "pdfioContentFill failed.\n");
- return false;
- }
- return true;
-}
-
-static bool
-is_valid_circle_char(char c)
-{
- if (c >= '/' && c <= '9') {
- return true;
- }
- if (c >= 'A' && c <= 'Z') {
- return true;
- }
- return false;
-}
-
-static bool
-draw_circle_with_char_inside(
- pdfio_stream_t *stream,
- double x,
- double y,
- double field_width,
- char c
-)
-{
- if (!is_valid_circle_char(c)) {
- fprintf(stderr, "is_valid_circle_char failed.\n");
- return false;
- }
- char str[2];
- str[0] = c;
- str[1] = 0;
- if (!pdfioContentSetTextFont(stream, "chord-diagram-symbols", field_width)) {
- fprintf(stderr, "pdfioContentSetTextFont failed.\n");
- return false;
- }
- /* INFO: Needs to be the color of the page background. This cannot be set at the moment. It will always be white. */
- if (!pdfioContentSetFillColorRGB(stream, 1.0, 1.0, 1.0)) {
- fprintf(stderr, "pdfioContentSetFillColorRGB failed.\n");
- return false;
- }
- if (!text_show(stream, "/", x-field_width/2, y-field_width/2.8)) {
- fprintf(stderr, "text_show failed.");
- return false;
- }
- if (!pdfioContentSetFillColorRGB(stream, 0.0, 0.0, 0.0)) {
- fprintf(stderr, "pdfioContentSetFillColorRGB failed.\n");
- return false;
- }
- if (!text_show(stream, (char *)&str, x-field_width/2, y-field_width/2.8)) {
- fprintf(stderr, "text_show failed.");
- return false;
- }
- return true;
-}
-
-struct StringDiagram *
-string_diagram_new(void)
-{
- struct StringDiagram *d = emalloc(sizeof(struct StringDiagram));
- d->name = NULL;
- d->base_fret = -2;
- memset(d->frets, -2, sizeof(d->frets));
- memset(d->fingers, -2, sizeof(d->fingers));
- return d;
-}
-
-static int
-string_diagram_string_count(struct StringDiagram *d)
-{
- int i;
- for (i = 0; d->frets[i] != -2 && i < 12; i++);
- return i;
-}
-
-static void
-string_diagram_free(struct StringDiagram *d)
-{
- free(d->name);
- free(d);
-}
-
-static struct StringDiagram *
-string_diagram_copy_all_but_name(struct StringDiagram *diagram)
-{
- struct StringDiagram *copy = emalloc(sizeof(struct StringDiagram));
- copy->base_fret = diagram->base_fret;
- int i;
- for (i = 0; i<12; i++) {
- copy->frets[i] = diagram->frets[i];
- }
- for (i = 0; i<12; i++) {
- copy->fingers[i] = diagram->fingers[i];
- }
- return copy;
-}
-
-/* static bool
-string_diagram_is_valid(struct StringDiagram *d)
-{
- int i;
- size_t fret_count, finger_count;
- if (d->base_fret < 1 || d->base_fret > 99) {
- return false;
- }
- i = 0;
- while (d->frets[i] != -2 && i < 12) {
- i++;
- }
- fret_count = i;
- i = 0;
- while (d->fingers[i] != -2 && i < 12) {
- i++;
- }
- finger_count = i;
- if (finger_count > 0 && fret_count != finger_count) {
- return false;
- }
- return true;
-} */
-
-static size_t
-string_diagram_fret_count(struct StringDiagram *d)
-{
- int i;
- for (i = 0; d->frets[i] != -2 && i < 12; i++);
- return i;
-}
-
-static char
-finger_to_char(int8_t finger)
-{
- switch (finger) {
- case 1:
- return '1';
- case 2:
- return '2';
- case 3:
- return '3';
- case 4:
- return '4';
- default:
- return '/';
- }
-}
-
-static bool
-string_diagram_draw(
- pdfio_stream_t *stream,
- struct StringDiagram *diagram,
- double x,
- double y,
- double width
-)
-{
- int i;
- int instrument_string_count = string_diagram_string_count(diagram);
- double field_width = width / (instrument_string_count - 1);
- double height = field_width * 4;
- double y_above_diagram = y + height + field_width / 2 + field_width / 2.5;
- double vertical_lines_height = height + field_width / 2;
- if (!pdfioContentSetLineWidth(stream, field_width * 0.09)) {
- fprintf(stderr, "pdfioContentSetLineWidth failed.\n");
- return false;
- }
- if (!draw_rectangle(stream, x, y, width, height, STROKE)) {
- fprintf(stderr, "draw_rectangle failed.\n");
- return false;
- }
- // from bottom to top draw horizontal lines
- for (i = 0; i<4; i++) {
- if (!draw_line(stream, x, y+field_width * (i+1), width, HORIZONTAL)) {
- fprintf(stderr, "draw_line failed.\n");
- return false;
- }
- }
- // from left to right draw vertical lines
- for (i = 0; i<instrument_string_count; i++) {
- if (!draw_line(stream, x+field_width*i, y, vertical_lines_height, VERTICAL)) {
- fprintf(stderr, "draw_line failed.\n");
- return false;
- }
- }
- if (diagram->base_fret == 1) {
- if (!draw_rectangle(stream, x, y+height, width, field_width/2, FILL_AND_STROKE)) {
- fprintf(stderr, "draw_rectangle failed.\n");
- return false;
- }
- } else {
- double base_pos_x;
- char base_position[5];
- base_position[4] = 0;
- sprintf((char *)&base_position, "%d", diagram->base_fret);
- if (diagram->base_fret > 9) {
- base_pos_x = x - field_width - field_width;
- } else {
- base_pos_x = x - field_width - field_width / 3;
- }
- if (!pdfioContentSetTextCharacterSpacing(stream, -1.5)) {
- fprintf(stderr, "pdfioContentSetTextCharacterSpacing failed.\n");
- return false;
- }
- if (!pdfioContentSetTextFont(stream, "chord-diagram-regular-font", field_width*1.15)) {
- fprintf(stderr, "pdfioContentSetTextFont failed.\n");
- return false;
- }
- if (!text_show(stream, base_position, base_pos_x, y+field_width*3+field_width*0.1)) {
- fprintf(stderr, "text_show failed.\n");
- return false;
- }
- }
- int8_t fret, finger;
- for (i = 0; i<instrument_string_count; i++) {
- fret = diagram->frets[i];
- finger = diagram->fingers[i];
- if (fret == -1) {
- if (!draw_x(stream, x+(i*field_width), y_above_diagram, field_width / 4)) {
- fprintf(stderr, "draw_x failed.\n");
- return false;
- }
- } else
- if (fret == 0) {
- if (!draw_bezier_circle(stream, x+(i*field_width), y_above_diagram, field_width / 4)) {
- fprintf(stderr, "draw_circle_with_char_inside failed.\n");
- return false;
- }
- } else
- if (fret < 5) {
- if (!draw_circle_with_char_inside(stream,
- x + i * field_width,
- y + field_width/2 + field_width * (4 - fret),
- field_width,
- finger_to_char(finger)
- )) {
- fprintf(stderr, "draw_circle_with_char_inside failed.\n");
- return false;
- }
- }
- }
- pdfio_obj_t *font_obj;
- double name_width, centered_x;
- font_obj = out_pdf_fnt_obj_get_by_name("chord-diagram-regular-font");
- if (!font_obj) {
- LOG_DEBUG("out_pdf_fnt_obj_get_by_name failed.");
- return false;
- }
- name_width = pdfioContentTextMeasure(font_obj, diagram->name, field_width*2.0);
- centered_x = (width - name_width) / 2;
- if (!pdfioContentSetTextFont(stream, "chord-diagram-regular-font", field_width*2.0)) {
- fprintf(stderr, "pdfioContentSetTextFont failed.\n");
- return false;
- }
- if (!text_show(stream, diagram->name, x+centered_x, y_above_diagram + 7.0)) {
- fprintf(stderr, "text_show failed.\n");
- return false;
- }
- return true;
-}
-
-struct KeyboardDiagram *
-keyboard_diagram_new(void)
-{
- struct KeyboardDiagram *d = emalloc(sizeof(struct KeyboardDiagram));
- d->name = NULL;
- memset(d->keys, -2, sizeof(d->keys));
- return d;
-}
-
-static struct KeyboardDiagram *
-keyboard_diagram_copy_all_but_name(struct KeyboardDiagram *diagram)
-{
- struct KeyboardDiagram *copy = keyboard_diagram_new();
- memcpy(copy->keys, diagram->keys, 24);
- return copy;
-}
-
-static void
-keyboard_diagram_free(struct KeyboardDiagram *d)
-{
- free(d->name);
- free(d);
-}
-
-struct ChordDiagram *
-chord_diagram_new()
-{
- struct ChordDiagram *d = emalloc(sizeof(struct ChordDiagram));
- d->show = true;
- d->color = cho_rgbcolor_new(20, 20, 20);
- return d;
-}
-
-void
-chord_diagram_free(struct ChordDiagram *d)
-{
- free(d->color);
- if (d->is_string_instrument) {
- string_diagram_free(d->u.sd);
- } else {
- keyboard_diagram_free(d->u.kd);
- }
- free(d);
-}
-
-static struct ChordDiagram *
-chord_diagram_copy_all_but_name(struct ChordDiagram *diagram)
-{
- struct ChordDiagram *copy = emalloc(sizeof(struct ChordDiagram));
- copy->show = diagram->show;
- copy->color = cho_color_copy(diagram->color);
- copy->is_string_instrument = diagram->is_string_instrument;
- if (diagram->is_string_instrument) {
- copy->u.sd = string_diagram_copy_all_but_name(diagram->u.sd);
- } else {
- copy->u.kd = keyboard_diagram_copy_all_but_name(diagram->u.kd);
- }
- return copy;
-}
-
-enum ChordDiagramContent
-chord_diagram_duplicate(
- struct ChordDiagram *diagram,
- struct ChordDiagram **custom_diagrams,
- int custom_diagrams_len,
- const char *name,
- const char *chord_to_copy,
- enum Instrument instrument
-)
-{
- int d;
- for (d = custom_diagrams_len-1; d >= 0; d--) {
- if (custom_diagrams[d]->is_string_instrument) {
- if (!strcmp(custom_diagrams[d]->u.sd->name, chord_to_copy)) {
- diagram->is_string_instrument = true;
- diagram->u.sd = string_diagram_copy_all_but_name(custom_diagrams[d]->u.sd);
- diagram->u.sd->name = strdup(name);
- return CDC_STRING;
- }
- } else {
- if (!strcmp(custom_diagrams[d]->u.kd->name, chord_to_copy)) {
- diagram->is_string_instrument = false;
- diagram->u.kd = keyboard_diagram_copy_all_but_name(custom_diagrams[d]->u.kd);
- diagram->u.kd->name = strdup(name);
- return CDC_KEYBOARD;
- }
- }
- }
- switch (instrument) {
- case INS_GUITAR: {
- size_t i;
- for (i = 0; i<LENGTH(guitar_diagrams); i++) {
- if (!strcmp(guitar_diagrams[i].name, chord_to_copy)) {
- diagram->is_string_instrument = true;
- diagram->u.sd = string_diagram_copy_all_but_name(&guitar_diagrams[i]);
- diagram->u.sd->name = strdup(name);
- return CDC_STRING;
- }
- }
- break;
- }
- case INS_KEYBOARD: {
- break;
- }
- case INS_MANDOLIN: {
- break;
- }
- case INS_UKULELE: {
- break;
- }
- }
- return -1;
-}
-
-void
-chord_diagrams_free(struct ChordDiagram **diagrams)
-{
- if (!diagrams) {
- return;
- }
- struct ChordDiagram **d;
- for (d = diagrams; *d; d++) {
- chord_diagram_free(*d);
- }
- free(diagrams);
-}
-
-#ifdef DEBUG
-void
-debug_chord_diagram_print(struct ChordDiagram *diagram)
-{
- int i;
- printf("---- CHORD DIAGRAM BEGIN ----\n");
- printf("show: %s\n", diagram->show ? "true" : "false");
-
- char str[8];
- str[7] = 0;
- sprintf((char *)&str, "#%02X%02X%02X", diagram->color->red, diagram->color->green, diagram->color->blue);
-
- printf("color: %s\n", str);
-
- if (diagram->is_string_instrument) {
- printf("name: %s\n", diagram->u.sd->name);
- printf("base-fret: %d\n", diagram->u.sd->base_fret);
- printf("frets: ");
- for (i = 0; i<12; i++) {
- printf("%d ", diagram->u.sd->frets[i]);
- }
- printf("\n");
- printf("fingers: ");
- for (i = 0; i<12; i++) {
- printf("%d ", diagram->u.sd->fingers[i]);
- }
- printf("\n");
- } else {
- printf("name: %s\n", diagram->u.kd->name);
- printf("keys: ");
- for (i = 0; i<24; i++) {
- printf("%d ", diagram->u.kd->keys[i]);
- }
- printf("\n");
- }
- printf("---- CHORD DIAGRAM END ------\n");
-}
-#endif /* DEBUG */
-
-struct ChordDiagram **
-chord_diagrams_create(
- struct Config *config,
- struct ChoChord ***chords,
- struct ChordDiagram **custom_diagrams
-)
-{
- struct ChordDiagram **diagrams = NULL;
- struct ChordDiagram **cd;
- struct ChoChord **c;
- int d = 0;
- size_t i;
- switch (config->output->diagram->instrument) {
- case INS_GUITAR:
- for (c = *chords; *c; c++) {
- for (cd = custom_diagrams; *cd; cd++) {
- if (
- (*cd)->is_string_instrument &&
- string_diagram_fret_count((*cd)->u.sd) == 6 &&
- !strcmp((*c)->name, (*cd)->u.sd->name)
- ) {
- diagrams = erealloc(diagrams, (d+1) * sizeof(struct ChordDiagram *));
- diagrams[d] = chord_diagram_copy_all_but_name(*cd);
- diagrams[d]->u.sd->name = cho_chord_name_generate(*c);
- printf("custom: name '%s'\n", diagrams[d]->u.sd->name);
- d++;
- goto NEXT_CHORD;
- }
- }
- for (i = 0; i<LENGTH(guitar_diagrams); i++) {
- if (!strcmp((*c)->name, guitar_diagrams[i].name)) {
- diagrams = erealloc(diagrams, (d+1) * sizeof(struct ChordDiagram *));
- diagrams[d] = chord_diagram_new();
- diagrams[d]->is_string_instrument = true;
- diagrams[d]->u.sd = string_diagram_copy_all_but_name(&guitar_diagrams[i]);
- diagrams[d]->u.sd->name = cho_chord_name_generate(*c);
- printf("predefined: name '%s'\n", diagrams[d]->u.sd->name);
- d++;
- }
- }
- NEXT_CHORD: ;
- }
- break;
- case INS_KEYBOARD:
- break;
- case INS_MANDOLIN:
- break;
- case INS_UKULELE:
- break;
- default:
- util_log(LOG_ERR, "Invalid Instrument enum value '%d'.", config->output->diagram->instrument);
- }
- diagrams = erealloc(diagrams, (d+1) * sizeof(struct ChordDiagram *));
- diagrams[d] = NULL;
- return diagrams;
-}
-
-bool
-chord_diagram_draw(
- pdfio_stream_t *stream,
- struct ChordDiagram *diagram,
- double x,
- double y,
- double width
-)
-{
- if (diagram->is_string_instrument) {
- if (!string_diagram_draw(stream, diagram->u.sd, x, y, width)) {
- LOG_DEBUG("draw_string_chord_diagram failed.");
- return false;
- }
- } else {
- util_log(LOG_TODO, "draw_keyboard_chord_diagram()");
- }
- return true;
-}
diff --git a/chord_diagram.h b/chord_diagram.h
@@ -1,26 +0,0 @@
-#include <pdfio.h>
-#include "types.h"
-
-enum TextRendering {
- FILL,
- STROKE,
- FILL_AND_STROKE
-};
-
-enum Direction {
- HORIZONTAL,
- VERTICAL
-};
-
-struct ChordDiagram *chord_diagram_new();
-void chord_diagram_free(struct ChordDiagram *d);
-bool chord_diagram_draw(pdfio_stream_t *stream, struct ChordDiagram *diagram, double x, double y, double width);
-enum ChordDiagramContent chord_diagram_duplicate(struct ChordDiagram *diagram, struct ChordDiagram **custom_diagrams, int custom_diagrams_len, const char *name, const char *chord_to_copy, enum Instrument instrument);
-
-struct StringDiagram *string_diagram_new(void);
-struct KeyboardDiagram *keyboard_diagram_new(void);
-
-void chord_diagrams_free(struct ChordDiagram **diagrams);
-struct ChordDiagram **chord_diagrams_create(struct Config *config, struct ChoChord ***chords, struct ChordDiagram **custom_diagram);
-
-void debug_chord_diagram_print(struct ChordDiagram *diagram);
diff --git a/chordpro.c b/chordpro.c
@@ -1,5474 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdbool.h>
-#include <stdarg.h>
-#include <unistd.h>
-#include <string.h>
-#include <strings.h>
-#include <ctype.h>
-#include <errno.h>
-#include <limits.h>
-#include "types.h"
-#include "chordpro.h"
-#include "util.h"
-#include "chord_diagram.h"
-#include "config.h"
-
-static const char *font_families[] = { "normal", "sans", "serif", "monospace" };
-static const char *font_styles[] = { "normal", "oblique", "italic" };
-static const char *font_weights[] = { "normal", "bold" };
-static const char *line_styles[] = { "single", "double", "none" };
-static const char *chord_qualifiers[] = { "m", "", "+", "°" };
-static const char *instruments[] = { "guitar", "keyboard", "mandolin", "ukulele" };
-
-static const char *state_enums[] = {
- "STATE_LYRICS",
- "STATE_BACKSLASH",
- "STATE_DIRECTIVE_NAME",
- "STATE_DIRECTIVE_VALUE",
- "STATE_CHORD",
- "STATE_ANNOTATION",
- "STATE_TAB",
- "STATE_MARKUP_TAG",
- "STATE_MARKUP_TAG_START",
- "STATE_MARKUP_TAG_END",
- "STATE_MARKUP_ATTR_NAME",
- "STATE_MARKUP_ATTR_VALUE",
- "STATE_COMMENT"
-};
-
-struct StyleProperty default_style_properties[] = {
- // TODO: label and footer are missing
- { TT_CHORD, SPT_FONT, { .font_name = NULL } },
- { TT_CHORD, SPT_SIZE, { .font_size = EMPTY_DOUBLE } },
- { TT_CHORD, SPT_COLOR, { .foreground_color = NULL } },
- { TT_CHORUS, SPT_FONT, { .font_name = NULL } },
- { TT_CHORUS, SPT_SIZE, { .font_size = EMPTY_DOUBLE } },
- { TT_CHORUS, SPT_COLOR, { .foreground_color = NULL } },
- { TT_GRID, SPT_FONT, { .font_name = NULL } },
- { TT_GRID, SPT_SIZE, { .font_size = EMPTY_DOUBLE } },
- { TT_GRID, SPT_COLOR, { .foreground_color = NULL } },
- { TT_TAB, SPT_FONT, { .font_name = NULL } },
- { TT_TAB, SPT_SIZE, { .font_size = EMPTY_DOUBLE } },
- { TT_TAB, SPT_COLOR, { .foreground_color = NULL } },
- { TT_TEXT, SPT_FONT, { .font_name = NULL } },
- { TT_TEXT, SPT_SIZE, { .font_size = EMPTY_DOUBLE } },
- { TT_TEXT, SPT_COLOR, { .foreground_color = NULL } },
- { TT_TITLE, SPT_FONT, { .font_name = NULL } },
- { TT_TITLE, SPT_SIZE, { .font_size = EMPTY_DOUBLE } },
- { TT_TITLE, SPT_COLOR, { .foreground_color = NULL } },
- { TT_TOC, SPT_FONT, { .font_name = NULL } },
- { TT_TOC, SPT_SIZE, { .font_size = EMPTY_DOUBLE } },
- { TT_TOC, SPT_COLOR, { .foreground_color = NULL } },
-};
-
-static const char *chord_extensions_major[] = {
- "2", "3", "4", "5", "6", "69", "7", "7-5",
- "7#5", "7#9", "7#9#5", "7#9b5", "7#9#11",
- "7b5", "7b9", "7b9#5", "7b9#9", "7b9#11", "7b9b13", "7b9b5", "7b9sus", "7b13", "7b13sus",
- "7-9", "7-9#11", "7-9#5", "7-9#9", "7-9-13", "7-9-5", "7-9sus",
- "711",
- "7#11",
- "7-13", "7-13sus",
- "7sus", "7susadd3",
- "7+",
- "7alt",
- "9",
- "9+",
- "9#5",
- "9b5",
- "9-5",
- "9sus",
- "9add6",
- "maj7", "maj711", "maj7#11", "maj13", "maj7#5", "maj7sus2", "maj7sus4",
- "^7", "^711", "^7#11", "^7#5", "^7sus2", "^7sus4",
- "maj9", "maj911",
- "^9", "^911",
- "^13",
- "^9#11",
- "11",
- "911",
- "9#11",
- "13",
- "13#11",
- "13#9",
- "13b9",
- "alt",
- "add2", "add4", "add9",
- "sus2", "sus4", "sus9",
- "6sus2", "6sus4",
- "7sus2", "7sus4",
- "13sus2", "13sus4",
- NULL
-};
-
-static const char *chord_extensions_minor[] = {
- // INFO: https://www.chordpro.org/beta/chordpro-chords/#extensions-for-minor-chords
- "#5",
- "#5",
- "m11",
- "-11",
- "m6",
- "-6",
- "m69",
- "-69",
- "m7b5",
- "-7b5",
- "m7-5",
- "-7-5",
- "mmaj7",
- "-maj7",
- "mmaj9",
- "-maj9",
- "m9maj7",
- "-9maj7",
- "m9^7",
- "-9^7",
- "madd9",
- "-add9",
- "mb6",
- "-b6",
- "m#7",
- "-#7",
- "msus4", "msus9",
- "-sus4", "-sus9",
- "m7sus4",
- "-7sus4",
- // INFO: custom
- "m7",
- "m9",
- "m",
- NULL
-};
-
-static bool g_show_info_logs = false;
-static enum TextType g_current_ttype = TT_TEXT;
-static enum TextType g_prev_ttype = TT_TEXT;
-static struct Config *g_config = NULL;
-static const char *g_chordpro_filepath = NULL;
-static int *g_transpose_history = NULL;
-static int *g_transpose = NULL;
-static size_t g_line_number = 1;
-struct ChoImage **g_image_assets = NULL;
-static int g_ia = 0;
-
-#ifdef DEBUG
-
-static const char *alignment_enums[] = {
- "A_LEFT",
- "A_CENTER",
- "A_RIGHT"
-};
-
-static const char *anchor_enums[] = {
- "AN_PAPER",
- "AN_PAGE",
- "AN_COLUMN",
- "AN_LINE",
- "AN_FLOAT"
-};
-
-static const char *chord_qualifier_enums[] = {
- "CQ_MIN",
- "CQ_MAJ",
- "CQ_AUG",
- "CQ_DIM"
-};
-
-static const char *directive_type_enums[] = {
- "DT_ENVIRONMENT",
- "DT_METADATA",
- "DT_FORMATTING",
- "DT_IMAGE",
- "DT_PREAMBLE",
- "DT_FONT",
- "DT_CHORD",
- "DT_OUTPUT",
- "DT_EXTENSION",
- "DT_CUSTOM"
-};
-
-static const char *section_type_enums[] = {
- "ST_NEWSONG",
- "ST_CHORUS",
- "ST_VERSE",
- "ST_BRIDGE",
- "ST_TAB",
- "ST_GRID",
- "ST_CUSTOM"
-};
-
-static const char *position_enums[] = {
- "POS_START",
- "POS_END",
- "POS_NO"
-};
-
-static const char *text_type_enums[] = {
- "TT_CHORD",
- "TT_ANNOT",
- "TT_CHORUS",
- "TT_FOOTER",
- "TT_GRID",
- "TT_TAB",
- "TT_TOC",
- "TT_TOC_TITLE",
- "TT_TEXT",
- "TT_TITLE",
- "TT_SUBTITLE",
- "TT_LABEL",
- "TT_COMMENT",
- "TT_COMMENT_ITALIC",
- "TT_COMMENT_BOX"
-};
-
-static const char *style_property_type_enums[] = {
- "SPT_FONT",
- "SPT_SIZE",
- "SPT_COLOR"
-};
-
-static void
-cho_debug_chord_print(struct ChoChord *chord)
-{
- printf("---- BEGIN CHORD ----\n");
- printf("is_canonical: %d\n", chord->is_canonical);
- printf("name: '%s'\n", chord->name);
- if (chord->root) {
- printf("root: '%s'\n", chord->root);
- } else {
- printf("root: 'NULL'\n");
- }
- printf("qual: '%s'\n", chord_qualifier_enums[chord->qual]);
- if (chord->ext) {
- printf("ext: '%s'\n", chord->ext);
- } else {
- printf("ext: 'NULL'\n");
- }
- if (chord->bass) {
- printf("bass: '%s'\n", chord->bass);
- } else {
- printf("bass: 'NULL'\n");
- }
- printf("---- END CHORD ------\n");
-}
-
-#endif /* DEBUG */
-
-void
-cho_log_enable_info_logs(void)
-{
- g_show_info_logs = true;
-}
-
-#if COLOR == 1
-static void
-cho_log(enum LogLevel level, const char *msg, ...)
-{
- if (level == LOG_INFO && !g_show_info_logs) {
- return;
- }
- va_list va;
- va_start(va, msg);
- const char *log_level;
- const char *color;
- switch (level) {
- case LOG_INFO:
- log_level = "INFO";
- color = COLOR_BOLD_WHITE;
- break;
- case LOG_WARN:
- log_level = "WARN";
- color = COLOR_BOLD_ORANGE;
- break;
- case LOG_ERR:
- log_level = " ERR";
- color = COLOR_BOLD_RED;
- break;
- case LOG_TODO:
- log_level = "TODO";
- color = COLOR_BOLD_BLUE;
- break;
- }
- if (isatty(2)) {
- if (g_chordpro_filepath) {
- fprintf(stderr, COLOR_BOLD_WHITE"%s:%ld:"COLOR_RESET" %s%s"COLOR_RESET": ",
- g_chordpro_filepath, g_line_number, color, log_level);
- vfprintf(stderr, msg, va);
- fprintf(stderr, "\n");
- } else {
- fprintf(stderr, "line "COLOR_BOLD_WHITE"%ld:"COLOR_RESET" %s%s"COLOR_RESET": ",
- g_line_number, color, log_level);
- vfprintf(stderr, msg, va);
- fprintf(stderr, "\n");
- }
- } else {
- if (g_chordpro_filepath) {
- fprintf(stderr, "%s:%ld: %s: ", g_chordpro_filepath, g_line_number,
- log_level);
- vfprintf(stderr, msg, va);
- fprintf(stderr, "\n");
- } else {
- fprintf(stderr, "line %ld: %s: ", g_line_number, log_level);
- vfprintf(stderr, msg, va);
- fprintf(stderr, "\n");
- }
- }
-}
-#else
-static void
-cho_log(enum LogLevel level, const char *msg, ...)
-{
- if (level == LOG_INFO && !g_show_info_logs) {
- return;
- }
- va_list va;
- va_start(va, msg);
- const char *log_level;
- switch (level) {
- case LOG_INFO:
- log_level = "INFO";
- break;
- case LOG_WARN:
- log_level = "WARN";
- break;
- case LOG_ERR:
- log_level = " ERR";
- break;
- case LOG_TODO:
- log_level = "TODO";
- break;
- }
- if (g_chordpro_filepath) {
- fprintf(stderr, "%s:%ld: %s: ", g_chordpro_filepath, g_line_number,
- log_level);
- vfprintf(stderr, msg, va);
- fprintf(stderr, "\n");
- } else {
- fprintf(stderr, "line %ld: %s: ", g_line_number, log_level);
- vfprintf(stderr, msg, va);
- fprintf(stderr, "\n");
- }
-}
-#endif /* COLOR */
-
-static inline bool
-is_whitespace(char c)
-{
- if (c == '\t' || c == ' ') {
- return true;
- }
- return false;
-}
-
-struct RGBColor *
-cho_rgbcolor_new(uint8_t red, uint8_t green, uint8_t blue)
-{
- struct RGBColor *color = emalloc(sizeof(struct RGBColor));
- color->red = red;
- color->green = green;
- color->blue = blue;
- return color;
-}
-
-static struct RGBColor *
-cho_rgbcolor_copy(struct RGBColor *color)
-{
- struct RGBColor *copy = emalloc(sizeof(struct RGBColor));
- copy->red = color->red;
- copy->green = color->green;
- copy->blue = color->blue;
- return copy;
-}
-
-static const char *
-cho_rgbcolor_to_string(struct RGBColor *color)
-{
- static char str[8];
- str[7] = 0;
- sprintf((char *)&str, "#%02X%02X%02X", color->red, color->green, color->blue);
- return (const char *)&str;
-}
-
-static struct RGBColor *
-cho_rgbcolor_parse(const char *str)
-{
- struct RGBColor *color = emalloc(sizeof(struct RGBColor));
- size_t len = strlen(str);
- char tmp[3];
- long primary_color;
- if (len == 7) {
- tmp[2] = 0;
- if (str[1] == '0' && str[2] == '0') {
- color->red = 0;
- } else {
- tmp[0] = str[1];
- tmp[1] = str[2];
- primary_color = strtol((char *)&tmp, NULL, 16);
- if (primary_color == 0) {
- cho_log(LOG_ERR, "Invalid primary color in rgb color.");
- free(color);
- return NULL;
- } else {
- color->red = primary_color;
- }
- }
- if (str[3] == '0' && str[4] == '0') {
- color->green = 0;
- } else {
- tmp[0] = str[3];
- tmp[1] = str[4];
- primary_color = strtol((char *)&tmp, NULL, 16);
- if (primary_color == 0) {
- cho_log(LOG_ERR, "Invalid primary color in rgb color.");
- free(color);
- return NULL;
- } else {
- color->green = primary_color;
- }
- }
- if (str[5] == '0' && str[6] == '0') {
- color->blue = 0;
- } else {
- tmp[0] = str[5];
- tmp[1] = str[6];
- primary_color = strtol((char *)&tmp, NULL, 16);
- if (primary_color == 0) {
- cho_log(LOG_ERR, "Invalid primary color in rgb color.");
- free(color);
- return NULL;
- } else {
- color->blue = primary_color;
- }
- }
- } else if (len == 4) {
- tmp[2] = 0;
- if (str[1] == '0') {
- color->red = 0;
- } else {
- tmp[0] = str[1];
- tmp[1] = str[1];
- primary_color = strtol((char *)&tmp, NULL, 16);
- if (primary_color == 0) {
- cho_log(LOG_ERR, "Invalid primary color in rgb color.");
- free(color);
- return NULL;
- } else {
- color->red = primary_color;
- }
- }
- if (str[2] == '0') {
- color->green = 0;
- } else {
- tmp[0] = str[2];
- tmp[1] = str[2];
- primary_color = strtol((char *)&tmp, NULL, 16);
- if (primary_color == 0) {
- cho_log(LOG_ERR, "Invalid primary color in rgb color.");
- free(color);
- return NULL;
- } else {
- color->green = primary_color;
- }
- }
- if (str[3] == '0') {
- color->blue = 0;
- } else {
- tmp[0] = str[3];
- tmp[1] = str[3];
- primary_color = strtol((char *)&tmp, NULL, 16);
- if (primary_color == 0) {
- cho_log(LOG_ERR, "Invalid primary color in rgb color.");
- free(color);
- return NULL;
- } else {
- color->blue = primary_color;
- }
- }
- } else {
- cho_log(LOG_ERR, "Invalid rgb color.");
- free(color);
- return NULL;
- }
- return color;
-}
-
-struct RGBColor *
-cho_color_parse(const char *str)
-{
- struct RGBColor *color = emalloc(sizeof(struct RGBColor));
- if (str[0] == '#') {
- struct RGBColor *rgb_color = cho_rgbcolor_parse(str);
- if (rgb_color) {
- free(color);
- color = rgb_color;
- } else {
- free(color);
- LOG_DEBUG("cho_rgbcolor_parse failed.");
- return NULL;
- }
- } else if (!strcmp(str, "red")) {
- color->red = 255;
- color->green = 48;
- color->blue = 48;
- } else if (!strcmp(str, "green")) {
- color->red = 0;
- color->green = 126;
- color->blue = 0;
- } else if (!strcmp(str, "blue")) {
- color->red = 0;
- color->green = 0;
- color->blue = 255;
- } else if (!strcmp(str, "yellow")) {
- color->red = 255;
- color->green = 255;
- color->blue = 0;
- } else if (!strcmp(str, "magenta")) {
- color->red = 255;
- color->green = 48;
- color->blue = 255;
- } else if (!strcmp(str, "cyan")) {
- color->red = 82;
- color->green = 255;
- color->blue = 255;
- } else if (!strcmp(str, "white")) {
- color->red = 255;
- color->green = 255;
- color->blue = 255;
- } else if (!strcmp(str, "grey")) {
- color->red = 191;
- color->green = 191;
- color->blue = 191;
- } else if (!strcmp(str, "black")) {
- color->red = 0;
- color->green = 0;
- color->blue = 0;
- } else {
- cho_log(LOG_ERR, "Invalid color value '%s'.", str);
- free(color);
- return NULL;
- }
- return color;
-}
-
-inline struct RGBColor *
-cho_color_copy(struct RGBColor *color)
-{
- return cho_rgbcolor_copy(color);
-}
-
-static struct Font *
-cho_font_new(void)
-{
- struct Font *font = emalloc(sizeof(struct Font));
- font->name = NULL;
- font->family = FF_NORMAL;
- font->style = FS_ROMAN;
- font->weight = FW_REGULAR;
- font->size = DEFAULT_FONT_SIZE;
- return font;
-}
-
-struct Font *
-cho_font_copy(struct Font *font)
-{
- struct Font *copy = emalloc(sizeof(struct Font));
- if (font->name)
- copy->name = strdup(font->name);
- else
- copy->name = NULL;
- copy->family = font->family;
- copy->style = font->style;
- copy->weight = font->weight;
- copy->size = font->size;
- return copy;
-}
-
-void
-cho_font_free(struct Font *font)
-{
- if (!font) {
- return;
- }
- free(font->name);
- free(font);
-}
-
-void
-cho_fonts_free(struct Font **fonts)
-{
- if (!fonts) {
- return;
- }
- struct Font **f;
- for (f = fonts; *f; f++) {
- cho_font_free(*f);
- }
- free(fonts);
-}
-
-enum FontFamily
-cho_font_family_parse(const char *str)
-{
- if (!strcmp(str, font_families[FF_SANS])) {
- return FF_SANS;
- } else if (!strcmp(str, font_families[FF_SERIF])) {
- return FF_SERIF;
- } else if (!strcmp(str, font_families[FF_MONOSPACE])) {
- return FF_MONOSPACE;
- } else if (!strcmp(str, font_families[FF_NORMAL])) {
- return FF_NORMAL;
- } else {
- return -1;
- }
-}
-
-const char *
-cho_font_family_to_config_string(enum FontFamily font_family)
-{
- return font_families[font_family];
-}
-
-enum FontStyle
-cho_font_style_parse(const char *str)
-{
- if (!strcmp(str, font_styles[FS_ITALIC])) {
- return FS_ITALIC;
- } else if (!strcmp(str, font_styles[FS_OBLIQUE])) {
- return FS_OBLIQUE;
- } else if (!strcmp(str, font_styles[FS_ROMAN])) {
- return FS_ROMAN;
- } else {
- return -1;
- }
-}
-
-const char *
-cho_font_style_to_config_string(enum FontStyle style)
-{
- return font_styles[style];
-}
-
-enum FontWeight
-cho_font_weight_parse(const char *str)
-{
- if (!strcmp(str, "bold")) {
- return FW_BOLD;
- } else if (!strcmp(str, "normal")) {
- return FW_REGULAR;
- } else {
- return -1;
- }
-}
-
-const char *
-cho_font_weight_to_config_string(enum FontWeight weight)
-{
- return font_weights[weight];
-}
-
-static void
-cho_font_print_as_toml(struct Font *font, const char *section)
-{
- printf("[output.styles.%s.font]\n", section);
- printf("name = \"%s\"\n", font->name);
- printf("family = \"%s\"\n", cho_font_family_to_config_string(font->family));
- printf("style = \"%s\"\n", cho_font_style_to_config_string(font->style));
- printf("weight = \"%s\"\n", cho_font_weight_to_config_string(font->weight));
- printf("size = %.1f\n\n", font->size);
-}
-
-void
-cho_font_print(struct Font *font)
-{
- printf("---- BEGIN FONT ----\n");
- if (font->name)
- printf("font name: %s\n", font->name);
- else
- printf("font name: NULL\n");
- printf("font family: %s\n", cho_font_family_to_config_string(font->family));
- printf("font style: %s\n", cho_font_style_to_config_string(font->style));
- printf("font weight: %s\n", cho_font_weight_to_config_string(font->weight));
- printf("font size: %f\n", font->size);
- printf("---- END FONT ------\n");
-}
-
-enum LineStyle
-cho_linestyle_parse(const char *str)
-{
- if (!strcmp(str, "single")) {
- return LS_SINGLE;
- } else if (!strcmp(str, "double")) {
- return LS_DOUBLE;
- } else if (!strcmp(str, "none")) {
- return LS_NONE;
- } else {
- return -1;
- }
-}
-
-const char *
-cho_linestyle_to_config_string(enum LineStyle linestyle)
-{
- return line_styles[linestyle];
-}
-
-#ifdef DEBUG
-
-static void
-cho_debug_the_default_style_properties(void)
-{
- unsigned int i;
- for (i = 0; i<LENGTH(default_style_properties); i++) {
- printf(
- "%s %s ",
- text_type_enums[default_style_properties[i].ttype],
- style_property_type_enums[default_style_properties[i].type]
- );
- switch (default_style_properties[i].type) {
- case SPT_FONT:
- if (default_style_properties[i].u.font_name)
- printf("%s\n", default_style_properties[i].u.font_name);
- else
- printf("NULL\n");
- break;
- case SPT_SIZE:
- printf("%.1f\n", default_style_properties[i].u.font_size);
- break;
- case SPT_COLOR:
- if (default_style_properties[i].u.foreground_color)
- printf("%s\n", cho_rgbcolor_to_string(default_style_properties[i].u.foreground_color));
- else
- printf("NULL\n");
- break;
- default:
- printf("Invalid StylePropertyType value '%d'.\n", default_style_properties[i].type);
- }
- }
-}
-
-void
-cho_debug_style_print(struct ChoStyle *style)
-{
- printf("---- BEGIN STYLE ----\n");
- cho_font_print(style->font);
- printf("foreground_color: %s\n", cho_rgbcolor_to_string(style->foreground_color));
- printf("background_color: %s\n", cho_rgbcolor_to_string(style->background_color));
- printf("underline_style: %s\n", cho_linestyle_to_config_string(style->underline_style));
- printf("underline_color: %s\n", cho_rgbcolor_to_string(style->underline_color));
- printf("overline_style: %s\n", cho_linestyle_to_config_string(style->overline_style));
- printf("overline_color: %s\n", cho_rgbcolor_to_string(style->overline_color));
- printf("strikethrough: %d\n", style->strikethrough);
- printf("strikethrough_color: %s\n", cho_rgbcolor_to_string(style->strikethrough_color));
- printf("boxed: %d\n", style->boxed);
- printf("boxed_color: %s\n", cho_rgbcolor_to_string(style->boxed_color));
- printf("rise: %f\n", style->rise);
- if (style->href)
- printf("href: %s\n", style->href);
- else
- printf("href: NULL\n");
- printf("---- END STYLE ------\n\n");
-}
-
-#endif /* DEBUG */
-
-static bool
-cho_style_property_apply_default(enum TextType current_ttype, enum StylePropertyType ptype, struct ChoStyle *style)
-{
- unsigned int i;
- for (i = 0; i<LENGTH(default_style_properties); i++) {
- if (
- default_style_properties[i].ttype == current_ttype &&
- default_style_properties[i].type == ptype
- ) {
- switch (ptype) {
- case SPT_FONT:
- if (default_style_properties[i].u.font_name) {
- free(style->font->name);
- style->font->name = strdup(default_style_properties[i].u.font_name);
- return true;
- } else {
- return false;
- }
- break;
- case SPT_SIZE:
- if (default_style_properties[i].u.font_size != EMPTY_DOUBLE) {
- style->font->size = default_style_properties[i].u.font_size;
- return true;
- } else {
- return false;
- }
- break;
- case SPT_COLOR:
- if (default_style_properties[i].u.foreground_color) {
- free(style->foreground_color);
- style->foreground_color = cho_rgbcolor_copy(default_style_properties[i].u.foreground_color);
- return true;
- } else {
- return false;
- }
- break;
- default:
- cho_log(LOG_WARN, "Invalid style property type '%d'.", ptype);
- return false;
- }
- }
- }
- return false;
-}
-
-static void
-cho_style_apply_default(enum TextType current_ttype, struct ChoStyle *style)
-{
- if (current_ttype == TT_CHORUS) {
- if (!cho_style_property_apply_default(TT_CHORUS, SPT_FONT, style)) {
- cho_style_property_apply_default(TT_TEXT, SPT_FONT, style);
- }
- if (!cho_style_property_apply_default(TT_CHORUS, SPT_SIZE, style)) {
- cho_style_property_apply_default(TT_TEXT, SPT_SIZE, style);
- }
- if (!cho_style_property_apply_default(TT_CHORUS, SPT_COLOR, style)) {
- cho_style_property_apply_default(TT_TEXT, SPT_COLOR, style);
- }
- } else {
- cho_style_property_apply_default(current_ttype, SPT_FONT, style);
- cho_style_property_apply_default(current_ttype, SPT_SIZE, style);
- cho_style_property_apply_default(current_ttype, SPT_COLOR, style);
- }
-}
-
-struct ChoStyle *
-cho_style_new(void)
-{
- struct ChoStyle *style = emalloc(sizeof(struct ChoStyle));
- style->font = cho_font_new();
- style->foreground_color = cho_rgbcolor_new(20, 20, 20);
- style->background_color = cho_rgbcolor_new(255, 255, 255);
- style->underline_style = LS_NONE;
- style->underline_color = cho_rgbcolor_new(20, 20, 20);
- style->overline_style = LS_NONE;
- style->overline_color = cho_rgbcolor_new(20, 20, 20);
- style->strikethrough = false;
- style->strikethrough_color = cho_rgbcolor_new(20, 20, 20);
- style->boxed = false;
- style->boxed_color = cho_rgbcolor_new(20, 20, 20);
- style->rise = 0.0;
- style->href = NULL;
- return style;
-}
-
-struct ChoStyle *
-cho_style_copy(struct ChoStyle *style)
-{
- struct ChoStyle *copy = emalloc(sizeof(struct ChoStyle));
- copy->font = cho_font_copy(style->font);
- copy->foreground_color = cho_rgbcolor_copy(style->foreground_color);
- copy->background_color = cho_rgbcolor_copy(style->background_color);
- copy->underline_style = style->underline_style;
- copy->underline_color = cho_rgbcolor_copy(style->underline_color);
- copy->overline_style = style->overline_style;
- copy->overline_color = cho_rgbcolor_copy(style->overline_color);
- copy->strikethrough = style->strikethrough;
- copy->strikethrough_color = cho_rgbcolor_copy(style->strikethrough_color);
- copy->boxed = style->boxed;
- copy->boxed_color = cho_rgbcolor_copy(style->boxed_color);
- copy->rise = style->rise;
- copy->href = style->href ? strdup(style->href) : NULL;
- return copy;
-}
-
-static void
-cho_style_complement(
- struct ChoStyle *old,
- struct ChoStyle *new,
- struct ChoStylePresence *presence
-)
-{
- if (presence->font.name) {
- free(old->font->name);
- old->font->name = strdup(new->font->name);
- }
- if (presence->font.family) {
- old->font->family = new->font->family;
- }
- if (presence->font.style) {
- old->font->style = new->font->style;
- }
- if (presence->font.weight) {
- old->font->weight = new->font->weight;
- }
- if (presence->font.size) {
- old->font->size = new->font->size;
- }
- if (presence->foreground_color) {
- free(old->foreground_color);
- old->foreground_color = cho_rgbcolor_copy(new->foreground_color);
- }
- if (presence->background_color) {
- free(old->background_color);
- old->background_color = cho_rgbcolor_copy(new->background_color);
- }
- if (presence->underline_style) {
- old->underline_style = new->underline_style;
- }
- if (presence->underline_color) {
- free(old->underline_color);
- old->underline_color = cho_rgbcolor_copy(new->underline_color);
- }
- if (presence->overline_style) {
- old->overline_style = new->overline_style;
- }
- if (presence->overline_color) {
- free(old->overline_color);
- old->overline_color = cho_rgbcolor_copy(new->overline_color);
- }
- if (presence->strikethrough) {
- old->strikethrough = new->strikethrough;
- }
- if (presence->strikethrough_color) {
- free(old->strikethrough_color);
- old->strikethrough_color = cho_rgbcolor_copy(new->strikethrough_color);
- }
- if (presence->boxed) {
- old->boxed = new->boxed;
- }
- if (presence->boxed_color) {
- free(old->boxed_color);
- old->boxed_color = cho_rgbcolor_copy(new->boxed_color);
- }
- if (presence->rise) {
- old->rise = new->rise;
- }
- if (presence->href) {
- free(old->href);
- old->href = strdup(new->href);
- }
-}
-
-static struct ChoStyle *
-cho_style_new_from_config(enum TextType ttype)
-{
- return cho_style_copy(g_config->output->styles[ttype]);
-}
-
-static struct ChoStyle *
-cho_style_new_default(void)
-{
- struct ChoStyle *style = cho_style_new_from_config(g_current_ttype);
- if (!style) {
- LOG_DEBUG("cho_style_new_from_config failed.");
- return NULL;
- }
- cho_style_apply_default(g_current_ttype, style);
- return style;
-}
-
-void
-cho_style_free(struct ChoStyle *style)
-{
- if (!style) {
- return;
- }
- cho_font_free(style->font);
- free(style->foreground_color);
- free(style->background_color);
- free(style->underline_color);
- free(style->overline_color);
- free(style->strikethrough_color);
- free(style->boxed_color);
- free(style->href);
- free(style);
-}
-
-static struct Font *
-cho_style_font_desc_parse(const char *str, struct ChoStylePresence *presence)
-{
- if (strlen(str) == 0) {
- return NULL;
- }
- struct Font *font = cho_font_new();
- double size = -1.0;
- char **words = emalloc(sizeof(char *));
- int w = 0;
- words[w] = NULL;
- int k = 0;
- int i;
- for (i = 0; str[i]; i++) {
- if (str[i] == ' ') {
- words[w] = erealloc(words[w], (k+1) * sizeof(char));
- words[w][k] = 0;
- if (strlen(words[w]) == 0) {
- free(words[w]);
- } else {
- w++;
- }
- k = 0;
- words = erealloc(words, (w+1) * sizeof(char *));
- words[w] = NULL;
- } else {
- words[w] = erealloc(words[w], (k+1) * sizeof(char));
- words[w][k] = str[i];
- k++;
- }
- }
- words[w] = erealloc(words[w], (k+1) * sizeof(char));
- words[w][k] = 0;
- w++;
- words = erealloc(words, (w+1) * sizeof(char *));
- words[w] = NULL;
- int stop_at = EMPTY_INT;
- for (w = 0; words[w]; w++) {
- if (strcasecmp(words[w], "italic") == 0) {
- font->style = FS_ITALIC;
- presence->font.style = true;
- if (stop_at == EMPTY_INT) {
- stop_at = w;
- }
- } else if (strcasecmp(words[w], "bold") == 0) {
- font->weight = FW_BOLD;
- presence->font.weight = true;
- if (stop_at == EMPTY_INT) {
- stop_at = w;
- }
- } else if (strcasecmp(words[w], "oblique") == 0) {
- font->style = FS_OBLIQUE;
- presence->font.style = true;
- if (stop_at == EMPTY_INT) {
- stop_at = w;
- }
- // TODO: Is that smart?
- } else if (strcasecmp(words[w], "regular") == 0) {
- font->weight = FW_REGULAR;
- presence->font.weight = true;
- if (stop_at == EMPTY_INT) {
- stop_at = w;
- }
- // TODO: Is that smart?
- } else if (strcasecmp(words[w], "normal") == 0) {
- font->style = FS_ROMAN;
- presence->font.style = true;
- if (stop_at == EMPTY_INT) {
- stop_at = w;
- }
- /* Commented because the family name sometimes contains 'sans' or 'serif' */
- /* } else if (strcasecmp(words[w], "sans") == 0) {
- font->family = FF_SANS;
- if (stop_at == EMPTY_INT)
- stop_at = w;
- } else if (strcasecmp(words[w], "serif") == 0) {
- font->family = FF_SERIF;
- if (stop_at == EMPTY_INT)
- stop_at = w; */
- } else if (strcasecmp(words[w], "monospace") == 0) {
- font->family = FF_MONOSPACE;
- presence->font.family = true;
- if (stop_at == EMPTY_INT) {
- stop_at = w;
- }
- } else {
- size = strtod(words[w], NULL);
- if (size == 0.0) {
- continue;
- }
- font->size = size;
- presence->font.size = true;
- if (stop_at == EMPTY_INT) {
- stop_at = w;
- }
- }
- }
- if (stop_at == EMPTY_INT) {
- stop_at = w;
- }
- if (stop_at > 0) {
- int n = 0;
- for (i = 0; i<stop_at; i++) {
- for (k = 0; words[i][k]; n++, k++) {
- font->name = erealloc(font->name, (n+1) * sizeof(char));
- font->name[n] = words[i][k];
- }
- font->name = erealloc(font->name, (n+1) * sizeof(char));
- font->name[n] = ' ';
- n++;
- }
- n--;
- font->name[n] = 0;
- presence->font.name = true;
- }
- for (w = 0; words[w]; w++) {
- free(words[w]);
- }
- free(words);
- return font;
-}
-
-static struct ChoStyle *
-cho_style_parse(
- const char *tag_name,
- struct Attr **attrs,
- struct ChoStyle *inherited_style,
- struct ChoStylePresence *presence
-)
-{
- size_t value_len, last_char;
- struct RGBColor *rgb_color;
- struct ChoStyle *style;
- struct Font *font;
- if (inherited_style) {
- style = cho_style_copy(inherited_style);
- } else {
- style = cho_style_new_default();
- }
- if (!strcmp(tag_name, "span")) {
- int a;
- for (a = 0; attrs[a]; a++) {
- if (!strcmp(attrs[a]->name, "font_desc")) {
- font = cho_style_font_desc_parse(attrs[a]->value, presence);
- if (font) {
- if (!font->name) {
- font->name = strdup(style->font->name);
- }
- cho_font_free(style->font);
- style->font = font;
- }
- } else if (
- !strcmp(attrs[a]->name, "font_family") ||
- !strcmp(attrs[a]->name, "face")
- ) {
- if (!strcmp(attrs[a]->value, "normal")) {
- style->font->family = FF_NORMAL;
- presence->font.family = true;
- } else if (!strcmp(attrs[a]->value, "sans")) {
- style->font->family = FF_SANS;
- presence->font.family = true;
- } else if (!strcmp(attrs[a]->value, "serif")) {
- style->font->family = FF_SERIF;
- presence->font.family = true;
- } else if (!strcmp(attrs[a]->value, "monospace")) {
- style->font->family = FF_MONOSPACE;
- presence->font.family = true;
- } else {
- cho_log(LOG_ERR, "Invalid value in attribute 'font_family/face'.");
- return NULL;
- }
- } else if (!strcmp(attrs[a]->name, "size")) {
- value_len = strlen(attrs[a]->value);
- last_char = value_len - 1;
- if (attrs[a]->value[last_char] == '%') {
- if (value_len < 5) {
- attrs[a]->value[last_char] = 0;
- int percentage = atoi(attrs[a]->value);
- if (percentage != 0 && percentage <= 100) {
- style->font->size *= percentage / 100.0;
- presence->font.size = true;
- } else {
- cho_log(LOG_ERR, "Invalid percentage in attribute 'size'.");
- return NULL;
- }
- } else {
- cho_log(LOG_ERR, "Invalid percentage in attribute 'size'.");
- return NULL;
- }
- } else if (isdigit(attrs[a]->value[0]) != 0) {
- double size = strtod(attrs[a]->value, NULL);
- if (size != 0.0) {
- style->font->size = size;
- presence->font.size = true;
- } else {
- cho_log(LOG_ERR, "Invalid number in attribute 'size'.");
- return NULL;
- }
- } else if (!strcmp(attrs[a]->value, "xx-small")) {
- style->font->size *= 0.8;
- style->font->size *= 0.8;
- style->font->size *= 0.8;
- presence->font.size = true;
- } else if (!strcmp(attrs[a]->value, "x-small")) {
- style->font->size *= 0.8;
- style->font->size *= 0.8;
- presence->font.size = true;
- } else if (!strcmp(attrs[a]->value, "small")) {
- style->font->size *= 0.8;
- presence->font.size = true;
- // } else if (!strcmp(attrs[a]->value, "medium")) {
- } else if (!strcmp(attrs[a]->value, "large")) {
- style->font->size *= 1.8;
- presence->font.size = true;
- } else if (!strcmp(attrs[a]->value, "x-large")) {
- style->font->size *= 1.8;
- style->font->size *= 1.8;
- presence->font.size = true;
- } else if (!strcmp(attrs[a]->value, "xx-large")) {
- style->font->size *= 1.8;
- style->font->size *= 1.8;
- style->font->size *= 1.8;
- presence->font.size = true;
- } else if (!strcmp(attrs[a]->value, "larger")) {
- style->font->size *= 1.8;
- presence->font.size = true;
- } else if (!strcmp(attrs[a]->value, "smaller")) {
- style->font->size *= 0.8;
- presence->font.size = true;
- } else {
- cho_log(LOG_ERR, "Invalid value '%s' for the attribute 'size'.", attrs[a]->value);
- return NULL;
- }
- } else if (!strcmp(attrs[a]->name, "style")) {
- if (!strcmp(attrs[a]->value, "normal")) {
- style->font->style = FS_ROMAN;
- presence->font.style = true;
- } else if (!strcmp(attrs[a]->value, "oblique")) {
- style->font->style = FS_OBLIQUE;
- presence->font.style = true;
- } else if (!strcmp(attrs[a]->value, "italic")) {
- style->font->style = FS_ITALIC;
- presence->font.style = true;
- } else {
- cho_log(LOG_ERR, "Invalid value in attribute 'style'.");
- return NULL;
- }
- } else if (!strcmp(attrs[a]->name, "weight")) {
- if (!strcmp(attrs[a]->value, "normal")) {
- style->font->weight = FW_REGULAR;
- presence->font.weight = true;
- } else if (!strcmp(attrs[a]->value, "bold")) {
- style->font->weight = FW_BOLD;
- presence->font.weight = true;
- } else {
- cho_log(LOG_ERR, "Invalid value in attribute 'weight'.");
- return NULL;
- }
- } else if (!strcmp(attrs[a]->name, "foreground")) {
- rgb_color = cho_color_parse(attrs[a]->value);
- if (!rgb_color) {
- LOG_DEBUG("cho_color_parse failed.");
- return NULL;
- } else {
- free(style->foreground_color);
- style->foreground_color = rgb_color;
- presence->foreground_color = true;
- }
- } else if (!strcmp(attrs[a]->name, "background")) {
- rgb_color = cho_color_parse(attrs[a]->value);
- if (!rgb_color) {
- LOG_DEBUG("cho_color_parse failed.");
- return NULL;
- } else {
- free(style->background_color);
- style->background_color = rgb_color;
- presence->background_color = true;
- }
- } else if (!strcmp(attrs[a]->name, "underline")) {
- if (!strcmp(attrs[a]->value, "single")) {
- style->underline_style = LS_SINGLE;
- presence->underline_style = true;
- } else if (!strcmp(attrs[a]->value, "double")) {
- style->underline_style = LS_DOUBLE;
- presence->underline_style = true;
- } else if (!strcmp(attrs[a]->value, "none")) {
- style->underline_style = LS_NONE;
- presence->underline_style = true;
- } else {
- cho_log(LOG_ERR, "Invalid value in attribute 'underline'.");
- return NULL;
- }
- } else if (!strcmp(attrs[a]->name, "underline_colour")) {
- rgb_color = cho_color_parse(attrs[a]->value);
- if (!rgb_color) {
- LOG_DEBUG("cho_color_parse failed.");
- return NULL;
- } else {
- free(style->underline_color);
- style->underline_color = rgb_color;
- presence->underline_color = true;
- }
- } else if (!strcmp(attrs[a]->name, "overline")) {
- if (!strcmp(attrs[a]->value, "single")) {
- style->overline_style = LS_SINGLE;
- presence->overline_style = true;
- } else if (!strcmp(attrs[a]->value, "double")) {
- style->overline_style = LS_DOUBLE;
- presence->overline_style = true;
- } else if (!strcmp(attrs[a]->value, "none")) {
- style->overline_style = LS_NONE;
- presence->overline_style = true;
- } else {
- cho_log(LOG_ERR, "Invalid value in attribute 'overline'.");
- return NULL;
- }
- } else if (!strcmp(attrs[a]->name, "overline_colour")) {
- rgb_color = cho_color_parse(attrs[a]->value);
- if (!rgb_color) {
- LOG_DEBUG("cho_color_parse failed.");
- return NULL;
- } else {
- free(style->overline_color);
- style->overline_color = rgb_color;
- presence->overline_color = true;
- }
- } else if (!strcmp(attrs[a]->name, "rise")) {
- value_len = strlen(attrs[a]->value);
- last_char = value_len - 1;
- if (attrs[a]->value[0] == '-') {
- if (attrs[a]->value[last_char] == '%') {
- if (value_len < 6) {
- attrs[a]->value[last_char] = 0;
- int percentage = atoi(&attrs[a]->value[1]);
- if (percentage != 0 && percentage <= 100) {
- style->rise = (style->font->size / 2) * percentage / 100.0;
- presence->rise = true;
- } else {
- cho_log(LOG_ERR, "Invalid percentage in attribute 'rise'.");
- return NULL;
- }
- }
- } else if (isdigit(attrs[a]->value[1]) != 0) {
- double rise = strtod(attrs[a]->value, NULL);
- if (rise != 0.0) {
- style->rise = rise;
- presence->rise = true;
- } else {
- cho_log(LOG_ERR, "Invalid number in attribute 'rise'.");
- return NULL;
- }
- } else {
- cho_log(LOG_ERR, "Invalid value '%s' for the attribute 'rise'.", attrs[a]->value);
- return NULL;
- }
- } else {
- if (attrs[a]->value[last_char] == '%') {
- if (value_len < 5) {
- attrs[a]->value[last_char] = 0;
- int percentage = atoi(attrs[a]->value);
- if (percentage != 0 && percentage <= 100) {
- // TODO: Test if that's right
- double more = style->font->size / 2.0 * percentage / 100.0;
- style->rise += more;
- presence->rise = true;
- } else {
- cho_log(LOG_ERR, "Invalid percentage in attribute 'rise'.");
- return NULL;
- }
- }
- } else if (isdigit(attrs[a]->value[1]) != 0) {
- double rise = strtod(attrs[a]->value, NULL);
- if (rise != 0.0) {
- style->rise = rise;
- presence->rise = true;
- } else {
- cho_log(LOG_ERR, "Invalid number in attribute 'rise'.");
- return NULL;
- }
- } else {
- cho_log(LOG_ERR, "Invalid value '%s' for the attribute 'rise'.", attrs[a]->value);
- return NULL;
- }
- }
- } else if (!strcmp(attrs[a]->name, "strikethrough")) {
- if (!strcmp(attrs[a]->value, "true")) {
- style->strikethrough = true;
- presence->strikethrough = true;
- } else if (!strcmp(attrs[a]->value, "false")) {
- style->strikethrough = false;
- presence->strikethrough = true;
- } else {
- cho_log(LOG_ERR, "Invalid value '%s' in attribute 'strikethrough'.", attrs[a]->value);
- return NULL;
- }
- } else if (!strcmp(attrs[a]->name, "strikethrough_colour")) {
- rgb_color = cho_color_parse(attrs[a]->value);
- if (!rgb_color) {
- LOG_DEBUG("cho_color_parse failed.");
- return NULL;
- } else {
- free(style->strikethrough_color);
- style->strikethrough_color = rgb_color;
- presence->strikethrough_color = true;
- }
- } else if (!strcmp(attrs[a]->name, "href")) {
- style->href = strdup(attrs[a]->value);
- presence->href = true;
- } else {
- cho_log(LOG_ERR, "Invalid attribute '%s'.", attrs[a]->name);
- return NULL;
- }
- }
- } else if (!strcmp(tag_name, "b")) {
- style->font->weight = FW_BOLD;
- presence->font.weight = true;
- } else if (!strcmp(tag_name, "big")) {
- style->font->size *= 0.8;
- presence->font.size = true;
- } else if (!strcmp(tag_name, "i")) {
- style->font->style = FS_ITALIC;
- presence->font.style = true;
- } else if (!strcmp(tag_name, "s")) {
- style->strikethrough = true;
- presence->strikethrough = true;
- } else if (!strcmp(tag_name, "sub")) {
- style->font->size *= 0.8;
- style->rise = -style->font->size * 0.3;
- presence->font.size = true;
- presence->rise = true;
- } else if (!strcmp(tag_name, "sup")) {
- style->font->size *= 0.8;
- style->rise = style->font->size * 0.3;
- presence->font.size = true;
- presence->rise = true;
- } else if (!strcmp(tag_name, "small")) {
- style->font->size *= 0.8;
- presence->font.size = true;
- } else if (!strcmp(tag_name, "tt")) {
- style->font->family = FF_MONOSPACE;
- presence->font.family = true;
- } else if (!strcmp(tag_name, "u")) {
- style->underline_style = LS_SINGLE;
- presence->underline_style = true;
- } else {
- cho_log(LOG_ERR, "Invalid tag name '%s'.", tag_name);
- cho_style_free(style);
- return NULL;
- }
- return style;
-}
-
-void
-cho_style_print_as_toml(struct ChoStyle *style, const char *section)
-{
- printf("foreground_color = \"%s\"\n", cho_rgbcolor_to_string(style->foreground_color));
- printf("background_color = \"%s\"\n", cho_rgbcolor_to_string(style->background_color));
- printf("underline_style = \"%s\"\n", cho_linestyle_to_config_string(style->underline_style));
- printf("underline_color = \"%s\"\n", cho_rgbcolor_to_string(style->underline_color));
- printf("overline_style = \"%s\"\n", cho_linestyle_to_config_string(style->overline_style));
- printf("overline_color = \"%s\"\n", cho_rgbcolor_to_string(style->overline_color));
- printf("strikethrough = %s\n", style->strikethrough ? "true" : "false");
- printf("strikethrough_color = \"%s\"\n", cho_rgbcolor_to_string(style->strikethrough_color));
- printf("boxed = %s\n", style->boxed ? "true" : "false");
- printf("boxed_color = \"%s\"\n", cho_rgbcolor_to_string(style->boxed_color));
- printf("rise = %.1f\n", style->rise);
- printf("href = \"%s\"\n\n", style->href ? style->href : "");
- cho_font_print_as_toml(style->font, section);
-}
-
-static bool
-cho_style_change_default(struct StyleProperty sprop)
-{
- if (sprop.type == -1)
- return false;
- unsigned int i;
- for (i = 0; i<LENGTH(default_style_properties); i++) {
- if (
- default_style_properties[i].ttype == sprop.ttype &&
- default_style_properties[i].type == sprop.type
- ) {
- switch (sprop.type) {
- case SPT_FONT:
- free(default_style_properties[i].u.font_name);
- if (sprop.u.font_name) {
- default_style_properties[i].u.font_name = strdup(sprop.u.font_name);
- } else {
- default_style_properties[i].u.font_name = NULL;
- }
- return true;
- case SPT_SIZE:
- default_style_properties[i].u.font_size = sprop.u.font_size;
- return true;
- case SPT_COLOR:
- free(default_style_properties[i].u.foreground_color);
- if (sprop.u.foreground_color) {
- default_style_properties[i].u.foreground_color = cho_rgbcolor_copy(sprop.u.foreground_color);
- } else {
- default_style_properties[i].u.foreground_color = NULL;
- }
- return true;
- default:
- cho_log(LOG_ERR, "Invalid style property type '%d'.", sprop.type);
- return false;
- }
- }
- }
- return false;
-}
-
-static bool
-cho_style_reset_default(void)
-{
- unsigned int i;
- for (i = 0; i<LENGTH(default_style_properties); i++) {
- switch (default_style_properties[i].type) {
- case SPT_FONT:
- free(default_style_properties[i].u.font_name);
- default_style_properties[i].u.font_name = NULL;
- return true;
- case SPT_SIZE:
- default_style_properties[i].u.font_size = EMPTY_DOUBLE;
- return true;
- case SPT_COLOR:
- free(default_style_properties[i].u.foreground_color);
- default_style_properties[i].u.foreground_color = NULL;
- return true;
- default:
- cho_log(LOG_ERR, "Invalid style property type '%d'.", default_style_properties[i].type);
- return false;
- }
- }
- return false;
-}
-
-static struct Attr *
-cho_tag_attr_new(void)
-{
- struct Attr *attr = emalloc(sizeof(struct Attr));
- attr->name = NULL;
- attr->value = NULL;
- return attr;
-}
-
-static void
-cho_tag_attr_free(struct Attr *attr)
-{
- if (!attr) {
- return;
- }
- free(attr->name);
- free(attr->value);
- free(attr);
-}
-
-static void
-cho_tag_attrs_free(struct Attr **attrs)
-{
- if (!attrs) {
- return;
- }
- struct Attr **a;
- for (a = attrs; *a; a++) {
- cho_tag_attr_free(*a);
- }
- free(attrs);
-}
-
-static struct Tag *
-cho_tag_new(void)
-{
- struct Tag *tag = emalloc(sizeof(struct Tag));
- tag->name = NULL;
- tag->style = NULL;
- tag->attrs = NULL;
- tag->is_closed = false;
- memset(&tag->style_presence, 0, sizeof(tag->style_presence));
- return tag;
-}
-
-static void
-cho_tag_free(struct Tag *tag)
-{
- if (!tag) {
- return;
- }
- free(tag->name);
- if (tag->style) {
- cho_style_free(tag->style);
- }
- if (tag->attrs) {
- cho_tag_attrs_free(tag->attrs);
- }
- free(tag);
-}
-
-static bool
-cho_tag_close_last_unclosed(const char *tag_name, struct Tag **tags, int last_index)
-{
- int i;
- for (i = last_index; i >= 0; i--) {
- if (!strcmp(tags[i]->name, tag_name) && !tags[i]->is_closed) {
- tags[i]->is_closed = true;
- return true;
- }
- }
- cho_log(LOG_ERR, "Didn't find a start tag for the end tag '%s'.", tag_name);
- return false;
-}
-
-static struct ChoStyle *
-cho_tag_style_inherit(struct Tag **tags, int prev_index)
-{
- int i;
- for (i = prev_index; i >= 0; i--) {
- if (!tags[i]->is_closed) {
- return tags[i]->style;
- }
- }
- /*
- Doesn't mean there is an error.
- If no style can be inherited the
- default style should be used.
- */
- return NULL;
-}
-
-static struct ChoMetadata *
-cho_metadata_new(void)
-{
- struct ChoMetadata *meta = emalloc(sizeof(struct ChoMetadata));
- meta->name = NULL;
- meta->value = NULL;
- meta->style = cho_style_new_default();
- return meta;
-}
-
-static void
-cho_metadata_free(struct ChoMetadata *meta)
-{
- if (!meta) {
- return;
- }
- free(meta->name);
- free(meta->value);
- if (meta->style) {
- cho_style_free(meta->style);
- }
- free(meta);
-}
-
-const char *
-cho_metadata_get(struct ChoMetadata **metadata, const char *name)
-{
- int m;
- for (m = 0; metadata[m]; m++) {
- if (!strcmp(metadata[m]->name, name)) {
- return metadata[m]->value;
- }
- }
- return NULL;
-}
-
-static struct ChoMetadata *
-cho_metadata_split(const char *directive_value)
-{
- struct ChoMetadata *meta = cho_metadata_new();
- bool is_name = true;
- char *value = str_remove_leading_whitespace(directive_value);
- int n = 0;
- int v = 0;
- int i;
- for (i = 0; value[i]; i++) {
- if (value[i] == ' ') {
- meta->name = erealloc(meta->name, (n+1) * sizeof(char));
- meta->name[n] = 0;
- is_name = false;
- } else {
- if (is_name) {
- meta->name = erealloc(meta->name, (n+1) * sizeof(char));
- meta->name[n] = value[i];
- n++;
- } else {
- meta->value = erealloc(meta->value, (v+1) * sizeof(char));
- meta->value[v] = value[i];
- v++;
- }
- }
- }
- meta->value = erealloc(meta->value, (v+1) * sizeof(char));
- meta->value[v] = 0;
- free(value);
- if (v > 1) {
- return meta;
- } else {
- free(meta->name);
- free(meta->value);
- free(meta);
- cho_log(LOG_ERR, "Failed to parse directive 'meta'.");
- return NULL;
- }
-}
-
-static bool
-transposition_parse(const char *str, int *transpose)
-{
- long i;
- char *endptr;
- i = strtol(str, &endptr, 10);
- if (str == endptr) {
- return false;
- }
- if (i == LONG_MIN || i == LONG_MAX) {
- return false;
- }
- if (i > INT_MAX) {
- return false;
- }
- *transpose = (int)i;
- return true;
-}
-
-static char *
-transposition_calc_chord_root(int index, enum NoteType type)
-{
- int transpose = *g_transpose;
- if (transpose == 0) {
- switch (type) {
- case NT_NOTE:
- return strdup(g_config->output->notes[index]->note);
- case NT_SHARP:
- return strdup(g_config->output->notes[index]->sharp);
- case NT_FLAT:
- return strdup(g_config->output->notes[index]->flat);
- }
- }
- int new_index = index;
- enum NoteType note_type = type;
- int i;
- if (transpose > 0) {
- for (i = 0; i<transpose; i++) {
- switch (note_type) {
- case NT_NOTE:
- switch (new_index) {
- case 2:
- new_index++;
- break;
- case 6:
- new_index = 0;
- break;
- default:
- note_type = NT_SHARP;
- }
- break;
- case NT_SHARP:
- new_index++;
- note_type = NT_NOTE;
- break;
- case NT_FLAT:
- note_type = NT_NOTE;
- break;
- }
- }
- } else {
- for (i = transpose; i<0; i++) {
- switch (note_type) {
- case NT_NOTE:
- switch (new_index) {
- case 0:
- new_index = 6;
- break;
- case 3:
- new_index--;
- break;
- default:
- note_type = NT_FLAT;
- }
- break;
- case NT_SHARP:
- note_type = NT_NOTE;
- break;
- case NT_FLAT:
- new_index--;
- note_type = NT_NOTE;
- break;
- }
- }
- }
- switch (note_type) {
- case NT_NOTE:
- return strdup(g_config->output->notes[new_index]->note);
- case NT_SHARP:
- return strdup(g_config->output->notes[new_index]->sharp);
- case NT_FLAT:
- return strdup(g_config->output->notes[new_index]->flat);
- }
- cho_log(LOG_ERR, "Invalid NoteType '%d'.", note_type);
- return NULL;
-}
-
-static struct ChoChord *
-cho_chord_new(void)
-{
- struct ChoChord *chord = emalloc(sizeof(struct ChoChord));
- chord->style = cho_style_new_default();
- chord->name = NULL;
- chord->is_canonical = false;
- chord->root = NULL;
- chord->qual = -1;
- chord->ext = NULL;
- chord->bass = NULL;
- return chord;
-}
-
-/* INFO: copy every field except for 'style' */
-static void
-cho_chord_complete(struct ChoChord *first, struct ChoChord *second)
-{
- first->name = strdup(second->name);
- first->is_canonical = second->is_canonical;
- first->qual = second->qual;
- if (second->root) {
- first->root = strdup(second->root);
- }
- if (second->ext) {
- first->ext = strdup(second->ext);
- }
- if (second->bass) {
- first->bass = strdup(second->bass);
- }
-}
-
-
-static void
-cho_chord_free(struct ChoChord *chord)
-{
- if (!chord) {
- return;
- }
- cho_style_free(chord->style);
- free(chord->name);
- free(chord->root);
- free(chord->ext);
- free(chord->bass);
- free(chord);
-}
-
-static struct ChoChord *
-cho_chord_copy(struct ChoChord *chord)
-{
- struct ChoChord *copy = emalloc(sizeof(struct ChoChord));
- copy->style = cho_style_copy(chord->style);
- copy->is_canonical = chord->is_canonical;
- copy->qual = chord->qual;
- copy->name = strdup(chord->name);
- copy->root = chord->root ? strdup(chord->root) : NULL;
- copy->ext = chord->ext ? strdup(chord->ext) : NULL;
- copy->bass = chord->bass ? strdup(chord->bass) : NULL;
- return copy;
-}
-
-bool
-cho_chords_has(struct ChoChord **chords, struct ChoChord *chord)
-{
- if (!chords) {
- return false;
- }
- struct ChoChord **c;
- for (c = chords; *c; c++) {
- if (
- !str_compare((*c)->name, chord->name) &&
- !str_compare((*c)->root, chord->root) &&
- !str_compare((*c)->ext, chord->ext) &&
- !str_compare((*c)->bass, chord->bass) &&
- (*c)->qual == chord->qual
- ) {
- return true;
- }
- }
- return false;
-}
-
-int
-cho_chord_compare(const void *a, const void *b)
-{
- struct ChoChord **aa = (struct ChoChord **)a;
- struct ChoChord **bb = (struct ChoChord **)b;
- return str_compare((*aa)->root, (*bb)->root);
-}
-
-size_t
-cho_chord_count(struct ChoChord **chords)
-{
- if (!chords) {
- return 0;
- }
- int i;
- for (i = 0; chords[i]; i++);
- return i;
-}
-
-void
-cho_chords_add(struct ChoChord ***chords, struct ChoChord *chord)
-{
- int i = 0;
- if (*chords) {
- struct ChoChord **c;
- for (c = *chords; *c; c++, i++);
- }
- *chords = erealloc(*chords, (i+2) * sizeof(struct ChoChord *));
- (*chords)[i] = cho_chord_copy(chord);
- (*chords)[i+1] = NULL;
-}
-
-void
-cho_chords_free(struct ChoChord **chords)
-{
- if (!chords) {
- return;
- }
- struct ChoChord **c;
- for (c = chords; *c; c++) {
- cho_chord_free(*c);
- }
- free(chords);
-}
-
-/* returns how many bytes make up the root; returns 0 if no root was found */
-static int
-cho_chord_root_parse(const char *str, struct ChoChord *chord)
-{
- const char *note = NULL;
- const char *sharp = NULL;
- const char *flat = NULL;
- char *transposed_root;
- int i;
- for (i = 0; i<7; i++) {
- sharp = g_config->parser->notes[i]->sharp;
- if (sharp && str_starts_with(str, sharp)) {
- transposed_root = transposition_calc_chord_root(i, NT_SHARP);
- if (!transposed_root) {
- LOG_DEBUG("transposition_calc_chord_root failed.");
- return 0;
- }
- chord->root = transposed_root;
- return strlen(sharp);
- }
- flat = g_config->parser->notes[i]->flat;
- if (flat && str_starts_with(str, flat)) {
- transposed_root = transposition_calc_chord_root(i, NT_FLAT);
- if (!transposed_root) {
- LOG_DEBUG("transposition_calc_chord_root failed.");
- return 0;
- }
- chord->root = transposed_root;
- return strlen(flat);
- }
- note = g_config->parser->notes[i]->note;
- if (str_starts_with(str, note)) {
- transposed_root = transposition_calc_chord_root(i, NT_NOTE);
- if (!transposed_root) {
- LOG_DEBUG("transposition_calc_chord_root failed.");
- return 0;
- }
- chord->root = transposed_root;
- return strlen(note);
- }
- }
- return 0;
-}
-
-static char *
-cho_chord_qualifier_strip(const char *str)
-{
- if (str_starts_with(str, "m") || str_starts_with(str, "-")) {
- return strdup((char *)&str[1]);
- }
- return strdup(str);
-}
-
-static int
-cho_chord_qualifier_and_extension_parse(const char *str, struct ChoChord *chord)
-{
- int i;
- for (i = 0; chord_extensions_major[i]; i++) {
- if (str_starts_with(str, chord_extensions_major[i])) {
- chord->ext = strdup(chord_extensions_major[i]);
- chord->qual = CQ_MAJ;
- return strlen(chord_extensions_major[i]);
- }
- }
- for (i = 0; chord_extensions_minor[i]; i++) {
- if (str_starts_with(str, chord_extensions_minor[i])) {
- chord->ext = cho_chord_qualifier_strip(chord_extensions_minor[i]);
- chord->qual = CQ_MIN;
- return strlen(chord_extensions_minor[i]);
- }
- }
- if (str_starts_with(str, "aug")) {
- chord->qual = CQ_AUG;
- return 3;
- }
- if (str_starts_with(str, "+")) {
- chord->qual = CQ_AUG;
- return 1;
- }
- if (str_starts_with(str, "dim")) {
- chord->qual = CQ_DIM;
- return 3;
- }
- if (str_starts_with(str, "0")) {
- chord->qual = CQ_DIM;
- return 1;
- }
- if (str_starts_with(str, "ø")) {
- chord->qual = CQ_DIM;
- return 1;
- }
- // TODO: What about 'ø', 'h', 'h7' and 'h9'?
- // TODO: What about extensions after 'aug', '+', 'dim', '0'?
- return 0;
-}
-
-static int
-cho_chord_bass_parse(const char *str, struct ChoChord *chord)
-{
- if (str[0] == '/') {
- const char *note = NULL;
- const char *sharp = NULL;
- const char *flat = NULL;
- const char *out_note = NULL;
- const char *out_sharp = NULL;
- const char *out_flat = NULL;
- int i;
- for (i = 0; i<7; i++) {
- sharp = g_config->parser->notes[i]->sharp;
- out_sharp = g_config->output->notes[i]->sharp;
- if (sharp && !strcmp((char *)&str[1], sharp)) {
- chord->bass = strdup(out_sharp);
- return strlen(sharp) + 1;
- }
- flat = g_config->parser->notes[i]->flat;
- out_flat = g_config->output->notes[i]->flat;
- if (flat && !strcmp((char *)&str[1], flat)) {
- chord->bass = strdup(out_flat);
- return strlen(flat) + 1;
- }
- note = g_config->parser->notes[i]->note;
- out_note = g_config->parser->notes[i]->note;
- if (!strcmp((char *)&str[1], note)) {
- chord->bass = strdup(out_note);
- return strlen(note) + 1;
- }
- }
- }
- return 0;
-}
-
-static struct ChoChord *
-cho_chord_parse(const char *str)
-{
- struct ChoChord *chord = cho_chord_new();
- size_t str_len = strlen(str);
- size_t bytes_parsed = 0;
- int ret;
- chord->name = strdup(str);
- ret = cho_chord_root_parse(str, chord);
- if (ret == 0) {
- return chord;
- }
- chord->qual = CQ_MAJ;
- bytes_parsed += ret;
- if (bytes_parsed == str_len) {
- chord->is_canonical = true;
- return chord;
- }
- ret = cho_chord_qualifier_and_extension_parse((const char *)&str[bytes_parsed], chord);
- bytes_parsed += ret;
- if (bytes_parsed == str_len) {
- chord->is_canonical = true;
- return chord;
- }
- ret = cho_chord_bass_parse((const char *)&str[bytes_parsed], chord);
- bytes_parsed += ret;
- if (bytes_parsed == str_len) {
- chord->is_canonical = true;
- return chord;
- }
- return chord;
-}
-
-char *
-cho_chord_name_generate(struct ChoChord *chord)
-{
- if (chord->is_canonical) {
- int n = 0;
- int i;
- char *name = NULL;
- size_t name_len = 0;
- name_len += strlen(chord->root);
- name = erealloc(name, name_len * sizeof(char));
- for (i = 0; chord->root[i]; i++) {
- name[n] = chord->root[i];
- n++;
- }
- const char *qual = chord_qualifiers[chord->qual];
- name_len += strlen(qual);
- name = erealloc(name, name_len * sizeof(char));
- for (i = 0; qual[i]; i++) {
- name[n] = qual[i];
- n++;
- }
- if (chord->ext) {
- name_len += strlen(chord->ext);
- name = erealloc(name, name_len * sizeof(char));
- for (i = 0; chord->ext[i]; i++) {
- name[n] = chord->ext[i];
- n++;
- }
- }
- if (chord->bass) {
- name_len++;
- name_len += strlen(chord->bass);
- name = erealloc(name, name_len * sizeof(char));
- name[n] = '/';
- n++;
- for (i = 0; chord->bass[i]; i++) {
- name[n] = chord->bass[i];
- n++;
- }
- }
- name_len++;
- name = erealloc(name, name_len * sizeof(char));
- name[n] = 0;
- return name;
- }
- return strdup(chord->name);
-}
-
-static struct ChoImage *
-cho_image_new(void)
-{
- struct ChoImage *image = emalloc(sizeof(struct ChoImage));
- image->is_asset = false;
- image->id = NULL;
- image->src = NULL;
- image->width = NULL;
- image->height = NULL;
- image->width_scale = NULL;
- image->height_scale = NULL;
- image->align = A_CENTER;
- image->border = EMPTY_DOUBLE;
- image->spread_space = NULL;
- image->href = NULL;
- image->x = NULL;
- image->y = NULL;
- image->anchor = AN_FLOAT;
- image->dx = NULL;
- image->dy = NULL;
- image->w = NULL;
- image->h = NULL;
- image->bbox = false;
- return image;
-}
-
-static void
-cho_image_free(struct ChoImage *image)
-{
- if (!image) {
- return;
- }
- free(image->id);
- free(image->src);
- free(image->width);
- free(image->height);
- free(image->width_scale);
- free(image->height_scale);
- free(image->spread_space);
- free(image->href);
- free(image->x);
- free(image->y);
- free(image->dx);
- free(image->dy);
- free(image->w);
- free(image->h);
- free(image);
-}
-
-static struct ChoImage *
-cho_image_copy(struct ChoImage *image)
-{
- struct ChoImage *copy = emalloc(sizeof(struct ChoImage));
- copy->is_asset = image->is_asset;
- copy->id = strdup(image->id);
- copy->src = strdup(image->src);
- copy->width = size_copy(image->width);
- copy->height = size_copy(image->height);
- copy->width_scale = size_copy(image->width_scale);
- copy->height_scale = size_copy(image->height_scale);
- copy->align = image->align;
- copy->border = image->border;
- copy->spread_space = size_copy(image->spread_space);
- copy->href = strdup(image->href);
- copy->x = size_copy(image->x);
- copy->y = size_copy(image->y);
- copy->anchor = image->anchor;
- copy->dx = size_copy(image->dx);
- copy->dy = size_copy(image->dy);
- copy->w = size_copy(image->w);
- copy->h = size_copy(image->h);
- copy->bbox = image->bbox;
- return copy;
-}
-
-static struct ChoImage *
-cho_image_find_asset(const char *id)
-{
- int i;
- for (i = 0; i<g_ia; i++) {
- if (!strcmp(g_image_assets[i]->id, id)) {
- return g_image_assets[i];
- }
- }
- return NULL;
-}
-
-#ifdef DEBUG
-void
-cho_debug_image_print(struct ChoImage *image)
-{
- printf("---- BEGIN IMAGE ----\n");
- printf("is_asset: %d\n", image->is_asset);
- if (image->id) {
- printf("id: %s\n", image->id);
- } else {
- printf("id: NULL\n");
- }
- if (image->src) {
- printf("src: %s\n", image->src);
- } else {
- printf("src: NULL\n");
- }
- if (image->width) {
- printf("width: %s\n", size_to_string(image->width));
- } else {
- printf("width: NULL\n");
- }
- if (image->height) {
- printf("height: %s\n", size_to_string(image->height));
- } else {
- printf("height: NULL\n");
- }
- if (image->width_scale) {
- printf("width_scale: %s\n", size_to_string(image->width_scale));
- } else {
- printf("width_scale: NULL\n");
- }
- if (image->height_scale) {
- printf("height_scale: %s\n", size_to_string(image->height_scale));
- } else {
- printf("height_scale: NULL\n");
- }
- printf("align: %s\n", alignment_enums[image->align]);
- printf("border: %.1f\n", image->border);
- if (image->spread_space) {
- printf("spread_space: %s\n", size_to_string(image->spread_space));
- } else {
- printf("spread_space: NULL\n");
- }
- if (image->href) {
- printf("href: %s\n", image->href);
- } else {
- printf("href: NULL\n");
- }
- if (image->x) {
- printf("x: %s\n", size_to_string(image->x));
- } else {
- printf("x: NULL\n");
- }
- if (image->y) {
- printf("y: %s\n", size_to_string(image->y));
- } else {
- printf("y: NULL\n");
- }
- printf("anchor: %s\n", anchor_enums[image->anchor]);
- if (image->dx) {
- printf("dx: %s\n", size_to_string(image->dx));
- } else {
- printf("dx: NULL\n");
- }
- if (image->dy) {
- printf("dy: %s\n", size_to_string(image->dy));
- } else {
- printf("dy: NULL\n");
- }
- if (image->w) {
- printf("w: %s\n", size_to_string(image->w));
- } else {
- printf("w: NULL\n");
- }
- if (image->h) {
- printf("h: %s\n", size_to_string(image->h));
- } else {
- printf("h: NULL\n");
- }
- printf("bbox: %d\n", image->bbox);
- printf("---- END IMAGE ------\n");
-}
-#endif /* DEBUG */
-
-static bool
-cho_image_option_parse(struct ChoImage *image, const char *name, const char *value)
-{
- char *endptr;
- struct Size *size;
- if (!strcmp(name, "id")) {
- image->id = strdup(value);
- } else
- if (!strcmp(name, "src")) {
- image->src = filepath_resolve_tilde(value);
- if (!image->src) {
- LOG_DEBUG("filepath_resolve_tilde failed.");
- return false;
- }
- } else
- if (!strcmp(name, "width")) {
- size = size_create(value);
- if (!size) {
- cho_log(LOG_ERR, "Invalid value in option 'width' in image directive.");
- return false;
- }
- if (size->type == ST_EM || size->type == ST_EX) {
- cho_log(LOG_ERR, "Invalid type of value in option 'width' in image directive. Allowed types are: points, percentage.");
- return false;
- }
- image->width = size;
- } else
- if (!strcmp(name, "height")) {
- size = size_create(value);
- if (!size) {
- cho_log(LOG_ERR, "Invalid value in option 'height' in image directive.");
- return false;
- }
- if (size->type == ST_EM || size->type == ST_EX) {
- cho_log(LOG_ERR, "Invalid type of value in option 'height' in image directive. Allowed types are: point, percentage.");
- return false;
- }
- image->height = size;
- } else
- if (!strcmp(name, "scale")) {
- char *comma;
- if ((comma = strchr(value, ','))) {
- *comma = 0;
- size = size_create(value);
- if (!size) {
- cho_log(LOG_ERR, "Invalid value in option 'scale' in image directive.");
- return false;
- }
- if (size->type == ST_EM || size->type == ST_EX) {
- cho_log(LOG_ERR, "Invalid type of value in option 'scale' in image directive. Allowed types are: point, percentage.");
- return false;
- }
- image->width_scale = size;
- size = size_create(++comma);
- if (!size) {
- cho_log(LOG_ERR, "Invalid value in option 'scale' in image directive.");
- return false;
- }
- if (size->type == ST_EM || size->type == ST_EX) {
- cho_log(LOG_ERR, "Invalid type of value in option 'scale' in image directive. Allowed types are: point, percentage.");
- return false;
- }
- image->height_scale = size;
- } else {
- size = size_create(value);
- if (!size) {
- cho_log(LOG_ERR, "Invalid value in option 'scale' in image directive.");
- return false;
- }
- if (size->type == ST_EM || size->type == ST_EX) {
- cho_log(LOG_ERR, "Invalid type of value in option 'scale' in image directive. Allowed types are: point, percentage.");
- return false;
- }
- image->width_scale = size;
- image->height_scale = size_copy(size);
- }
- } else
- if (!strcmp(name, "align")) {
- if (!strcmp(value, "left")) {
- image->align = A_LEFT;
- } else
- if (!strcmp(value, "right")) {
- image->align = A_RIGHT;
- } else
- if (!strcmp(value, "center")) {
- image->align = A_CENTER;
- } else {
- cho_log(LOG_ERR, "Invalid value in option 'align' in image directive.");
- return false;
- }
- } else
- if (!strcmp(name, "border")) {
- image->border = strtod(value, &endptr);
- if (value == endptr || errno == ERANGE) {
- LOG_DEBUG("strtod failed.");
- return false;
- }
- } else
- if (!strcmp(name, "spread")) {
- size = size_create(value);
- if (!size) {
- cho_log(LOG_ERR, "Invalid value in option 'spread' in image directive.");
- return false;
- }
- if (size->type == ST_EM || size->type == ST_EX) {
- cho_log(LOG_ERR, "Invalid type of value in option 'spread' in image directive. Allowed types are: point, percentage.");
- return false;
- }
- image->spread_space = size;
- } else
- if (!strcmp(name, "href")) {
- image->href = strdup(value);
- } else
- if (!strcmp(name, "x")) {
- size = size_create(value);
- if (!size) {
- cho_log(LOG_ERR, "Invalid value in option 'x' in image directive.");
- return false;
- }
- if (size->type == ST_EM || size->type == ST_EX) {
- cho_log(LOG_ERR, "Invalid type of value in option 'x' in image directive. Allowed types are: point, percentage.");
- return false;
- }
- image->x = size;
- } else
- if (!strcmp(name, "y")) {
- size = size_create(value);
- if (!size) {
- cho_log(LOG_ERR, "Invalid value in option 'y' in image directive.");
- return false;
- }
- if (size->type == ST_EM || size->type == ST_EX) {
- cho_log(LOG_ERR, "Invalid type of value in option 'y' in image directive. Allowed types are: point, percentage.");
- return false;
- }
- image->y = size;
- } else
- if (!strcmp(name, "anchor")) {
- if (!strcmp(value, "paper")) {
- image->anchor = AN_PAPER;
- } else
- if (!strcmp(value, "page")) {
- image->anchor = AN_PAGE;
- } else
- if (!strcmp(value, "column")) {
- image->anchor = AN_COLUMN;
- } else
- if (!strcmp(value, "line")) {
- image->anchor = AN_LINE;
- } else
- if (!strcmp(value, "float")) {
- image->anchor = AN_FLOAT;
- } else {
- cho_log(LOG_ERR, "Invalid value in option 'anchor' in image directive.");
- return false;
- }
- }
- return true;
-}
-
-static struct ChoImage *
-cho_image_directive_parse(const char *str)
-{
- struct ChoImage *image = cho_image_new();
- struct ChoImage *asset;
- char c;
- enum OptionState state = OS_NAME;
- enum AttrValueSyntax avs = -1;
- char name[6+1];
- char value[URL_MAX_LEN+1];
- int n = 0;
- int v = 0;
- memset(name, 0, sizeof(name));
- memset(value, 0, sizeof(value));
- int option_count = 0;
- int i;
- for (i = 0; str[i]; i++) {
- c = str[i];
- switch (state) {
- case OS_NAME:
- if (is_whitespace(c)) {
- if (n == 0) {
- break;
- } else {
- name[n] = 0;
- cho_log(LOG_ERR, "Option with name '%s' in image directive has no value.", name);
- return NULL;
- }
- }
- if (c == '=') {
- name[n] = 0;
- state = OS_VALUE;
- break;
- }
- if (n > 5) {
- cho_log(LOG_ERR, "Option name in image directive is too long.");
- return NULL;
- }
- name[n] = c;
- n++;
- break;
- case OS_VALUE:
- if (avs == -1) {
- if (is_whitespace(c)) {
- cho_log(LOG_ERR, "Whitespace character after equals sign in image directive is invalid.");
- return NULL;
- }
- if (c == '\'') {
- avs = AVS_APOSTROPHE;
- } else if (c == '"') {
- avs = AVS_QUOTATION_MARK;
- } else {
- avs = AVS_UNQUOTED;
- value[v] = c;
- v++;
- }
- break;
- }
- if (c == '\n') {
- cho_log(LOG_ERR, "Newline character inside an option value in image directive is invalid.");
- return NULL;
- }
- if (
- (avs == AVS_APOSTROPHE && c == '\'') ||
- (avs == AVS_QUOTATION_MARK && c == '"') ||
- (avs == AVS_UNQUOTED && (c == ' ' || c == '\t'))
- ) {
- value[v] = 0;
- if (!cho_image_option_parse(image, name, value)) {
- LOG_DEBUG("cho_image_option_check failed.");
- return NULL;
- }
- option_count++;
- memset(name, 0, n);
- memset(value, 0, v);
- n = 0;
- v = 0;
- avs = -1;
- state = OS_NAME;
- break;
- }
- value[v] = c;
- v++;
- break;
- }
- }
- if (avs == AVS_UNQUOTED) {
- value[v] = 0;
- if (!cho_image_option_parse(image, name, value)) {
- LOG_DEBUG("cho_image_option_check failed.");
- return NULL;
- }
- option_count++;
- }
- if (image->id) {
- if (image->src) {
- if (option_count > 2) {
- cho_log(LOG_ERR, "Defining an image asset disallows any options other than 'id' and 'src'.");
- return NULL;
- }
- image->is_asset = true;
- } else {
- asset = cho_image_find_asset(image->id);
- if (!asset) {
- cho_log(LOG_ERR, "There is no image asset with the id '%s'.", image->id);
- return NULL;
- }
- image->src = strdup(asset->src);
- }
- }
- return image;
-}
-
-static struct ChoImage *
-cho_image_tag_parse(struct Attr **attrs)
-{
- struct ChoImage *image = cho_image_new();
- struct ChoImage *asset;
- struct Size *size;
- int a;
- for (a = 0; attrs[a]; a++) {
- if (!strcmp(attrs[a]->name, "src")) {
- image->src = filepath_resolve_tilde(attrs[a]->value);
- if (!image->src) {
- LOG_DEBUG("filepath_resolve_tilde failed.");
- return NULL;
- }
- } else
- if (!strcmp(attrs[a]->name, "id")) {
- image->id = strdup(attrs[a]->value);
- } else
- if (!strcmp(attrs[a]->name, "width")) {
- size = size_create(attrs[a]->value);
- if (!size) {
- cho_log(LOG_ERR, "Invalid value in attribute 'width' in 'img' tag.");
- return NULL;
- }
- if (size->type == ST_PERCENT) {
- cho_log(LOG_ERR, "Invalid type of value in attribute 'width' in 'img' tag. Allowed types are: point, em, ex.");
- return NULL;
- }
- image->width = size;
- } else
- if (!strcmp(attrs[a]->name, "height")) {
- size = size_create(attrs[a]->value);
- if (!size) {
- cho_log(LOG_ERR, "Invalid value in attribute 'height' in 'img' tag.");
- return NULL;
- }
- if (size->type == ST_PERCENT) {
- cho_log(LOG_ERR, "Invalid type of value in attribute 'height' in 'img' tag. Allowed types are: point, em, ex.");
- return NULL;
- }
- image->height = size;
- } else
- if (!strcmp(attrs[a]->name, "dx")) {
- size = size_create(attrs[a]->value);
- if (!size) {
- cho_log(LOG_ERR, "Invalid value in attribute 'dx' in 'img' tag.");
- return NULL;
- }
- if (size->type == ST_PERCENT) {
- cho_log(LOG_ERR, "Invalid type of value in attribute 'dx' in 'img' tag. Allowed types are: point, em, ex.");
- return NULL;
- }
- image->dx = size;
- } else
- if (!strcmp(attrs[a]->name, "dy")) {
- size = size_create(attrs[a]->value);
- if (!size) {
- cho_log(LOG_ERR, "Invalid value in attribute 'dy' in 'img' tag.");
- return NULL;
- }
- if (size->type == ST_PERCENT) {
- cho_log(LOG_ERR, "Invalid type of value in attribute 'dy' in 'img' tag. Allowed types are: point, em, ex.");
- return NULL;
- }
- image->dy = size;
- } else
- if (!strcmp(attrs[a]->name, "scale")) {
- char *comma;
- if ((comma = strchr(attrs[a]->value, ','))) {
- *comma = 0;
- size = size_create(attrs[a]->value);
- if (!size) {
- cho_log(LOG_ERR, "Invalid value in attribute 'scale' in 'img' tag.");
- return NULL;
- }
- if (size->type == ST_EM || size->type == ST_EX) {
- cho_log(LOG_ERR, "Invalid type of value in attribute 'scale' in 'img' tag. Allowed types are: point, percent");
- return NULL;
- }
- image->width_scale = size;
- size = size_create(++comma);
- if (!size) {
- cho_log(LOG_ERR, "Invalid value in attribute 'scale' in 'img' tag.");
- return NULL;
- }
- if (size->type == ST_EM || size->type == ST_EX) {
- cho_log(LOG_ERR, "Invalid type of value in attribute 'scale' in 'img' tag. Allowed types are: point, percent");
- return NULL;
- }
- image->height_scale = size;
- } else {
- size = size_create(attrs[a]->value);
- if (!size) {
- cho_log(LOG_ERR, "Invalid value in attribute 'scale' in 'img' tag.");
- return NULL;
- }
- if (size->type == ST_EM || size->type == ST_EX) {
- cho_log(LOG_ERR, "Invalid type of value in attribute 'scale' in 'img' tag. Allowed types are: point, percent");
- return NULL;
- }
- image->width_scale = size;
- image->height_scale = size_copy(size);
- }
- } else
- if (!strcmp(attrs[a]->name, "align")) {
- if (!strcmp(attrs[a]->value, "left")) {
- image->align = A_LEFT;
- } else
- if (!strcmp(attrs[a]->value, "right")) {
- image->align = A_RIGHT;
- } else
- if (!strcmp(attrs[a]->value, "center")) {
- image->align = A_CENTER;
- } else {
- cho_log(LOG_ERR, "Invalid value in attribute 'align' in 'img' tag.");
- return NULL;
- }
- } else
- if (!strcmp(attrs[a]->name, "bbox")) {
- if (!strcmp(attrs[a]->value, "1")) {
- image->bbox = true;
- } else
- if (!strcmp(attrs[a]->value, "0")) {
- image->bbox = false;
- } else {
- cho_log(LOG_ERR, "Invalid value in attribute 'bbox' in 'img' tag.");
- return NULL;
- }
- } else
- if (!strcmp(attrs[a]->name, "w")) {
- size = size_create(attrs[a]->value);
- if (!size) {
- cho_log(LOG_ERR, "Invalid value in attribute 'w' in 'img' tag.");
- return NULL;
- }
- if (size->type != ST_POINT) {
- cho_log(LOG_ERR, "Invalid type of value in attribute 'w' in 'img' tag. Allowed type is: point");
- return NULL;
- }
- image->w = size;
- } else
- if (!strcmp(attrs[a]->name, "h")) {
- size = size_create(attrs[a]->value);
- if (!size) {
- cho_log(LOG_ERR, "Invalid value in attribute 'h' in 'img' tag.");
- return NULL;
- }
- if (size->type != ST_POINT) {
- cho_log(LOG_ERR, "Invalid type of value in attribute 'h' in 'img' tag. Allowed type is: point");
- return NULL;
- }
- image->h = size;
- } else {
- cho_log(LOG_ERR, "Invalid attribute '%s' in 'img' tag.", attrs[a]->name);
- return NULL;
- }
- }
- if (image->id) {
- if (image->src) {
- cho_log(LOG_ERR, "'img' tag can't have both attributes 'id' and 'src' at the same time.");
- return NULL;
- } else {
- asset = cho_image_find_asset(image->id);
- if (!asset) {
- cho_log(LOG_ERR, "There is no image asset with the id '%s'.", image->id);
- return NULL;
- }
- image->src = strdup(asset->src);
- }
- } else {
- if (!image->src) {
- cho_log(LOG_ERR, "'img' tag has to have at least either the attribute 'id' or 'src'.");
- return NULL;
- }
- }
- return image;
-}
-
-static int8_t
-char_to_positive_int(char c)
-{
- if (c >= '0' && c <= '9') {
- return c - 48;
- }
- return -1;
-}
-
-static int8_t
-finger_to_int(char c)
-{
- if (c == '-' || c == 'x' || c == 'X' || c == 'N') {
- return -1;
- }
- if (c >= '0' && c <= '9') {
- return c - 48;
- }
- if (c >= 'A' && c <= 'Z') {
- return c - 64;
- }
- return -2;
-}
-
-static struct ChordDiagram *
-cho_chord_diagram_parse(
- const char *str,
- struct ChordDiagram **custom_diagrams,
- int custom_diagrams_len
-)
-{
- struct ChordDiagram *diagram = chord_diagram_new();
- enum ChordDiagramState state = CDS_NAME;
- enum ChordDiagramContent current_content = -1;
- enum ChordDiagramContent future_content = -1;
- bool is_maybe_minus_one = false;
- char name[20];
- char option[10];
- char key[3];
- char base_fret[3];
- char diagram_value[7+1];
- char chord_to_copy[20];
- int i = 0;
- int f = 0;
- int fret_count = 0;
- int finger_count = 0;
- int8_t number = -2;
- long l;
- const char *c;
- for (c = str; *c; c++) {
- // printf("c '%c' state '%d'\n", c, state);
- switch (state) {
- case CDS_NAME: {
- if (is_whitespace(*c)) {
- if (i == 0) {
- break;
- }
- name[i] = 0;
- i = 0;
- state = CDS_OPTION_NAME;
- break;
- }
- if (i > 18) {
- cho_log(LOG_ERR, "Chord name in chord diagram is too long.");
- return NULL;
- }
- name[i] = *c;
- i++;
- break;
- }
- case CDS_OPTION_NAME: {
- if (is_whitespace(*c)) {
- if (i == 0) {
- break;
- }
- option[i] = 0;
- future_content = -1;
- if (!strcmp(option, "base-fret")) {
- state = CDS_BASE_FRET;
- future_content = CDC_STRING;
- } else
- if (!strcmp(option, "frets")) {
- state = CDS_FRETS;
- future_content = CDC_STRING;
- } else
- if (!strcmp(option, "fingers")) {
- state = CDS_FINGERS;
- future_content = CDC_STRING;
- } else
- if (!strcmp(option, "keys")) {
- state = CDS_KEYS;
- future_content = CDC_KEYBOARD;
- } else
- if (!strcmp(option, "diagram")) {
- state = CDS_DIAGRAM;
- } else
- if (!strcmp(option, "copy")) {
- state = CDS_COPY;
- } else {
- cho_log(LOG_ERR, "Invalid option '%s' in define directive.", option);
- return NULL;
- }
- memset(option, 0, i);
- i = 0;
- if (current_content == -1 && future_content != -1) {
- current_content = future_content;
- switch (future_content) {
- case CDC_STRING:
- diagram->is_string_instrument = true;
- diagram->u.sd = string_diagram_new();
- diagram->u.sd->name = strdup(name);
- break;
- case CDC_KEYBOARD:
- diagram->is_string_instrument = false;
- diagram->u.kd = keyboard_diagram_new();
- diagram->u.kd->name = strdup(name);
- break;
- default:
- cho_log(LOG_ERR, "'future_content' cannot be empty at this point.\n");
- }
- }
- break;
- }
- if (i > 8) {
- cho_log(LOG_ERR, "Option in chord diagram is too long.");
- return NULL;
- }
- option[i] = *c;
- i++;
- break;
- }
- case CDS_BASE_FRET: {
- if (is_whitespace(*c)) {
- if (i == 0) {
- break;
- }
- base_fret[i] = 0;
- i = 0;
- l = str_to_number(base_fret);
- if (l == -1) {
- LOG_DEBUG("str_to_number failed.");
- cho_log(LOG_ERR, "Invalid base-fret value '%s' in chord diagram.", base_fret);
- return NULL;
- }
- if (l == 0) {
- cho_log(LOG_ERR, "Invalid base-fret value '%c' in chord diagram.", *c);
- return NULL;
- }
- printf("base-fret %d\n", (int8_t)l);
- diagram->u.sd->base_fret = (int8_t)l;
- state = CDS_OPTION_NAME;
- break;
- }
- if (i > 1) {
- cho_log(LOG_ERR, "base-fret value is too long.");
- printf("c: %c\n", *c);
- return NULL;
- }
- printf("parsing base-fret '%c'\n", *c);
- base_fret[i] = *c;
- i++;
- break;
- }
- case CDS_FRETS: {
- number = -2;
- if (is_whitespace(*c)) {
- break;
- }
- if (*c == '-') {
- is_maybe_minus_one = true;
- break;
- }
- if (is_maybe_minus_one) {
- if (*c == '1') {
- number = -1;
- is_maybe_minus_one = false;
- } else {
- cho_log(LOG_ERR, "Invalid frets value '-%c' in chord diagram.", *c);
- return NULL;
- }
- }
- if (*c == 'N' || *c == 'x') {
- number = -1;
- } else
- if (isalpha(*c)) {
- f = 0;
- state = CDS_OPTION_NAME;
- c--;
- break;
- }
- if (number == -2) {
- number = char_to_positive_int(*c);
- if (number == -1) {
- LOG_DEBUG("char_to_positive_int failed.");
- cho_log(LOG_ERR, "Invalid frets value '%c' in chord diagram.", *c);
- return NULL;
- }
- }
- if (f > 11) {
- cho_log(LOG_ERR, "Too many fret values in chord diagram.");
- return NULL;
- }
- diagram->u.sd->frets[f] = number;
- f++;
- fret_count++;
- break;
- }
- case CDS_FINGERS: {
- if (is_whitespace(*c)) {
- break;
- }
- if (*c == 'b' || *c == 'f') {
- f = 0;
- state = CDS_OPTION_NAME;
- c--;
- break;
- }
- number = finger_to_int(*c);
- if (number == -2) {
- cho_log(LOG_ERR, "Invalid fingers value '%c' in chord diagram.", *c);
- return NULL;
- }
- if (f > 11) {
- cho_log(LOG_ERR, "Too many finger values in chord diagram.");
- return NULL;
- }
- diagram->u.sd->fingers[f] = number;
- f++;
- finger_count++;
- break;
- }
- case CDS_KEYS: {
- if (is_whitespace(*c)) {
- if (i == 0) {
- break;
- }
- key[i] = 0;
- i = 0;
- l = str_to_number(key);
- if (l == -1) {
- LOG_DEBUG("str_to_number failed.");
- cho_log(LOG_ERR, "Invalid number in keys in chord diagram.");
- return NULL;
- }
- if (f > 23) {
- cho_log(LOG_ERR, "Too many key values in chord diagram.");
- return NULL;
- }
- diagram->u.kd->keys[f] = (int8_t)l;
- f++;
- break;
- }
- if (isalpha(*c)) {
- state = CDS_OPTION_NAME;
- c--;
- break;
- }
- if (i > 1) {
- cho_log(LOG_ERR, "Too high key value in chord diagram. '%d'", i);
- printf("key '%s'\n", key);
- return NULL;
- }
- key[i] = *c;
- i++;
- break;
- }
- case CDS_DIAGRAM: {
- if (is_whitespace(*c)) {
- if (i == 0) {
- break;
- }
- diagram_value[i] = 0;
- i = 0;
- if (!strcmp(diagram_value, "off")) {
- diagram->show = false;
- } else
- if (!strcmp(diagram_value, "on")) {
- // INFO: but this is already the default
- diagram->show = true;
- } else {
- diagram->color = cho_color_parse(diagram_value);
- if (!diagram->color) {
- LOG_DEBUG("cho_color_parse failed.");
- return NULL;
- }
- }
- state = CDS_OPTION_NAME;
- break;
- }
- diagram_value[i] = *c;
- i++;
- break;
- }
- case CDS_COPY: {
- if (is_whitespace(*c)) {
- if (i == 0) {
- break;
- }
- chord_to_copy[i] = 0;
- if (current_content != -1) {
- cho_log(LOG_ERR, "The define options 'base-fret', 'frets', 'fingers' and 'keys' are not allowed before the 'copy' option.");
- return NULL;
- }
- enum Instrument ins = g_config->output->diagram->instrument;
- current_content = chord_diagram_duplicate(diagram, custom_diagrams, custom_diagrams_len, name, chord_to_copy, ins);
- if (current_content == -1) {
- cho_log(LOG_ERR, "Can't copy the diagram for the chord '%s'"
- "because no previous definition was found and also"
- "no predefined chord diagram for the instrument '%s'"
- "was found.", chord_to_copy, instruments[ins]);
- return NULL;
- }
- i = 0;
- state = CDS_OPTION_NAME;
- break;
- }
- chord_to_copy[i] = *c;
- i++;
- break;
- }
- }
- }
- switch (state) {
- case CDS_BASE_FRET: {
- base_fret[i] = 0;
- i = 0;
- l = str_to_number(base_fret);
- if (l == -1) {
- LOG_DEBUG("str_to_number failed.");
- cho_log(LOG_ERR, "Invalid base-fret value '%s' in chord diagram.", base_fret);
- return NULL;
- }
- if (l == 0) {
- cho_log(LOG_ERR, "Invalid base-fret value '%c' in chord diagram.", *c);
- return NULL;
- }
- diagram->u.sd->base_fret = (int8_t)l;
- break;
- }
- case CDS_KEYS: {
- key[i] = 0;
- if (strlen(key) > 0) {
- l = str_to_number(key);
- if (l == -1) {
- LOG_DEBUG("str_to_number failed.");
- cho_log(LOG_ERR, "Invalid number in keys in chord diagram.");
- return NULL;
- }
- if (f > 23) {
- cho_log(LOG_ERR, "Too many key values in chord diagram.");
- return NULL;
- }
- diagram->u.kd->keys[f] = (int8_t)l;
- }
- break;
- }
- case CDS_DIAGRAM: {
- diagram_value[i] = 0;
- if (!strcmp(diagram_value, "off")) {
- diagram->show = false;
- } else
- if (!strcmp(diagram_value, "on")) {
- // INFO: but this is already the default
- diagram->show = true;
- } else {
- free(diagram->color);
- diagram->color = cho_color_parse(diagram_value);
- if (!diagram->color) {
- LOG_DEBUG("cho_color_parse failed.");
- return NULL;
- }
- }
- break;
- }
- case CDS_COPY: {
- chord_to_copy[i] = 0;
- if (current_content != -1) {
- cho_log(LOG_ERR, "The define options 'base-fret', 'frets',"
- "'fingers' and 'keys' are not allowed before the 'copy'"
- "option.");
- return NULL;
- }
- enum Instrument ins = g_config->output->diagram->instrument;
- current_content = chord_diagram_duplicate(diagram, custom_diagrams, custom_diagrams_len, name, chord_to_copy, ins);
- if (current_content == -1) {
- cho_log(LOG_ERR, "Can't copy the diagram for the chord '%s' because"
- "no previous definition was found and also no predefined"
- "chord diagram for the instrument '%s' was found.",
- chord_to_copy, instruments[ins]);
- return NULL;
- }
- break;
- }
- default:
- }
- if (
- current_content == CDC_STRING &&
- fret_count > 0 &&
- finger_count > 0 &&
- fret_count != finger_count
- ) {
- cho_log(LOG_ERR, "The number of frets (%d) and fingers (%d) in the chord diagram must be equal.", fret_count, finger_count);
- return NULL;
- }
- return diagram;
-}
-
-static struct ChoText *
-cho_text_new(void)
-{
- struct ChoText *text = emalloc(sizeof(struct ChoText));
- text->style = cho_style_new_default();
- text->text = NULL;
- return text;
-}
-
-static void
-cho_text_free(struct ChoText *text)
-{
- if (!text) {
- return;
- }
- cho_style_free(text->style);
- free(text->text);
- free(text);
-}
-
-static struct ChoText *
-cho_text_copy(struct ChoText *text)
-{
- struct ChoText *copy = emalloc(sizeof(struct ChoText));
- copy->style = cho_style_copy(text->style);
- copy->text = strdup(text->text);
- return copy;
-}
-
-static void
-cho_text_above_free(struct ChoLineItemAbove *text_above)
-{
- if (!text_above) {
- return;
- }
- if (text_above->is_chord) {
- cho_chord_free(text_above->u.chord);
- } else {
- cho_text_free(text_above->u.annot);
- }
- free(text_above);
-}
-
-static struct ChoLineItemAbove *
-cho_text_above_copy(struct ChoLineItemAbove *text_above)
-{
- struct ChoLineItemAbove *copy = emalloc(sizeof(struct ChoLineItemAbove));
- copy->position = text_above->position;
- copy->is_chord = text_above->is_chord;
- if (copy->is_chord) {
- copy->u.chord = cho_chord_copy(text_above->u.chord);
- } else {
- copy->u.annot = cho_text_copy(text_above->u.annot);
- }
- return copy;
-}
-
-static struct ChoLineItem *
-cho_line_item_new(void)
-{
- struct ChoLineItem *item = emalloc(sizeof(struct ChoLineItem));
- item->is_text = true;
- item->u.text = cho_text_new();
- return item;
-}
-
-static void
-cho_line_item_free(struct ChoLineItem *item)
-{
- if (!item) {
- return;
- }
- if (item->is_text) {
- cho_text_free(item->u.text);
- } else {
- if (item->u.image) {
- cho_image_free(item->u.image);
- }
- }
- free(item);
-}
-
-static struct ChoLineItem *
-cho_line_item_copy(struct ChoLineItem *item)
-{
- struct ChoLineItem *copy = emalloc(sizeof(struct ChoLineItem));
- if (item->is_text) {
- copy->is_text = true;
- copy->u.text = cho_text_copy(item->u.text);
- } else {
- copy->is_text = false;
- copy->u.image = cho_image_copy(item->u.image);
- }
- return copy;
-}
-
-static struct ChoLine *
-cho_line_new(void)
-{
- struct ChoLine *line = emalloc(sizeof(struct ChoLine));
- line->text_above = NULL;
- line->items = NULL;
- line->btype = BT_LINE;
- return line;
-}
-
-static void
-cho_line_free(struct ChoLine *line)
-{
- if (!line) {
- return;
- }
- struct ChoLineItem **it;
- for (it = line->items; *it; it++) {
- cho_line_item_free(*it);
- }
- struct ChoLineItemAbove **above;
- for (above = line->text_above; *above; above++) {
- cho_text_above_free(*above);
- }
- free(line->items);
- free(line->text_above);
- free(line);
-}
-
-static int
-cho_line_compute_text_above_position(struct ChoLine *line, int ly, int te)
-{
- if (ly == 0) {
- return te;
- }
- size_t lyrics_len = 0;
- int i;
- for (i = ly-1; i >= 0; i--) {
- if (line->items[i]->is_text) {
- lyrics_len += strlen(line->items[i]->u.text->text);
- }
- }
- return lyrics_len + te;
-}
-
-static struct ChoSection *
-cho_section_new(void)
-{
- struct ChoSection *section = emalloc(sizeof(struct ChoSection));
- section->type = -1;
- section->label = NULL;
- section->lines = NULL;
- return section;
-}
-
-static void
-cho_section_free(struct ChoSection *section)
-{
- if (!section) {
- return;
- }
- if (section->label) {
- cho_text_free(section->label);
- }
- struct ChoLine **li;
- for (li = section->lines; *li; li++) {
- cho_line_free(*li);
- }
- free(section->lines);
- free(section);
-}
-
-static struct ChoSection *
-cho_section_copy(struct ChoSection *section)
-{
- struct ChoSection *copy = emalloc(sizeof(struct ChoSection));
- copy->type = section->type;
- if (section->label) {
- copy->label = cho_text_copy(section->label);
- } else {
- copy->label = NULL;
- }
- copy->lines = NULL;
- int li, c, ly;
- for (li = 0; section->lines[li]; li++) {
- copy->lines = erealloc(copy->lines, (li+1) * sizeof(struct ChoLine *));
- copy->lines[li] = cho_line_new();
- copy->lines[li]->btype = section->lines[li]->btype;
- for (c = 0; section->lines[li]->text_above[c]; c++) {
- copy->lines[li]->text_above = erealloc(copy->lines[li]->text_above, (c+1) * sizeof(struct ChoLineItemAbove *));
- copy->lines[li]->text_above[c] = cho_text_above_copy(section->lines[li]->text_above[c]);
- }
- copy->lines[li]->text_above = erealloc(copy->lines[li]->text_above, (c+1) * sizeof(struct ChoLineItemAbove *));
- copy->lines[li]->text_above[c] = NULL;
- for (ly = 0; section->lines[li]->items[ly]; ly++) {
- copy->lines[li]->items = erealloc(copy->lines[li]->items, (ly+1) * sizeof(struct ChoLineItem *));
- copy->lines[li]->items[ly] = cho_line_item_copy(section->lines[li]->items[ly]);
- }
- copy->lines[li]->items = erealloc(copy->lines[li]->items, (ly+1) * sizeof(struct ChoLineItem *));
- copy->lines[li]->items[ly] = NULL;
- }
- copy->lines = erealloc(copy->lines, (li+1) * sizeof(struct ChoLine *));
- copy->lines[li] = NULL;
- return copy;
-}
-
-static struct ChoSong *
-cho_song_new(void)
-{
- struct ChoSong *song = emalloc(sizeof(struct ChoSong));
- song->metadata = NULL;
- song->sections = NULL;
- song->diagrams = NULL;
- memset(song->present_text_types, 0, TT_LENGTH);
- return song;
-}
-
-int
-cho_song_count(struct ChoSong **songs)
-{
- int i;
- for (i = 0; songs[i]; i++);
- return i;
-}
-
-static const char *
-cho_song_get_title(struct ChoSong *song)
-{
- struct ChoMetadata **m;
- for (m = song->metadata; *m; m++) {
- if (!strcmp((*m)->name, "sorttitle")) {
- return (*m)->value;
- }
- }
- for (m = song->metadata; *m; m++) {
- if (!strcmp((*m)->name, "title")) {
- return (*m)->value;
- }
- }
- return NULL;
-}
-
-int
-cho_song_compare(const void *a, const void *b)
-{
- struct ChoSong *song;
- const char *a_title, *b_title;
- song = *(struct ChoSong **)a;
- a_title = cho_song_get_title(song);
- song = *(struct ChoSong **)b;
- b_title = cho_song_get_title(song);
- return str_compare(a_title, b_title);
-}
-
-static void
-cho_song_free(struct ChoSong *song)
-{
- if (!song) {
- return;
- }
- struct ChoMetadata **m;
- struct ChoSection **se;
- struct ChordDiagram **dia;
- for (m = song->metadata; *m; m++) {
- cho_metadata_free(*m);
- }
- for (se = song->sections; *se; se++) {
- cho_section_free(*se);
- }
- for (dia = song->diagrams; *dia; dia++) {
- chord_diagram_free(*dia);
- }
- free(song->metadata);
- free(song->sections);
- free(song->diagrams);
- free(song);
-}
-
-void
-cho_songs_free(struct ChoSong **songs)
-{
- if (!songs) {
- return;
- }
- struct ChoSong **so;
- for (so = songs; *so; so++) {
- cho_song_free(*so);
- }
- free(songs);
-}
-
-static struct ChoSection *
-cho_find_previous_chorus(struct ChoSection **sections, int se)
-{
- int i;
- for (i = se; i>=0; i--) {
- if (sections[i]->type == ST_CHORUS) {
- return sections[i];
- }
- }
- return NULL;
-}
-
-static struct ChoDirective *
-cho_directive_new(void)
-{
- struct ChoDirective *directive = emalloc(sizeof(struct ChoDirective));
- directive->dtype = -1;
- directive->stype = -1;
- directive->position = -1;
- directive->sprop = -1;
- directive->ttype = -1;
- directive->btype = -1;
- directive->meta = -1;
- directive->ctype = -1;
- directive->style = cho_style_new_default();
- return directive;
-}
-
-static void
-cho_directive_free(struct ChoDirective *directive)
-{
- if (!directive) {
- return;
- }
- cho_style_free(directive->style);
- free(directive);
-}
-
-static struct ChoDirective *
-cho_directive_parse(const char *name)
-{
- struct ChoDirective *directive = cho_directive_new();
- if (
- !strcmp(name, "start_of_chorus") ||
- !strcmp(name, "soc")
- ) {
- directive->dtype = DT_ENVIRONMENT;
- directive->position = POS_START;
- directive->stype = ST_CHORUS;
- directive->ttype = TT_CHORUS;
- return directive;
- } else if (
- !strcmp(name, "end_of_chorus") ||
- !strcmp(name, "eoc")
- ) {
- directive->dtype = DT_ENVIRONMENT;
- directive->position = POS_END;
- directive->stype = ST_CHORUS;
- directive->ttype = TT_TEXT;
- return directive;
- } else if (!strcmp(name, "chorus")) {
- directive->dtype = DT_ENVIRONMENT;
- directive->position = POS_NO;
- directive->ttype = TT_LABEL;
- return directive;
- } else if (
- !strcmp(name, "start_of_verse") ||
- !strcmp(name, "sov")
- ) {
- directive->dtype = DT_ENVIRONMENT;
- directive->position = POS_START;
- directive->stype = ST_VERSE;
- directive->ttype = TT_TEXT;
- return directive;
- } else if (
- !strcmp(name, "end_of_verse") ||
- !strcmp(name, "eov")
- ) {
- directive->dtype = DT_ENVIRONMENT;
- directive->position = POS_END;
- directive->stype = ST_VERSE;
- directive->ttype = TT_TEXT;
- return directive;
- } else if (
- !strcmp(name, "start_of_bridge") ||
- !strcmp(name, "sob")
- ) {
- directive->dtype = DT_ENVIRONMENT;
- directive->position = POS_START;
- directive->stype = ST_BRIDGE;
- directive->ttype = TT_TEXT;
- return directive;
- } else if (
- !strcmp(name, "end_of_bridge") ||
- !strcmp(name, "eob")
- ) {
- directive->dtype = DT_ENVIRONMENT;
- directive->position = POS_END;
- directive->stype = ST_BRIDGE;
- directive->ttype = TT_TEXT;
- return directive;
- } else if (
- !strcmp(name, "start_of_tab") ||
- !strcmp(name, "sot")
- ) {
- directive->dtype = DT_ENVIRONMENT;
- directive->position = POS_START;
- directive->stype = ST_TAB;
- directive->ttype = TT_TAB;
- return directive;
- } else if (
- !strcmp(name, "end_of_tab") ||
- !strcmp(name, "eot")
- ) {
- directive->dtype = DT_ENVIRONMENT;
- directive->position = POS_END;
- directive->stype = ST_TAB;
- directive->ttype = TT_TEXT;
- return directive;
- } else if (
- !strcmp(name, "start_of_grid") ||
- !strcmp(name, "sog")
- ) {
- directive->dtype = DT_ENVIRONMENT;
- directive->position = POS_START;
- directive->stype = ST_GRID;
- directive->ttype = TT_GRID;
- return directive;
- } else if (
- !strcmp(name, "end_of_grid") ||
- !strcmp(name, "eog")
- ) {
- directive->dtype = DT_ENVIRONMENT;
- directive->position = POS_END;
- directive->stype = ST_GRID;
- directive->ttype = TT_TEXT;
- return directive;
- }
- if (
- !strcmp(name, "title") ||
- !strcmp(name, "t")
- ) {
- directive->dtype = DT_METADATA;
- directive->meta = TITLE;
- cho_style_free(directive->style);
- g_prev_ttype = g_current_ttype;
- g_current_ttype = TT_TITLE;
- directive->style = cho_style_new_default();
- g_current_ttype = g_prev_ttype;
- return directive;
-
- } else if (
- !strcmp(name, "subtitle") ||
- !strcmp(name, "st")
- ) {
- directive->dtype = DT_METADATA;
- directive->meta = SUBTITLE;
- cho_style_free(directive->style);
- g_prev_ttype = g_current_ttype;
- g_current_ttype = TT_SUBTITLE;
- directive->style = cho_style_new_default();
- g_current_ttype = g_prev_ttype;
- return directive;
- }
- if (
- !strcmp(name, "sorttitle") ||
- !strcmp(name, "artist") ||
- !strcmp(name, "composer") ||
- !strcmp(name, "lyricist") ||
- !strcmp(name, "copyright") ||
- !strcmp(name, "album") ||
- !strcmp(name, "year") ||
- !strcmp(name, "key") ||
- !strcmp(name, "time") ||
- !strcmp(name, "tempo") ||
- !strcmp(name, "duration") ||
- !strcmp(name, "capo") ||
- !strcmp(name, "meta") ||
- !strcmp(name, "arranger")
- ) {
- directive->dtype = DT_METADATA;
- return directive;
- }
- if (
- !strcmp(name, "comment") ||
- !strcmp(name, "c") ||
- !strcmp(name, "highlight")
- ) {
- directive->dtype = DT_FORMATTING;
- g_prev_ttype = g_current_ttype;
- g_current_ttype = TT_COMMENT;
- cho_style_free(directive->style);
- directive->style = cho_style_new_default();
- g_current_ttype = g_prev_ttype;
- directive->ttype = TT_COMMENT;
- return directive;
- } else if (
- !strcmp(name, "comment_italic") ||
- !strcmp(name, "ci")
- ) {
- directive->dtype = DT_FORMATTING;
- g_prev_ttype = g_current_ttype;
- g_current_ttype = TT_COMMENT_ITALIC;
- cho_style_free(directive->style);
- directive->style = cho_style_new_default();
- g_current_ttype = g_prev_ttype;
- directive->ttype = TT_COMMENT_ITALIC;
- return directive;
- } else if (
- !strcmp(name, "comment_box") ||
- !strcmp(name, "cb")
- ) {
- directive->dtype = DT_FORMATTING;
- g_prev_ttype = g_current_ttype;
- g_current_ttype = TT_COMMENT_BOX;
- cho_style_free(directive->style);
- directive->style = cho_style_new_default();
- g_current_ttype = g_prev_ttype;
- directive->ttype = TT_COMMENT_BOX;
- return directive;
- }
- if (!strcmp(name, "image")) {
- directive->dtype = DT_IMAGE;
- return directive;
- }
- if (
- !strcmp(name, "new_song") ||
- !strcmp(name, "ns")
- ) {
- directive->dtype = DT_PREAMBLE;
- directive->stype = ST_NEWSONG;
- return directive;
- }
- if (
- !strcmp(name, "chordfont") ||
- !strcmp(name, "cf")
- ) {
- directive->dtype = DT_FONT;
- directive->sprop = SPT_FONT;
- directive->ttype = TT_CHORD;
- return directive;
- } else if (
- !strcmp(name, "chordsize") ||
- !strcmp(name, "cs")
- ) {
- directive->dtype = DT_FONT;
- directive->sprop = SPT_SIZE;
- directive->ttype = TT_CHORD;
- return directive;
- } else if (!strcmp(name, "chordcolour")) {
- directive->dtype = DT_FONT;
- directive->sprop = SPT_COLOR;
- directive->ttype = TT_CHORD;
- return directive;
- } else if (!strcmp(name, "chorusfont")) {
- directive->dtype = DT_FONT;
- directive->sprop = SPT_FONT;
- directive->ttype = TT_CHORUS;
- return directive;
- } else if (!strcmp(name, "chorussize")) {
- directive->dtype = DT_FONT;
- directive->sprop = SPT_SIZE;
- directive->ttype = TT_CHORUS;
- return directive;
- } else if (!strcmp(name, "choruscolour")) {
- directive->dtype = DT_FONT;
- directive->sprop = SPT_COLOR;
- directive->ttype = TT_CHORUS;
- return directive;
- } else if (!strcmp(name, "gridfont")) {
- directive->dtype = DT_FONT;
- directive->sprop = SPT_FONT;
- directive->ttype = TT_GRID;
- return directive;
- } else if (!strcmp(name, "gridsize")) {
- directive->dtype = DT_FONT;
- directive->sprop = SPT_SIZE;
- directive->ttype = TT_GRID;
- return directive;
- } else if (!strcmp(name, "gridcolour")) {
- directive->dtype = DT_FONT;
- directive->sprop = SPT_COLOR;
- directive->ttype = TT_GRID;
- return directive;
- } else if (!strcmp(name, "tabfont")) {
- directive->dtype = DT_FONT;
- directive->sprop = SPT_FONT;
- directive->ttype = TT_TAB;
- return directive;
- } else if (!strcmp(name, "tabsize")) {
- directive->dtype = DT_FONT;
- directive->sprop = SPT_SIZE;
- directive->ttype = TT_TAB;
- return directive;
- } else if (!strcmp(name, "tabcolour")) {
- directive->dtype = DT_FONT;
- directive->sprop = SPT_COLOR;
- directive->ttype = TT_TAB;
- return directive;
- } else if (
- !strcmp(name, "textfont") ||
- !strcmp(name, "tf")
- ) {
- directive->dtype = DT_FONT;
- directive->sprop = SPT_FONT;
- directive->ttype = TT_TEXT;
- return directive;
- } else if (
- !strcmp(name, "textsize") ||
- !strcmp(name, "ts")
- ) {
- directive->dtype = DT_FONT;
- directive->sprop = SPT_SIZE;
- directive->ttype = TT_TEXT;
- return directive;
- } else if (!strcmp(name, "textcolour")) {
- directive->dtype = DT_FONT;
- directive->sprop = SPT_COLOR;
- directive->ttype = TT_TEXT;
- return directive;
- } else if (!strcmp(name, "titlefont")) {
- directive->dtype = DT_FONT;
- directive->sprop = SPT_FONT;
- directive->ttype = TT_TITLE;
- return directive;
- } else if (!strcmp(name, "titlesize")) {
- directive->dtype = DT_FONT;
- directive->sprop = SPT_SIZE;
- directive->ttype = TT_TITLE;
- return directive;
- } else if (!strcmp(name, "titlecolour")) {
- directive->dtype = DT_FONT;
- directive->sprop = SPT_COLOR;
- directive->ttype = TT_TITLE;
- return directive;
- } else if (!strcmp(name, "tocfont")) {
- directive->dtype = DT_FONT;
- directive->sprop = SPT_FONT;
- directive->ttype = TT_TOC;
- } else if (!strcmp(name, "tocsize")) {
- directive->dtype = DT_FONT;
- directive->sprop = SPT_SIZE;
- directive->ttype = TT_TOC;
- } else if (!strcmp(name, "toccolour")) {
- directive->dtype = DT_FONT;
- directive->sprop = SPT_COLOR;
- directive->ttype = TT_TOC;
- } /* else if (!strcmp(name, "footerfont")) {
- } else if (!strcmp(name, "footersize")) {
- } else if (!strcmp(name, "footercolour")) {
- } else if (!strcmp(name, "labelfont")) {
- } else if (!strcmp(name, "labelsize")) {
- } else if (!strcmp(name, "labelcolour")) {
- } */
- if (!strcmp(name, "transpose")) {
- directive->dtype = DT_CHORD;
- directive->ctype = TRANSPOSE;
- return directive;
- } else if (!strcmp(name, "define")) {
- directive->dtype = DT_CHORD;
- directive->ctype = DEFINE;
- return directive;
- } /* else if (!strcmp(name, "chord")) {
- } */
- if (
- !strcmp(name, "new_page") ||
- !strcmp(name, "np")
- ) {
- directive->dtype = DT_OUTPUT;
- directive->btype = BT_PAGE;
- return directive;
- } else if (
- !strcmp(name, "column_break") ||
- !strcmp(name, "colb")
- ) {
- directive->dtype = DT_OUTPUT;
- directive->btype = BT_COLUMN;
- return directive;
- }
- if (str_starts_with(name, "start_of_")) {
- directive->dtype = DT_ENVIRONMENT;
- directive->position = POS_START;
- directive->stype = ST_CUSTOM;
- directive->ttype = TT_TEXT;
- return directive;
- } else if (str_starts_with(name, "end_of_")) {
- directive->dtype = DT_ENVIRONMENT;
- directive->position = POS_END;
- directive->stype = ST_CUSTOM;
- directive->ttype = TT_TEXT;
- return directive;
- }
- if (str_starts_with(name, "x_")) {
- directive->dtype = DT_EXTENSION;
- return directive;
- }
- directive->dtype = DT_CUSTOM;
- return directive;
-}
-
-static char *
-cho_directive_label_parse(const char *directive_name, const char *str)
-{
- char *label_name = NULL;
- char c;
- enum OptionState state = OS_NAME;
- enum AttrValueSyntax avs = -1;
- char name[5+1];
- char value[URL_MAX_LEN+1];
- int n = 0;
- int v = 0;
- memset(name, 0, sizeof(name));
- memset(value, 0, sizeof(value));
- int i;
- for (i = 0; str[i]; i++) {
- c = str[i];
- switch (state) {
- case OS_NAME:
- if (is_whitespace(c)) {
- if (n == 0) {
- break;
- } else {
- name[n] = 0;
- cho_log(LOG_ERR, "Option with name '%s' in environment directive '%s' has no value.", name, directive_name);
- return NULL;
- }
- }
- if (c == '=') {
- name[n] = 0;
- if (strcmp(name, "label") != 0) {
- cho_log(LOG_ERR, "Invalid option name '%s' in environment directive '%s'.", name, directive_name);
- }
- memset(name, 0, n);
- n = 0;
- state = OS_VALUE;
- break;
- }
- if (n > 4) {
- cho_log(LOG_ERR, "Option name in environment directive '%s' is too long.", directive_name);
- return NULL;
- }
- name[n] = c;
- n++;
- break;
- case OS_VALUE:
- if (avs == -1) {
- if (is_whitespace(c)) {
- cho_log(LOG_ERR, "Whitespace character after equals sign in environment directive '%s' is invalid.", directive_name);
- return NULL;
- }
- if (c == '\'') {
- avs = AVS_APOSTROPHE;
- } else if (c == '"') {
- avs = AVS_QUOTATION_MARK;
- } else {
- avs = AVS_UNQUOTED;
- value[v] = c;
- v++;
- }
- break;
- }
- if (c == '\n') {
- cho_log(LOG_ERR, "Newline character inside an option value in environment directive '%s' is invalid.", directive_name);
- return NULL;
- }
- if (
- (avs == AVS_APOSTROPHE && c == '\'') ||
- (avs == AVS_QUOTATION_MARK && c == '"') ||
- (avs == AVS_UNQUOTED && (c == ' ' || c == '\t'))
- ) {
- value[v] = 0;
- label_name = strdup(value);
- memset(value, 0, v);
- v = 0;
- avs = -1;
- state = OS_NAME;
- break;
- }
- value[v] = c;
- v++;
- break;
- }
- }
- if (avs == AVS_UNQUOTED) {
- value[v] = 0;
- label_name = strdup(value);
- }
- return label_name;
-}
-
-struct ChoSong **
-cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config)
-{
- g_config = config;
- g_chordpro_filepath = chordpro_filepath;
- bool is_chord_already_initialized = false;
- bool is_maybe_end_of_tab_directive = false;
- bool directive_has_tag = false;
- char buf = 0;
- char prev_buf = '\n';
- char directive_name[128];
- char directive_value[4096];
- char chord[15];
- char tag_start[6];
- char tag_end[6];
- char custom_directive[64];
- char *label, *metadata_value, *stripped_directive_value;
- enum State state = STATE_LYRICS;
- enum State state_before_comment = STATE_LYRICS;
- enum State state_before_tag = STATE_LYRICS;
- enum State state_before_backslash = STATE_LYRICS;
- int dn = 0;
- int dv = 0;
- int ch = 0;
- int c = 0;
- int m = 0;
- int ly = 0;
- int t = 0;
- int so = 0;
- int se = 0;
- int li = 0;
- int ta = -1;
- int te = 0;
- int at = 0;
- int atn = 0;
- int atv = 0;
- int ann = 0;
- int text_above_pos;
- int transpose;
- int th = 0;
- int dia = 0;
- size_t read;
- g_transpose_history = erealloc(g_transpose_history, (th+1) * sizeof(int *));
- g_transpose_history[th] = 0;
- g_transpose = &g_transpose_history[th];
- th++;
- enum AttrValueSyntax avs = -1;
- struct ChoDirective *directive = NULL;
- struct ChoMetadata *metadata = NULL;
- struct ChoLine ***lines;
- struct ChoSong **songs = emalloc(sizeof(struct ChoSong *));
- songs[so] = cho_song_new();
- songs[so]->sections = emalloc((se+1) * sizeof(struct ChoSection *));
- songs[so]->sections[se] = cho_section_new();
- songs[so]->sections[se]->lines = emalloc(sizeof(struct ChoLine *));
- songs[so]->sections[se]->lines[li] = cho_line_new();
- lines = &songs[so]->sections[se]->lines;
- (*lines)[li]->items = emalloc(sizeof(struct ChoLineItem *));
- (*lines)[li]->items[ly] = cho_line_item_new();
- songs[so]->present_text_types[TT_TOC] = config->output->toc->show;
- struct Tag **tags = NULL;
- struct ChoStyle *tag_style;
- struct StyleProperty sprop;
- struct ChoChord *tmp_chord;
- struct ChoSection *chorus;
- struct ChoImage *image;
- struct ChordDiagram *diagram;
- while (feof(fp) == 0) {
- read = fread(&buf, 1, 1, fp);
- if (read == 1) {
- if (buf == '\n') {
- g_line_number++;
- }
- // printf("state: %s, buf: %c\n", state_enums[state], buf);
- if (buf == '\r') {
- continue;
- }
- switch (state) {
- case STATE_LYRICS: {
- if (prev_buf == '\n' && buf == '#') {
- state_before_comment = STATE_LYRICS;
- state = STATE_COMMENT;
- break;
- }
- if (prev_buf == '\n' && buf == '{') {
- state = STATE_DIRECTIVE_NAME;
- break;
- }
- if (buf == '[') {
- state = STATE_CHORD;
- break;
- }
- if (buf == '<') {
- if ((*lines)[li]->items[ly]->is_text) {
- (*lines)[li]->items[ly]->u.text->text = erealloc((*lines)[li]->items[ly]->u.text->text, (te+1) * sizeof(char));
- (*lines)[li]->items[ly]->u.text->text[te] = 0;
- if (strlen((*lines)[li]->items[ly]->u.text->text) == 0) {
- cho_line_item_free((*lines)[li]->items[ly]);
- } else {
- ly++;
- }
- } else {
- ly++;
- }
- te = 0;
- (*lines)[li]->items = erealloc((*lines)[li]->items, (ly+1) * sizeof(struct ChoLineItem *));
- (*lines)[li]->items[ly] = cho_line_item_new();
- state_before_tag = STATE_LYRICS;
- state = STATE_MARKUP_TAG;
- break;
- }
- if (buf == '\n') {
- if (prev_buf == '\\') {
- state_before_backslash = STATE_LYRICS;
- state = STATE_BACKSLASH;
- te--; // INFO: This will later overwrite the backslash
- break;
- }
- if (ta > -1 && !tags[ta]->is_closed && strcmp(tags[ta]->name, "img")) {
- cho_log(LOG_ERR, "Tag has to be closed on same line.");
- return NULL;
- }
- if ((*lines)[li]->items[ly]->is_text) {
- (*lines)[li]->items[ly]->u.text->text = erealloc((*lines)[li]->items[ly]->u.text->text, (te+1) * sizeof(char));
- (*lines)[li]->items[ly]->u.text->text[te] = 0;
- if (strlen((*lines)[li]->items[ly]->u.text->text) == 0) {
- cho_line_item_free((*lines)[li]->items[ly]);
- if (ly == 0) {
- if (
- !(*lines)[li]->text_above &&
- (*lines)[li]->btype == BT_LINE
- ) {
- free((*lines)[li]->items);
- free((*lines)[li]);
- *lines = erealloc(*lines, (li+1) * sizeof(struct ChoLine *));
- (*lines)[li] = cho_line_new();
- (*lines)[li]->items = erealloc((*lines)[li]->items, (ly+1) * sizeof(struct ChoLineItem *));
- (*lines)[li]->items[ly] = cho_line_item_new();
- break;
- }
- }
- } else {
- ly++;
- }
- } else {
- ly++;
- }
- (*lines)[li]->items = erealloc((*lines)[li]->items, (ly+1) * sizeof(struct ChoLineItem *));
- (*lines)[li]->items[ly] = NULL;
- ly = 0;
- te = 0;
- (*lines)[li]->text_above = erealloc((*lines)[li]->text_above, (c+1) * sizeof(struct ChoLineItemAbove *));
- (*lines)[li]->text_above[c] = NULL;
- c = 0;
- li++;
- *lines = erealloc(*lines, (li+1) * sizeof(struct ChoLine *));
- (*lines)[li] = cho_line_new();
- (*lines)[li]->items = erealloc((*lines)[li]->items, (ly+1) * sizeof(struct ChoLineItem *));
- (*lines)[li]->items[ly] = cho_line_item_new();
- break;
- }
- (*lines)[li]->items[ly]->u.text->text = erealloc((*lines)[li]->items[ly]->u.text->text, (te+1) * sizeof(char));
- (*lines)[li]->items[ly]->u.text->text[te] = buf;
- te++;
- break;
- }
- case STATE_BACKSLASH: {
- if (!is_whitespace(buf)) {
- if (fseek(fp, -1, SEEK_CUR)) {
- LOG_DEBUG("fseek failed.");
- return NULL;
- }
- printf("Hopefully not losing byte 0x%02X|%c\n", buf, buf);
- state = state_before_backslash;
- break;
- }
- break;
- }
- case STATE_DIRECTIVE_NAME: {
- if (buf == '}') {
- directive_name[dn] = 0;
- dn = 0;
- directive = cho_directive_parse(directive_name);
- /* printf(
- "directive: '%s'\ndtype: %s, stype: %s, position: %s\n",
- directive_name, cho_debug_dtype(directive->dtype), cho_debug_the_stype(directive->stype), cho_debug_the_pos(directive->position)
- ); */
- switch (directive->dtype) {
- case DT_ENVIRONMENT: {
- g_current_ttype = directive->ttype;
- switch (directive->position) {
- case POS_START: {
- if (directive->stype == ST_CUSTOM) {
- memset(custom_directive, 0, sizeof(custom_directive));
- strcpy(custom_directive, &directive_name[9]);
- }
- cho_line_item_free((*lines)[li]->items[ly]);
- free((*lines)[li]->items);
- ly = 0;
- free((*lines)[li]);
- (*lines)[li] = NULL;
- se++;
- songs[so]->sections = erealloc(songs[so]->sections, (se+1) * sizeof(struct ChoSection *));
- songs[so]->sections[se] = cho_section_new();
- songs[so]->sections[se]->type = directive->stype;
- li = 0;
- lines = &songs[so]->sections[se]->lines;
- *lines = emalloc(sizeof(struct ChoLine *));
- (*lines)[li] = cho_line_new();
- (*lines)[li]->items = emalloc(sizeof(struct ChoLineItem *));
- (*lines)[li]->items[ly] = cho_line_item_new();
- songs[so]->present_text_types[directive->ttype] = true;
- break;
- }
- case POS_END: {
- if (directive->stype == songs[so]->sections[se]->type) {
- if (directive->stype == ST_CUSTOM) {
- if (strcmp(custom_directive, &directive_name[7]) != 0) {
- break;
- }
- }
- cho_line_item_free((*lines)[li]->items[ly]);
- free((*lines)[li]->items);
- ly = 0;
- free((*lines)[li]);
- (*lines)[li] = NULL;
- se++;
- songs[so]->sections = erealloc(songs[so]->sections, (se+1) * sizeof(struct ChoSection *));
- songs[so]->sections[se] = cho_section_new();
- li = 0;
- lines = &songs[so]->sections[se]->lines;
- *lines = emalloc(sizeof(struct ChoLine *));
- (*lines)[li] = cho_line_new();
- (*lines)[li]->items = emalloc(sizeof(struct ChoLineItem *));
- (*lines)[li]->items[ly] = cho_line_item_new();
- }
- break;
- }
- case POS_NO: {
- /* INFO: {chorus} */
- chorus = cho_find_previous_chorus(songs[so]->sections, se);
- if (chorus) {
- if (config->output->chorus->quote) {
- if ((*lines)[li]->items[ly]->is_text) {
- (*lines)[li]->items[ly]->u.text->text = erealloc((*lines)[li]->items[ly]->u.text->text, (te+1) * sizeof(char));
- (*lines)[li]->items[ly]->u.text->text[te] = 0;
- }
- ly++;
- (*lines)[li]->items = erealloc((*lines)[li]->items, (ly+1) * sizeof(struct ChoLineItem *));
- (*lines)[li]->items[ly] = NULL;
- ly = 0;
- te = 0;
- (*lines)[li]->text_above = erealloc((*lines)[li]->text_above, (c+1) * sizeof(struct ChoLineItemAbove *));
- (*lines)[li]->text_above[c] = NULL;
- c = 0;
- cho_line_free((*lines)[li]);
- (*lines)[li] = NULL;
- li = 0;
- se++;
- songs[so]->sections = erealloc(songs[so]->sections, (se+1) * sizeof(struct ChoSection *));
- songs[so]->sections[se] = cho_section_copy(chorus);
- se++;
- songs[so]->sections = erealloc(songs[so]->sections, (se+1) * sizeof(struct ChoSection *));
- songs[so]->sections[se] = cho_section_new();
- lines = &songs[so]->sections[se]->lines;
- *lines = emalloc(sizeof(struct ChoLine *));
- (*lines)[li] = cho_line_new();
- (*lines)[li]->items = emalloc(sizeof(struct ChoLineItem *));
- (*lines)[li]->items[ly] = cho_line_item_new();
- } else {
- if (chorus->label) {
- label = strdup(chorus->label->text);
- } else {
- label = strdup(config->output->chorus->label);
- }
- if ((*lines)[li]->items[ly]->is_text) {
- (*lines)[li]->items[ly]->u.text->text = erealloc((*lines)[li]->items[ly]->u.text->text, (te+1) * sizeof(char));
- (*lines)[li]->items[ly]->u.text->text[te] = 0;
- if (strlen((*lines)[li]->items[ly]->u.text->text) == 0) {
- cho_line_item_free((*lines)[li]->items[ly]);
- } else {
- ly++;
- }
- } else {
- ly++;
- }
- (*lines)[li]->items = erealloc((*lines)[li]->items, (ly+1) * sizeof(struct ChoLineItem *));
- (*lines)[li]->items[ly] = cho_line_item_new();
- cho_style_free((*lines)[li]->items[ly]->u.text->style);
- g_current_ttype = TT_LABEL;
- (*lines)[li]->items[ly]->u.text->style = cho_style_new_default();
- (*lines)[li]->items[ly]->u.text->text = label;
- te += strlen(label);
- }
- } else {
- if (config->output->chorus->quote) {
- cho_log(LOG_WARN, "Can't quote chorus because it's not defined previously.");
- }
- label = strdup(config->output->chorus->label);
- if ((*lines)[li]->items[ly]->is_text) {
- (*lines)[li]->items[ly]->u.text->text = erealloc((*lines)[li]->items[ly]->u.text->text, (te+1) * sizeof(char));
- (*lines)[li]->items[ly]->u.text->text[te] = 0;
- if (strlen((*lines)[li]->items[ly]->u.text->text) == 0) {
- cho_line_item_free((*lines)[li]->items[ly]);
- } else {
- ly++;
- }
- } else {
- ly++;
- }
- (*lines)[li]->items = erealloc((*lines)[li]->items, (ly+1) * sizeof(struct ChoLineItem *));
- (*lines)[li]->items[ly] = cho_line_item_new();
- cho_style_free((*lines)[li]->items[ly]->u.text->style);
- g_current_ttype = TT_LABEL;
- (*lines)[li]->items[ly]->u.text->style = cho_style_new_default();
- (*lines)[li]->items[ly]->u.text->text = label;
- te += strlen(label);
- }
- break;
- }
- default:
- cho_log(LOG_ERR, "Invalid position value '%d'.", directive->position);
- return NULL;
- }
- break;
- }
- case DT_METADATA:
- cho_log(LOG_WARN, "Ignoring metadata directive '%s' because it has no value.", directive_name);
- break;
- case DT_FORMATTING:
- cho_log(LOG_WARN, "Formatting directive '%s' has no value.", directive_name);
- break;
- case DT_IMAGE:
- cho_log(LOG_ERR, "Directive 'image' has no value.");
- return NULL;
- case DT_PREAMBLE: {
- // INFO: The only preamble directive is 'new_song'
- cho_line_item_free((*lines)[li]->items[ly]);
- free((*lines)[li]->items);
- free((*lines)[li]);
- (*lines)[li] = NULL;
- songs[so]->metadata = erealloc(songs[so]->metadata, (m+1) * sizeof(struct ChoMetadata *));
- songs[so]->metadata[m] = NULL;
- se++;
- songs[so]->sections = erealloc(songs[so]->sections, (se+1) * sizeof(struct ChoSection *));
- songs[so]->sections[se] = NULL;
- songs[so]->diagrams = erealloc(songs[so]->diagrams, (dia+1) * sizeof(struct ChordDiagram *));
- songs[so]->diagrams[dia] = NULL;
- if (!cho_style_reset_default()) {
- LOG_DEBUG("cho_style_reset_default failed.");
- return NULL;
- }
- so++;
- songs = erealloc(songs, (so+1) * sizeof(struct ChoSong *));
- songs[so] = cho_song_new();
- se = 0;
- li = 0;
- ly = 0;
- m = 0;
- dia = 0;
- songs[so]->sections = emalloc((se+1) * sizeof(struct ChoSection *));
- songs[so]->sections[se] = cho_section_new();
- lines = &songs[so]->sections[se]->lines;
- *lines = erealloc(*lines, (li+1) * sizeof(struct ChoLine *));
- (*lines)[li] = cho_line_new();
- (*lines)[li]->items = emalloc(sizeof(struct ChoLineItem *));
- (*lines)[li]->items[ly] = cho_line_item_new();
- break;
- }
- case DT_FONT: {
- sprop.ttype = directive->ttype;
- sprop.type = directive->sprop;
- switch (directive->sprop) {
- case SPT_FONT:
- sprop.u.font_name = NULL;
- break;
- case SPT_SIZE:
- sprop.u.font_size = EMPTY_DOUBLE;
- break;
- case SPT_COLOR:
- sprop.u.foreground_color = NULL;
- break;
- default:
- cho_log(LOG_ERR, "Invalid style property type '%d'.", directive->sprop);
- return NULL;
- }
- if (!cho_style_change_default(sprop)) {
- LOG_DEBUG("cho_style_change_default failed.");
- return NULL;
- }
- break;
- }
- case DT_CHORD: {
- switch (directive->ctype) {
- case TRANSPOSE:
- g_transpose--;
- th--;
- break;
- case DEFINE:
- cho_log(LOG_WARN, "Ignoring chord directive '%s' because it has no value.", directive_name);
- break;
- }
- break;
- }
- case DT_OUTPUT:
- if (directive->btype != -1) {
- (*lines)[li]->btype = directive->btype;
- }
- break;
- case DT_EXTENSION:
- // INFO: Such a directive should not be logged.
- break;
- case DT_CUSTOM:
- cho_log(LOG_INFO, "Ignoring custom directive '%s'.", directive_name);
- break;
- default:
- cho_log(LOG_ERR, "Invalid directive '%s'.", directive_name);
- return NULL;
- }
- if (directive->stype == ST_TAB) {
- state = STATE_TAB;
- } else {
- state = STATE_LYRICS;
- }
- cho_directive_free(directive);
- directive = NULL;
- break;
- }
- if (buf == '{') {
- cho_log(LOG_ERR, "Can't start a new directive if the previous one is not yet closed.");
- return NULL;
- }
- if (buf == '\n') {
- if (prev_buf == '\\') {
- state_before_backslash = STATE_DIRECTIVE_NAME;
- state = STATE_BACKSLASH;
- dn--;
- break;
- }
- cho_log(LOG_ERR, "Can't have a newline in a directive name.");
- return NULL;
- }
- if (buf == ':' || buf == ' ') {
- directive_name[dn] = 0;
- dn = 0;
- state = STATE_DIRECTIVE_VALUE;
- break;
- }
- directive_name[dn] = buf;
- dn++;
- break;
- }
- case STATE_DIRECTIVE_VALUE: {
- if (buf == '}') {
- directive_value[dv] = 0;
- dv = 0;
- stripped_directive_value = str_remove_leading_whitespace(directive_value);
- directive = cho_directive_parse(directive_name);
- /* printf(
- "directive: '%s'\ndtype: %s, stype: %s, position: %s\n",
- directive_name, dtype(directive->dtype), the_stype(directive->stype), pos(directive->position)
- ); */
- switch (directive->dtype) {
- case DT_ENVIRONMENT: {
- if (strlen(stripped_directive_value) > 0) {
- songs[so]->present_text_types[TT_LABEL] = true;
- }
- g_current_ttype = directive->ttype;
- switch (directive->position) {
- case POS_START: {
- if (directive->stype == ST_CUSTOM) {
- memset(custom_directive, 0, sizeof(custom_directive));
- strcpy(custom_directive, &directive_name[9]);
- }
- cho_line_item_free((*lines)[li]->items[ly]);
- free((*lines)[li]->items);
- ly = 0;
- free((*lines)[li]);
- (*lines)[li] = NULL;
- se++;
- songs[so]->sections = erealloc(songs[so]->sections, (se+1) * sizeof(struct ChoSection *));
- songs[so]->sections[se] = cho_section_new();
- songs[so]->sections[se]->type = directive->stype;
- songs[so]->sections[se]->label = emalloc(sizeof(struct ChoText));
- if (strstr(directive_value, "=")) {
- label = cho_directive_label_parse(directive_name, directive_value);
- if (!label) {
- LOG_DEBUG("cho_directive_label_parse failed.");
- cho_log(LOG_ERR, "Failed to parse the section label. You have to ways of specifying a label:\n\t\t\t1. {start_of_*: label=\"Label name\"}\n\t\t\t2. {start_of*: Label name}");
- return NULL;
- }
- songs[so]->sections[se]->label->text = label;
- } else {
- songs[so]->sections[se]->label->text = strdup(stripped_directive_value);
- }
- songs[so]->sections[se]->label->style = cho_style_new_from_config(TT_LABEL);
- if (directive_has_tag) {
- cho_style_complement(songs[so]->sections[se]->label->style, tags[ta]->style, &tags[ta]->style_presence);
- directive_has_tag = false;
- }
- li = 0;
- lines = &songs[so]->sections[se]->lines;
- *lines = emalloc(sizeof(struct ChoLine *));
- (*lines)[li] = cho_line_new();
- (*lines)[li]->items = emalloc(sizeof(struct ChoLineItem *));
- (*lines)[li]->items[ly] = cho_line_item_new();
- songs[so]->present_text_types[directive->ttype] = true;
- break;
- }
- case POS_END: {
- if (directive->stype == songs[so]->sections[se]->type) {
- cho_line_item_free((*lines)[li]->items[ly]);
- free((*lines)[li]->items);
- ly = 0;
- free((*lines)[li]);
- (*lines)[li] = NULL;
- se++;
- songs[so]->sections = erealloc(songs[so]->sections, (se+1) * sizeof(struct ChoSection *));
- songs[so]->sections[se] = cho_section_new();
- li = 0;
- lines = &songs[so]->sections[se]->lines;
- *lines = emalloc(sizeof(struct ChoLine *));
- (*lines)[li] = cho_line_new();
- (*lines)[li]->items = emalloc(sizeof(struct ChoLineItem *));
- (*lines)[li]->items[ly] = cho_line_item_new();
- }
- break;
- }
- case POS_NO: {
- /* INFO: {chorus: ...} */
- label = strdup(stripped_directive_value);
- chorus = cho_find_previous_chorus(songs[so]->sections, se);
- if (chorus) {
- if (config->output->chorus->quote) {
- if ((*lines)[li]->items[ly]->is_text) {
- (*lines)[li]->items[ly]->u.text->text = erealloc((*lines)[li]->items[ly]->u.text->text, (te+1) * sizeof(char));
- (*lines)[li]->items[ly]->u.text->text[te] = 0;
- }
- ly++;
- (*lines)[li]->items = erealloc((*lines)[li]->items, (ly+1) * sizeof(struct ChoLineItem *));
- (*lines)[li]->items[ly] = NULL;
- ly = 0;
- te = 0;
- (*lines)[li]->text_above = erealloc((*lines)[li]->text_above, (c+1) * sizeof(struct ChoLineItemAbove *));
- (*lines)[li]->text_above[c] = NULL;
- c = 0;
- cho_line_free((*lines)[li]);
- // songs[so]->sections[se]->lines = erealloc(songs[so]->sections[se]->lines, (li+1) * sizeof(struct ChoLine *));
- (*lines)[li] = NULL;
- li = 0;
- se++;
- songs[so]->sections = erealloc(songs[so]->sections, (se+1) * sizeof(struct ChoSection *));
- songs[so]->sections[se] = cho_section_copy(chorus);
- if (songs[so]->sections[se]->label) {
- free(songs[so]->sections[se]->label->text);
- songs[so]->sections[se]->label->text = label;
- } else {
- g_current_ttype = TT_LABEL;
- songs[so]->sections[se]->label = cho_text_new();
- songs[so]->sections[se]->label->text = label;
- }
- if (directive_has_tag) {
- cho_style_complement(songs[so]->sections[se]->label->style, tags[ta]->style, &tags[ta]->style_presence);
- directive_has_tag = false;
- }
- se++;
- songs[so]->sections = erealloc(songs[so]->sections, (se+1) * sizeof(struct ChoSection *));
- songs[so]->sections[se] = cho_section_new();
- lines = &songs[so]->sections[se]->lines;
- *lines = emalloc(sizeof(struct ChoLine *));
- (*lines)[li] = cho_line_new();
- (*lines)[li]->items = emalloc(sizeof(struct ChoLineItem *));
- (*lines)[li]->items[ly] = cho_line_item_new();
- } else {
- if ((*lines)[li]->items[ly]->is_text) {
- (*lines)[li]->items[ly]->u.text->text = erealloc((*lines)[li]->items[ly]->u.text->text, (te+1) * sizeof(char));
- (*lines)[li]->items[ly]->u.text->text[te] = 0;
- if (strlen((*lines)[li]->items[ly]->u.text->text) == 0) {
- cho_line_item_free((*lines)[li]->items[ly]);
- } else {
- ly++;
- }
- } else {
- ly++;
- }
- (*lines)[li]->items = erealloc((*lines)[li]->items, (ly+1) * sizeof(struct ChoLineItem *));
- (*lines)[li]->items[ly] = cho_line_item_new();
- cho_style_free((*lines)[li]->items[ly]->u.text->style);
- g_current_ttype = TT_LABEL;
- (*lines)[li]->items[ly]->u.text->style = cho_style_new_default();
- (*lines)[li]->items[ly]->u.text->text = label;
- if (directive_has_tag) {
- cho_style_complement((*lines)[li]->items[ly]->u.text->style, tags[ta]->style, &tags[ta]->style_presence);
- directive_has_tag = false;
- }
- te += strlen(label);
- }
- } else {
- if (config->output->chorus->quote) {
- cho_log(LOG_WARN, "Can't quote chorus because it's not defined previously.");
- }
- if ((*lines)[li]->items[ly]->is_text) {
- (*lines)[li]->items[ly]->u.text->text = erealloc((*lines)[li]->items[ly]->u.text->text, (te+1) * sizeof(char));
- (*lines)[li]->items[ly]->u.text->text[te] = 0;
- if (strlen((*lines)[li]->items[ly]->u.text->text) == 0) {
- cho_line_item_free((*lines)[li]->items[ly]);
- } else {
- ly++;
- }
- } else {
- ly++;
- }
- (*lines)[li]->items = erealloc((*lines)[li]->items, (ly+1) * sizeof(struct ChoLineItem *));
- (*lines)[li]->items[ly] = cho_line_item_new();
- cho_style_free((*lines)[li]->items[ly]->u.text->style);
- g_current_ttype = TT_LABEL;
- (*lines)[li]->items[ly]->u.text->style = cho_style_new_default();
- (*lines)[li]->items[ly]->u.text->text = label;
- if (directive_has_tag) {
- cho_style_complement((*lines)[li]->items[ly]->u.text->style, tags[ta]->style, &tags[ta]->style_presence);
- }
- te += strlen(label);
- }
- break;
- }
- default:
- cho_log(LOG_ERR, "Invalid position value '%d'.", directive->position);
- return NULL;
- }
- break;
- }
- case DT_METADATA: {
- metadata_value = strdup(stripped_directive_value);
- if (strlen(metadata_value) == 0) {
- cho_log(LOG_WARN, "Ignoring metadata directive '%s' because it has no value.", directive_name);
- free(metadata_value);
- break;
- }
- switch (directive->meta) {
- case TITLE:
- songs[so]->metadata = erealloc(songs[so]->metadata, (m+1) * sizeof(struct ChoMetadata *));
- songs[so]->metadata[m] = cho_metadata_new();
- songs[so]->metadata[m]->name = strdup("title");
- songs[so]->metadata[m]->value = metadata_value;
- cho_style_free(songs[so]->metadata[m]->style);
- songs[so]->metadata[m]->style = cho_style_copy(directive->style);
- songs[so]->present_text_types[TT_TITLE] = true;
- break;
- case SUBTITLE:
- songs[so]->metadata = erealloc(songs[so]->metadata, (m+1) * sizeof(struct ChoMetadata *));
- songs[so]->metadata[m] = cho_metadata_new();
- songs[so]->metadata[m]->name = strdup("subtitle");
- songs[so]->metadata[m]->value = metadata_value;
- cho_style_free(songs[so]->metadata[m]->style);
- songs[so]->metadata[m]->style = cho_style_copy(directive->style);
- songs[so]->present_text_types[TT_SUBTITLE] = true;
- break;
- default:
- if (!strcmp(directive_name, "meta")) {
- metadata = cho_metadata_split(directive_value);
- if (!metadata) {
- LOG_DEBUG("cho_metadata_split failed.");
- return NULL;
- }
- songs[so]->metadata = erealloc(songs[so]->metadata, (m+1) * sizeof(struct ChoMetadata *));
- songs[so]->metadata[m] = metadata;
- free(metadata_value);
- } else {
- songs[so]->metadata = erealloc(songs[so]->metadata, (m+1) * sizeof(struct ChoMetadata *));
- songs[so]->metadata[m] = cho_metadata_new();
- songs[so]->metadata[m]->name = strdup(directive_name);
- songs[so]->metadata[m]->value = metadata_value;
- }
- }
- if (directive_has_tag) {
- cho_style_complement(songs[so]->metadata[m]->style, tags[ta]->style, &tags[ta]->style_presence);
- directive_has_tag = false;
- }
- m++;
- break;
- }
- case DT_FORMATTING: {
- if ((*lines)[li]->items[ly]->is_text) {
- (*lines)[li]->items[ly]->u.text->text = erealloc((*lines)[li]->items[ly]->u.text->text, (te+1) * sizeof(char));
- (*lines)[li]->items[ly]->u.text->text[te] = 0;
- if (strlen((*lines)[li]->items[ly]->u.text->text) == 0) {
- cho_line_item_free((*lines)[li]->items[ly]);
- } else {
- ly++;
- }
- } else {
- ly++;
- }
- (*lines)[li]->items = erealloc((*lines)[li]->items, (ly+1) * sizeof(struct ChoLineItem *));
- (*lines)[li]->items[ly] = cho_line_item_new();
- cho_style_free((*lines)[li]->items[ly]->u.text->style);
- (*lines)[li]->items[ly]->u.text->style = cho_style_copy(directive->style);
- (*lines)[li]->items[ly]->u.text->text = strdup(stripped_directive_value);
- if (directive_has_tag) {
- cho_style_complement((*lines)[li]->items[ly]->u.text->style, tags[ta]->style, &tags[ta]->style_presence);
- directive_has_tag = false;
- }
- te += strlen(stripped_directive_value);
- songs[so]->present_text_types[directive->ttype] = true;
- break;
- }
- case DT_IMAGE: {
- if (strstr(directive_value, "=")) {
- image = cho_image_directive_parse(directive_value);
- if (!image) {
- LOG_DEBUG("cho_image_directive_parse failed.");
- return NULL;
- }
- } else {
- image = cho_image_new();
- image->src = strdup(stripped_directive_value);
- }
- if (image->is_asset) {
- g_image_assets = erealloc(g_image_assets, (g_ia+1) * sizeof(struct ChoImage *));
- g_image_assets[g_ia] = image;
- g_ia++;
- } else {
- if ((*lines)[li]->items[ly]->is_text) {
- (*lines)[li]->items[ly]->u.text->text = erealloc((*lines)[li]->items[ly]->u.text->text, (te+1) * sizeof(char));
- (*lines)[li]->items[ly]->u.text->text[te] = 0;
- te = 0;
- }
- ly++;
- (*lines)[li]->items = erealloc((*lines)[li]->items, (ly+1) * sizeof(struct ChoLineItem *));
- (*lines)[li]->items[ly] = cho_line_item_new();
- cho_text_free((*lines)[li]->items[ly]->u.text);
- (*lines)[li]->items[ly]->is_text = false;
- (*lines)[li]->items[ly]->u.image = image;
- }
- break;
- }
- case DT_PREAMBLE:
- cho_log(LOG_ERR, "Preamble directive '%s' can't have a value.", directive_name);
- return NULL;
- case DT_FONT: {
- sprop.ttype = directive->ttype;
- char *dir_value = strdup(stripped_directive_value);
- switch (directive->sprop) {
- case SPT_FONT:
- sprop.u.font_name = emalloc((strlen(dir_value)+1) * sizeof(char));
- strcpy(sprop.u.font_name, dir_value);
- sprop.type = SPT_FONT;
- break;
- case SPT_SIZE:
- sprop.u.font_size = strtod(dir_value, NULL);
- if (sprop.u.font_size == 0.0) {
- cho_log(LOG_ERR, "Font directive '%s' has an invalid value.", directive_name);
- return NULL;
- }
- sprop.type = SPT_SIZE;
- break;
- case SPT_COLOR:
- sprop.u.foreground_color = cho_color_parse(dir_value);
- if (sprop.u.foreground_color == NULL) {
- cho_log(LOG_ERR, "Font directive '%s' has an invalid value.", directive_name);
- return NULL;
- }
- sprop.type = SPT_COLOR;
- break;
- default:
- cho_log(LOG_ERR, "Invalid style property type '%d'.", directive->sprop);
- return NULL;
- }
- if (!cho_style_change_default(sprop)) {
- LOG_DEBUG("cho_style_change_default failed.");
- return NULL;
- }
- if (sprop.type == SPT_FONT) {
- free(sprop.u.font_name);
- } else if (sprop.type == SPT_COLOR) {
- free(sprop.u.foreground_color);
- }
- free(dir_value);
- break;
- }
- case DT_CHORD: {
- switch (directive->ctype) {
- case TRANSPOSE:
- if (!transposition_parse(directive_value, &transpose)) {
- LOG_DEBUG("transposition_parse failed.");
- cho_log(LOG_ERR, "Directive 'transpose' has an invalid value.");
- return NULL;
- }
- g_transpose_history = erealloc(g_transpose_history, (th+1) * sizeof(int *));
- g_transpose_history[th] = g_transpose_history[th-1] + transpose;
- g_transpose = &g_transpose_history[th];
- th++;
- break;
- case DEFINE:
- diagram = cho_chord_diagram_parse(directive_value, songs[so]->diagrams, dia);
- if (!diagram) {
- LOG_DEBUG("cho_chord_diagram_parse failed.");
- return NULL;
- }
- songs[so]->diagrams = erealloc(songs[so]->diagrams, (dia+1) * sizeof(struct ChordDiagram *));
- songs[so]->diagrams[dia] = diagram;
- dia++;
- // debug_chord_diagram_print(diagram);
- break;
- }
- break;
- }
- case DT_OUTPUT:
- cho_log(LOG_ERR, "Directive '%s' can't have a value.", directive_name);
- return NULL;
- case DT_EXTENSION:
- // INFO: Such a directive should not be logged.
- break;
- case DT_CUSTOM:
- cho_log(LOG_INFO, "Ignoring custom directive '%s'.", directive_name);
- break;
- default:
- cho_log(LOG_ERR, "Invalid directive type '%d'.", directive->dtype);
- return NULL;
- }
- memset(directive_value, 0, strlen(directive_value));
- free(stripped_directive_value);
- cho_directive_free(directive);
- directive = NULL;
- state = STATE_LYRICS;
- break;
- }
- if (buf == '<') {
- state_before_tag = STATE_DIRECTIVE_VALUE;
- state = STATE_MARKUP_TAG;
- break;
- }
- if (buf == '{') {
- cho_log(LOG_ERR, "Can't start a new directive if the previous one is not yet closed.");
- return NULL;
- }
- if (buf == '\n') {
- if (prev_buf == '\\') {
- state_before_backslash = STATE_DIRECTIVE_VALUE;
- state = STATE_BACKSLASH;
- dv--;
- break;
- }
- cho_log(LOG_ERR, "Newline character inside a directive value is invalid.");
- return NULL;
- }
- if (dv > 4094) {
- cho_log(LOG_ERR, "Directive value can't be greater than 4095 bytes.");
- return NULL;
- }
- directive_value[dv] = buf;
- dv++;
- break;
- }
- case STATE_CHORD: {
- if (buf == ']') {
- chord[ch] = 0;
- ch = 0;
- g_prev_ttype = g_current_ttype;
- g_current_ttype = TT_CHORD;
- if (is_chord_already_initialized) {
- text_above_pos = cho_line_compute_text_above_position(songs[so]->sections[se]->lines[li], ly, te);
- (*lines)[li]->text_above[c]->position = text_above_pos;
- tmp_chord = cho_chord_parse(chord);
- cho_chord_complete((*lines)[li]->text_above[c]->u.chord, tmp_chord);
- if (!(*lines)[li]->text_above[c]->u.chord->is_canonical) {
- cho_log(LOG_INFO, "Didn't recognize the chord '%s'.", (*lines)[li]->text_above[c]->u.chord->name);
- }
- cho_chord_free(tmp_chord);
- is_chord_already_initialized = false;
- } else {
- (*lines)[li]->text_above = erealloc((*lines)[li]->text_above, (c+1) * sizeof(struct ChoLineItemAbove *));
- (*lines)[li]->text_above[c] = emalloc(sizeof(struct ChoLineItemAbove));
- (*lines)[li]->text_above[c]->is_chord = true;
- text_above_pos = cho_line_compute_text_above_position((*lines)[li], ly, te);
- (*lines)[li]->text_above[c]->position = text_above_pos;
- (*lines)[li]->text_above[c]->u.chord = cho_chord_parse(chord);
- if (!(*lines)[li]->text_above[c]->u.chord->is_canonical) {
- cho_log(LOG_INFO, "Didn't recognize the chord '%s'.", (*lines)[li]->text_above[c]->u.chord->name);
- }
- }
- songs[so]->present_text_types[TT_CHORD] = true;
- memset(chord, 0, strlen(chord));
- c++;
- g_current_ttype = g_prev_ttype;
- state = STATE_LYRICS;
- break;
- }
- if (prev_buf == '[' && buf == '*') {
- g_prev_ttype = g_current_ttype;
- g_current_ttype = TT_ANNOT;
- (*lines)[li]->text_above = erealloc((*lines)[li]->text_above, (c+1) * sizeof(struct ChoLineItemAbove *));
- (*lines)[li]->text_above[c] = emalloc(sizeof(struct ChoLineItemAbove));
- (*lines)[li]->text_above[c]->is_chord = false;
- text_above_pos = cho_line_compute_text_above_position((*lines)[li], ly, te);
- (*lines)[li]->text_above[c]->position = text_above_pos;
- (*lines)[li]->text_above[c]->u.annot = cho_text_new();
- state = STATE_ANNOTATION;
- break;
- }
- if (buf == '\n') {
- if (prev_buf == '\\') {
- state_before_backslash = STATE_CHORD;
- state = STATE_BACKSLASH;
- ch--;
- break;
- }
- cho_log(LOG_ERR, "Newline character inside a chord is invalid.");
- return NULL;
- }
- if (buf == '[') {
- cho_log(LOG_ERR, "Can't start a new chord/annotation if the previous one is not yet closed.");
- return NULL;
- }
- if (buf == '<') {
- if (prev_buf == '[') {
- (*lines)[li]->text_above = erealloc((*lines)[li]->text_above, (c+1) * sizeof(struct ChoLineItemAbove *));
- (*lines)[li]->text_above[c] = emalloc(sizeof(struct ChoLineItemAbove));
- (*lines)[li]->text_above[c]->is_chord = true;
- (*lines)[li]->text_above[c]->u.chord = cho_chord_new();
- is_chord_already_initialized = true;
- }
- state_before_tag = STATE_CHORD;
- state = STATE_MARKUP_TAG;
- break;
- }
- chord[ch] = buf;
- ch++;
- break;
- }
- case STATE_ANNOTATION: {
- if (buf == ']') {
- (*lines)[li]->text_above[c]->u.annot->text = erealloc((*lines)[li]->text_above[c]->u.annot->text, (ann+1) * sizeof(char));
- (*lines)[li]->text_above[c]->u.annot->text[ann] = 0;
- songs[so]->present_text_types[TT_ANNOT] = true;
- ann = 0;
- c++;
- g_current_ttype = g_prev_ttype;
- state = STATE_LYRICS;
- break;
- }
- if (buf == '<') {
- state_before_tag = STATE_ANNOTATION;
- state = STATE_MARKUP_TAG;
- break;
- }
- if (buf == '\n') {
- if (prev_buf == '\\') {
- state_before_backslash = STATE_ANNOTATION;
- state = STATE_BACKSLASH;
- ann--;
- break;
- }
- cho_log(LOG_ERR, "Newline character inside an annotation is invalid.");
- return NULL;
- }
- (*lines)[li]->text_above[c]->u.annot->text = erealloc((*lines)[li]->text_above[c]->u.annot->text, (ann+1) * sizeof(char));
- (*lines)[li]->text_above[c]->u.annot->text[ann] = buf;
- ann++;
- break;
- }
- case STATE_TAB: {
- // INFO: similar to STATE_LYRICS but without markup and directives
- if (prev_buf == '\n' && buf == '#') {
- state_before_comment = STATE_TAB;
- state = STATE_COMMENT;
- break;
- }
- if (is_maybe_end_of_tab_directive) {
- if (buf == '}') {
- directive_name[dn] = 0;
- dn = 0;
- is_maybe_end_of_tab_directive = false;
- if (!strcmp(directive_name, "end_of_tab") || !strcmp(directive_name, "eot")) {
- cho_line_item_free((*lines)[li]->items[ly]);
- free((*lines)[li]->items);
- ly = 0;
- free((*lines)[li]);
- (*lines)[li] = NULL;
- se++;
- songs[so]->sections = erealloc(songs[so]->sections, (se+1) * sizeof(struct ChoSection *));
- songs[so]->sections[se] = cho_section_new();
- li = 0;
- lines = &songs[so]->sections[se]->lines;
- *lines = emalloc(sizeof(struct ChoLine *));
- (*lines)[li] = cho_line_new();
- (*lines)[li]->items = emalloc(sizeof(struct ChoLineItem *));
- (*lines)[li]->items[ly] = cho_line_item_new();
- g_current_ttype = TT_TEXT;
- state = STATE_LYRICS;
- break;
- } else {
- (*lines)[li]->items[ly]->u.text->text = erealloc((*lines)[li]->items[ly]->u.text->text, (te+1) * sizeof(char));
- (*lines)[li]->items[ly]->u.text->text[te] = '{';
- te++;
- char *k;
- for (k = (char *)&directive_name; *k; k++, te++) {
- (*lines)[li]->items[ly]->u.text->text = erealloc((*lines)[li]->items[ly]->u.text->text, (te+1) * sizeof(char));
- (*lines)[li]->items[ly]->u.text->text[te] = *k;
- }
- (*lines)[li]->items[ly]->u.text->text = erealloc((*lines)[li]->items[ly]->u.text->text, (te+1) * sizeof(char));
- (*lines)[li]->items[ly]->u.text->text[te] = '}';
- te++;
- }
- break;
- }
- if (buf == ' ' || buf == ':') {
- directive_name[dn] = 0;
- dn = 0;
- is_maybe_end_of_tab_directive = false;
- (*lines)[li]->items[ly]->u.text->text = erealloc((*lines)[li]->items[ly]->u.text->text, (te+1) * sizeof(char));
- (*lines)[li]->items[ly]->u.text->text[te] = '{';
- te++;
- char *k;
- for (k = (char *)&directive_name; *k; k++, te++) {
- (*lines)[li]->items[ly]->u.text->text = erealloc((*lines)[li]->items[ly]->u.text->text, (te+1) * sizeof(char));
- (*lines)[li]->items[ly]->u.text->text[te] = *k;
- }
- (*lines)[li]->items[ly]->u.text->text = erealloc((*lines)[li]->items[ly]->u.text->text, (te+1) * sizeof(char));
- (*lines)[li]->items[ly]->u.text->text[te] = buf;
- te++;
- break;
- }
- directive_name[dn] = buf;
- dn++;
- break;
- }
- if (prev_buf == '\n' && buf == '{') {
- is_maybe_end_of_tab_directive = true;
- break;
- }
- if (buf == '\n') {
- if (prev_buf == '\\') {
- state_before_backslash = STATE_TAB;
- state = STATE_BACKSLASH;
- // INFO: This will later overwrite the backslash
- te--;
- break;
- }
- if (ta > -1 && !tags[ta]->is_closed && strcmp(tags[ta]->name, "img")) {
- cho_log(LOG_ERR, "Tag has to be closed on same line.");
- return NULL;
- }
- if ((*lines)[li]->items[ly]->is_text) {
- (*lines)[li]->items[ly]->u.text->text = erealloc((*lines)[li]->items[ly]->u.text->text, (te+1) * sizeof(char));
- (*lines)[li]->items[ly]->u.text->text[te] = 0;
- if (strlen((*lines)[li]->items[ly]->u.text->text) == 0) {
- cho_line_item_free((*lines)[li]->items[ly]);
- if (ly == 0) {
- if (
- !(*lines)[li]->text_above &&
- (*lines)[li]->btype == BT_LINE
- ) {
- free((*lines)[li]->items);
- free((*lines)[li]);
- *lines = erealloc(*lines, (li+1) * sizeof(struct ChoLine *));
- (*lines)[li] = cho_line_new();
- (*lines)[li]->items = erealloc((*lines)[li]->items, (ly+1) * sizeof(struct ChoLineItem *));
- (*lines)[li]->items[ly] = cho_line_item_new();
- break;
- }
- }
- } else {
- ly++;
- }
- } else {
- ly++;
- }
- (*lines)[li]->items = erealloc((*lines)[li]->items, (ly+1) * sizeof(struct ChoLineItem *));
- (*lines)[li]->items[ly] = NULL;
- ly = 0;
- te = 0;
- (*lines)[li]->text_above = erealloc((*lines)[li]->text_above, (c+1) * sizeof(struct ChoLineItemAbove *));
- (*lines)[li]->text_above[c] = NULL;
- c = 0;
- li++;
- *lines = erealloc(*lines, (li+1) * sizeof(struct ChoLine *));
- (*lines)[li] = cho_line_new();
- (*lines)[li]->items = erealloc((*lines)[li]->items, (ly+1) * sizeof(struct ChoLineItem *));
- (*lines)[li]->items[ly] = cho_line_item_new();
- break;
- }
- (*lines)[li]->items[ly]->u.text->text = erealloc((*lines)[li]->items[ly]->u.text->text, (te+1) * sizeof(char));
- (*lines)[li]->items[ly]->u.text->text[te] = buf;
- te++;
- break;
- }
- case STATE_MARKUP_TAG: {
- if (buf == '/') {
- state = STATE_MARKUP_TAG_END;
- break;
- }
- ta++;
- tags = erealloc(tags, (ta+1) * sizeof(struct Tag *));
- tags[ta] = cho_tag_new();
- state = STATE_MARKUP_TAG_START;
- if (fseek(fp, -1, SEEK_CUR)) {
- LOG_DEBUG("fseek failed.");
- return NULL;
- }
- break;
- }
- case STATE_MARKUP_TAG_START: {
- if (buf == '>') {
- tag_start[t] = 0;
- t = 0;
- if (!strcmp(tag_start, "img")) {
- cho_log(LOG_ERR, "'img' tag has to have at least the 'src' attribute.");
- return NULL;
- }
- tags[ta]->name = strdup(tag_start);
- tag_style = cho_style_parse(tag_start, NULL, cho_tag_style_inherit(tags, ta-1), &tags[ta]->style_presence);
- if (!tag_style) {
- LOG_DEBUG("cho_style_parse failed.");
- return NULL;
- }
- tags[ta]->style = tag_style;
- switch (state_before_tag) {
- case STATE_LYRICS:
- cho_style_free((*lines)[li]->items[ly]->u.text->style);
- (*lines)[li]->items[ly]->u.text->style = cho_style_copy(tag_style);
- break;
- case STATE_CHORD:
- cho_style_free((*lines)[li]->text_above[c]->u.chord->style);
- (*lines)[li]->text_above[c]->u.chord->style = cho_style_copy(tag_style);
- break;
- case STATE_ANNOTATION:
- if (ann > 0) {
- (*lines)[li]->text_above[c]->u.annot->text = erealloc((*lines)[li]->text_above[c]->u.annot->text, (ann+1) * sizeof(char));
- (*lines)[li]->text_above[c]->u.annot->text[ann] = 0;
- ann = 0;
- c++;
- (*lines)[li]->text_above = erealloc((*lines)[li]->text_above, (c+1) * sizeof(struct ChoLineItemAbove *));
- (*lines)[li]->text_above[c] = emalloc(sizeof(struct ChoLineItemAbove));
- (*lines)[li]->text_above[c]->is_chord = false;
- (*lines)[li]->text_above[c]->position = text_above_pos;
- (*lines)[li]->text_above[c]->u.annot = cho_text_new();
- }
- cho_style_free((*lines)[li]->text_above[c]->u.annot->style);
- (*lines)[li]->text_above[c]->u.annot->style = cho_style_copy(tag_style);
- break;
- case STATE_DIRECTIVE_VALUE:
- directive_has_tag = true;
- break;
- default:
- cho_log(LOG_ERR, "Invalid state_before_tag '%s'.", state_enums[state_before_tag]);
- return NULL;
- }
- memset(tag_start, 0, strlen(tag_start));
- state = state_before_tag;
- break;
- }
- if (is_whitespace(buf)) {
- tag_start[t] = 0;
- t = 0;
- tags[ta]->name = strdup(tag_start);
- tags[ta]->attrs = erealloc(tags[ta]->attrs, (at+1) * sizeof(struct Attr *));
- tags[ta]->attrs[at] = cho_tag_attr_new();
- state = STATE_MARKUP_ATTR_NAME;
- break;
- }
- if (buf == '\n') {
- if (prev_buf == '\\') {
- state_before_backslash = STATE_MARKUP_TAG_START;
- state = STATE_BACKSLASH;
- t--;
- break;
- }
- cho_log(LOG_ERR, "Newline character inside a tag name is invalid.");
- return NULL;
- }
- if (t == 5) {
- cho_log(LOG_ERR, "Start tag name is too long.");
- return NULL;
- }
- tag_start[t] = buf;
- t++;
- break;
- }
- case STATE_MARKUP_TAG_END: {
- if (buf == '>') {
- tag_end[t] = 0;
- t = 0;
- if (!cho_tag_close_last_unclosed(tag_end, tags, ta)) {
- LOG_DEBUG("cho_tag_close_last_unclosed failed.");
- return NULL;
- }
- memset(tag_end, 0, strlen(tag_end));
- state = state_before_tag;
- break;
- }
- if (buf == '\n') {
- if (prev_buf == '\\') {
- state_before_backslash = STATE_MARKUP_TAG_END;
- state = STATE_BACKSLASH;
- t--;
- break;
- }
- cho_log(LOG_ERR, "Newline character inside a tag name is invalid.");
- return NULL;
- }
- if (t == 5) {
- cho_log(LOG_ERR, "End tag name is too long.");
- return NULL;
- }
- tag_end[t] = buf;
- t++;
- break;
- }
- case STATE_MARKUP_ATTR_NAME: {
- if (buf == '=') {
- tags[ta]->attrs[at]->name = erealloc(tags[ta]->attrs[at]->name, (atn+1) * sizeof(char));
- tags[ta]->attrs[at]->name[atn] = 0;
- atn = 0;
- state = STATE_MARKUP_ATTR_VALUE;
- break;
- }
- if (is_whitespace(buf)) {
- if (at == 0) {
- if (!tags[ta]->attrs[at]->name) {
- break;
- } else {
- tags[ta]->attrs[at]->name = erealloc(tags[ta]->attrs[at]->name, (atn+1) * sizeof(char));
- tags[ta]->attrs[at]->name[atn] = 0;
- cho_log(LOG_ERR, "Attribute with name '%s' of tag '%s' has no value.", tags[ta]->attrs[at]->name, tag_start);
- return NULL;
- }
- }
- if (tags[ta]->attrs[at-1]->name && tags[ta]->attrs[at-1]->value) {
- break;
- }
- if (!tags[ta]->attrs[at-1]->name && !tags[ta]->attrs[at-1]->value) {
- break;
- }
- tags[ta]->attrs[at]->name = erealloc(tags[ta]->attrs[at]->name, (atn+1) * sizeof(char));
- tags[ta]->attrs[at]->name[atn] = 0;
- cho_log(LOG_ERR, "Attribute with name '%s' of tag '%s' has no value.", tags[ta]->attrs[at]->name, tag_start);
- return NULL;
- }
- if (buf == '>') {
- if (tags[ta]->attrs[at-1]->value) {
- cho_tag_attr_free(tags[ta]->attrs[at]);
- tags[ta]->attrs[at] = NULL;
- atn = 0;
- if (!strcmp(tags[ta]->name, "img")) {
- cho_text_free((*lines)[li]->items[ly]->u.text);
- (*lines)[li]->items[ly]->is_text = false;
- image = cho_image_tag_parse(tags[ta]->attrs);
- if (!image) {
- LOG_DEBUG("cho_image_tag_parse failed.");
- return NULL;
- }
- (*lines)[li]->items[ly]->u.image = image;
- ly++;
- (*lines)[li]->items = erealloc((*lines)[li]->items, (ly+1) * sizeof(struct ChoLineItem *));
- (*lines)[li]->items[ly] = cho_line_item_new();
- } else {
- tag_style = cho_style_parse(tag_start, tags[ta]->attrs, cho_tag_style_inherit(tags, ta-1), &tags[ta]->style_presence);
- if (!tag_style) {
- LOG_DEBUG("cho_style_parse failed.");
- return NULL;
- }
- tags[ta]->style = tag_style;
- switch (state_before_tag) {
- case STATE_LYRICS:
- cho_style_free((*lines)[li]->items[ly]->u.text->style);
- (*lines)[li]->items[ly]->u.text->style = cho_style_copy(tag_style);
- break;
- case STATE_CHORD:
- cho_style_free((*lines)[li]->text_above[c]->u.chord->style);
- (*lines)[li]->text_above[c]->u.chord->style = cho_style_copy(tag_style);
- break;
- case STATE_ANNOTATION:
- cho_style_free((*lines)[li]->text_above[c]->u.annot->style);
- (*lines)[li]->text_above[c]->u.annot->style = cho_style_copy(tag_style);
- break;
- case STATE_DIRECTIVE_VALUE:
- directive_has_tag = true;
- break;
- default:
- cho_log(LOG_ERR, "Invalid state_before_tag '%s'.", state_enums[state_before_tag]);
- return NULL;
- }
- }
- at = 0;
- memset(tag_start, 0, strlen(tag_start));
- state = state_before_tag;
- break;
- } else {
- tags[ta]->attrs[at]->name = erealloc(tags[ta]->attrs[at]->name, (atn+1) * sizeof(char));
- tags[ta]->attrs[at]->name[atn] = 0;
- atn = 0;
- cho_log(LOG_ERR, "Attribute with name '%s' of tag '%s' has no value.", tags[ta]->attrs[at]->name, tag_start);
- return NULL;
- }
- }
- if (buf == '\n') {
- if (prev_buf == '\\') {
- state_before_backslash = STATE_MARKUP_ATTR_NAME;
- state = STATE_BACKSLASH;
- atn--;
- break;
- }
- cho_log(LOG_ERR, "Newline character inside an tag attribute name is invalid.");
- return NULL;
- }
- tags[ta]->attrs[at]->name = erealloc(tags[ta]->attrs[at]->name, (atn+1) * sizeof(char));
- tags[ta]->attrs[at]->name[atn] = buf;
- atn++;
- break;
- }
- case STATE_MARKUP_ATTR_VALUE: {
- if (buf == '\n') {
- if (prev_buf == '\\') {
- state_before_backslash = STATE_MARKUP_ATTR_VALUE;
- state = STATE_BACKSLASH;
- atv--;
- break;
- }
- cho_log(LOG_ERR, "Newline character inside an attribute value is invalid.");
- return NULL;
- }
- if (avs == -1) {
- if (is_whitespace(buf)) {
- cho_log(LOG_ERR, "Whitespace character after equals sign is invalid.");
- return NULL;
- }
- if (buf == '>') {
- cho_log(LOG_ERR, "Attribute with name '%s' of tag '%s' has no value.", tags[ta]->attrs[at]->name, tag_start);
- return NULL;
- }
- if (buf == '\'') {
- avs = AVS_APOSTROPHE;
- } else if (buf == '"') {
- avs = AVS_QUOTATION_MARK;
- } else {
- avs = AVS_UNQUOTED;
- tags[ta]->attrs[at]->value = erealloc(tags[ta]->attrs[at]->value, (atv+1) * sizeof(char));
- tags[ta]->attrs[at]->value[atv] = buf;
- atv++;
- }
- break;
- }
- if (avs == AVS_UNQUOTED && buf == '>') {
- tags[ta]->attrs[at]->value = erealloc(tags[ta]->attrs[at]->value, (atv+1) * sizeof(char));
- tags[ta]->attrs[at]->value[atv] = 0;
- atv = 0;
- at++;
- tags[ta]->attrs = erealloc(tags[ta]->attrs, (at+1) * sizeof(struct Attr *));
- tags[ta]->attrs[at] = NULL;
- if (!strcmp(tags[ta]->name, "img")) {
- cho_text_free((*lines)[li]->items[ly]->u.text);
- (*lines)[li]->items[ly]->is_text = false;
- image = cho_image_tag_parse(tags[ta]->attrs);
- if (!image) {
- LOG_DEBUG("cho_image_tag_parse failed.");
- return NULL;
- }
- (*lines)[li]->items[ly]->u.image = image;
- ly++;
- (*lines)[li]->items = erealloc((*lines)[li]->items, (ly+1) * sizeof(struct ChoLineItem *));
- (*lines)[li]->items[ly] = cho_line_item_new();
- } else {
- tag_style = cho_style_parse(tag_start, tags[ta]->attrs, cho_tag_style_inherit(tags, ta-1), &tags[ta]->style_presence);
- if (!tag_style) {
- LOG_DEBUG("cho_style_parse failed.");
- return NULL;
- }
- tags[ta]->style = tag_style;
- switch (state_before_tag) {
- case STATE_LYRICS:
- cho_style_free((*lines)[li]->items[ly]->u.text->style);
- (*lines)[li]->items[ly]->u.text->style = cho_style_copy(tag_style);
- break;
- case STATE_CHORD:
- cho_style_free((*lines)[li]->text_above[c]->u.chord->style);
- (*lines)[li]->text_above[c]->u.chord->style = cho_style_copy(tag_style);
- break;
- case STATE_ANNOTATION:
- cho_style_free((*lines)[li]->text_above[c]->u.annot->style);
- (*lines)[li]->text_above[c]->u.annot->style = cho_style_copy(tag_style);
- break;
- case STATE_DIRECTIVE_VALUE:
- directive_has_tag = true;
- break;
- default:
- cho_log(LOG_ERR, "Invalid state_before_tag '%s'.", state_enums[state_before_tag]);
- return NULL;
- }
- }
- at = 0;
- avs = -1;
- memset(tag_start, 0, strlen(tag_start));
- state = state_before_tag;
- break;
- }
- if (
- (avs == AVS_APOSTROPHE && buf == '\'') ||
- (avs == AVS_QUOTATION_MARK && buf == '"') ||
- (avs == AVS_UNQUOTED && (buf == ' ' || buf == '\t'))
- ) {
- tags[ta]->attrs[at]->value = erealloc(tags[ta]->attrs[at]->value, (atv+1) * sizeof(char));
- tags[ta]->attrs[at]->value[atv] = 0;
- atv = 0;
- at++;
- tags[ta]->attrs = erealloc(tags[ta]->attrs, (at+1) * sizeof(struct Attr *));
- tags[ta]->attrs[at] = cho_tag_attr_new();
- avs = -1;
- state = STATE_MARKUP_ATTR_NAME;
- break;
- }
- tags[ta]->attrs[at]->value = erealloc(tags[ta]->attrs[at]->value, (atv+1) * sizeof(char));
- tags[ta]->attrs[at]->value[atv] = buf;
- atv++;
- break;
- }
- case STATE_COMMENT: {
- if (buf == '\n') {
- state = state_before_comment;
- break;
- }
- break;
- }
- }
- prev_buf = buf;
- } else {
- break;
- }
- }
- int e = 0;
- while (e <= ta) {
- cho_tag_free(tags[e]);
- e++;
- }
- free(tags);
- if ((*lines)[li]->items[ly]->is_text) {
- if ((*lines)[li]->items[ly]->u.text->text) {
- (*lines)[li]->items[ly]->u.text->text = erealloc((*lines)[li]->items[ly]->u.text->text, (te+1) * sizeof(char));
- (*lines)[li]->items[ly]->u.text->text[te] = 0;
- ly++;
- (*lines)[li]->items = erealloc((*lines)[li]->items, (ly+1) * sizeof(struct ChoLineItem *));
- (*lines)[li]->items[ly] = NULL;
- (*lines)[li]->text_above = erealloc((*lines)[li]->text_above, (c+1) * sizeof(struct ChoLineItemAbove *));
- (*lines)[li]->text_above[c] = NULL;
- li++;
- *lines = erealloc(*lines, (li+1) * sizeof(struct ChoLine *));
- (*lines)[li] = NULL;
- } else {
- cho_line_item_free((*lines)[li]->items[ly]);
- free((*lines)[li]->items);
- free((*lines)[li]->text_above);
- free((*lines)[li]);
- (*lines)[li] = NULL;
- }
- }
- if (!cho_style_reset_default()) {
- LOG_DEBUG("cho_style_reset_default failed.");
- return NULL;
- }
- songs[so]->metadata = erealloc(songs[so]->metadata, (m+1) * sizeof(struct ChoMetadata *));
- songs[so]->metadata[m] = NULL;
- se++;
- songs[so]->sections = erealloc(songs[so]->sections, (se+1) * sizeof(struct ChoSection *));
- songs[so]->sections[se] = NULL;
- songs[so]->diagrams = erealloc(songs[so]->diagrams, (dia+1) * sizeof(struct ChordDiagram *));
- songs[so]->diagrams[dia] = NULL;
- so++;
- songs = erealloc(songs, (so+1) * sizeof(struct ChoSong *));
- songs[so] = NULL;
- g_current_ttype = TT_TEXT;
- g_prev_ttype = TT_TEXT;
- g_config = NULL;
- g_chordpro_filepath = NULL;
- free(g_transpose_history);
- g_transpose_history = NULL;
- g_transpose = NULL;
- g_line_number = 1;
- for (e = 0; e<g_ia; e++) {
- cho_image_free(g_image_assets[e]);
- }
- free(g_image_assets);
- g_image_assets = NULL;
- g_ia = 0;
- bool exist_title = false;
- for (so = 0; songs[so]; so++) {
- for (m = 0; songs[so]->metadata[m]; m++) {
- if (
- !strcmp(songs[so]->metadata[m]->name, "title") &&
- songs[so]->metadata[m]->value &&
- strcmp(songs[so]->metadata[m]->value, "") != 0
- ) {
- exist_title = true;
- }
- }
- if (!exist_title) {
- g_line_number = 0;
- /* INFO: This cho_log() is not line specific. It's a workaround. */
- cho_log(LOG_ERR, "Song has no title.");
- return NULL;
- }
- exist_title = false;
- }
- return songs;
-}
-
-#ifdef DEBUG
-void
-cho_debug_songs_print(struct ChoSong **songs)
-{
- struct ChoSong **s;
- struct ChoSection **se;
- struct ChoLine **li;
- struct ChoLineItem **it;
- struct ChoLineItemAbove **above;
- char *name;
- for (s = songs; *s; s++) {
- for (se = (*s)->sections; *se; se++) {
- printf("## Section");
- if ((*se)->label) {
- printf(": %s\n", (*se)->label->text);
- } else {
- printf("\n");
- }
- for (li = (*se)->lines; *li; li++) {
- printf("## Line\n");
- it = (*li)->items;
- for (above = (*li)->text_above; *above; above++) {
- if ((*above)->is_chord) {
- name = cho_chord_name_generate((*above)->u.chord);
- printf("chord: %s\n", name);
- free(name);
- } else {
- printf("annotation: %s\n", (*above)->u.annot->text);
- }
- }
- for (it = (*li)->items; *it; it++) {
- if ((*it)->is_text) {
- printf("text: %s\n", (*it)->u.text->text);
- } else {
- printf("image: %s\n", (*it)->u.image->src);
- }
- }
- }
- }
- }
-}
-#endif /* DEBUG */
diff --git a/chordpro.h b/chordpro.h
@@ -1,175 +0,0 @@
-#include <stdint.h>
-#include "types.h"
-
-#ifndef _CHORDPRO_H_
-#define _CHORDPRO_H_
-
-#define ERROR -1.0
-#define EMPTY_DOUBLE -1.0
-#define EMPTY_INT -1
-#define DEFAULT_FONT_SIZE 14.0
-#define DEFAULT_TITLE_FONT_SIZE 18.0
-// INFO: Based on https://stackoverflow.com/a/417184
-#define URL_MAX_LEN 2000
-#define FONT_NAME_MAX 100
-
-enum AttrValueSyntax : int8_t {
- AVS_QUOTATION_MARK,
- AVS_APOSTROPHE,
- AVS_UNQUOTED
-};
-
-enum ChordDiagramState {
- CDS_NAME,
- CDS_OPTION_NAME,
- CDS_BASE_FRET,
- CDS_FRETS,
- CDS_FINGERS,
- CDS_KEYS,
- CDS_DIAGRAM,
- CDS_COPY
-};
-
-enum ChordDirective {
- TRANSPOSE, DEFINE /* , CHORD */
-};
-
-enum DirectiveType {
- DT_ENVIRONMENT,
- DT_METADATA,
- DT_FORMATTING,
- DT_IMAGE,
- DT_PREAMBLE,
- DT_FONT,
- DT_CHORD,
- DT_OUTPUT,
- DT_EXTENSION,
- DT_CUSTOM
-};
-
-enum MetadataDirective {
- TITLE,
- SUBTITLE
-};
-
-enum OptionState {
- OS_NAME,
- OS_VALUE
-};
-
-enum Position {
- POS_START,
- POS_END,
- POS_NO
-};
-
-enum State {
- STATE_LYRICS,
- STATE_BACKSLASH,
- STATE_DIRECTIVE_NAME,
- STATE_DIRECTIVE_VALUE,
- STATE_CHORD,
- STATE_ANNOTATION,
- STATE_TAB,
- STATE_MARKUP_TAG,
- STATE_MARKUP_TAG_START,
- STATE_MARKUP_TAG_END,
- STATE_MARKUP_ATTR_NAME,
- STATE_MARKUP_ATTR_VALUE,
- STATE_COMMENT
-};
-
-enum StylePropertyType : int8_t {
- SPT_FONT,
- SPT_SIZE,
- SPT_COLOR
-};
-
-struct Attr {
- char *name;
- char *value;
-};
-
-/*
- INFO: Depending on the 'dtype' the other
- fields have a meaningful value or not.
-*/
-
-struct ChoDirective {
- enum DirectiveType dtype;
- enum SectionType stype;
- enum Position position;
- enum StylePropertyType sprop;
- enum TextType ttype;
- enum BreakType btype;
- enum MetadataDirective meta;
- enum ChordDirective ctype;
- struct ChoStyle *style;
-};
-
-union StylePropertyValue {
- char *font_name;
- double font_size;
- struct RGBColor *foreground_color;
-};
-
-struct StyleProperty {
- enum TextType ttype;
- enum StylePropertyType type;
- union StylePropertyValue u;
-};
-
-struct Tag {
- char *name;
- struct ChoStyle *style;
- struct ChoStylePresence style_presence;
- struct Attr **attrs;
- bool is_closed;
-};
-
-void cho_log_enable_info_logs(void);
-
-struct ChoSong **cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config);
-int cho_song_count(struct ChoSong **songs);
-int cho_song_compare(const void *a, const void *b);
-void cho_songs_free(struct ChoSong **song);
-
-int cho_line_item_count(struct ChoLineItem **items);
-char *cho_chord_name_generate(struct ChoChord *chord);
-
-void cho_chords_add(struct ChoChord ***chords, struct ChoChord *chord);
-bool cho_chords_has(struct ChoChord **chords, struct ChoChord *chord);
-size_t cho_chord_count(struct ChoChord **chords);
-int cho_chord_compare(const void *a, const void *b);
-void cho_chords_free(struct ChoChord **chords);
-
-const char *cho_metadata_get(struct ChoMetadata **metadata, const char *name);
-
-struct ChoStyle *cho_style_new(void);
-void cho_style_free(struct ChoStyle *style);
-struct ChoStyle *cho_style_copy(struct ChoStyle *style);
-void cho_style_print_as_toml(struct ChoStyle *style, const char *section);
-
-struct RGBColor *cho_rgbcolor_new(uint8_t red, uint8_t green, uint8_t blue);
-struct RGBColor *cho_color_parse(const char *str);
-struct RGBColor *cho_color_copy(struct RGBColor *color);
-enum LineStyle cho_linestyle_parse(const char *str);
-
-// const char *cho_image_name_create(struct ChoImage *image, const char *dirname);
-
-void cho_font_free(struct Font *font);
-void cho_font_print(struct Font *font);
-struct Font *cho_font_copy(struct Font *font);
-void cho_fonts_free(struct Font **fonts);
-char *cho_font_name_normalize(const char *name);
-enum FontFamily cho_font_family_parse(const char *str);
-const char *cho_font_family_to_config_string(enum FontFamily font_family);
-enum FontStyle cho_font_style_parse(const char *str);
-const char *cho_font_style_to_config_string(enum FontStyle style);
-enum FontWeight cho_font_weight_parse(const char *str);
-const char *cho_font_weight_to_config_string(enum FontWeight weight);
-
-void cho_debug_style_print(struct ChoStyle *style);
-// void cho_debug_songs_print(struct ChoSong **songs);
-
-#endif /* _CHORDPRO_H_ */
diff --git a/config.c b/config.c
@@ -1,1065 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <toml.h>
-#include "types.h"
-#include "config.h"
-#include "chordpro.h"
-#include "util.h"
-#include "chord_diagram.h"
-
-static const char *notation_systems[] = {
- "common",
- "german",
- "scandinavian",
- "latin",
- "roman",
- "nashville",
- "custom" // TODO: Is this needed
-};
-
-static const char *parse_modes[] = {
- "strict",
- "relaxed"
-};
-
-static const char *instruments[] = {
- "guitar",
- "keyboard",
- "mandolin",
- "ukulele"
-};
-
-static const char *text_types[] = {
- "chord", "annotation", "chorus",
- "footer", "grid", "tab", "toc", "toc_title", "text",
- "title", "subtitle", "label", "comment",
- "comment_italic", "comment_box"
-};
-
-static const char *alignments[] = {
- "left", "center", "right"
-};
-
-/* static const char *g_valid_styles[] = {
- "title",
- "subtitle",
- "footer", // TODO
- "text",
- "chorus",
- "chord",
- "annotation",
- "comment",
- "comment_italic",
- "comment_boxed",
- "tab",
- "label",
- "toc",
- "grid",
- "grid_margin", // TODO
- "empty", // TODO
- "diagram", // TODO
- "diagram_base", // TODO
- "chordfingers" // TODO
-}; */
-
-static struct Note notes_common[] = {
- { .note = "C", .sharp = "C#", .flat = NULL },
- { .note = "D", .sharp = "D#", .flat = "Db" },
- { .note = "E", .sharp = NULL, .flat = "Eb" },
- { .note = "F", .sharp = "F#", .flat = NULL },
- { .note = "G", .sharp = "G#", .flat = "Gb" },
- { .note = "A", .sharp = "A#", .flat = "Ab" },
- { .note = "B", .sharp = NULL, .flat = "Bb" }
-};
-
-static struct Note notes_german[] = {
- { .note = "C", .sharp = "Cis", .flat = NULL },
- { .note = "D", .sharp = "Dis", .flat = "Des" },
- { .note = "E", .sharp = NULL, .flat = "Es" },
- { .note = "F", .sharp = "Fis", .flat = NULL },
- { .note = "G", .sharp = "Gis", .flat = "Ges" },
- { .note = "A", .sharp = "Ais", .flat = "As" },
- { .note = "H", .sharp = NULL, .flat = "B"},
-};
-
-static struct Note notes_scandinavian[] = {
- { .note = "C", .sharp = "C#", .flat = NULL },
- { .note = "D", .sharp = "D#", .flat = "Db"},
- { .note = "E", .sharp = NULL, .flat = "Eb"},
- { .note = "F", .sharp = "F#", .flat = NULL },
- { .note = "G", .sharp = "G#", .flat = "Gb"},
- { .note = "A", .sharp = "A#", .flat = "Ab"},
- { .note = "H", .sharp = NULL, .flat = "B"},
-};
-
-static struct Note notes_latin[] = {
- { .note = "Do", .sharp = "Do#", .flat = NULL },
- { .note = "Re", .sharp = "Re#", .flat = "Reb"},
- { .note = "Mi", .sharp = NULL, .flat = "Mib"},
- { .note = "Fa", .sharp = "Fa#", .flat = NULL },
- { .note = "Sol", .sharp = "Sol#", .flat = "Solb"},
- { .note = "La", .sharp = "La#", .flat = "Lab"},
- { .note = "Si", .sharp = NULL, .flat = "Sib"},
-};
-
-static struct Note notes_roman[] = {
- { .note = "I", .sharp = "I#", .flat = NULL },
- { .note = "II", .sharp = "II#", .flat = "IIb" },
- { .note = "III", .sharp = NULL, .flat = "IIIb" },
- { .note = "IV", .sharp = "IV#", .flat = NULL },
- { .note = "V", .sharp = "V#", .flat = "Vb" },
- { .note = "VI", .sharp = "VI#", .flat = "VIb" },
- { .note = "VII", .sharp = NULL, .flat = "VIIb" },
-};
-
-static struct Note notes_nashville[] = {
- { .note = "1", .sharp = "1#", .flat = NULL },
- { .note = "2", .sharp = "2#", .flat = "2b" },
- { .note = "3", .sharp = NULL, .flat = "3b" },
- { .note = "4", .sharp = "4#", .flat = NULL },
- { .note = "5", .sharp = "5#", .flat = "5b" },
- { .note = "6", .sharp = "6#", .flat = "6b" },
- { .note = "7", .sharp = NULL, .flat = "7b" },
-};
-
-static enum TextType
-config_text_type_parse(const char *str)
-{
- if (!strcmp(str, text_types[TT_CHORD])) {
- return TT_CHORD;
- } else
- if (!strcmp(str, text_types[TT_ANNOT])) {
- return TT_ANNOT;
- } else
- if (!strcmp(str, text_types[TT_CHORUS])) {
- return TT_CHORUS;
- } else
- if (!strcmp(str, text_types[TT_FOOTER])) {
- return TT_FOOTER;
- } else
- if (!strcmp(str, text_types[TT_GRID])) {
- return TT_GRID;
- } else
- if (!strcmp(str, text_types[TT_TAB])) {
- return TT_TAB;
- } else
- if (!strcmp(str, text_types[TT_TOC])) {
- return TT_TOC;
- } else
- if (!strcmp(str, text_types[TT_TOC_TITLE])) {
- return TT_TOC_TITLE;
- } else
- if (!strcmp(str, text_types[TT_TEXT])) {
- return TT_TEXT;
- } else
- if (!strcmp(str, text_types[TT_TITLE])) {
- return TT_TITLE;
- } else
- if (!strcmp(str, text_types[TT_SUBTITLE])) {
- return TT_SUBTITLE;
- } else
- if (!strcmp(str, text_types[TT_LABEL])) {
- return TT_LABEL;
- } else
- if (!strcmp(str, text_types[TT_COMMENT])) {
- return TT_COMMENT;
- } else
- if (!strcmp(str, text_types[TT_COMMENT_ITALIC])) {
- return TT_COMMENT_ITALIC;
- } else
- if (!strcmp(str, text_types[TT_COMMENT_BOX])) {
- return TT_COMMENT_BOX;
- }
- return -1;
-}
-
-static enum NotationSystem
-config_notation_system_parse(const char *str)
-{
- if (!strcmp(str, notation_systems[NS_COMMON]) || !strcmp(str, "dutch")) {
- return NS_COMMON;
- } else if (!strcmp(str, notation_systems[NS_GERMAN])) {
- return NS_GERMAN;
- } else if (!strcmp(str, notation_systems[NS_SCANDINAVIAN])) {
- return NS_SCANDINAVIAN;
- } else if (!strcmp(str, notation_systems[NS_LATIN])) {
- return NS_LATIN;
- } else if (!strcmp(str, notation_systems[NS_ROMAN])) {
- return NS_ROMAN;
- } else if (!strcmp(str, notation_systems[NS_NASHVILLE])) {
- return NS_NASHVILLE;
- } else {
- return NS_CUSTOM;
- }
-}
-
-static const char *
-config_notation_system_to_config_string(enum NotationSystem system)
-{
- return notation_systems[system];
-}
-
-static enum Instrument
-config_instrument_parse(const char *str)
-{
- if (!strcmp(str, "guitar")) {
- return INS_GUITAR;
- } else
- if (!strcmp(str, "keyboard")) {
- return INS_KEYBOARD;
- } else
- if (!strcmp(str, "mandolin")) {
- return INS_MANDOLIN;
- } else
- if (!strcmp(str, "ukulele")) {
- return INS_UKULELE;
- }
- return -1;
-}
-
-static const char *
-config_instrument_to_config_string(enum Instrument ins)
-{
- return instruments[ins];
-}
-
-static struct Note *
-config_note_new(void)
-{
- struct Note *note = emalloc(sizeof(struct Note));
- note->note = NULL;
- note->sharp = NULL;
- note->flat = NULL;
- return note;
-}
-
-static void
-config_note_free(struct Note *note)
-{
- free(note->note);
- free(note->sharp);
- free(note->flat);
- free(note);
-}
-
-static void
-config_notes_free(struct Note **notes)
-{
- int i;
- for (i = 0; i<7; i++) {
- config_note_free(notes[i]);
- }
- free(notes);
-}
-
-static struct Note **
-config_notes_new_default(enum NotationSystem system)
-{
- struct Note **notes_default = emalloc(8 * sizeof(struct Note *));
- struct Note *notes;
- switch (system) {
- case NS_GERMAN:
- notes = (struct Note *)¬es_german;
- break;
- case NS_SCANDINAVIAN:
- notes = (struct Note *)¬es_scandinavian;
- break;
- case NS_LATIN:
- notes = (struct Note *)¬es_latin;
- break;
- case NS_ROMAN:
- notes = (struct Note *)¬es_roman;
- break;
- case NS_NASHVILLE:
- notes = (struct Note *)¬es_nashville;
- break;
- default:
- notes = (struct Note *)¬es_common;
- break;
- }
- int i;
- for (i = 0; i<7; i++) {
- notes_default[i] = config_note_new();
- if (notes[i].note) {
- notes_default[i]->note = strdup(notes[i].note);
- }
- if (notes[i].sharp) {
- notes_default[i]->sharp = strdup(notes[i].sharp);
- }
- if (notes[i].flat) {
- notes_default[i]->flat = strdup(notes[i].flat);
- }
- }
- // notes_default[7] = NULL; // TODO: This is probably needless
- return notes_default;
-}
-
-static struct Note **
-config_notes_load(toml_table_t *notes, const char *system)
-{
- struct Note **custom_notes = emalloc(8 * sizeof(struct Note *));
- toml_array_t *arr = toml_table_array(notes, system);
- int arr_len = toml_array_len(arr);
- if (arr_len != 7) {
- util_log(LOG_ERR, "Custom notation system '%s' in [notes] has to have exactly 7 items. For an example see `lorid --print-default-config`.", system);
- free(notes);
- return NULL;
- }
- toml_table_t *note;
- toml_value_t value;
- int i;
- for (i = 0; i<arr_len; i++) {
- note = toml_array_table(arr, i);
- if (note) {
- custom_notes[i] = config_note_new();
- value = toml_table_string(note, "note");
- if (value.ok) {
- custom_notes[i]->note = value.u.s;
- }
- value = toml_table_string(note, "sharp");
- if (value.ok) {
- custom_notes[i]->sharp = value.u.s;
- if (i == 2 || i == 6) {
- util_log(LOG_ERR, "Custom notation system '%s' in [notes] can't have sharp value at array index '%d'.", system, i);
- goto CLEAN;
- }
- }
- value = toml_table_string(note, "flat");
- if (value.ok) {
- custom_notes[i]->flat = value.u.s;
- if (i == 0 || i == 3) {
- util_log(LOG_ERR, "Custom notation system '%s' in [notes] can't have flat value at array index '%d'.", system, i);
- goto CLEAN;
- }
- }
- }
- }
- custom_notes[7] = NULL;
- return custom_notes;
- CLEAN:
- for (int k=i; k>=0; k--) {
- config_note_free(custom_notes[k]);
- }
- free(custom_notes);
- return NULL;
-}
-
-static void
-config_notes_print_as_toml(enum NotationSystem system)
-{
- struct Note *notes;
- switch (system) {
- case NS_COMMON:
- notes = (struct Note *)¬es_common;
- break;
- case NS_GERMAN:
- notes = (struct Note *)¬es_german;
- break;
- case NS_SCANDINAVIAN:
- notes = (struct Note *)¬es_scandinavian;
- break;
- case NS_LATIN:
- notes = (struct Note *)¬es_latin;
- break;
- case NS_ROMAN:
- notes = (struct Note *)¬es_roman;
- break;
- case NS_NASHVILLE:
- notes = (struct Note *)¬es_nashville;
- break;
- case NS_CUSTOM:
- return;
- }
- printf("%s = [\n", config_notation_system_to_config_string(system));
- int i;
- for (i = 0; i<7; i++) {
- printf("\t{ note = \"%s\",", notes[i].note);
- if (notes[i].sharp) {
- printf(" sharp = \"%s\",", notes[i].sharp);
- }
- if (notes[i].flat) {
- printf(" flat = \"%s\"", notes[i].flat);
- }
- printf(" },\n");
- }
- printf("]\n\n");
-}
-
-static const char *
-config_parse_mode_to_config_string(enum ParseMode mode)
-{
- return parse_modes[mode];
-}
-
-static enum Alignment
-config_alignment_parse(const char *str)
-{
- if (!strcmp(str, "left")) {
- return A_LEFT;
- } else
- if (!strcmp(str, "center")) {
- return A_CENTER;
- } else
- if (!strcmp(str, "right")) {
- return A_RIGHT;
- }
- return -1;
-}
-
-static const char *
-config_alignment_to_config_string(enum Alignment align)
-{
- return alignments[align];
-}
-
-static struct Config *
-config_load_default(void)
-{
- struct Config *config = emalloc(sizeof(struct Config));
- config->output = emalloc(sizeof(struct ConfigOutput));
- config->output->toc = emalloc(sizeof(struct ConfigToc));
- config->output->toc->show = false;
- config->output->toc->title = strdup("Table Of Contents");
- config->output->chorus = emalloc(sizeof(struct ConfigChorus));
- config->output->chorus->label = strdup("Chorus");
- config->output->chorus->quote = false;
- config->output->diagram = emalloc(sizeof(struct ChordDiagram));
- config->output->diagram->show = true;
- config->output->diagram->instrument = INS_GUITAR;
- config->output->page_no = emalloc(sizeof(struct ConfigPageNo));
- config->output->page_no->show = true;
- config->output->page_no->align = A_CENTER;
- config->output->notation_system = NS_COMMON;
- config->output->start_song_on_new_page = true;
- config->output->styles = emalloc(TT_LENGTH * sizeof(struct ChoStyle *));
-
- config->output->styles[TT_CHORD] = cho_style_new();
- config->output->styles[TT_CHORD]->font->name = strdup(DEFAULT_FONT_FAMILY);
- config->output->styles[TT_CHORD]->font->weight = FW_BOLD;
- config->output->styles[TT_ANNOT] = cho_style_new();
- config->output->styles[TT_ANNOT]->font->name = strdup(DEFAULT_FONT_FAMILY);
- config->output->styles[TT_ANNOT]->font->style = FS_ITALIC;
- config->output->styles[TT_CHORUS] = cho_style_new();
- config->output->styles[TT_CHORUS]->font->name = strdup(DEFAULT_FONT_FAMILY);
- config->output->styles[TT_FOOTER] = cho_style_new();
- config->output->styles[TT_GRID] = cho_style_new();
- config->output->styles[TT_GRID]->font->name = strdup(DEFAULT_FONT_FAMILY);
- config->output->styles[TT_GRID]->font->weight = FW_BOLD;
- config->output->styles[TT_TAB] = cho_style_new();
- config->output->styles[TT_TAB]->font->name = strdup("Courier");
- // config->output->styles[TT_TAB]->font->family = FF_MONOSPACE;
- config->output->styles[TT_TOC] = cho_style_new();
- config->output->styles[TT_TOC]->font->name = strdup(DEFAULT_FONT_FAMILY);
- config->output->styles[TT_TOC]->font->size = 12.0;
- config->output->styles[TT_TOC_TITLE] = cho_style_new();
- config->output->styles[TT_TOC_TITLE]->font->name = strdup(DEFAULT_FONT_FAMILY);
- config->output->styles[TT_TOC_TITLE]->font->weight = FW_BOLD;
- config->output->styles[TT_TOC_TITLE]->font->size = 18.0;
- config->output->styles[TT_TEXT] = cho_style_new();
- config->output->styles[TT_TEXT]->font->name = strdup(DEFAULT_FONT_FAMILY);
- config->output->styles[TT_TITLE] = cho_style_new();
- config->output->styles[TT_TITLE]->font->name = strdup(DEFAULT_FONT_FAMILY);
- config->output->styles[TT_TITLE]->font->weight = FW_BOLD;
- config->output->styles[TT_TITLE]->font->size = 18.0;
- config->output->styles[TT_SUBTITLE] = cho_style_new();
- config->output->styles[TT_SUBTITLE]->font->name = strdup(DEFAULT_FONT_FAMILY);
- config->output->styles[TT_SUBTITLE]->font->size = 12.0;
- config->output->styles[TT_LABEL] = cho_style_new();
- config->output->styles[TT_LABEL]->font->name = strdup(DEFAULT_FONT_FAMILY);
- config->output->styles[TT_LABEL]->font->style = FS_ITALIC;
- config->output->styles[TT_COMMENT] = cho_style_new();
- config->output->styles[TT_COMMENT]->font->name = strdup(DEFAULT_FONT_FAMILY);
- config->output->styles[TT_COMMENT]->background_color->red = 228;
- config->output->styles[TT_COMMENT]->background_color->green = 228;
- config->output->styles[TT_COMMENT]->background_color->blue = 228;
- config->output->styles[TT_COMMENT_ITALIC] = cho_style_new();
- config->output->styles[TT_COMMENT_ITALIC]->font->name = strdup(DEFAULT_FONT_FAMILY);
- config->output->styles[TT_COMMENT_ITALIC]->font->style = FS_ITALIC;
- config->output->styles[TT_COMMENT_BOX] = cho_style_new();
- config->output->styles[TT_COMMENT_BOX]->font->name = strdup(DEFAULT_FONT_FAMILY);
- config->output->styles[TT_COMMENT_BOX]->boxed = true;
-
- // config->output->styles[15] = NULL;
- config->output->notes = config_notes_new_default(NS_COMMON);
- config->parser = emalloc(sizeof(struct ConfigParser));
- config->parser->chords = emalloc(sizeof(struct ConfigChords));
- config->parser->chords->notation_system = NS_COMMON;
- config->parser->chords->mode = PM_STRICT;
- config->parser->notes = config_notes_new_default(NS_COMMON);
- return config;
-}
-
-void
-config_print_default(void)
-{
- struct Config *config = config_load_default();
- printf("[notes]\n");
- config_notes_print_as_toml(NS_COMMON);
- config_notes_print_as_toml(NS_GERMAN);
- config_notes_print_as_toml(NS_SCANDINAVIAN);
- config_notes_print_as_toml(NS_LATIN);
- config_notes_print_as_toml(NS_ROMAN);
- config_notes_print_as_toml(NS_NASHVILLE);
-
- printf("[parser]\n");
- printf("[parser.chords]\n");
- printf("mode = \"%s\"\n", config_parse_mode_to_config_string(config->parser->chords->mode));
- printf("notation_system = \"%s\"\n\n", config_notation_system_to_config_string(config->parser->chords->notation_system));
-
- printf("[output]\n");
- printf("notation_system = \"%s\"\n", config_notation_system_to_config_string(config->output->notation_system));
- printf("start_song_on_new_page = %s\n\n", config->output->start_song_on_new_page ? "true" : "false");
- printf("[output.toc]\n");
- printf("show = %s\n", config->output->toc->show ? "true" : "false");
- printf("title = \"%s\"\n\n", config->output->toc->title);
- printf("[output.chord_diagram]\n");
- printf("show = %s\n", config->output->diagram->show ? "true" : "false");
- printf("instrument = \"%s\"\n\n", config_instrument_to_config_string(config->output->diagram->instrument));
- printf("[output.chorus]\n");
- printf("label = \"Chorus\"\n");
- printf("quote = false\n\n");
- printf("[output.page_no]\n");
- printf("show = %s\n", config->output->page_no->show ? "true" : "false");
- printf("alignment = \"%s\"\n\n", config_alignment_to_config_string(config->output->page_no->align));
- printf("[output.styles]\n");
- int i;
- for (i = 1; i<TT_LENGTH; i++) {
- printf("[output.styles.%s]\n\n", text_types[i]);
- cho_style_print_as_toml(config->output->styles[i], text_types[i]);
- }
- config_free(config);
-}
-
-static bool
-config_load_font(struct Font *font, toml_table_t *table, const char *key_name, struct ChoStylePresence *presence)
-{
- enum FontFamily family;
- enum FontStyle style;
- enum FontWeight weight;
- toml_value_t value;
- value = toml_table_string(table, "name");
- if (value.ok) {
- presence->font.name = true;
- free(font->name);
- font->name = value.u.s;
- }
- value = toml_table_string(table, "family");
- if (value.ok) {
- presence->font.family = true;
- family = cho_font_family_parse(value.u.s);
- if (family != -1) {
- font->family = family;
- } else {
- util_log(LOG_ERR, "Config section [output.styles.%s.font] family value is invalid.", key_name);
- return false;
- }
- free(value.u.s);
- }
- value = toml_table_string(table, "style");
- if (value.ok) {
- presence->font.style = true;
- style = cho_font_style_parse(value.u.s);
- if (style != -1) {
- font->style = style;
- } else {
- util_log(LOG_ERR, "Config section [output.styles.%s.font] style value is invalid.", key_name);
- return false;
- }
- free(value.u.s);
- }
- value = toml_table_string(table, "weight");
- if (value.ok) {
- presence->font.weight = true;
- weight = cho_font_weight_parse(value.u.s);
- if (weight != -1) {
- font->weight = weight;
- } else {
- util_log(LOG_ERR, "Config section [output.styles.%s.font] weight value is invalid.", key_name);
- return false;
- }
- free(value.u.s);
- }
- value = toml_table_int(table, "size");
- if (value.ok) {
- presence->font.size = true;
- font->size = value.u.i;
- }
- return true;
-}
-
-static bool
-config_load_style(
- struct ChoStyle *style,
- toml_table_t *table,
- const char *key_name,
- struct ChoStylePresence *presence
-)
-{
- toml_value_t value;
- struct RGBColor *color;
- enum LineStyle line_style;
- toml_table_t *font_section = toml_table_table(table, "font");
- if (font_section) {
- if (!config_load_font(style->font, font_section, key_name, presence)) {
- LOG_DEBUG("config_load_font failed.");
- return false;
- }
- }
- value = toml_table_string(table, "foreground_color");
- if (value.ok) {
- presence->foreground_color = true;
- color = cho_color_parse(value.u.s);
- if (color) {
- free(style->foreground_color);
- style->foreground_color = color;
- } else {
- util_log(LOG_ERR, "Config section [output.styles.%s] foreground color value is invalid.", key_name);
- return false;
- }
- free(value.u.s);
- }
- value = toml_table_string(table, "background_color");
- if (value.ok) {
- presence->background_color = true;
- color = cho_color_parse(value.u.s);
- if (color) {
- free(style->background_color);
- style->background_color = color;
- } else {
- util_log(LOG_ERR, "Config section [output.styles.%s] background color value is invalid.", key_name);
- return false;
- }
- free(value.u.s);
- }
- value = toml_table_string(table, "underline_style");
- if (value.ok) {
- presence->underline_style = true;
- line_style = cho_linestyle_parse(value.u.s);
- if (line_style != -1) {
- style->underline_style = line_style;
- } else {
- util_log(LOG_ERR, "Config section [output.styles.%s] underline style value is invalid.", key_name);
- return false;
- }
- free(value.u.s);
- }
- value = toml_table_string(table, "underline_color");
- if (value.ok) {
- presence->underline_color = true;
- color = cho_color_parse(value.u.s);
- if (color) {
- free(style->underline_color);
- style->underline_color = color;
- } else {
- util_log(LOG_ERR, "Config section [output.styles.%s] underline color value is invalid.", key_name);
- return false;
- }
- free(value.u.s);
- }
- value = toml_table_string(table, "overline_style");
- if (value.ok) {
- presence->overline_style = true;
- line_style = cho_linestyle_parse(value.u.s);
- if (line_style != -1) {
- style->overline_style = line_style;
- } else {
- util_log(LOG_ERR, "Config section [output.styles.%s] overline style value is invalid.", key_name);
- return false;
- }
- free(value.u.s);
- }
- value = toml_table_string(table, "overline_color");
- if (value.ok) {
- presence->overline_color = true;
- color = cho_color_parse(value.u.s);
- if (color) {
- free(style->overline_color);
- style->overline_color = color;
- } else {
- util_log(LOG_ERR, "Config section [output.styles.%s] overline color valeu is invalid.", key_name);
- return false;
- }
- free(value.u.s);
- }
- value = toml_table_bool(table, "strikethrough");
- if (value.ok) {
- presence->strikethrough = true;
- style->strikethrough = value.u.b;
- }
- value = toml_table_string(table, "strikethrough_color");
- if (value.ok) {
- presence->strikethrough_color = true;
- color = cho_color_parse(value.u.s);
- if (color) {
- free(style->strikethrough_color);
- style->strikethrough_color = color;
- } else {
- util_log(LOG_ERR, "Config section [output.styles.%s] strikethrough color value is invalid.", key_name);
- return false;
- }
- free(value.u.s);
- }
- value = toml_table_bool(table, "boxed");
- if (value.ok) {
- presence->boxed = true;
- style->boxed = value.u.b;
- }
- value = toml_table_string(table, "boxed_color");
- if (value.ok) {
- presence->boxed_color = true;
- color = cho_color_parse(value.u.s);
- if (color) {
- free(style->boxed_color);
- style->boxed_color = color;
- } else {
- util_log(LOG_ERR, "Config section [output.styles.%s] boxed color value is invalid.", key_name);
- return false;
- }
- free(value.u.s);
- }
- value = toml_table_double(table, "rise");
- if (value.ok) {
- presence->rise = true;
- style->rise = value.u.d;
- }
- value = toml_table_string(table, "href");
- if (value.ok) {
- presence->href = true;
- style->href = value.u.s;
- }
- return true;
-}
-
-#ifdef DEBUG
-
-static void
-presence_print(const char *name, struct ChoStylePresence *presence)
-{
- printf("---- BEGIN PRESENCE ----\n");
- printf("style '%s'\n", name);
- printf("font.name %d\n", presence->font.name);
- printf("font.family %d\n", presence->font.family);
- printf("font.style %d\n", presence->font.style);
- printf("font.weight %d\n", presence->font.weight);
- printf("font.size %d\n", presence->font.size);
- printf("foreground_color %d\n", presence->foreground_color);
- printf("background_color %d\n", presence->background_color);
- printf("underline_style %d\n", presence->underline_style);
- printf("underline_color %d\n", presence->underline_color);
- printf("overline_style %d\n", presence->overline_style);
- printf("overline_color %d\n", presence->overline_color);
- printf("strikethrough %d\n", presence->strikethrough);
- printf("strikethrough_color %d\n", presence->strikethrough_color);
- printf("boxed %d\n", presence->boxed);
- printf("boxed_color %d\n", presence->boxed_color);
- printf("rise %d\n", presence->rise);
- printf("href %d\n", presence->href);
- printf("---- END PRESENCE ------\n");
-}
-
-#endif /* DEBUG */
-
-static void
-set_text_style(
- struct ChoStylePresence *text_presence,
- struct ChoStyle *text_style,
- struct ChoStylePresence *presence,
- struct ChoStyle *style
-)
-{
-
- if (!presence->font.name &&
- text_presence->font.name) {
- free(style->font->name);
- style->font->name = strdup(text_style->font->name);
- }
- if (!presence->font.family && text_presence->font.family) {
- style->font->family = text_style->font->family;
- }
- if (!presence->font.style && text_presence->font.style) {
- style->font->style = text_style->font->style;
- }
- if (!presence->font.weight && text_presence->font.weight) {
- style->font->weight = text_style->font->weight;
- }
- if (!presence->font.size && text_presence->font.size) {
- style->font->size = text_style->font->size;
- }
- if (!presence->foreground_color && text_presence->foreground_color) {
- free(style->foreground_color);
- style->foreground_color = cho_color_copy(text_style->foreground_color);
- }
- if (!presence->background_color && text_presence->background_color) {
- free(style->background_color);
- style->background_color = cho_color_copy(text_style->background_color);
- }
- if (!presence->underline_style && text_presence->underline_style) {
- style->underline_style = text_style->underline_style;
- }
- if (!presence->underline_color && text_presence->underline_color) {
- free(style->underline_color);
- style->underline_color = cho_color_copy(text_style->underline_color);
- }
- if (!presence->overline_style && text_presence->overline_style) {
- style->overline_style = text_style->overline_style;
- }
- if (!presence->overline_color && text_presence->overline_color) {
- free(style->overline_color);
- style->overline_color = cho_color_copy(text_style->overline_color);
- }
- if (!presence->strikethrough && text_presence->strikethrough) {
- style->strikethrough = text_style->strikethrough;
- }
- if (!presence->strikethrough_color && text_presence->strikethrough_color) {
- free(style->strikethrough_color);
- style->strikethrough_color = cho_color_copy(text_style->strikethrough_color);
- }
- if (!presence->boxed && text_presence->boxed) {
- style->boxed = text_style->boxed;
- }
- if (!presence->boxed_color && text_presence->boxed_color) {
- free(style->boxed_color);
- style->boxed_color = cho_color_copy(text_style->boxed_color);
- }
- if (!presence->rise && text_presence->rise) {
- style->rise = text_style->rise;
- }
- if (!presence->href && text_presence->href) {
- free(style->href);
- style->href = strdup(text_style->href);
- }
-}
-
-static void
-lyrics_set_text_style_as_default(
- struct ChoStylePresence presences[],
- struct ChoStyle **styles
-)
-{
- struct ChoStyle *style, *text_style;
- struct ChoStylePresence *presence, *text_presence;
- enum TextType lyric_types[] = {
- TT_CHORUS, TT_COMMENT,
- TT_COMMENT_ITALIC, TT_COMMENT_BOX
- };
- text_presence = &presences[TT_TEXT];
- text_style = styles[TT_TEXT];
- size_t i;
- for (i = 0; i<LENGTH(lyric_types); i++) {
- presence = &presences[lyric_types[i]];
- style = styles[lyric_types[i]];
- set_text_style(text_presence, text_style, presence, style);
- }
-}
-
-struct Config *
-config_load(const char *filepath)
-{
- struct Config *config = config_load_default();
- char *home = getenv("HOME");
- char path[26+strlen(home)+1];
- if (!filepath) {
- sprintf(path, "%s/.config/lorid/config.toml", home);
- filepath = path;
- }
- FILE *fp = fopen(filepath, "r");
- if (!fp) {
- util_log(LOG_WARN, "Couldn't open config file '%s'. Using default configuration.", filepath);
- return config;
- }
- char errbuf[200];
- toml_table_t *table = toml_parse_file(fp, (char *)&errbuf, sizeof(errbuf));
- if (!table) {
- LOG_DEBUG("toml_parse_file failed.");
- util_log(LOG_ERR, "Config file is not a valid toml file: %s.", (char *)&errbuf);
- return NULL;
- }
- toml_table_t *output = toml_table_table(table, "output");
- if (output) {
- toml_table_t *styles, *notes, *chorus, *diagram, *toc, *page_no;
- toml_value_t value;
- enum NotationSystem notation_system;
- enum Instrument instrument;
- enum Alignment align;
- struct Note **custom_notes;
- chorus = toml_table_table(output, "chorus");
- if (chorus) {
- value = toml_table_string(chorus, "label");
- if (value.ok) {
- free(config->output->chorus->label);
- config->output->chorus->label = value.u.s;
- }
- value = toml_table_bool(chorus, "quote");
- if (value.ok) {
- config->output->chorus->quote = value.u.b;
- }
- }
- toc = toml_table_table(output, "toc");
- if (toc) {
- value = toml_table_bool(toc, "show");
- if (value.ok) {
- config->output->toc->show = value.u.b;
- }
- value = toml_table_string(toc, "title");
- if (value.ok) {
- free(config->output->toc->title);
- config->output->toc->title = value.u.s;
- }
- }
- diagram = toml_table_table(output, "chord_diagram");
- if (diagram) {
- value = toml_table_bool(diagram, "show");
- if (value.ok) {
- config->output->diagram->show = value.u.b;
- }
- value = toml_table_string(diagram, "instrument");
- if (value.ok) {
- instrument = config_instrument_parse(value.u.s);
- if (instrument == -1) {
- util_log(LOG_ERR, "Unknown instrument '%s' in [output.chord_diagram].", value.u.s);
- return NULL;
- }
- config->output->diagram->instrument = instrument;
- free(value.u.s);
- }
- }
- value = toml_table_string(output, "notation_system");
- if (value.ok) {
- notation_system = config_notation_system_parse(value.u.s);
- if (notation_system == NS_CUSTOM) {
- notes = toml_table_table(table, "notes");
- if (!notes) {
- util_log(LOG_ERR, "Custom notes '%s' has no corresponding definition in [notes].", value.u.s);
- return NULL;
- }
- custom_notes = config_notes_load(notes, value.u.s);
- if (custom_notes) {
- config_notes_free(config->output->notes);
- config->output->notes = custom_notes;
- } else {
- LOG_DEBUG("config_notes_load failed.");
- util_log(LOG_ERR, "Couldn't load custom notes '%s' from [notes] section.", value.u.s);
- return NULL;
- }
- } else {
- config_notes_free(config->output->notes);
- config->output->notes = config_notes_new_default(notation_system);
- }
- free(value.u.s);
- }
- value = toml_table_bool(output, "start_song_on_new_page");
- if (value.ok) {
- config->output->start_song_on_new_page = value.u.b;
- }
- page_no = toml_table_table(output, "page_no");
- if (page_no) {
- value = toml_table_bool(page_no, "show");
- if (value.ok) {
- config->output->page_no->show = value.u.b;
- }
- value = toml_table_string(page_no, "alignment");
- if (value.ok) {
- align = config_alignment_parse(value.u.s);
- if (align == -1) {
- LOG_DEBUG("config_alignment_parse failed.");
- return NULL;
- }
- config->output->page_no->align = align;
- free(value.u.s);
- }
- }
- styles = toml_table_table(output, "styles");
- if (styles) {
- int i, unused;
- const char *key_name;
- enum TextType ttype;
- struct ChoStyle *style;
- struct ChoStylePresence presences[TT_LENGTH] = {0};
- toml_table_t *key;
- for (i = 0; i<toml_table_len(styles); i++) {
- key_name = toml_table_key(styles, i, &unused);
- ttype = config_text_type_parse(key_name);
- if (ttype != -1) {
- key = toml_table_table(styles, key_name);
- if (key) {
- style = config->output->styles[ttype];
- if (!config_load_style(style, key, key_name, &presences[ttype])) {
- LOG_DEBUG("config_load_style failed.");
- return NULL;
- }
- }
- }
- }
- lyrics_set_text_style_as_default(presences, config->output->styles);
- }
- }
- toml_table_t *parser = toml_table_table(table, "parser");
- if (parser) {
- toml_table_t *chords = toml_table_table(parser, "chords");
- if (chords) {
- toml_table_t *notes;
- toml_value_t value;
- enum NotationSystem notation_system;
- struct Note **custom_notes;
- value = toml_table_string(chords, "notation_system");
- if (value.ok) {
- notation_system = config_notation_system_parse(value.u.s);
- if (notation_system == NS_CUSTOM) {
- notes = toml_table_table(table, "notes");
- if (!notes) {
- util_log(LOG_ERR, "Custom notes '%s' has no corresponding definition in [notes].", value.u.s);
- return NULL;
- }
- custom_notes = config_notes_load(notes, value.u.s);
- if (custom_notes) {
- config_notes_free(config->parser->notes);
- config->parser->notes = custom_notes;
- } else {
- LOG_DEBUG("config_notes_load failed.");
- util_log(LOG_ERR, "Couldn't load custom notes '%s' from [notes] section.", value.u.s);
- return NULL;
- }
- } else {
- config_notes_free(config->parser->notes);
- config->parser->notes = config_notes_new_default(notation_system);
- }
- free(value.u.s);
- }
- value = toml_table_string(chords, "mode");
- if (value.ok) {
- if (!strcmp(value.u.s, "strict")) {
- config->parser->chords->mode = PM_STRICT;
- } else if (!strcmp(value.u.s, "relaxed")) {
- config->parser->chords->mode = PM_RELAXED;
- }
- free(value.u.s);
- }
- }
- }
- toml_free(table);
- fclose(fp);
- return config;
-}
-
-void
-config_free(struct Config *config)
-{
- free(config->output->toc->title);
- free(config->output->toc);
- free(config->output->chorus->label);
- free(config->output->chorus);
- int i;
- for (i = 0; i<TT_LENGTH; i++) {
- cho_style_free(config->output->styles[i]);
- }
- free(config->output->styles);
- config_notes_free(config->output->notes);
- free(config->output->diagram);
- free(config->output->page_no);
- free(config->output);
- free(config->parser->chords);
- config_notes_free(config->parser->notes);
- free(config->parser);
- free(config);
-}
diff --git a/config.h b/config.h
@@ -1,17 +0,0 @@
-#include "types.h"
-
-#ifndef _CONFIG_H_
-#define _CONFIG_H_
-
-#ifdef DEBUG
-#define SYMBOLS_FILEPATH "./misc/ChordProSymbols.ttf"
-#else
-#define SYMBOLS_FILEPATH PREFIX"/share/lorid/ChordProSymbols.ttf"
-#endif /* DEBUG */
-#define DEFAULT_FONT_FAMILY "Open Sans"
-
-struct Config *config_load(const char *filepath);
-void config_free(struct Config *config);
-void config_print_default(void);
-
-#endif /* _CONFIG_H_ */
diff --git a/diagrams.h b/diagrams.h
@@ -1,4394 +0,0 @@
-static struct StringDiagram guitar_diagrams[] = {
- {
- .name = "C",
- .base_fret = 1,
- .frets = { 0, 3, 2, 0, 1, 0, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 3, 2, 0, 1, 0, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Cm",
- .base_fret = 3,
- .frets = { 1, 1, 3, 3, 2, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 3, 4, 2, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "C+",
- .base_fret = 1,
- .frets = { -1, -1, 2, 1, 1, 4, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 2, 1, 1, 4, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Caug",
- .base_fret = 1,
- .frets = { -1, -1, 2, 1, 1, 4, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 2, 1, 1, 4, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Cdim",
- .base_fret = 3,
- .frets = { -1, 1, 2, 3, 2, -1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 1, 2, 4, 3, 0, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "C0",
- .base_fret = 1,
- .frets = { -1, -1, 1, 2, 1, 2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 3, 2, 4, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Cdim",
- .base_fret = 1,
- .frets = { -1, -1, 1, 2, 1, 2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 3, 2, 4, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Cdim7",
- .base_fret = 1,
- .frets = { -1, -1, 1, 2, 1, 2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 3, 2, 4, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "C7",
- .base_fret = 1,
- .frets = { 0, 3, 2, 3, 1, 0, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 3, 2, 4, 1, 0, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Cmaj7",
- .base_fret = 1,
- .frets = { -1, 3, 2, 0, 0, 0, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 3, 2, 0, 0, 0, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Cm7",
- .base_fret = 3,
- .frets = { 1, 1, 3, 1, 2, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 3, 1, 2, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "C#",
- .base_fret = 1,
- .frets = { -1, -1, 3, 1, 2, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 3, 1, 2, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "C#m",
- .base_fret = 1,
- .frets = { -1, -1, 2, 1, 2, 0, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 2, 1, 3, 0, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "C#+",
- .base_fret = 2,
- .frets = { -1, 3, 2, 1, 1, -1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 4, 3, 1, 2, 0, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "C#aug",
- .base_fret = 2,
- .frets = { -1, 3, 2, 1, 1, -1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 4, 3, 1, 2, 0, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "C#dim",
- .base_fret = 1,
- .frets = { -1, -1, 2, 0, 2, 0, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 3, 0, 4, 0, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "C#0",
- .base_fret = 2,
- .frets = { -1, -1, 1, 2, 1, 2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 3, 2, 4, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "C#dim",
- .base_fret = 2,
- .frets = { -1, -1, 1, 2, 1, 2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 3, 2, 4, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "C#dim7",
- .base_fret = 2,
- .frets = { -1, -1, 1, 2, 1, 2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 3, 2, 4, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "C#7",
- .base_fret = 2,
- .frets = { -1, -1, 2, 3, 1, 3, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 2, 3, 1, 4, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "C#maj7",
- .base_fret = 1,
- .frets = { -1, 4, 3, 1, 1, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 4, 3, 1, 1, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "C#m7",
- .base_fret = 1,
- .frets = { -1, 4, 2, 1, 0, 0, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 4, 2, 1, 0, 0, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Db",
- .base_fret = 1,
- .frets = { -1, -1, 3, 1, 2, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 3, 1, 2, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Dbm",
- .base_fret = 1,
- .frets = { -1, -1, 2, 1, 2, 0, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 2, 1, 3, 0, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Db+",
- .base_fret = 2,
- .frets = { -1, 3, 2, 1, 1, -1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 4, 3, 1, 2, 0, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Dbaug",
- .base_fret = 2,
- .frets = { -1, 3, 2, 1, 1, -1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 4, 3, 1, 2, 0, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Dbdim",
- .base_fret = 1,
- .frets = { -1, -1, 2, 0, 2, 0, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 3, 0, 4, 0, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Db0",
- .base_fret = 2,
- .frets = { -1, -1, 1, 2, 1, 2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 3, 2, 4, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Dbdim",
- .base_fret = 2,
- .frets = { -1, -1, 1, 2, 1, 2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 3, 2, 4, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Dbdim7",
- .base_fret = 2,
- .frets = { -1, -1, 1, 2, 1, 2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 3, 2, 4, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Db7",
- .base_fret = 2,
- .frets = { -1, -1, 2, 3, 1, 3, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 2, 3, 1, 4, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Dbmaj7",
- .base_fret = 1,
- .frets = { -1, 4, 3, 1, 1, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 4, 3, 1, 1, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Dbm7",
- .base_fret = 1,
- .frets = { -1, 4, 2, 1, 0, 0, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 4, 2, 1, 0, 0, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "D",
- .base_fret = 1,
- .frets = { -1, -1, 0, 2, 3, 2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 0, 1, 3, 2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Dm",
- .base_fret = 1,
- .frets = { -1, -1, 0, 2, 3, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 0, 2, 3, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "D+",
- .base_fret = 1,
- .frets = { -1, -1, 0, 3, 3, 2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 0, 2, 3, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Daug",
- .base_fret = 1,
- .frets = { -1, -1, 0, 3, 3, 2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 0, 2, 3, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Ddim",
- .base_fret = 1,
- .frets = { -1, -1, 0, 1, 3, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 0, 1, 3, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "D0",
- .base_fret = 1,
- .frets = { -1, -1, 0, 1, 0, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 0, 1, 0, 2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Ddim",
- .base_fret = 1,
- .frets = { -1, -1, 0, 1, 0, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 0, 1, 0, 2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Ddim7",
- .base_fret = 1,
- .frets = { -1, -1, 0, 1, 0, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 0, 1, 0, 2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "D7",
- .base_fret = 1,
- .frets = { -1, -1, 0, 2, 1, 2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 0, 2, 1, 3, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Dmaj7",
- .base_fret = 1,
- .frets = { -1, -1, 0, 2, 2, 2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 0, 1, 2, 3, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Dm7",
- .base_fret = 1,
- .frets = { -1, -1, 0, 2, 1, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 0, 2, 1, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "D#",
- .base_fret = 3,
- .frets = { -1, -1, 3, 1, 2, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 3, 1, 2, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "D#m",
- .base_fret = 1,
- .frets = { -1, -1, 4, 3, 4, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 3, 2, 4, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "D#+",
- .base_fret = 1,
- .frets = { 3, 2, 1, 0, 0, 3, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 2, 1, 0, 0, 4, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "D#aug",
- .base_fret = 1,
- .frets = { 3, 2, 1, 0, 0, 3, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 2, 1, 0, 0, 4, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "D#dim",
- .base_fret = 2,
- .frets = { -1, -1, 3, 1, 3, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 3, 1, 4, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "D#0",
- .base_fret = 1,
- .frets = { -1, -1, 1, 2, 1, 2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 3, 2, 4, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "D#dim",
- .base_fret = 1,
- .frets = { -1, -1, 1, 2, 1, 2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 3, 2, 4, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "D#dim7",
- .base_fret = 1,
- .frets = { -1, -1, 1, 2, 1, 2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 3, 2, 4, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "D#7",
- .base_fret = 1,
- .frets = { -1, -1, 1, 3, 2, 3, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 3, 2, 4, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "D#maj7",
- .base_fret = 1,
- .frets = { -1, -1, 1, 3, 3, 3, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 2, 3, 4, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "D#m7",
- .base_fret = 1,
- .frets = { -1, -1, 1, 3, 2, 2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 2, 3, 4, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Eb",
- .base_fret = 3,
- .frets = { -1, -1, 3, 1, 2, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 3, 1, 2, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Ebm",
- .base_fret = 1,
- .frets = { -1, -1, 4, 3, 4, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 3, 2, 4, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Eb+",
- .base_fret = 1,
- .frets = { 3, 2, 1, 0, 0, 3, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 2, 1, 0, 0, 4, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Ebaug",
- .base_fret = 1,
- .frets = { 3, 2, 1, 0, 0, 3, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 2, 1, 0, 0, 4, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Ebdim",
- .base_fret = 2,
- .frets = { -1, -1, 3, 1, 3, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 3, 1, 4, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Eb0",
- .base_fret = 1,
- .frets = { -1, -1, 1, 2, 1, 2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 3, 2, 4, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Ebdim",
- .base_fret = 1,
- .frets = { -1, -1, 1, 2, 1, 2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 3, 2, 4, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Ebdim7",
- .base_fret = 1,
- .frets = { -1, -1, 1, 2, 1, 2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 3, 2, 4, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Eb7",
- .base_fret = 1,
- .frets = { -1, -1, 1, 3, 2, 3, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 3, 2, 4, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Ebmaj7",
- .base_fret = 1,
- .frets = { -1, -1, 1, 3, 3, 3, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 2, 3, 4, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Ebm7",
- .base_fret = 1,
- .frets = { -1, -1, 1, 3, 2, 2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 2, 3, 4, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "E",
- .base_fret = 1,
- .frets = { 0, 2, 2, 1, 0, 0, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 2, 3, 1, 0, 0, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Em",
- .base_fret = 1,
- .frets = { 0, 2, 2, 0, 0, 0, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 2, 3, 0, 0, 0, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "E+",
- .base_fret = 1,
- .frets = { 0, 3, 2, 1, -1, -1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 3, 2, 1, 0, 0, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Eaug",
- .base_fret = 1,
- .frets = { 0, 3, 2, 1, -1, -1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 3, 2, 1, 0, 0, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Edim",
- .base_fret = 3,
- .frets = { -1, -1, 3, 1, 3, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 3, 1, 4, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "E0",
- .base_fret = 2,
- .frets = { -1, -1, 1, 2, 1, 2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 3, 2, 4, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Edim",
- .base_fret = 2,
- .frets = { -1, -1, 1, 2, 1, 2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 3, 2, 4, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Edim7",
- .base_fret = 2,
- .frets = { -1, -1, 1, 2, 1, 2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 3, 2, 4, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "E7",
- .base_fret = 1,
- .frets = { 0, 2, 0, 1, 0, 0, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 2, 0, 1, 0, 0, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Emaj7",
- .base_fret = 1,
- .frets = { 0, 2, 1, 1, 0, -1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 3, 1, 2, 0, 0, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Em7",
- .base_fret = 1,
- .frets = { 0, 2, 0, 0, 0, 0, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 2, 0, 0, 0, 0, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "F",
- .base_fret = 1,
- .frets = { 1, 3, 3, 2, 1, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 4, 2, 1, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Fm",
- .base_fret = 1,
- .frets = { 1, 3, 3, 1, 1, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 4, 1, 1, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "F+",
- .base_fret = 1,
- .frets = { -1, -1, 1, 4, 4, 3, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 3, 4, 2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Faug",
- .base_fret = 1,
- .frets = { -1, -1, 1, 4, 4, 3, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 3, 4, 2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Fdim",
- .base_fret = 4,
- .frets = { -1, -1, 3, 1, 3, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 3, 1, 4, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "F0",
- .base_fret = 1,
- .frets = { -1, -1, 0, 1, 0, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 0, 1, 0, 2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Fdim",
- .base_fret = 1,
- .frets = { -1, -1, 0, 1, 0, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 0, 1, 0, 2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Fdim7",
- .base_fret = 1,
- .frets = { -1, -1, 0, 1, 0, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 0, 1, 0, 2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "F7",
- .base_fret = 1,
- .frets = { 1, 3, 1, 2, 1, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 1, 2, 1, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Fmaj7",
- .base_fret = 1,
- .frets = { -1, -1, 3, 2, 1, 0, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 3, 2, 1, 0, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Fm7",
- .base_fret = 1,
- .frets = { 1, 3, 1, 1, 1, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 1, 1, 1, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "F#",
- .base_fret = 2,
- .frets = { 1, 3, 3, 2, 1, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 4, 2, 1, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "F#m",
- .base_fret = 2,
- .frets = { 1, 3, 3, 1, 1, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 4, 1, 1, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "F#+",
- .base_fret = 1,
- .frets = { 2, 1, 0, 3, 3, 2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 0, 4, 4, 3, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "F#aug",
- .base_fret = 1,
- .frets = { 2, 1, 0, 3, 3, 2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 0, 4, 4, 3, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "F#dim",
- .base_fret = 5,
- .frets = { -1, -1, 3, 1, 3, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 3, 1, 4, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "F#0",
- .base_fret = 1,
- .frets = { -1, -1, 1, 2, 1, 2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 3, 2, 4, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "F#dim",
- .base_fret = 1,
- .frets = { -1, -1, 1, 2, 1, 2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 3, 2, 4, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "F#dim7",
- .base_fret = 1,
- .frets = { -1, -1, 1, 2, 1, 2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 3, 2, 4, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "F#7",
- .base_fret = 2,
- .frets = { 1, 3, 1, 2, 1, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 1, 2, 1, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "F#maj7",
- .base_fret = 1,
- .frets = { -1, -1, 4, 3, 2, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 4, 3, 2, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "F#m7",
- .base_fret = 2,
- .frets = { 1, 3, 1, 1, 1, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 1, 1, 1, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gb",
- .base_fret = 2,
- .frets = { 1, 3, 3, 2, 1, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 4, 2, 1, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gbm",
- .base_fret = 2,
- .frets = { 1, 3, 3, 1, 1, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 4, 1, 1, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gb+",
- .base_fret = 1,
- .frets = { 2, 1, 0, 3, 3, 2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 0, 4, 4, 3, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gbaug",
- .base_fret = 1,
- .frets = { 2, 1, 0, 3, 3, 2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 0, 4, 4, 3, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gbdim",
- .base_fret = 5,
- .frets = { -1, -1, 3, 1, 3, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 3, 1, 4, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gb0",
- .base_fret = 1,
- .frets = { -1, -1, 1, 2, 1, 2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 3, 2, 4, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gbdim",
- .base_fret = 1,
- .frets = { -1, -1, 1, 2, 1, 2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 3, 2, 4, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gbdim7",
- .base_fret = 1,
- .frets = { -1, -1, 1, 2, 1, 2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 3, 2, 4, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gb7",
- .base_fret = 2,
- .frets = { 1, 3, 1, 2, 1, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 1, 2, 1, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gbmaj7",
- .base_fret = 1,
- .frets = { -1, -1, 4, 3, 2, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 4, 3, 2, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gbm7",
- .base_fret = 2,
- .frets = { 1, 3, 1, 1, 1, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 1, 1, 1, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "G",
- .base_fret = 1,
- .frets = { 3, 2, 0, 0, 0, 3, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 0, 0, 0, 3, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gm",
- .base_fret = 3,
- .frets = { 1, 3, 3, 1, 1, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 4, 1, 1, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "G+",
- .base_fret = 5,
- .frets = { -1, -1, 1, 4, 4, 3, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 3, 4, 2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gaug",
- .base_fret = 5,
- .frets = { -1, -1, 1, 4, 4, 3, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 3, 4, 2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gdim",
- .base_fret = 6,
- .frets = { -1, -1, 3, 1, 3, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 3, 1, 4, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "G0",
- .base_fret = 2,
- .frets = { -1, -1, 1, 2, 1, 2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 3, 2, 4, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gdim",
- .base_fret = 2,
- .frets = { -1, -1, 1, 2, 1, 2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 3, 2, 4, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gdim7",
- .base_fret = 2,
- .frets = { -1, -1, 1, 2, 1, 2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 3, 2, 4, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "G7",
- .base_fret = 1,
- .frets = { 3, 2, 0, 0, 0, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 2, 0, 0, 0, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gmaj7",
- .base_fret = 2,
- .frets = { -1, -1, 4, 3, 2, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 4, 3, 2, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gm7",
- .base_fret = 3,
- .frets = { 1, 3, 1, 1, 1, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 1, 1, 1, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "G#",
- .base_fret = 4,
- .frets = { 1, 3, 3, 2, 1, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 4, 2, 1, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "G#m",
- .base_fret = 4,
- .frets = { 1, 3, 3, 1, 1, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 4, 1, 1, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "G#+",
- .base_fret = 1,
- .frets = { 0, 3, 2, 1, 1, 0, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 4, 3, 1, 2, 0, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "G#aug",
- .base_fret = 1,
- .frets = { 0, 3, 2, 1, 1, 0, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 4, 3, 1, 2, 0, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "G#dim",
- .base_fret = 7,
- .frets = { -1, -1, 3, 1, 3, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 3, 1, 4, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "G#0",
- .base_fret = 1,
- .frets = { -1, -1, 0, 1, 0, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 0, 1, 0, 2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "G#dim",
- .base_fret = 1,
- .frets = { -1, -1, 0, 1, 0, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 0, 1, 0, 2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "G#dim7",
- .base_fret = 1,
- .frets = { -1, -1, 0, 1, 0, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 0, 1, 0, 2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "G#7",
- .base_fret = 4,
- .frets = { 1, 3, 1, 2, 1, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 1, 2, 1, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "G#maj7",
- .base_fret = 1,
- .frets = { -1, -1, 1, 1, 1, 3, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 1, 1, 3, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "G#m7",
- .base_fret = 4,
- .frets = { 1, 3, 1, 1, 1, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 1, 1, 1, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Ab",
- .base_fret = 4,
- .frets = { 1, 3, 3, 2, 1, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 4, 2, 1, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Abm",
- .base_fret = 4,
- .frets = { 1, 3, 3, 1, 1, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 4, 1, 1, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Ab+",
- .base_fret = 1,
- .frets = { 0, 3, 2, 1, 1, 0, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 4, 3, 1, 2, 0, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Abaug",
- .base_fret = 1,
- .frets = { 0, 3, 2, 1, 1, 0, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 4, 3, 1, 2, 0, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Abdim",
- .base_fret = 7,
- .frets = { -1, -1, 3, 1, 3, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 3, 1, 4, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Ab0",
- .base_fret = 1,
- .frets = { -1, -1, 0, 1, 0, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 0, 1, 0, 2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Abdim",
- .base_fret = 1,
- .frets = { -1, -1, 0, 1, 0, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 0, 1, 0, 2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Abdim7",
- .base_fret = 1,
- .frets = { -1, -1, 0, 1, 0, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 0, 1, 0, 2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Ab7",
- .base_fret = 4,
- .frets = { 1, 3, 1, 2, 1, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 1, 2, 1, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Abmaj7",
- .base_fret = 1,
- .frets = { -1, -1, 1, 1, 1, 3, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 1, 1, 3, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Abm7",
- .base_fret = 4,
- .frets = { 1, 3, 1, 1, 1, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 1, 1, 1, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "A",
- .base_fret = 1,
- .frets = { -1, 0, 2, 2, 2, 0, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 2, 3, 0, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Am",
- .base_fret = 1,
- .frets = { -1, 0, 2, 2, 1, 0, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 2, 3, 1, 0, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "A+",
- .base_fret = 1,
- .frets = { -1, 0, 3, 2, 2, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 4, 2, 3, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Aaug",
- .base_fret = 1,
- .frets = { -1, 0, 3, 2, 2, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 4, 2, 3, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Adim",
- .base_fret = 1,
- .frets = { -1, 0, 1, 2, 1, -1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 2, 3, 0, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "A0",
- .base_fret = 1,
- .frets = { -1, -1, 1, 2, 1, 2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 3, 2, 4, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Adim",
- .base_fret = 1,
- .frets = { -1, -1, 1, 2, 1, 2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 3, 2, 4, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Adim7",
- .base_fret = 1,
- .frets = { -1, -1, 1, 2, 1, 2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 3, 2, 4, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "A7",
- .base_fret = 1,
- .frets = { -1, 0, 2, 0, 2, 0, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 0, 3, 0, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Amaj7",
- .base_fret = 1,
- .frets = { -1, 0, 2, 1, 2, 0, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 2, 1, 3, 0, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Am7",
- .base_fret = 1,
- .frets = { -1, 0, 2, 0, 1, 0, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 2, 0, 1, 0, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "A#",
- .base_fret = 1,
- .frets = { 1, 1, 3, 3, 3, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 2, 3, 4, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "A#m",
- .base_fret = 1,
- .frets = { 1, 1, 3, 3, 2, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 3, 4, 2, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "A#+",
- .base_fret = 1,
- .frets = { 2, 1, 0, 3, 3, 2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 0, 4, 4, 3, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "A#aug",
- .base_fret = 1,
- .frets = { 2, 1, 0, 3, 3, 2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 0, 4, 4, 3, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "A#dim",
- .base_fret = 1,
- .frets = { -1, 1, 2, 3, 2, -1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 1, 2, 4, 3, 0, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "A#0",
- .base_fret = 2,
- .frets = { -1, -1, 1, 2, 1, 2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 3, 2, 4, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "A#dim",
- .base_fret = 2,
- .frets = { -1, -1, 1, 2, 1, 2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 3, 2, 4, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "A#dim7",
- .base_fret = 2,
- .frets = { -1, -1, 1, 2, 1, 2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 3, 2, 4, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "A#7",
- .base_fret = 1,
- .frets = { -1, 1, 3, 1, 3, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 1, 2, 1, 3, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "A#maj7",
- .base_fret = 1,
- .frets = { -1, 1, 3, 2, 3, -1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 1, 3, 2, 4, 0, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "A#m7",
- .base_fret = 1,
- .frets = { 1, 1, 3, 1, 2, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 3, 1, 2, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bb",
- .base_fret = 1,
- .frets = { 1, 1, 3, 3, 3, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 2, 3, 4, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bbm",
- .base_fret = 1,
- .frets = { 1, 1, 3, 3, 2, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 3, 4, 2, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bb+",
- .base_fret = 1,
- .frets = { 2, 1, 0, 3, 3, 2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 0, 4, 4, 3, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bbaug",
- .base_fret = 1,
- .frets = { 2, 1, 0, 3, 3, 2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 0, 4, 4, 3, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bbdim",
- .base_fret = 1,
- .frets = { -1, 1, 2, 3, 2, -1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 1, 2, 4, 3, 0, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bb0",
- .base_fret = 2,
- .frets = { -1, -1, 1, 2, 1, 2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 3, 2, 4, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bbdim",
- .base_fret = 2,
- .frets = { -1, -1, 1, 2, 1, 2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 3, 2, 4, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bbdim7",
- .base_fret = 2,
- .frets = { -1, -1, 1, 2, 1, 2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 3, 2, 4, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bb7",
- .base_fret = 1,
- .frets = { -1, 1, 3, 1, 3, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 1, 2, 1, 3, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bbmaj7",
- .base_fret = 1,
- .frets = { -1, 1, 3, 2, 3, -1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 1, 3, 2, 4, 0, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bbm7",
- .base_fret = 1,
- .frets = { 1, 1, 3, 1, 2, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 3, 1, 2, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "B",
- .base_fret = 2,
- .frets = { 1, 1, 3, 3, 3, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 2, 3, 4, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bm",
- .base_fret = 2,
- .frets = { 1, 1, 3, 3, 2, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 3, 4, 2, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "B+",
- .base_fret = 1,
- .frets = { -1, 3, 2, 0, 0, -1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 2, 1, 0, 0, 0, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Baug",
- .base_fret = 1,
- .frets = { -1, 3, 2, 0, 0, -1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 2, 1, 0, 0, 0, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bdim",
- .base_fret = 2,
- .frets = { -1, 1, 2, 3, 2, -1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 1, 2, 4, 3, 0, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "B0",
- .base_fret = 1,
- .frets = { -1, -1, 0, 1, 0, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 0, 1, 0, 2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bdim",
- .base_fret = 1,
- .frets = { -1, -1, 0, 1, 0, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 0, 1, 0, 2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bdim7",
- .base_fret = 1,
- .frets = { -1, -1, 0, 1, 0, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 0, 1, 0, 2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "B7",
- .base_fret = 1,
- .frets = { -1, 2, 1, 2, 0, 2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 2, 1, 3, 0, 4, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bmaj7",
- .base_fret = 2,
- .frets = { -1, 1, 3, 2, 3, -1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 1, 3, 2, 4, 0, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bm7",
- .base_fret = 2,
- .frets = { 1, 1, 3, 1, 2, 1, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 3, 1, 2, 1, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "C9",
- .base_fret = 2,
- .frets = { -1, 2, 1, 2, 2, 2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 2, 1, 3, 3, 3, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "C#9",
- .base_fret = 3,
- .frets = { -1, 2, 1, 2, 2, 2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 2, 1, 3, 3, 3, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Db9",
- .base_fret = 3,
- .frets = { -1, 2, 1, 2, 2, 2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 2, 1, 3, 3, 3, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "D9",
- .base_fret = 4,
- .frets = { -1, 2, 1, 2, 2, 2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 2, 1, 3, 3, 3, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "D#9",
- .base_fret = 5,
- .frets = { -1, 2, 1, 2, 2, 2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 2, 1, 3, 3, 3, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Eb9",
- .base_fret = 5,
- .frets = { -1, 2, 1, 2, 2, 2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 2, 1, 3, 3, 3, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "E9",
- .base_fret = 1,
- .frets = { 0, 2, 0, 1, 0, 2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 2, 0, 1, 0, 3, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "F9",
- .base_fret = 1,
- .frets = { 1, 3, 1, 2, 1, 3, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 1, 2, 1, 4, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "F#9",
- .base_fret = 2,
- .frets = { 1, 3, 1, 2, 1, 3, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 1, 2, 1, 4, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gb9",
- .base_fret = 2,
- .frets = { 1, 3, 1, 2, 1, 3, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 1, 2, 1, 4, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "G9",
- .base_fret = 3,
- .frets = { 1, 3, 1, 2, 1, 3, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 1, 2, 1, 4, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "G#9",
- .base_fret = 4,
- .frets = { 1, 3, 1, 2, 1, 3, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 1, 2, 1, 4, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Ab9",
- .base_fret = 4,
- .frets = { 1, 3, 1, 2, 1, 3, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 1, 2, 1, 4, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "A9",
- .base_fret = 5,
- .frets = { 1, 3, 1, 2, 1, 3, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 1, 2, 1, 4, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "A#9",
- .base_fret = 6,
- .frets = { 1, 3, 1, 2, 1, 3, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 1, 2, 1, 4, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bb9",
- .base_fret = 6,
- .frets = { 1, 3, 1, 2, 1, 3, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 1, 2, 1, 4, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "B9",
- .base_fret = 1,
- .frets = { -1, 2, 1, 2, 2, 2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 2, 1, 3, 3, 3, -2, -2, -2, -2, -2, -2 }
- }
-};
-
-static const struct StringDiagram ukulele_diagrams[] = {
- {
- .name = "A",
- .base_fret = 1,
- .frets = { 2, 1, 0, 0, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 0, 0, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Am",
- .base_fret = 1,
- .frets = { 2, 0, 0, 0, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 0, 0, 0, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "A7",
- .base_fret = 1,
- .frets = { 0, 1, 0, 0, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 1, 0, 0, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Am7",
- .base_fret = 1,
- .frets = { 0, 0, 0, 0, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 0, 0, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Adim",
- .base_fret = 2,
- .frets = { 1, 2, 1, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 2, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Amaj7",
- .base_fret = 1,
- .frets = { 1, 1, 0, 0, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 2, 0, 0, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "A6",
- .base_fret = 2,
- .frets = { 1, 3, 1, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 2, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Asus2",
- .base_fret = 2,
- .frets = { 1, 3, 4, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 3, 4, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Asus",
- .base_fret = 1,
- .frets = { 2, 2, 0, 0, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 2, 0, 0, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Asus4",
- .base_fret = 1,
- .frets = { 2, 2, 0, 0, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 2, 0, 0, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "A+",
- .base_fret = 1,
- .frets = { 2, 1, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Aaug",
- .base_fret = 1,
- .frets = { 2, 1, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "A9",
- .base_fret = 1,
- .frets = { 0, 1, 0, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 1, 0, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "A#",
- .base_fret = 1,
- .frets = { 3, 2, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 2, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "A#m",
- .base_fret = 1,
- .frets = { 3, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "A#7",
- .base_fret = 1,
- .frets = { 1, 2, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 2, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "A#m7",
- .base_fret = 1,
- .frets = { 1, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "A#dim",
- .base_fret = 1,
- .frets = { 0, 1, 0, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 1, 0, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "A#maj7",
- .base_fret = 1,
- .frets = { 2, 2, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 2, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "A#6",
- .base_fret = 1,
- .frets = { 0, 2, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 2, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "A#sus2",
- .base_fret = 1,
- .frets = { 3, 0, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 0, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "A#sus",
- .base_fret = 1,
- .frets = { 3, 3, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 3, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "A#sus4",
- .base_fret = 1,
- .frets = { 3, 3, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 3, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "A#+",
- .base_fret = 1,
- .frets = { 3, 1, 1, 5, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "A#aug",
- .base_fret = 1,
- .frets = { 3, 1, 1, 5, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "A#9",
- .base_fret = 1,
- .frets = { 1, 2, 1, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 2, 1, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bb",
- .base_fret = 1,
- .frets = { 3, 2, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 2, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bbm",
- .base_fret = 1,
- .frets = { 3, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bb7",
- .base_fret = 1,
- .frets = { 1, 2, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 2, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bbm7",
- .base_fret = 1,
- .frets = { 1, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bbdim",
- .base_fret = 1,
- .frets = { 0, 1, 0, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 1, 0, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bbmaj7",
- .base_fret = 1,
- .frets = { 2, 2, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 2, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bb6",
- .base_fret = 1,
- .frets = { 0, 2, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 2, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bbsus2",
- .base_fret = 1,
- .frets = { 3, 0, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 0, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bbsus",
- .base_fret = 1,
- .frets = { 3, 3, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 3, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bbsus4",
- .base_fret = 1,
- .frets = { 3, 3, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 3, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bb+",
- .base_fret = 1,
- .frets = { 3, 1, 1, 5, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bbaug",
- .base_fret = 1,
- .frets = { 3, 1, 1, 5, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bb9",
- .base_fret = 1,
- .frets = { 1, 2, 1, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 2, 1, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "B",
- .base_fret = 2,
- .frets = { 3, 2, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 2, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bm",
- .base_fret = 2,
- .frets = { 3, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "B7",
- .base_fret = 2,
- .frets = { 1, 2, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 2, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bm7",
- .base_fret = 2,
- .frets = { 1, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bdim",
- .base_fret = 1,
- .frets = { 1, 2, 1, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 2, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bmaj7",
- .base_fret = 2,
- .frets = { 2, 2, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 2, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "B6",
- .base_fret = 1,
- .frets = { 1, 3, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 4, 2, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bsus2",
- .base_fret = 1,
- .frets = { 5, 1, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 4, 1, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bsus",
- .base_fret = 2,
- .frets = { 3, 3, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 2, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bsus4",
- .base_fret = 2,
- .frets = { 3, 3, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 2, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "B+",
- .base_fret = 1,
- .frets = { 0, 3, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 2, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Baug",
- .base_fret = 1,
- .frets = { 0, 3, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 2, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "B9",
- .base_fret = 2,
- .frets = { 1, 2, 1, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 3, 2, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "C",
- .base_fret = 1,
- .frets = { 0, 0, 0, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 0, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Cm",
- .base_fret = 1,
- .frets = { 0, 3, 3, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 1, 2, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "C7",
- .base_fret = 1,
- .frets = { 0, 0, 0, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 0, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Cm7",
- .base_fret = 3,
- .frets = { 1, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Cdim",
- .base_fret = 2,
- .frets = { 1, 2, 1, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 2, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Cmaj7",
- .base_fret = 1,
- .frets = { 0, 0, 0, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 0, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "C6",
- .base_fret = 1,
- .frets = { 0, 0, 0, 0, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 0, 0, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Csus2",
- .base_fret = 1,
- .frets = { 0, 2, 3, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 1, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Csus",
- .base_fret = 1,
- .frets = { 0, 0, 1, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Csus4",
- .base_fret = 1,
- .frets = { 0, 0, 1, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "C+",
- .base_fret = 1,
- .frets = { 1, 0, 0, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 0, 0, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Caug",
- .base_fret = 1,
- .frets = { 1, 0, 0, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 0, 0, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "C9",
- .base_fret = 1,
- .frets = { 0, 2, 0, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 2, 0, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "C#",
- .base_fret = 1,
- .frets = { 1, 1, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "C#m",
- .base_fret = 1,
- .frets = { 1, 4, 4, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 2, 3, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "C#7",
- .base_fret = 1,
- .frets = { 1, 1, 1, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 1, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "C#m7",
- .base_fret = 1,
- .frets = { 2, 2, 1, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 2, 1, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "C#dim",
- .base_fret = 1,
- .frets = { 0, 1, 0, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 1, 0, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "C#maj7",
- .base_fret = 1,
- .frets = { 1, 1, 1, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 1, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "C#6",
- .base_fret = 1,
- .frets = { 1, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "C#sus2",
- .base_fret = 1,
- .frets = { 1, 3, 4, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 2, 3, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "C#sus",
- .base_fret = 1,
- .frets = { 1, 1, 2, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 2, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "C#sus4",
- .base_fret = 1,
- .frets = { 1, 1, 2, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 2, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "C#+",
- .base_fret = 1,
- .frets = { 2, 1, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "C#aug",
- .base_fret = 1,
- .frets = { 2, 1, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "C#9",
- .base_fret = 1,
- .frets = { 1, 3, 1, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 1, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Db",
- .base_fret = 1,
- .frets = { 1, 1, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Dbm",
- .base_fret = 1,
- .frets = { 1, 4, 4, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 2, 3, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Db7",
- .base_fret = 1,
- .frets = { 1, 1, 1, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 1, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Dbm7",
- .base_fret = 1,
- .frets = { 2, 2, 1, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 2, 1, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Dbdim",
- .base_fret = 1,
- .frets = { 0, 1, 0, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 1, 0, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Dbmaj7",
- .base_fret = 1,
- .frets = { 1, 1, 1, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 1, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Db6",
- .base_fret = 1,
- .frets = { 1, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Dbsus2",
- .base_fret = 1,
- .frets = { 1, 3, 4, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 2, 3, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Dbsus",
- .base_fret = 1,
- .frets = { 1, 1, 2, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 2, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Dbsus4",
- .base_fret = 1,
- .frets = { 1, 1, 2, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 2, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Db+",
- .base_fret = 1,
- .frets = { 2, 1, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Dbaug",
- .base_fret = 1,
- .frets = { 2, 1, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Db9",
- .base_fret = 1,
- .frets = { 1, 3, 1, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 1, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "D",
- .base_fret = 1,
- .frets = { 2, 2, 2, 0, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 2, 3, 0, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Dm",
- .base_fret = 1,
- .frets = { 2, 2, 1, 0, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 2, 1, 0, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "D7",
- .base_fret = 2,
- .frets = { 1, 1, 1, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 1, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Dm7",
- .base_fret = 1,
- .frets = { 2, 2, 1, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 2, 1, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Ddim",
- .base_fret = 1,
- .frets = { 1, 2, 1, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 2, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Dmaj7",
- .base_fret = 2,
- .frets = { 1, 1, 1, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 1, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "D6",
- .base_fret = 2,
- .frets = { 1, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Dsus2",
- .base_fret = 1,
- .frets = { 2, 2, 0, 0, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 2, 0, 0, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Dsus",
- .base_fret = 1,
- .frets = { 0, 2, 3, 0, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 1, 2, 0, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Dsus4",
- .base_fret = 1,
- .frets = { 0, 2, 3, 0, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 1, 2, 0, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "D+",
- .base_fret = 2,
- .frets = { 2, 1, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Daug",
- .base_fret = 2,
- .frets = { 2, 1, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "D9",
- .base_fret = 2,
- .frets = { 1, 3, 1, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 1, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "D#",
- .base_fret = 1,
- .frets = { 0, 3, 3, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 2, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "D#m",
- .base_fret = 1,
- .frets = { 3, 3, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 3, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "D#7",
- .base_fret = 3,
- .frets = { 1, 1, 1, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 1, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "D#m7",
- .base_fret = 2,
- .frets = { 2, 2, 1, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 2, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "D#dim",
- .base_fret = 2,
- .frets = { 1, 2, 1, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "D#maj7",
- .base_fret = 3,
- .frets = { 1, 1, 1, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 2, 1, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "D#6",
- .base_fret = 3,
- .frets = { 1, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "D#sus2",
- .base_fret = 1,
- .frets = { 3, 3, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 2, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "D#sus",
- .base_fret = 1,
- .frets = { 1, 3, 4, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 3, 4, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "D#sus4",
- .base_fret = 1,
- .frets = { 1, 3, 4, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 3, 4, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "D#+",
- .base_fret = 1,
- .frets = { 0, 3, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 2, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "D#aug",
- .base_fret = 1,
- .frets = { 0, 3, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 2, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "D#9",
- .base_fret = 1,
- .frets = { 0, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Eb",
- .base_fret = 1,
- .frets = { 0, 3, 3, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 2, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Ebm",
- .base_fret = 1,
- .frets = { 3, 3, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 3, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Eb7",
- .base_fret = 3,
- .frets = { 1, 1, 1, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 1, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Ebm7",
- .base_fret = 2,
- .frets = { 2, 2, 1, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 2, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Ebdim",
- .base_fret = 2,
- .frets = { 1, 2, 1, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Ebmaj7",
- .base_fret = 3,
- .frets = { 1, 1, 1, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 2, 1, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Eb6",
- .base_fret = 3,
- .frets = { 1, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Ebsus2",
- .base_fret = 1,
- .frets = { 3, 3, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 2, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Ebsus",
- .base_fret = 1,
- .frets = { 1, 3, 4, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 3, 4, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Ebsus4",
- .base_fret = 1,
- .frets = { 1, 3, 4, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 3, 4, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Eb+",
- .base_fret = 1,
- .frets = { 0, 3, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 2, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Ebaug",
- .base_fret = 1,
- .frets = { 0, 3, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 2, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Eb9",
- .base_fret = 1,
- .frets = { 0, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "E",
- .base_fret = 2,
- .frets = { 3, 3, 3, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 3, 4, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Em",
- .base_fret = 2,
- .frets = { 3, 3, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 3, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "E7",
- .base_fret = 1,
- .frets = { 1, 2, 0, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 2, 0, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Em7",
- .base_fret = 1,
- .frets = { 0, 2, 0, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 1, 0, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Edim",
- .base_fret = 1,
- .frets = { 0, 1, 0, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 1, 0, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Emaj7",
- .base_fret = 1,
- .frets = { 1, 3, 0, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 0, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "E6",
- .base_fret = 4,
- .frets = { 1, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Esus2",
- .base_fret = 2,
- .frets = { 3, 3, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 3, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Esus",
- .base_fret = 1,
- .frets = { 2, 4, 0, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 4, 0, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Esus4",
- .base_fret = 1,
- .frets = { 2, 4, 0, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 4, 0, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "E+",
- .base_fret = 1,
- .frets = { 1, 0, 0, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 0, 0, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Eaug",
- .base_fret = 1,
- .frets = { 1, 0, 0, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 0, 0, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "E9",
- .base_fret = 1,
- .frets = { 1, 2, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 2, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "F",
- .base_fret = 1,
- .frets = { 2, 0, 1, 0, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 0, 1, 0, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Fm",
- .base_fret = 1,
- .frets = { 1, 0, 1, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 0, 2, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "F7",
- .base_fret = 1,
- .frets = { 2, 3, 1, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 3, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Fm7",
- .base_fret = 1,
- .frets = { 1, 3, 1, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 2, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Fdim",
- .base_fret = 1,
- .frets = { 1, 2, 1, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 2, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Fmaj7",
- .base_fret = 1,
- .frets = { 2, 4, 1, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 4, 1, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "F6",
- .base_fret = 1,
- .frets = { 2, 2, 1, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 2, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Fsus2",
- .base_fret = 1,
- .frets = { 0, 0, 1, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Fsus",
- .base_fret = 1,
- .frets = { 3, 0, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 0, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Fsus4",
- .base_fret = 1,
- .frets = { 3, 0, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 0, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "F+",
- .base_fret = 1,
- .frets = { 2, 1, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Faug",
- .base_fret = 1,
- .frets = { 2, 1, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "F9",
- .base_fret = 2,
- .frets = { 1, 2, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 2, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "F#",
- .base_fret = 1,
- .frets = { 3, 1, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 1, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "F#m",
- .base_fret = 1,
- .frets = { 2, 1, 2, 0, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 3, 0, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "F#7",
- .base_fret = 1,
- .frets = { 3, 4, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 4, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "F#m7",
- .base_fret = 2,
- .frets = { 1, 3, 1, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 2, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "F#dim",
- .base_fret = 2,
- .frets = { 1, 2, 1, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 2, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "F#maj7",
- .base_fret = 2,
- .frets = { 2, 4, 1, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 4, 1, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "F#6",
- .base_fret = 2,
- .frets = { 2, 2, 1, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 2, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "F#sus2",
- .base_fret = 1,
- .frets = { 1, 1, 2, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 2, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "F#sus",
- .base_fret = 1,
- .frets = { 4, 1, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 4, 1, 2, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "F#sus4",
- .base_fret = 1,
- .frets = { 4, 1, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 4, 1, 2, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "F#+",
- .base_fret = 2,
- .frets = { 2, 1, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "F#aug",
- .base_fret = 2,
- .frets = { 2, 1, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "F#9",
- .base_fret = 3,
- .frets = { 1, 2, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 2, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gb",
- .base_fret = 1,
- .frets = { 3, 1, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 1, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gbm",
- .base_fret = 1,
- .frets = { 2, 1, 2, 0, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 3, 0, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gb7",
- .base_fret = 1,
- .frets = { 3, 4, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 4, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gbm7",
- .base_fret = 2,
- .frets = { 1, 3, 1, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 2, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gbdim",
- .base_fret = 2,
- .frets = { 1, 2, 1, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 2, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gbmaj7",
- .base_fret = 2,
- .frets = { 2, 4, 1, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 4, 1, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gb6",
- .base_fret = 2,
- .frets = { 2, 2, 1, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 2, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gbsus2",
- .base_fret = 1,
- .frets = { 1, 1, 2, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 2, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gbsus",
- .base_fret = 1,
- .frets = { 4, 1, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 4, 1, 2, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gbsus4",
- .base_fret = 1,
- .frets = { 4, 1, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 4, 1, 2, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gb+",
- .base_fret = 2,
- .frets = { 2, 1, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gbaug",
- .base_fret = 2,
- .frets = { 2, 1, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gb9",
- .base_fret = 3,
- .frets = { 1, 2, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 2, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "G",
- .base_fret = 1,
- .frets = { 0, 2, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 1, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gm",
- .base_fret = 1,
- .frets = { 0, 2, 3, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 2, 3, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "G7",
- .base_fret = 1,
- .frets = { 0, 2, 1, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 2, 1, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gm7",
- .base_fret = 1,
- .frets = { 0, 2, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 2, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gdim",
- .base_fret = 1,
- .frets = { 0, 1, 0, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 1, 0, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gmaj7",
- .base_fret = 1,
- .frets = { 0, 2, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 1, 2, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "G6",
- .base_fret = 1,
- .frets = { 0, 2, 0, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 1, 0, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gsus2",
- .base_fret = 1,
- .frets = { 0, 2, 3, 0, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 1, 2, 0, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gsus",
- .base_fret = 1,
- .frets = { 0, 2, 3, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 1, 2, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gsus4",
- .base_fret = 1,
- .frets = { 0, 2, 3, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 1, 2, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "G+",
- .base_fret = 1,
- .frets = { 0, 3, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 2, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gaug",
- .base_fret = 1,
- .frets = { 0, 3, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 2, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "G9",
- .base_fret = 1,
- .frets = { 2, 2, 1, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 3, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "G#",
- .base_fret = 3,
- .frets = { 3, 1, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 1, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "G#m",
- .base_fret = 1,
- .frets = { 1, 3, 4, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 4, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "G#7",
- .base_fret = 1,
- .frets = { 1, 3, 2, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 2, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "G#m7",
- .base_fret = 1,
- .frets = { 1, 3, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 4, 2, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "G#dim",
- .base_fret = 1,
- .frets = { 1, 2, 1, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 2, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "G#maj7",
- .base_fret = 1,
- .frets = { 1, 3, 3, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 2, 3, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "G#6",
- .base_fret = 1,
- .frets = { 1, 3, 1, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 2, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "G#sus2",
- .base_fret = 1,
- .frets = { 1, 3, 4, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 3, 4, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "G#sus",
- .base_fret = 1,
- .frets = { 1, 2, 4, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 3, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "G#sus4",
- .base_fret = 1,
- .frets = { 1, 2, 4, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 3, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "G#+",
- .base_fret = 1,
- .frets = { 1, 0, 0, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 0, 0, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "G#aug",
- .base_fret = 1,
- .frets = { 1, 0, 0, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 0, 0, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "G#9",
- .base_fret = 1,
- .frets = { 1, 0, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 0, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Ab",
- .base_fret = 3,
- .frets = { 3, 1, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 1, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Abm",
- .base_fret = 1,
- .frets = { 1, 3, 4, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 4, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Ab7",
- .base_fret = 1,
- .frets = { 1, 3, 2, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 2, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Abm7",
- .base_fret = 1,
- .frets = { 1, 3, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 4, 2, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Abdim",
- .base_fret = 1,
- .frets = { 1, 2, 1, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 2, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Abmaj7",
- .base_fret = 1,
- .frets = { 1, 3, 3, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 2, 3, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Ab6",
- .base_fret = 1,
- .frets = { 1, 3, 1, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 2, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Absus2",
- .base_fret = 1,
- .frets = { 1, 3, 4, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 3, 4, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Absus",
- .base_fret = 1,
- .frets = { 1, 2, 4, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 3, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Absus4",
- .base_fret = 1,
- .frets = { 1, 2, 4, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 3, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Ab+",
- .base_fret = 1,
- .frets = { 1, 0, 0, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 0, 0, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Abaug",
- .base_fret = 1,
- .frets = { 1, 0, 0, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 0, 0, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Ab9",
- .base_fret = 1,
- .frets = { 1, 0, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 0, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- }
-};
-
-static const struct StringDiagram mandolin_diagrams[] = {
- {
- .name = "A",
- .base_fret = 1,
- .frets = { 2, 2, 4, 0, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 3, 0, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Am",
- .base_fret = 1,
- .frets = { 2, 2, 3, 0, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 2, 0, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "A7",
- .base_fret = 2,
- .frets = { 1, 1, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Am7",
- .base_fret = 2,
- .frets = { 1, 1, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Aø",
- .base_fret = 1,
- .frets = { 2, 1, 3, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 3, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Am7b5",
- .base_fret = 1,
- .frets = { 2, 1, 3, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 3, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Ah",
- .base_fret = 1,
- .frets = { 2, 1, 3, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 3, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "A0",
- .base_fret = 1,
- .frets = { 2, 1, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 4, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Adim",
- .base_fret = 1,
- .frets = { 2, 1, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 4, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Adim7",
- .base_fret = 1,
- .frets = { 2, 1, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 4, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Amaj7",
- .base_fret = 2,
- .frets = { 1, 1, 3, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 3, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "A6",
- .base_fret = 2,
- .frets = { 1, 1, 3, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 3, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Asus2",
- .base_fret = 1,
- .frets = { 2, 2, 2, 0, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 1, 0, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Asus",
- .base_fret = 1,
- .frets = { 2, 0, 0, 0, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 0, 0, 0, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Asus4",
- .base_fret = 1,
- .frets = { 2, 0, 0, 0, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 0, 0, 0, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "A+",
- .base_fret = 1,
- .frets = { 2, 3, 4, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 3, 4, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Aaug",
- .base_fret = 1,
- .frets = { 2, 3, 4, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 3, 4, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "A9",
- .base_fret = 2,
- .frets = { 1, 4, 3, 6, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 2, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "A#",
- .base_fret = 1,
- .frets = { 3, 0, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 0, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "A#m",
- .base_fret = 3,
- .frets = { 1, 1, 2, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 2, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "A#7",
- .base_fret = 3,
- .frets = { 1, 1, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "A#m7",
- .base_fret = 3,
- .frets = { 1, 1, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "A#ø",
- .base_fret = 2,
- .frets = { 2, 1, 3, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 3, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "A#m7b5",
- .base_fret = 2,
- .frets = { 2, 1, 3, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 3, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "A#h",
- .base_fret = 2,
- .frets = { 2, 1, 3, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 3, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "A#0",
- .base_fret = 2,
- .frets = { 2, 1, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 4, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "A#dim",
- .base_fret = 2,
- .frets = { 2, 1, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 4, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "A#dim7",
- .base_fret = 2,
- .frets = { 2, 1, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 4, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "A#maj7",
- .base_fret = 1,
- .frets = { 3, 0, 0, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 0, 0, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "A#6",
- .base_fret = 1,
- .frets = { 0, 0, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "A#sus2",
- .base_fret = 3,
- .frets = { 1, 1, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "A#sus",
- .base_fret = 1,
- .frets = { 3, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "A#sus4",
- .base_fret = 1,
- .frets = { 3, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "A#+",
- .base_fret = 1,
- .frets = { 3, 0, 1, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 0, 1, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "A#aug",
- .base_fret = 1,
- .frets = { 3, 0, 1, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 0, 1, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "A#9",
- .base_fret = 1,
- .frets = { 3, 0, 3, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 0, 2, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bb",
- .base_fret = 1,
- .frets = { 3, 0, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 0, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bbm",
- .base_fret = 3,
- .frets = { 1, 1, 2, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 2, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bb7",
- .base_fret = 3,
- .frets = { 1, 1, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bbm7",
- .base_fret = 3,
- .frets = { 1, 1, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bbø",
- .base_fret = 2,
- .frets = { 2, 1, 3, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 3, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bbm7b5",
- .base_fret = 2,
- .frets = { 2, 1, 3, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 3, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bbh",
- .base_fret = 2,
- .frets = { 2, 1, 3, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 3, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bb0",
- .base_fret = 2,
- .frets = { 2, 1, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 4, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bbdim",
- .base_fret = 2,
- .frets = { 2, 1, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 4, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bbdim7",
- .base_fret = 2,
- .frets = { 2, 1, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 4, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bbmaj7",
- .base_fret = 1,
- .frets = { 3, 0, 0, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 0, 0, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bb6",
- .base_fret = 1,
- .frets = { 0, 0, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bbsus2",
- .base_fret = 3,
- .frets = { 1, 1, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bbsus",
- .base_fret = 1,
- .frets = { 3, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bbsus4",
- .base_fret = 1,
- .frets = { 3, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bb+",
- .base_fret = 1,
- .frets = { 3, 0, 1, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 0, 1, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bbaug",
- .base_fret = 1,
- .frets = { 3, 0, 1, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 0, 1, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bb9",
- .base_fret = 1,
- .frets = { 3, 0, 3, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 0, 2, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "B",
- .base_fret = 4,
- .frets = { 1, 1, 3, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 3, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bm",
- .base_fret = 1,
- .frets = { 4, 0, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 0, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "B7",
- .base_fret = 4,
- .frets = { 1, 1, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bm7",
- .base_fret = 1,
- .frets = { 4, 0, 0, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 0, 0, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bø",
- .base_fret = 1,
- .frets = { 2, 0, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 0, 3, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bm7b5",
- .base_fret = 1,
- .frets = { 2, 0, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 0, 3, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bh",
- .base_fret = 1,
- .frets = { 2, 0, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 0, 3, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "B0",
- .base_fret = 1,
- .frets = { 1, 0, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 0, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bdim",
- .base_fret = 1,
- .frets = { 1, 0, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 0, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bdim7",
- .base_fret = 1,
- .frets = { 1, 0, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 0, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bmaj7",
- .base_fret = 1,
- .frets = { 4, 1, 1, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 4, 1, 1, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "B6",
- .base_fret = 1,
- .frets = { 1, 1, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bsus2",
- .base_fret = 4,
- .frets = { 1, 1, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bsus",
- .base_fret = 2,
- .frets = { 3, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Bsus4",
- .base_fret = 2,
- .frets = { 3, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "B+",
- .base_fret = 1,
- .frets = { 4, 1, 2, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 4, 1, 2, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Baug",
- .base_fret = 1,
- .frets = { 4, 1, 2, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 4, 1, 2, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "B9",
- .base_fret = 1,
- .frets = { 4, 1, 4, 5, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 3, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "C",
- .base_fret = 1,
- .frets = { 5, 2, 3, 0, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 4, 1, 2, 0, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Cm",
- .base_fret = 5,
- .frets = { 1, 1, 2, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 2, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "C7",
- .base_fret = 1,
- .frets = { 5, 2, 1, 0, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 4, 2, 1, 0, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Cm7",
- .base_fret = 5,
- .frets = { 1, 1, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Cø",
- .base_fret = 1,
- .frets = { 3, 1, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 1, 4, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Cm7b5",
- .base_fret = 1,
- .frets = { 3, 1, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 1, 4, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Ch",
- .base_fret = 1,
- .frets = { 3, 1, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 1, 4, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "C0",
- .base_fret = 1,
- .frets = { 2, 1, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 4, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Cdim",
- .base_fret = 1,
- .frets = { 2, 1, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 4, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Cdim7",
- .base_fret = 1,
- .frets = { 2, 1, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 4, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Cmaj7",
- .base_fret = 2,
- .frets = { 4, 1, 1, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 4, 1, 1, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "C6",
- .base_fret = 2,
- .frets = { 1, 1, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Csus2",
- .base_fret = 1,
- .frets = { 5, 0, 3, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 0, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Csus",
- .base_fret = 3,
- .frets = { 3, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Csus4",
- .base_fret = 3,
- .frets = { 3, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "C+",
- .base_fret = 2,
- .frets = { 4, 1, 2, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 4, 1, 2, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Caug",
- .base_fret = 2,
- .frets = { 4, 1, 2, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 4, 1, 2, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "C9",
- .base_fret = 1,
- .frets = { 5, 0, 7, 6, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 0, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "C#",
- .base_fret = 1,
- .frets = { 6, 3, 4, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 4, 2, 3, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "C#m",
- .base_fret = 1,
- .frets = { 6, 6, 4, 0, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 3, 1, 0, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "C#7",
- .base_fret = 2,
- .frets = { 5, 2, 1, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 4, 2, 1, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "C#m7",
- .base_fret = 6,
- .frets = { 1, 1, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "C#ø",
- .base_fret = 2,
- .frets = { 3, 1, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 1, 4, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "C#m7b5",
- .base_fret = 2,
- .frets = { 3, 1, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 1, 4, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "C#h",
- .base_fret = 2,
- .frets = { 3, 1, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 1, 4, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "C#0",
- .base_fret = 1,
- .frets = { 3, 2, 1, 0, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 1, 0, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "C#dim",
- .base_fret = 1,
- .frets = { 3, 2, 1, 0, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 1, 0, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "C#dim7",
- .base_fret = 1,
- .frets = { 3, 2, 1, 0, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 1, 0, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "C#maj7",
- .base_fret = 3,
- .frets = { 4, 1, 1, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 4, 1, 1, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "C#6",
- .base_fret = 3,
- .frets = { 1, 1, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "C#sus2",
- .base_fret = 1,
- .frets = { 1, 1, 4, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 3, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "C#sus",
- .base_fret = 4,
- .frets = { 3, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "C#sus4",
- .base_fret = 4,
- .frets = { 3, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "C#+",
- .base_fret = 1,
- .frets = { 6, 3, 0, 5, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 4, 1, 0, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "C#aug",
- .base_fret = 1,
- .frets = { 6, 3, 0, 5, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 4, 1, 0, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "C#9",
- .base_fret = 3,
- .frets = { 4, 1, 4, 5, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 3, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Db",
- .base_fret = 1,
- .frets = { 6, 3, 4, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 4, 2, 3, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Dbm",
- .base_fret = 1,
- .frets = { 6, 6, 4, 0, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 3, 1, 0, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Db7",
- .base_fret = 2,
- .frets = { 5, 2, 1, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 4, 2, 1, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Dbm7",
- .base_fret = 6,
- .frets = { 1, 1, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Dbø",
- .base_fret = 2,
- .frets = { 3, 1, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 1, 4, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Dbm7b5",
- .base_fret = 2,
- .frets = { 3, 1, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 1, 4, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Dbh",
- .base_fret = 2,
- .frets = { 3, 1, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 1, 4, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Db0",
- .base_fret = 1,
- .frets = { 3, 2, 1, 0, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 1, 0, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Dbdim",
- .base_fret = 1,
- .frets = { 3, 2, 1, 0, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 1, 0, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Dbdim7",
- .base_fret = 1,
- .frets = { 3, 2, 1, 0, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 1, 0, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Dbmaj7",
- .base_fret = 3,
- .frets = { 4, 1, 1, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 4, 1, 1, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Db6",
- .base_fret = 3,
- .frets = { 1, 1, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Dbsus2",
- .base_fret = 1,
- .frets = { 1, 1, 4, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 3, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Dbsus",
- .base_fret = 4,
- .frets = { 3, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Dbsus4",
- .base_fret = 4,
- .frets = { 3, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Db+",
- .base_fret = 1,
- .frets = { 6, 3, 0, 5, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 4, 1, 0, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Dbaug",
- .base_fret = 1,
- .frets = { 6, 3, 0, 5, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 4, 1, 0, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Db9",
- .base_fret = 3,
- .frets = { 4, 1, 4, 5, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 3, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "D",
- .base_fret = 1,
- .frets = { 2, 0, 0, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 0, 0, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Dm",
- .base_fret = 1,
- .frets = { 2, 0, 0, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 0, 0, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "D7",
- .base_fret = 1,
- .frets = { 2, 0, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 0, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Dm7",
- .base_fret = 1,
- .frets = { 2, 0, 3, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 0, 3, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Dø",
- .base_fret = 1,
- .frets = { 1, 0, 3, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 0, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Dm7b5",
- .base_fret = 1,
- .frets = { 1, 0, 3, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 0, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Dh",
- .base_fret = 1,
- .frets = { 1, 0, 3, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 0, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "D0",
- .base_fret = 1,
- .frets = { 1, 0, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 0, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Ddim",
- .base_fret = 1,
- .frets = { 1, 0, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 0, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Ddim7",
- .base_fret = 1,
- .frets = { 1, 0, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 0, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Dmaj7",
- .base_fret = 1,
- .frets = { 2, 0, 4, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 0, 4, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "D6",
- .base_fret = 1,
- .frets = { 2, 0, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 0, 2, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Dsus2",
- .base_fret = 1,
- .frets = { 2, 0, 0, 0, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 0, 0, 0, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Dsus",
- .base_fret = 1,
- .frets = { 2, 0, 0, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 0, 0, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Dsus4",
- .base_fret = 1,
- .frets = { 2, 0, 0, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 0, 0, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "D+",
- .base_fret = 1,
- .frets = { 3, 0, 1, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 0, 1, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Daug",
- .base_fret = 1,
- .frets = { 3, 0, 1, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 0, 1, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "D9",
- .base_fret = 1,
- .frets = { 7, 4, 3, 0, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 4, 2, 1, 0, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "D#",
- .base_fret = 1,
- .frets = { 3, 1, 1, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 1, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "D#m",
- .base_fret = 1,
- .frets = { 3, 1, 1, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 1, 1, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "D#7",
- .base_fret = 1,
- .frets = { 3, 1, 4, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 4, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "D#m7",
- .base_fret = 1,
- .frets = { 3, 1, 4, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 1, 4, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "D#ø",
- .base_fret = 1,
- .frets = { 2, 1, 4, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 4, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "D#m7b5",
- .base_fret = 1,
- .frets = { 2, 1, 4, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 4, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "D#h",
- .base_fret = 1,
- .frets = { 2, 1, 4, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 4, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "D#0",
- .base_fret = 1,
- .frets = { 2, 1, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 4, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "D#dim",
- .base_fret = 1,
- .frets = { 2, 1, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 4, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "D#dim7",
- .base_fret = 1,
- .frets = { 2, 1, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 4, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "D#maj7",
- .base_fret = 1,
- .frets = { 3, 1, 5, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 4, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "D#6",
- .base_fret = 1,
- .frets = { 3, 1, 3, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 3, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "D#sus2",
- .base_fret = 1,
- .frets = { 3, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "D#sus",
- .base_fret = 1,
- .frets = { 3, 1, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 1, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "D#sus4",
- .base_fret = 1,
- .frets = { 3, 1, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 1, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "D#+",
- .base_fret = 1,
- .frets = { 0, 1, 2, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 1, 2, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "D#aug",
- .base_fret = 1,
- .frets = { 0, 1, 2, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 1, 2, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "D#9",
- .base_fret = 5,
- .frets = { 4, 1, 4, 5, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 3, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Eb",
- .base_fret = 1,
- .frets = { 3, 1, 1, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 1, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Ebm",
- .base_fret = 1,
- .frets = { 3, 1, 1, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 1, 1, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Eb7",
- .base_fret = 1,
- .frets = { 3, 1, 4, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 4, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Ebm7",
- .base_fret = 1,
- .frets = { 3, 1, 4, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 1, 4, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Ebø",
- .base_fret = 1,
- .frets = { 2, 1, 4, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 4, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Ebm7b5",
- .base_fret = 1,
- .frets = { 2, 1, 4, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 4, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Ebh",
- .base_fret = 1,
- .frets = { 2, 1, 4, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 4, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Eb0",
- .base_fret = 1,
- .frets = { 2, 1, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 4, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Ebdim",
- .base_fret = 1,
- .frets = { 2, 1, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 4, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Ebdim7",
- .base_fret = 1,
- .frets = { 2, 1, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 4, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Ebmaj7",
- .base_fret = 1,
- .frets = { 3, 1, 5, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 4, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Eb6",
- .base_fret = 1,
- .frets = { 3, 1, 3, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 3, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Ebsus2",
- .base_fret = 1,
- .frets = { 3, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Ebsus",
- .base_fret = 1,
- .frets = { 3, 1, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 1, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Ebsus4",
- .base_fret = 1,
- .frets = { 3, 1, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 1, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Eb+",
- .base_fret = 1,
- .frets = { 0, 1, 2, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 1, 2, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Ebaug",
- .base_fret = 1,
- .frets = { 0, 1, 2, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 1, 2, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Eb9",
- .base_fret = 5,
- .frets = { 4, 1, 4, 5, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 3, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "E",
- .base_fret = 1,
- .frets = { 1, 2, 2, 0, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 2, 3, 0, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Em",
- .base_fret = 1,
- .frets = { 0, 2, 2, 0, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 2, 3, 0, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "E7",
- .base_fret = 1,
- .frets = { 1, 0, 2, 0, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 0, 2, 0, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Em7",
- .base_fret = 1,
- .frets = { 0, 0, 2, 0, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 2, 0, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Eø",
- .base_fret = 1,
- .frets = { 0, 0, 1, 0, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 0, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Em7b5",
- .base_fret = 1,
- .frets = { 0, 0, 1, 0, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 0, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Eh",
- .base_fret = 1,
- .frets = { 0, 0, 1, 0, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 0, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "E0",
- .base_fret = 2,
- .frets = { 2, 1, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 4, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Edim",
- .base_fret = 2,
- .frets = { 2, 1, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 4, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Edim7",
- .base_fret = 2,
- .frets = { 2, 1, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 4, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Emaj7",
- .base_fret = 1,
- .frets = { 1, 1, 2, 0, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 2, 0, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "E6",
- .base_fret = 1,
- .frets = { 4, 6, 4, 0, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 2, 0, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Esus2",
- .base_fret = 2,
- .frets = { 3, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Esus",
- .base_fret = 1,
- .frets = { 4, 2, 0, 0, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 1, 0, 0, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Esus4",
- .base_fret = 1,
- .frets = { 4, 2, 0, 0, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 1, 0, 0, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "E+",
- .base_fret = 1,
- .frets = { 1, 2, 3, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 2, 3, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Eaug",
- .base_fret = 1,
- .frets = { 1, 2, 3, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 2, 3, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "E9",
- .base_fret = 6,
- .frets = { 4, 1, 4, 5, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 3, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "F",
- .base_fret = 1,
- .frets = { 2, 3, 0, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 3, 0, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Fm",
- .base_fret = 1,
- .frets = { 1, 3, 3, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 4, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "F7",
- .base_fret = 1,
- .frets = { 2, 1, 3, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 3, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Fm7",
- .base_fret = 1,
- .frets = { 1, 1, 3, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 3, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Fø",
- .base_fret = 1,
- .frets = { 1, 1, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Fm7b5",
- .base_fret = 1,
- .frets = { 1, 1, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Fh",
- .base_fret = 1,
- .frets = { 1, 1, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "F0",
- .base_fret = 1,
- .frets = { 1, 0, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 0, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Fdim",
- .base_fret = 1,
- .frets = { 1, 0, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 0, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Fdim7",
- .base_fret = 1,
- .frets = { 1, 0, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 0, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Fmaj7",
- .base_fret = 1,
- .frets = { 2, 2, 3, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 3, 4, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "F6",
- .base_fret = 1,
- .frets = { 2, 0, 3, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 0, 3, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Fsus2",
- .base_fret = 1,
- .frets = { 0, 3, 3, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 3, 4, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Fsus",
- .base_fret = 1,
- .frets = { 5, 3, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 4, 2, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Fsus4",
- .base_fret = 1,
- .frets = { 5, 3, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 4, 2, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "F+",
- .base_fret = 2,
- .frets = { 1, 2, 3, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 2, 3, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Faug",
- .base_fret = 2,
- .frets = { 1, 2, 3, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 2, 3, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "F9",
- .base_fret = 7,
- .frets = { 4, 1, 4, 5, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 3, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "F#",
- .base_fret = 2,
- .frets = { 2, 3, 3, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 3, 4, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "F#m",
- .base_fret = 2,
- .frets = { 1, 3, 3, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 4, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "F#7",
- .base_fret = 2,
- .frets = { 2, 1, 3, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 3, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "F#m7",
- .base_fret = 2,
- .frets = { 1, 1, 3, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 3, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "F#ø",
- .base_fret = 2,
- .frets = { 1, 1, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "F#m7b5",
- .base_fret = 2,
- .frets = { 1, 1, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "F#h",
- .base_fret = 2,
- .frets = { 1, 1, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "F#0",
- .base_fret = 1,
- .frets = { 2, 1, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 4, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "F#dim",
- .base_fret = 1,
- .frets = { 2, 1, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 4, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "F#dim7",
- .base_fret = 1,
- .frets = { 2, 1, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 4, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "F#maj7",
- .base_fret = 2,
- .frets = { 2, 2, 3, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 3, 4, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "F#6",
- .base_fret = 1,
- .frets = { 3, 1, 4, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 1, 4, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "F#sus2",
- .base_fret = 4,
- .frets = { 3, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "F#sus",
- .base_fret = 2,
- .frets = { 5, 3, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 4, 2, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "F#sus4",
- .base_fret = 2,
- .frets = { 5, 3, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 4, 2, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "F#+",
- .base_fret = 3,
- .frets = { 1, 2, 3, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 2, 3, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "F#aug",
- .base_fret = 3,
- .frets = { 1, 2, 3, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 2, 3, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "F#9",
- .base_fret = 1,
- .frets = { 11, 8, 11, 0, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 3, 0, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gb",
- .base_fret = 2,
- .frets = { 2, 3, 3, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 3, 4, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gbm",
- .base_fret = 2,
- .frets = { 1, 3, 3, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 4, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gb7",
- .base_fret = 2,
- .frets = { 2, 1, 3, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 3, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gbm7",
- .base_fret = 2,
- .frets = { 1, 1, 3, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 3, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gbø",
- .base_fret = 2,
- .frets = { 1, 1, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gbm7b5",
- .base_fret = 2,
- .frets = { 1, 1, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gbh",
- .base_fret = 2,
- .frets = { 1, 1, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gb0",
- .base_fret = 1,
- .frets = { 2, 1, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 4, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gbdim",
- .base_fret = 1,
- .frets = { 2, 1, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 4, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gbdim7",
- .base_fret = 1,
- .frets = { 2, 1, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 4, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gbmaj7",
- .base_fret = 2,
- .frets = { 2, 2, 3, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 3, 4, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gb6",
- .base_fret = 1,
- .frets = { 3, 1, 4, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 1, 4, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gbsus2",
- .base_fret = 4,
- .frets = { 3, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 3, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gbsus",
- .base_fret = 2,
- .frets = { 5, 3, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 4, 2, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gbsus4",
- .base_fret = 2,
- .frets = { 5, 3, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 4, 2, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gb+",
- .base_fret = 3,
- .frets = { 1, 2, 3, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 2, 3, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gbaug",
- .base_fret = 3,
- .frets = { 1, 2, 3, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 2, 3, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gb9",
- .base_fret = 7,
- .frets = { 4, 1, 4, 0, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 3, 0, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "G",
- .base_fret = 1,
- .frets = { 0, 0, 2, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gm",
- .base_fret = 1,
- .frets = { 0, 0, 1, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "G7",
- .base_fret = 1,
- .frets = { 0, 0, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gm7",
- .base_fret = 1,
- .frets = { 0, 0, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gø",
- .base_fret = 3,
- .frets = { 1, 1, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gm7b5",
- .base_fret = 3,
- .frets = { 1, 1, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gh",
- .base_fret = 3,
- .frets = { 1, 1, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "G0",
- .base_fret = 2,
- .frets = { 2, 1, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 4, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gdim",
- .base_fret = 2,
- .frets = { 2, 1, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 4, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gdim7",
- .base_fret = 2,
- .frets = { 2, 1, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 2, 1, 4, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gmaj7",
- .base_fret = 1,
- .frets = { 0, 0, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "G6",
- .base_fret = 1,
- .frets = { 0, 0, 2, 0, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 2, 0, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gsus2",
- .base_fret = 1,
- .frets = { 0, 0, 0, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 0, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gsus",
- .base_fret = 1,
- .frets = { 0, 0, 3, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gsus4",
- .base_fret = 1,
- .frets = { 0, 0, 3, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 0, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "G+",
- .base_fret = 1,
- .frets = { 0, 1, 2, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 1, 2, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Gaug",
- .base_fret = 1,
- .frets = { 0, 1, 2, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 1, 2, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "G9",
- .base_fret = 1,
- .frets = { 0, 3, 0, 7, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 0, 1, 0, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "G#",
- .base_fret = 1,
- .frets = { 1, 1, 3, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 3, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "G#m",
- .base_fret = 1,
- .frets = { 1, 1, 2, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 2, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "G#7",
- .base_fret = 1,
- .frets = { 1, 1, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "G#m7",
- .base_fret = 1,
- .frets = { 1, 1, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "G#ø",
- .base_fret = 1,
- .frets = { 1, 0, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 0, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "G#m7b5",
- .base_fret = 1,
- .frets = { 1, 0, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 0, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "G#h",
- .base_fret = 1,
- .frets = { 1, 0, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 0, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "G#0",
- .base_fret = 1,
- .frets = { 1, 0, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 0, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "G#dim",
- .base_fret = 1,
- .frets = { 1, 0, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 0, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "G#dim7",
- .base_fret = 1,
- .frets = { 1, 0, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 0, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "G#maj7",
- .base_fret = 1,
- .frets = { 1, 1, 3, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 3, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "G#6",
- .base_fret = 1,
- .frets = { 1, 1, 3, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 3, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "G#sus2",
- .base_fret = 1,
- .frets = { 1, 1, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "G#sus",
- .base_fret = 1,
- .frets = { 1, 1, 4, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 3, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "G#sus4",
- .base_fret = 1,
- .frets = { 1, 1, 4, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 3, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "G#+",
- .base_fret = 1,
- .frets = { 1, 2, 3, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 2, 3, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "G#aug",
- .base_fret = 1,
- .frets = { 1, 2, 3, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 2, 3, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "G#9",
- .base_fret = 1,
- .frets = { 1, 4, 3, 6, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 2, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Ab",
- .base_fret = 1,
- .frets = { 1, 1, 3, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 3, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Abm",
- .base_fret = 1,
- .frets = { 1, 1, 2, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 2, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Ab7",
- .base_fret = 1,
- .frets = { 1, 1, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Abm7",
- .base_fret = 1,
- .frets = { 1, 1, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Abø",
- .base_fret = 1,
- .frets = { 1, 0, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 0, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Abm7b5",
- .base_fret = 1,
- .frets = { 1, 0, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 0, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Abh",
- .base_fret = 1,
- .frets = { 1, 0, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 0, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Ab0",
- .base_fret = 1,
- .frets = { 1, 0, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 0, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Abdim",
- .base_fret = 1,
- .frets = { 1, 0, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 0, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Abdim7",
- .base_fret = 1,
- .frets = { 1, 0, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 0, 3, 2, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Abmaj7",
- .base_fret = 1,
- .frets = { 1, 1, 3, 3, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 3, 3, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Ab6",
- .base_fret = 1,
- .frets = { 1, 1, 3, 1, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 3, 1, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Absus2",
- .base_fret = 1,
- .frets = { 1, 1, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 1, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Absus",
- .base_fret = 1,
- .frets = { 1, 1, 4, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 3, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Absus4",
- .base_fret = 1,
- .frets = { 1, 1, 4, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 1, 3, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Ab+",
- .base_fret = 1,
- .frets = { 1, 2, 3, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 2, 3, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Abaug",
- .base_fret = 1,
- .frets = { 1, 2, 3, 4, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 2, 3, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- },
- {
- .name = "Ab9",
- .base_fret = 1,
- .frets = { 1, 4, 3, 6, -2, -2, -2, -2, -2, -2, -2, -2 },
- .fingers = { 1, 3, 2, 4, -2, -2, -2, -2, -2, -2, -2, -2 }
- }
-};
diff --git a/lorid.c b/lorid.c
@@ -1,117 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdbool.h>
-#include <string.h>
-#include <getopt.h>
-#include "types.h"
-#include "chordpro.h"
-#include "config.h"
-#include "out_pdf.h"
-#include "util.h"
-
-int
-main(int argc, char *argv[])
-{
- static struct option long_options[] = {
- { "print-default-config", no_argument, 0, 'p' },
- { "config", required_argument, 0, 'c' },
- { "output", required_argument, 0, 'o' },
- { "verbose", no_argument, 0, 'v' },
- { "version", no_argument, 0, 'V' },
- { "help", no_argument, 0, 'h' },
- { 0, 0, 0, 0 }
- };
- int o, option_index;
- const char *chordpro_filepath = NULL;
- char *config_filepath = NULL;
- char *output = NULL;
- struct ChoSong **so, **all_songs = NULL, **songs = NULL;
- int s = 0;
- FILE *fp;
- while ((o = getopt_long(argc, argv, "pc:o:Vvh", long_options, &option_index)) != -1) {
- switch(o) {
- case 'p':
- config_print_default();
- return 0;
- case 'c':
- config_filepath = emalloc((strlen(optarg)+1) * sizeof(char));
- strcpy(config_filepath, optarg);
- break;
- case 'o':
- output = erealloc(output, (strlen(optarg)+1) * sizeof(char));
- strcpy(output, optarg);
- break;
- case 'V':
- printf(VERSION"\n");
- return 0;
- case 'v':
- cho_log_enable_info_logs();
- util_log_enable_info_logs();
- break;
- case 'h':
- return system("man lorid");
- }
- }
- struct Config *config = config_load(config_filepath);
- if (!config) {
- LOG_DEBUG("config_load failed.");
- return 1;
- }
- free(config_filepath);
- if (argc == optind) {
- fp = stdin;
- all_songs = cho_songs_parse(fp, NULL, config);
- if (!all_songs) {
- LOG_DEBUG("cho_songs_parse failed.");
- return 1;
- }
- } else if (argc == optind+1) {
- fp = fopen(argv[argc-1], "r");
- if (!fp) {
- LOG_DEBUG("fopen failed.");
- return 1;
- }
- chordpro_filepath = argv[argc-1];
- all_songs = cho_songs_parse(fp, chordpro_filepath, config);
- if (!all_songs) {
- LOG_DEBUG("cho_songs_parse failed.");
- return 1;
- }
- fclose(fp);
- } else {
- int file_count = argc - optind;
- int i;
- for (i = argc-file_count; i<argc; i++) {
- fp = fopen(argv[i], "r");
- if (!fp) {
- LOG_DEBUG("fopen failed.");
- return 1;
- }
- songs = cho_songs_parse(fp, argv[i], config);
- if (!songs) {
- LOG_DEBUG("cho_songs_parse failed.");
- return 1;
- }
- fclose(fp);
- for (so = songs; *so; s++, so++) {
- all_songs = erealloc(all_songs, (s+1) * sizeof(struct ChoSong *));
- all_songs[s] = *so;
- }
- free(songs);
- }
- all_songs = erealloc(all_songs, (s+1) * sizeof(struct ChoSong *));
- all_songs[s] = NULL;
- qsort(all_songs, cho_song_count(all_songs), sizeof(struct ChoSong *), cho_song_compare);
- }
- char *pdf_filename = out_pdf_create(chordpro_filepath, output, all_songs, config);
- if (!pdf_filename) {
- LOG_DEBUG("out_pdf_new failed.");
- return 1;
- }
- util_log(LOG_INFO, "Writing pdf to file: '%s'.", pdf_filename);
- free(pdf_filename);
- free(output);
- cho_songs_free(all_songs);
- config_free(config);
- return 0;
-}
diff --git a/out_pdf.c b/out_pdf.c
@@ -1,2819 +0,0 @@
-#include <stdbool.h>
-#include <string.h>
-#include <unistd.h>
-#include <pdfio.h>
-#include <pdfio-content.h>
-#include <sys/stat.h>
-#include <errno.h>
-#include <fontconfig/fontconfig.h>
-#include <grapheme.h>
-#include <math.h>
-#include "types.h"
-#include "out_pdf.h"
-#include "chordpro.h"
-#include "config.h"
-#include "util.h"
-#include "chord_diagram.h"
-
-static struct Obj **g_fonts = NULL;
-static char g_cho_dirpath[PATH_MAX];
-static char g_current_font_name[200];
-static double g_current_font_size;
-static int g_current_page_index;
-static pdfio_file_t *g_pdf_file = NULL;
-static struct Config *g_config = NULL;
-
-static const char *g_base_fonts[] = {
- "Courier",
- "Courier-Bold",
- "Courier-BoldItalic",
- "Courier-Italic",
- "Helvetica",
- "Helvetica-Bold",
- "Helvetica-BoldOblique",
- "Helvetica-Oblique",
- "Symbol",
- "Times-Bold",
- "Times-BoldItalic",
- "Times-Italic",
- "Times-Roman",
- "ZapfDingbats"
-};
-
-static struct Obj *
-obj_new(void)
-{
- struct Obj *obj = emalloc(sizeof(struct Obj));
- obj->name = NULL;
- obj->value = NULL;
- return obj;
-}
-
-static void
-obj_free(struct Obj *obj)
-{
- free(obj->name);
- free(obj);
-}
-
-static void
-objs_free(struct Obj **objs)
-{
- if (!objs) {
- return;
- }
- struct Obj **start = objs;
- for (; *objs; objs++) {
- obj_free(*objs);
- }
- free(start);
-}
-
-static pdfio_obj_t *
-objs_get_obj(struct Obj **objs, const char *name)
-{
- if (!objs) {
- return NULL;
- }
- struct Obj **o;
- for (o = objs; *o; o++) {
- if (!strcmp((*o)->name, name)) {
- return (*o)->value;
- }
- }
- return NULL;
-}
-
-static void
-objs_add_obj(struct Obj ***array, struct Obj *obj)
-{
- if (!*array) {
- *array = erealloc(*array, 2 * sizeof(struct Obj *));
- (*array)[0] = obj;
- (*array)[1] = NULL;
- } else {
- int a;
- for (a = 0; (*array)[a]; a++);
- *array = erealloc(*array, (a+2) * sizeof(struct Obj *));
- (*array)[a] = obj;
- (*array)[a+1] = NULL;
- }
-}
-
-pdfio_obj_t *
-out_pdf_fnt_obj_get_by_name(const char *name)
-{
- int i;
- for (i = 0; g_fonts[i]; i++) {
- if (!strcmp(g_fonts[i]->name, name)) {
- return g_fonts[i]->value;
- }
- }
- printf("name '%s'\n", name);
- return NULL;
-}
-
-static char *
-fnt_name_create(struct Font *font)
-{
- char *name = str_normalize(font->name);
- const char *family = cho_font_family_to_config_string(font->family);
- const char *style = cho_font_style_to_config_string(font->style);
- const char *weight = cho_font_weight_to_config_string(font->weight);
- size_t len = strlen(name) + strlen(family) + strlen(style) + strlen(weight);
- int n = 0;
- int i;
- char *fnt_name = emalloc((len + 4) * sizeof(char));
- for (i = 0; name[i]; i++, n++) {
- fnt_name[n] = name[i];
- }
- fnt_name[n] = '-';
- n++;
- for (i = 0; family[i]; i++, n++) {
- fnt_name[n] = family[i];
- }
- fnt_name[n] = '-';
- n++;
- for (i = 0; style[i]; i++, n++) {
- fnt_name[n] = style[i];
- }
- fnt_name[n] = '-';
- n++;
- for (i = 0; weight[i]; i++, n++) {
- fnt_name[n] = weight[i];
- }
- fnt_name[n] = 0;
- free(name);
- return fnt_name;
-}
-
-static bool
-fonts_add_if_not_in(struct Font ***array, struct Font *font)
-{
- if (!*array) {
- *array = erealloc(*array, 2 * sizeof(struct Font *));
- (*array)[0] = font;
- (*array)[1] = NULL;
- return true;
- } else {
- int a;
- for (a = 0; (*array)[a]; a++) {
- if (
- !strcmp((*array)[a]->name, font->name) &&
- (*array)[a]->family == font->family &&
- (*array)[a]->style == font->style &&
- (*array)[a]->weight == font->weight
- ) {
- return false;
- }
- }
- *array = erealloc(*array, (a+2) * sizeof(struct Font *));
- (*array)[a] = font;
- (*array)[a+1] = NULL;
- return true;
- }
-}
-
-static struct Font **
-fonts_get_all(struct ChoSong **songs, struct Config *config)
-{
- struct Font **fonts = NULL;
- struct Font *font;
- struct ChoSong **so;
- struct ChoMetadata **m;
- struct ChoSection **se;
- struct ChoLine **li;
- struct ChoLineItemAbove **above;
- struct ChoLineItem **it;
- struct ChoStyle *style;
- bool added;
- int i;
- for (so = songs; *so; so++) {
- for (i = 0; i < TT_LENGTH; i++) {
- if ((*so)->present_text_types[i]) {
- font = cho_font_copy(config->output->styles[i]->font);
- added = fonts_add_if_not_in(&fonts, font);
- if (!added) {
- cho_font_free(font);
- }
- }
- }
- for (m = (*so)->metadata; *m; m++) {
- font = cho_font_copy((*m)->style->font);
- added = fonts_add_if_not_in(&fonts, font);
- if (!added) {
- cho_font_free(font);
- }
- }
- for (se = (*so)->sections; *se; se++) {
- for (li = (*se)->lines; *li; li++) {
- for (above = (*li)->text_above; *above; above++) {
- if ((*above)->is_chord) {
- style = (*above)->u.chord->style;
- } else {
- style = (*above)->u.annot->style;
- }
- if (style->font->name) {
- font = cho_font_copy(style->font);
- added = fonts_add_if_not_in(&fonts, font);
- if (!added) {
- cho_font_free(font);
- }
- }
- }
- for (it = (*li)->items; *it; it++) {
- if ((*it)->is_text) {
- style = (*it)->u.text->style;
- if (style->font->name) {
- font = cho_font_copy(style->font);
- added = fonts_add_if_not_in(&fonts, font);
- if (!added) {
- cho_font_free(font);
- }
- }
- }
- }
- }
- }
- }
- return fonts;
-}
-
-static int
-fontpath_count_fonts(FcChar8 *path)
-{
- int count;
- FcFontSet *set;
- set = FcFontSetCreate();
- if (!FcFileScan(set, NULL, NULL, NULL, path, false)) {
- LOG_DEBUG("fontpath_count_fonts failed.");
- return -1;
- }
- count = set->nfont;
- FcFontSetDestroy(set);
- return count;
-}
-
-static char *
-fontpath_find(struct Font *font, enum FontType font_type)
-{
- FcObjectSet *obj;
- FcPattern *pattern;
- char *filepath = NULL;
- obj = FcObjectSetBuild(FC_FAMILY, FC_SLANT, FC_WIDTH, FC_WEIGHT, FC_FONTFORMAT, FC_FONT_WRAPPER, FC_FILE, NULL);
- pattern = FcPatternCreate();
- FcValue family = { .type = FcTypeString, .u.s = (FcChar8 *)font->name };
- FcPatternAdd(pattern, FC_FAMILY, family, FcFalse);
- FcValue font_wrapper = { .type = FcTypeString, .u.s = (FcChar8 *)"SFNT" };
- FcPatternAdd(pattern, FC_FONT_WRAPPER, font_wrapper, FcFalse);
- FcValue variable = { .type = FcTypeBool, .u.b = FcFalse };
- FcPatternAdd(pattern, FC_VARIABLE, variable, FcFalse);
- FcValue width = { .type = FcTypeInteger, .u.i = FC_WIDTH_NORMAL };
- FcPatternAdd(pattern, FC_WIDTH, width, FcFalse);
- /* TODO: Also handle FF_NORMAL, FF_SANS and FF_SERIF, but how? */
- if (font->family == FF_MONOSPACE) {
- FcValue spacing = { .type = FcTypeInteger, .u.i = FC_MONO };
- FcPatternAdd(pattern, FC_SPACING, spacing, FcFalse);
- }
- FcValue type;
- type.type = FcTypeString;
- if (font_type == FT_OTF)
- type.u.s = (FcChar8 *)"CFF";
- else
- type.u.s = (FcChar8 *)"TrueType";
- FcPatternAdd(pattern, FC_FONTFORMAT, type, FcFalse);
- FcValue style;
- style.type = FcTypeInteger;
- switch (font->style) {
- case FS_ROMAN:
- style.u.i = FC_SLANT_ROMAN;
- break;
- case FS_OBLIQUE:
- style.u.i = FC_SLANT_OBLIQUE;
- break;
- case FS_ITALIC:
- style.u.i = FC_SLANT_ITALIC;
- break;
- default:
- util_log(LOG_ERR, "Invalid font style value '%d'.", font->style);
- return NULL;
- }
- FcPatternAdd(pattern, FC_SLANT, style, FcFalse);
- FcValue weight;
- weight.type = FcTypeInteger;
- switch (font->weight) {
- case FW_REGULAR:
- weight.u.i = FC_WEIGHT_REGULAR;
- break;
- case FW_BOLD:
- weight.u.i = FC_WEIGHT_BOLD;
- break;
- default:
- util_log(LOG_ERR, "Invalid font weight value '%d'.", font->weight);
- return NULL;
- }
- FcPatternAdd(pattern, FC_WEIGHT, weight, FcFalse);
- FcFontSet *set = FcFontList(NULL, pattern, obj);
- FcChar8 *file;
- int i;
- for (i = 0; i<set->nfont; i++) {
- if (FcPatternGetString(set->fonts[i], FC_FILE, 0, &file) == FcResultMatch) {
- if (
- !file_extension_equals((const char *)file, "ttc") &&
- fontpath_count_fonts(file) == 1
- ) {
- filepath = strdup((const char *)file);
- break;
- }
- }
- }
- FcObjectSetDestroy(obj);
- FcPatternDestroy(pattern);
- FcFontSetDestroy(set);
- return filepath;
-}
-
-static bool
-pdf_load_chord_diagram_fonts(void)
-{
- struct Obj *fnt;
- fnt = obj_new();
- fnt->name = strdup("chord-diagram-regular-font");
- fnt->value = pdfioFileCreateFontObjFromBase(g_pdf_file, "Helvetica");
- objs_add_obj(&g_fonts, fnt);
- fnt = obj_new();
- fnt->name = strdup("chord-diagram-symbols");
- fnt->value = pdfioFileCreateFontObjFromFile(g_pdf_file, SYMBOLS_FILEPATH, true);
- objs_add_obj(&g_fonts, fnt);
- return true;
-}
-
-static const char *
-is_base_font(struct Font *font)
-{
- int i;
- for (i = 0; i<14; i++) {
- if (!strcmp(font->name, g_base_fonts[i])) {
- return g_base_fonts[i];
- }
- }
- return NULL;
-}
-
-static bool
-font_name_is_path(const char *name)
-{
- if (strchr(name, '/')) {
- return true;
- }
- if (file_extension_equals(name, "ttf") || file_extension_equals(name, "otf")) {
- return true;
- }
- return false;
-}
-
-static bool
-pdf_load_fonts(struct Font **needed_fonts, struct Config *config)
-{
- char *fontpath;
- const char *name;
- struct Font **f;
- struct Obj *fnt;
- for (f = needed_fonts; *f; f++) {
- if (font_name_is_path((*f)->name)) {
- fontpath = filepath_resolve_tilde((*f)->name);
- fnt = obj_new();
- fnt->name = fnt_name_create(*f);
- fnt->value = pdfioFileCreateFontObjFromFile(g_pdf_file, fontpath, true);
- if (!fnt->value) {
- LOG_DEBUG("pdfioFileCreateFontObjFromFile failed.");
- return false;
- }
- free(fontpath);
- util_log(LOG_INFO, "Loaded font from '%s'.", (*f)->name);
- // cho_font_print(*f);
- objs_add_obj(&g_fonts, fnt);
- } else
- if ((name = is_base_font(*f))) {
- fnt = obj_new();
- fnt->name = fnt_name_create(*f);
- fnt->value = pdfioFileCreateFontObjFromBase(g_pdf_file, name);
- if (!fnt->value) {
- LOG_DEBUG("pdfioFileCreateFontObjFromBase failed.");
- return false;
- }
- objs_add_obj(&g_fonts, fnt);
- } else {
- fontpath = fontpath_find(*f, FT_TTF);
- if (fontpath) {
- fnt = obj_new();
- fnt->name = fnt_name_create(*f);
- fnt->value = pdfioFileCreateFontObjFromFile(g_pdf_file, fontpath, true);
- if (!fnt->value) {
- LOG_DEBUG("pdfioFileCreateFontObjFromFile failed.");
- return false;
- }
- util_log(LOG_INFO, "Loaded font from '%s'.", fontpath);
- // cho_font_print(*f);
- objs_add_obj(&g_fonts, fnt);
- free(fontpath);
- } else {
- fontpath = fontpath_find(*f, FT_OTF);
- if (fontpath) {
- fnt = obj_new();
- fnt->name = fnt_name_create(*f);
- fnt->value = pdfioFileCreateFontObjFromFile(g_pdf_file, fontpath, true);
- if (!fnt->value) {
- LOG_DEBUG("pdfioFileCreateFontObjFromFile failed.");
- return false;
- }
- util_log(LOG_INFO, "Loaded font from '%s'.", fontpath);
- // cho_font_print(*f);
- objs_add_obj(&g_fonts, fnt);
- free(fontpath);
- } else {
- util_log(LOG_ERR, "Didn't find font file for following font:");
- cho_font_print(*f);
- return false;
- }
- }
- }
- }
- if (config->output->diagram->show) {
- if (!pdf_load_chord_diagram_fonts()) {
- LOG_DEBUG("pdf_load_chord_diagram_fonts failed.");
- return false;
- }
- }
- return true;
-}
-
-static char *
-pdf_filename_generate_from_songs(struct ChoSong **songs)
-{
- char *filename;
- char *normalized_title;
- const char *title;
- int len = cho_song_count(songs);
- if (len == 0)
- return NULL;
- if (len == 1) {
- title = cho_metadata_get(songs[0]->metadata, "title");
- if (!title) {
- /* INFO: unreachable because the parser already checks the presence of the 'title' directive */
- util_log(LOG_ERR, "Song has no title.");
- return NULL;
- }
- normalized_title = str_normalize(title);
- filename = file_extension_replace_or_add(normalized_title, "pdf");
- free(normalized_title);
- return filename;
- }
- return strdup("collection-of-songs.pdf");
-}
-
-static char *
-pdf_filepath_create(struct ChoSong **songs, const char *cho_filepath, const char *out)
-{
- char *pdf_filepath = NULL;
- char *pdf_filename;
- char *tmp;
- enum FileType type;
- if (cho_filepath) {
- pdf_filepath = file_extension_replace_or_add(cho_filepath, "pdf");
- pdf_filename = filepath_basename(pdf_filepath);
- } else {
- pdf_filename = pdf_filename_generate_from_songs(songs);
- if (!pdf_filename) {
- LOG_DEBUG("pdf_filename_generate_from_songs failed.");
- return NULL;
- }
- }
- if (out) {
- type = file_type(out);
- switch (type) {
- case F_ERROR:
- tmp = filepath_dirname(out);
- if (file_type(tmp) == F_FOLDER) {
- free(pdf_filepath);
- free(pdf_filename);
- free(tmp);
- return strdup(out);
- } else {
- free(tmp);
- util_log(LOG_ERR, "Invalid argument --output/-o value.");
- return NULL;
- }
- break;
- case F_REG_FILE:
- free(pdf_filepath);
- free(pdf_filename);
- return strdup(out);
- case F_FOLDER:
- tmp = filepath_add_ending_slash_if_missing(out);
- tmp = erealloc(tmp, (strlen(tmp)+strlen(pdf_filename)+1) * sizeof(char));
- strcat(tmp, pdf_filename);
- free(pdf_filename);
- free(pdf_filepath);
- return tmp;
- case F_OTHER:
- util_log(LOG_ERR, "Invalid argument --output/-o value. It doesn't refer to a folder or regular file.");
- return NULL;
- default:
- util_log(LOG_ERR, "Invalid enum FileType value '%d'.", type);
- return NULL;
- }
- } else {
- if (pdf_filepath) {
- free(pdf_filename);
- return pdf_filepath;
- }
- return pdf_filename;
- }
-}
-
-static bool
-pdf_font_set(pdfio_stream_t *stream, struct Font *font)
-{
- static int page_index = 0;
- char *name = fnt_name_create(font);
- if (
- !strcmp(name, g_current_font_name) &&
- font->size == g_current_font_size &&
- g_current_page_index == page_index
- ) {
- free(name);
- return true;
- }
- if (!pdfioContentSetTextFont(stream, name, font->size)) {
- LOG_DEBUG("pdfioContentSetTextFont failed.");
- return false;
- }
- strcpy(g_current_font_name, name);
- g_current_font_size = font->size;
- page_index = g_current_page_index;
- free(name);
- return true;
-}
-
-static double
-text_width(const char *text, struct ChoStyle *style)
-{
- char *name = fnt_name_create(style->font);
- pdfio_obj_t *font_obj = out_pdf_fnt_obj_get_by_name(name);
- if (!font_obj) {
- LOG_DEBUG("out_pdf_fnt_obj_get_by_name failed.");
- return -1.0;
- }
- free(name);
- return pdfioContentTextMeasure(font_obj, text, style->font->size);
-}
-
-static double
-text_above_width(struct ChoLineItemAbove *above)
-{
- double width;
- if (above->is_chord) {
- char *name;
- name = cho_chord_name_generate(above->u.chord);
- width = text_width(name, above->u.chord->style);
- if (width == ERROR) {
- LOG_DEBUG("text_width failed.");
- return ERROR;
- }
- free(name);
- } else {
- width = text_width(above->u.annot->text, above->u.annot->style);
- if (width == ERROR) {
- LOG_DEBUG("text_width failed.");
- return ERROR;
- }
- }
- return width;
-}
-
-static int
-find_whitespace(const char *str, size_t start)
-{
- int i;
- for (i = start; i>=0; i--) {
- if (str[i] == ' ' || str[i] == '\t') {
- return i;
- }
- }
- return -1;
-}
-
-static int
-text_find_fitting(
- const char *str,
- struct ChoStyle *style,
- double x,
- double max_width
-)
-{
- size_t len = strlen(str);
- size_t start = len - 1;
- char tmp[len+1];
- strcpy((char *)&tmp, str);
- double width;
- int i;
- do {
- i = find_whitespace((const char *)&tmp, start);
- if (i == -1) {
- util_log(LOG_ERR, "Can't split text because no whitespace was found.");
- return -1;
- }
- tmp[i] = 0;
- width = text_width((const char *)&tmp, style);
- if (width == ERROR) {
- LOG_DEBUG("text_width failed.");
- return -1;
- }
- start = i - 1;
- } while (x + width > max_width);
- return i;
-}
-
-static bool
-pdf_draw_line(
- pdfio_stream_t *stream,
- struct PDFText *text,
- double y,
- double width,
- enum LineLocation line_location
-)
-{
- double red, green, blue;
- switch (line_location) {
- case LL_UNDER:
- red = text->style->underline_color->red / 255.0;
- green = text->style->underline_color->green / 255.0;
- blue = text->style->underline_color->blue / 255.0;
- y -= 2.0;
- break;
- case LL_STRIKETHROUGH:
- red = text->style->strikethrough_color->red / 255.0;
- green = text->style->strikethrough_color->green / 255.0;
- blue = text->style->strikethrough_color->blue / 255.0;
- y += text->style->font->size * 0.3;
- break;
- case LL_OVER:
- red = text->style->overline_color->red / 255.0;
- green = text->style->overline_color->green / 255.0;
- blue = text->style->overline_color->blue / 255.0;
- y += text->style->font->size * 0.8;
- break;
- }
- if (!pdfioContentPathMoveTo(stream, text->x, y)) {
- LOG_DEBUG("pdfioContentPathMoveTo failed.");
- return false;
- }
- if (!pdfioContentPathLineTo(stream, text->x + width, y)) {
- LOG_DEBUG("pdfioContentPathLineTo failed.");
- return false;
- }
- if (!pdfioContentSetStrokeColorRGB(stream, red, green, blue)) {
- LOG_DEBUG("pdfioContentSetStrokeColorRGB failed.");
- return false;
- }
- if (!pdfioContentStroke(stream)) {
- LOG_DEBUG("pdfioContentStroke failed.");
- return false;
- }
- return true;
-}
-
-static bool
-pdf_draw_rectangle(
- pdfio_stream_t *stream,
- struct PDFText *text
-)
-{
- double height;
- double red, green, blue;
- red = text->style->background_color->red / 255.0;
- green = text->style->background_color->green / 255.0;
- blue = text->style->background_color->blue / 255.0;
- if (!pdfioContentSetFillColorRGB(stream, red, green, blue)) {
- fprintf(stderr, "pdfioContentSetFillColorRGB failed.\n");
- return false;
- }
- height = (8.0 + text->style->font->size) - text->style->font->size * 0.8;
- if (!pdfioContentPathRect(stream, text->x, text->y, text->width, height)) {
- fprintf(stderr, "pdfioContentPathRect failed.\n");
- return false;
- }
- if (!pdfioContentFill(stream, true)) {
- fprintf(stderr, "pdfioContentFill failed.\n");
- return false;
- }
- return true;
-}
-
-static bool
-is_purest_white(struct RGBColor *color)
-{
- if (color->red == 255 && color->green == 255 && color->blue == 255) {
- return true;
- }
- return false;
-}
-
-static bool
-pdf_text_show(pdfio_stream_t *stream, struct PDFText *text)
-{
- double red, green, blue;
- bool unicode;
- if (!pdf_font_set(stream, text->style->font)) {
- LOG_DEBUG("pdf_font_set failed.");
- return false;
- }
- unicode = !is_base_font(text->style->font);
- if (!is_purest_white(text->style->background_color)) {
- if (!pdf_draw_rectangle(stream, text)) {
- LOG_DEBUG("draw_rectangle failed.");
- return false;
- }
- }
- red = text->style->foreground_color->red / 255.0;
- green = text->style->foreground_color->green / 255.0;
- blue = text->style->foreground_color->blue / 255.0;
- if (!pdfioContentSetFillColorRGB(stream, red, green, blue)) {
- LOG_DEBUG("pdfioContentSetFillColorRGB failed.");
- return false;
- }
- if (!pdfioContentTextBegin(stream)) {
- LOG_DEBUG("pdfioContentTextBegin failed.");
- return false;
- }
- if (!pdfioContentTextMoveTo(stream, text->x, text->y)) {
- LOG_DEBUG("pdfioContentTextMoveTo failed.");
- return false;
- }
- if (!pdfioContentSetTextRise(stream, text->style->rise)) {
- LOG_DEBUG("pdfioContentSetTextRise failed.");
- return false;
- }
- if (!pdfioContentTextShow(stream, unicode, text->text)) {
- LOG_DEBUG("pdfioContentTextShow failed.");
- return false;
- }
- if (!pdfioContentTextEnd(stream)) {
- LOG_DEBUG("pdfioContentTextEnd failed.");
- return false;
- }
- if (text->style->underline_style == LS_SINGLE) {
- pdf_draw_line(stream, text, text->y, text->width, LL_UNDER);
- } else if (text->style->underline_style == LS_DOUBLE) {
- pdf_draw_line(stream, text, text->y, text->width, LL_UNDER);
- pdf_draw_line(stream, text, text->y-1.5, text->width, LL_UNDER);
- }
- if (text->style->strikethrough) {
- pdf_draw_line(stream, text, text->y, text->width, LL_STRIKETHROUGH);
- }
- if (text->style->overline_style == LS_SINGLE) {
- pdf_draw_line(stream, text, text->y, text->width, LL_OVER);
- } else if (text->style->overline_style == LS_DOUBLE) {
- pdf_draw_line(stream, text, text->y, text->width, LL_OVER);
- pdf_draw_line(stream, text, text->y+1.5, text->width, LL_OVER);
- }
- if (text->style->boxed) {
- red = text->style->boxed_color->red / 255.0;
- green = text->style->boxed_color->green / 255.0;
- blue = text->style->boxed_color->blue / 255.0;
- if (!pdfioContentSetStrokeColorRGB(stream, red, green, blue)) {
- LOG_DEBUG("pdfioContentSetFillColorRGB failed.");
- return false;
- }
- if (!pdfioContentPathRect(stream, text->x - 2.0, text->y - 2.0, text->width + 4.0, text->style->font->size * 0.8 + 4.0)) {
- LOG_DEBUG("pdfioContentPathRect failed.");
- return false;
- }
- if (!pdfioContentStroke(stream)) {
- LOG_DEBUG("pdfioContentStroke failed.");
- return false;
- }
- }
- return true;
-}
-
-static bool
-annot_page_link_add(
- struct PDFContext *ctx,
- struct TocEntry *entry,
- int toc_page_count,
- int line_count,
- double font_size
-)
-{
- int page_index;
- pdfio_rect_t rect;
- pdfio_dict_t *annot;
- pdfio_array_t *destination;
- rect.x1 = MARGIN_HORIZONTAL;
- rect.x2 = MARGIN_HORIZONTAL + LINE_WIDTH;
- rect.y1 = ctx->y - 2.0;
- rect.y2 = ctx->y + (8.0 + font_size) * line_count - font_size * 0.8;
- page_index = entry->page_index + toc_page_count;
- annot = pdfioDictCreate(g_pdf_file);
- if (!pdfioDictSetName(annot, "Subtype", "Link")) {
- LOG_DEBUG("pdfioDictSetName failed.");
- return false;
- }
- if (!pdfioDictSetRect(annot, "Rect", &rect)) {
- LOG_DEBUG("pdfioDictSetRect failed.");
- return false;
- }
- destination = pdfioArrayCreate(g_pdf_file);
- if (!pdfioArrayAppendNumber(destination, page_index)) {
- LOG_DEBUG("pdfioArrayAppendNumber failed.");
- return false;
- }
- if (!pdfioArrayAppendName(destination, "FitH")) {
- LOG_DEBUG("pdfioArrayAppendName failed.");
- return false;
- }
- // TODO: Is this constant '30.0' correct with different font sizes, etc. ?
- // clicking the annotation should show the song including the song title at the top
- if (!pdfioArrayAppendNumber(destination, entry->page_y + 30.0)) {
- LOG_DEBUG("pdfioArrayAppendNumber failed.");
- return false;
- }
- if (!pdfioDictSetArray(annot, "Dest", destination)) {
- LOG_DEBUG("pdfioDictSetArray failed.");
- return false;
- }
- if (!pdfioArrayAppendDict(ctx->content->pages[ctx->page]->annots, annot)) {
- LOG_DEBUG("pdfioArrayAppendDict failed.");
- return false;
- }
- return true;
-}
-
-static bool
-annot_url_link_add(struct PDFContext *ctx, struct ChoStyle *style, double width)
-{
- pdfio_rect_t rect;
- pdfio_dict_t *annot, *action;
- rect.x1 = ctx->x;
- rect.x2 = ctx->x + width;
- rect.y1 = ctx->y - 2.0;
- rect.y2 = ctx->y + style->font->size * 0.8;
- annot = pdfioDictCreate(g_pdf_file);
- if (!pdfioDictSetName(annot, "Subtype", "Link")) {
- LOG_DEBUG("pdfioDictSetName failed.");
- return false;
- }
- if (!pdfioDictSetRect(annot, "Rect", &rect)) {
- LOG_DEBUG("pdfioDictSetRect failed.");
- return false;
- }
- action = pdfioDictCreate(g_pdf_file);
- if (!pdfioDictSetName(action, "S", "URI")) {
- LOG_DEBUG("pdfioDictSetName failed.");
- return false;
- }
- if (!pdfioDictSetString(action, "URI", style->href)) {
- LOG_DEBUG("pdfioDictSetString failed.");
- return false;
- }
- if (!pdfioDictSetDict(annot, "A", action)) {
- LOG_DEBUG("pdfioDictSetDict failed.");
- return false;
- }
- if (!pdfioArrayAppendDict(ctx->content->pages[ctx->page]->annots, annot)) {
- LOG_DEBUG("pdfioArrayAppendDict failed.");
- return false;
- }
- return true;
-}
-
-static bool
-pdf_set_title(pdfio_file_t *pdf, struct ChoSong **songs)
-{
- // INFO: Set pdf title only if a single song exist
- if (songs[0] && !songs[1]) {
- const char *title;
- title = cho_metadata_get(songs[0]->metadata, "title");
- if (title) {
- pdfioFileSetTitle(pdf, title);
- return true;
- }
- return false;
- }
- return true;
-}
-
-static pdfio_stream_t *
-pdf_page_create(
- pdfio_file_t *pdf,
- struct PDFImage **imgs,
- pdfio_array_t *annots
-)
-{
- pdfio_dict_t *page_dict;
- pdfio_stream_t *page_stream;
- pdfio_array_t *color_array = pdfioArrayCreateColorFromStandard(pdf, 3, PDFIO_CS_ADOBE);
- struct Obj **f;
- struct PDFImage **i;
- page_dict = pdfioDictCreate(pdf);
- if (!pdfioPageDictAddColorSpace(page_dict, "rgbcolorspace", color_array)) {
- LOG_DEBUG("pdfioPageDictAddColorSpace failed.");
- return NULL;
- }
- if (!pdfioDictSetArray(page_dict, "Annots", annots)) {
- LOG_DEBUG("pdfioDictSetArray failed.");
- return NULL;
- }
- if (imgs) {
- for (i = imgs; *i; i++) {
- if (!pdfioPageDictAddImage(page_dict, (*i)->name, (*i)->obj)) {
- LOG_DEBUG("pdfioPageDictAddImage failed.");
- return NULL;
- }
- }
- }
- for (f = g_fonts; *f; f++) {
- if (!pdfioPageDictAddFont(page_dict, (*f)->name, (*f)->value)) {
- LOG_DEBUG("pdfioPageDictAddFont failed.");
- return NULL;
- }
- }
- page_stream = pdfioFileCreatePage(pdf, page_dict);
- if (!pdfioContentSetFillColorSpace(page_stream, "rgbcolorspace")) {
- LOG_DEBUG("pdfioContentSetFillColorSpace failed.");
- return NULL;
- }
- if (!pdfioContentSetStrokeColorSpace(page_stream, "rgbcolorspace")) {
- LOG_DEBUG("pdfioContentSetStrokeColorSpace failed.");
- return NULL;
- }
- return page_stream;
-}
-
-static double
-image_width(struct ChoImage *image, pdfio_obj_t *obj)
-{
- double width;
- width = pdfioImageGetWidth(obj);
- if (image->width) {
- if (image->width->type == ST_POINT) {
- width = image->width->d;
- } else
- if (image->width->type == ST_PERCENT) {
- width = LINE_WIDTH * image->width->d;
- }
- }
- if (image->width_scale) {
- width *= image->width_scale->d;
- }
- width += image->border;
- return width;
-}
-
-static double
-image_height(struct ChoImage *image, pdfio_obj_t *obj)
-{
- double height;
- height = pdfioImageGetHeight(obj);
- if (image->height) {
- if (image->height->type == ST_POINT) {
- height = image->height->d;
- } else
- if (image->height->type == ST_PERCENT) {
- height = LINE_WIDTH * image->height->d;
- }
- }
- if (image->height_scale) {
- height *= image->height_scale->d;
- }
- height += image->border;
- return height;
-}
-
-static char *
-image_name(struct ChoImage *image)
-{
- char tmp[PATH_MAX];
- char *image_path;
- struct stat s;
- if (strchr(image->src, '/')) {
- image_path = image->src;
- } else {
- strcpy((char *)&tmp, g_cho_dirpath);
- strcat((char *)&tmp, "/");
- strcat((char *)&tmp, image->src);
- image_path = (char *)&tmp;
- }
- if (stat(image_path, &s)) {
- LOG_DEBUG("stat failed.");
- util_log(LOG_ERR, "%s: %s", image_path, strerror(errno));
- return NULL;
- }
- memset(tmp, 0, PATH_MAX);
- sprintf((char *)&tmp, "%ld", s.st_ino);
- return strdup(tmp);
-}
-
-static bool
-pdf_load_images(struct Obj ***images, pdfio_file_t *file, struct ChoSong **songs)
-{
- struct ChoSong **s;
- struct ChoSection **se;
- struct ChoLine **li;
- struct ChoLineItem **it;
- int i = 0;
- char filepath[PATH_MAX];
- char *name;
- char *image_filepath;
- for (s = songs; *s; s++) {
- for (se = (*s)->sections; *se; se++) {
- for (li = (*se)->lines; *li; li++) {
- for (it = (*li)->items; *it; it++) {
- if (!(*it)->is_text) {
- memset(filepath, 0, PATH_MAX);
- strcpy((char *)&filepath, g_cho_dirpath);
- strcat((char *)&filepath, "/");
- strcat((char *)&filepath, (*it)->u.image->src);
- name = image_name((*it)->u.image);
- if (!name) {
- LOG_DEBUG("image_name failed.");
- return false;
- }
- if (!objs_get_obj(*images, name)) {
- *images = erealloc(*images, (i+2) * sizeof(struct Obj *));
- (*images)[i] = obj_new();
- (*images)[i]->name = strdup(name);
- if (strchr((*it)->u.image->src, '/')) {
- image_filepath = (*it)->u.image->src;
- } else {
- image_filepath = (char *)&filepath;
- }
- (*images)[i]->value = pdfioFileCreateImageObjFromFile(file, image_filepath, true);
- if (!(*images)[i]->value) {
- LOG_DEBUG("pdfioFileCreateImageObjFromFile failed.");
- return false;
- }
- util_log(LOG_INFO, "Loaded image from '%s'.", image_filepath);
- (*images)[i+1] = NULL;
- }
- free(name);
- i++;
- }
- }
- }
- }
- }
- return true;
-}
-
-static bool
-pdf_get_chords(struct ChoSong *song, struct ChoChord ***chords)
-{
- struct ChoSection **se;
- struct ChoLine **li;
- struct ChoLineItemAbove **above;
- for (se = song->sections; *se; se++) {
- for (li = (*se)->lines; *li; li++) {
- for (above = (*li)->text_above; *above; above++) {
- if ((*above)->is_chord) {
- if (!cho_chords_has(*chords, (*above)->u.chord)) {
- cho_chords_add(chords, (*above)->u.chord);
- }
- }
- }
- }
- }
- return true;
-}
-
-static double
-line_width_until_text_above(
- struct ChoLineItem **items,
- struct ChoLineItemAbove *above,
- struct Obj **img_objs,
- struct SpaceNeeded *space
-)
-{
- int i, save_i, save_k;
- int k = EMPTY_INT;
- int pos = 0;
- double width = 0.0;
- char *name;
- pdfio_obj_t *font_obj;
- pdfio_obj_t *obj;
- struct ChoText *text;
- for (i = 0; items[i]; i++) {
- if (items[i]->is_text) {
- for (k = 0; items[i]->u.text->text[k]; k++) {
- if (above->position == pos) {
- save_i = i;
- save_k = k;
- goto FOUND;
- }
- pos++;
- }
- }
- }
- /* INFO: If the chord/annotation is the last thing in the line */
- save_i = i;
- save_k = k;
- FOUND:
- if (space) {
- space->line_item_index = save_i;
- space->text_index = save_k;
- }
- for (i = 0; items[i] && i <= save_i; i++) {
- if (items[i]->is_text) {
- text = items[i]->u.text;
- name = fnt_name_create(text->style->font);
- font_obj = out_pdf_fnt_obj_get_by_name(name);
- if (!font_obj) {
- LOG_DEBUG("out_pdf_fnt_obj_get_by_name failed.");
- return ERROR;
- }
- if (save_i == i) {
- char tmp[strlen(text->text)+1];
- strcpy((char *)&tmp, text->text);
- tmp[save_k] = 0;
- width += pdfioContentTextMeasure(font_obj, (const char *)&tmp, text->style->font->size);
- } else {
- width += pdfioContentTextMeasure(font_obj, text->text, text->style->font->size);
- }
- free(name);
- } else {
- name = image_name(items[i]->u.image);
- if (!name) {
- LOG_DEBUG("image_name failed.");
- return ERROR;
- }
- obj = objs_get_obj(img_objs, name);
- if (!obj) {
- LOG_DEBUG("objs_get_obj failed.");
- return ERROR;
- }
- width += image_width(items[i]->u.image, obj);
- free(name);
- }
- }
- return width;
-}
-
-static struct PDFImage *
-pdf_image_new(void)
-{
- struct PDFImage *image = emalloc(sizeof(struct PDFImage));
- image->x = 0.0;
- image->y = 0.0;
- image->width = 0.0;
- image->height = 0.0;
- image->name = NULL;
- image->obj = NULL;
- return image;
-}
-
-static void
-pdf_image_free(struct PDFImage *image)
-{
- if (!image) {
- return;
- }
- free(image->name);
- free(image);
-}
-
-static struct PDFText *
-pdf_text_new(void)
-{
- struct PDFText *t = emalloc(sizeof(struct PDFText));
- t->text = NULL;
- t->style = NULL;
- t->x = 0.0;
- t->y = 0.0;
- t->width = 0.0;
- return t;
-}
-
-static void
-pdf_text_free(struct PDFText *text)
-{
- if (!text) {
- return;
- }
- free(text->text);
- cho_style_free(text->style);
- free(text);
-}
-
-static void
-toc_entry_free(struct TocEntry *entry)
-{
- free(entry->title);
- free(entry);
-}
-
-static struct PDFPage *
-pdf_page_new(void)
-{
- struct PDFPage *page = emalloc(sizeof(struct PDFPage));
- page->texts = NULL;
- page->images = NULL;
- page->diagrams = NULL;
- page->annots = pdfioArrayCreate(g_pdf_file);
- return page;
-}
-
-static void
-pdf_page_free(struct PDFPage *page)
-{
- if (!page) {
- return;
- }
- struct PDFText **t;
- struct PDFImage **i;
- struct ChordDiagram **d;
- if ((t = page->texts)) {
- for (; *t; t++) {
- pdf_text_free(*t);
- }
- free(page->texts);
- }
- if ((i = page->images)) {
- for (; *i; i++) {
- pdf_image_free(*i);
- }
- free(page->images);
- }
- if ((d = page->diagrams)) {
- for (; *d; d++) {
- chord_diagram_free(*d);
- }
- free(page->diagrams);
- }
- free(page);
-}
-
-static void
-pdf_context_init(struct PDFContext *ctx)
-{
- ctx->content = NULL;
- ctx->x = MARGIN_HORIZONTAL;
- ctx->y = MEDIABOX_HEIGHT - MARGIN_TOP;
- ctx->text = 0;
- ctx->image = 0;
- ctx->diagram = 0;
- ctx->page = 0;
- ctx->toc_entry = 0;
- ctx->spaces = NULL;
- ctx->biggest_font_size = 0.0;
- ctx->consumed_lyrics = 0;
- ctx->prev_added_space = 0.0;
- ctx->margin_bottom = MARGIN_BOTTOM;
-}
-
-static struct PDFContent *
-pdf_content_new(void)
-{
- struct PDFContent *content = emalloc(sizeof(struct PDFContent));
- content->pages = NULL;
- content->toc = NULL;
- return content;
-}
-
-static void
-pdf_content_free(struct PDFContent *content)
-{
- if (!content) {
- return;
- }
- struct PDFPage **p;
- struct TocEntry **toc;
- for (p = content->pages; *p; p++) {
- pdf_page_free(*p);
- }
- free(content->pages);
- if ((toc = content->toc)) {
- for (; *toc; toc++) {
- toc_entry_free(*toc);
- }
- free(content->toc);
- }
- free(content);
-}
-
-static void
-spaces_free(struct SpaceNeeded **spaces)
-{
- if (!spaces) {
- return;
- }
- struct SpaceNeeded **s;
- for (s = spaces; *s; s++) {
- free(*s);
- }
- free(spaces);
-}
-
-static bool
-calc_space_between_text_above(
- struct ChoLineItem **items,
- struct ChoLineItemAbove **text_above,
- struct Obj **img_objs,
- struct SpaceNeeded ***spaces
-)
-{
- if (!*text_above) {
- return true;
- }
- int sp = 0;
- int i;
- for (i = 1; text_above[i]; i++) {
- struct SpaceNeeded space = {
- .line_item_index = 0,
- .text_index = 0,
- .text_above_index = 0,
- .amount = 0.0
- };
- double width_between;
- double width_until_cur;
- double width_until_prev;
- double prev_width;
- width_until_cur = line_width_until_text_above(items, text_above[i], img_objs, NULL);
- if (width_until_cur == ERROR) {
- LOG_DEBUG("line_width_until_text_above failed.");
- return false;
- }
- i--;
- width_until_prev = line_width_until_text_above(items, text_above[i], img_objs, &space);
- if (width_until_prev == ERROR) {
- LOG_DEBUG("line_width_until_text_above failed.");
- return false;
- }
- prev_width = text_above_width(text_above[i]);
- if (prev_width == ERROR) {
- LOG_DEBUG("text_above_width failed.");
- return false;
- }
- i++;
- width_between = width_until_cur - width_until_prev;
- if (prev_width + MIN_CHORD_GAP_WIDTH >= width_between) {
- space.text_above_index = i;
- space.amount = prev_width - width_between + MIN_CHORD_GAP_WIDTH;
- *spaces = erealloc(*spaces, (sp+1) * sizeof(struct SpaceNeeded *));
- (*spaces)[sp] = emalloc(sizeof(struct SpaceNeeded));
- *((*spaces)[sp]) = space;
- sp++;
- } else {
- }
- }
- *spaces = erealloc(*spaces, (sp+1) * sizeof(struct SpaceNeeded *));
- (*spaces)[sp] = NULL;
- return true;
-}
-
-static double
-item_width(struct ChoLineItem *item, int i, struct SpaceNeeded **spaces, struct Obj **img_objs)
-{
- double width;
- if (item->is_text) {
- width = text_width(item->u.text->text, item->u.text->style);
- if (width == ERROR) {
- LOG_DEBUG("text_width failed.");
- return ERROR;
- }
- struct SpaceNeeded **s;
- if ((s = spaces)) {
- for (; *s; s++) {
- if ((*s)->line_item_index == i) {
- width += (*s)->amount;
- }
- }
- }
- } else {
- char *name;
- pdfio_obj_t *obj;
- name = image_name(item->u.image);
- if (!name) {
- LOG_DEBUG("image_name failed.");
- return ERROR;
- }
- obj = objs_get_obj(img_objs, name);
- if (!obj) {
- LOG_DEBUG("objs_get_obj failed.");
- return ERROR;
- }
- free(name);
- width = image_width(item->u.image, obj);
- }
- return width;
-}
-
-static struct CharPosition *
-items_find_position_to_break_line(
- struct ChoLineItem **items,
- struct SpaceNeeded **spaces,
- struct Obj **img_objs
-)
-{
- struct CharPosition *pos = emalloc(sizeof(struct CharPosition));
- pos->line_item_index = EMPTY_INT;
- pos->text_index = EMPTY_INT;
- double width = 0.0;
- double d;
- struct ChoLineItem **it = items;
- int i;
- for (i = 0; it[i]; i++) {
- d = item_width(it[i], i, spaces, img_objs);
- if (d == ERROR) {
- LOG_DEBUG("item_width failed.");
- return NULL;
- }
- if (width + d > LINE_WIDTH) {
- if (it[i]->is_text) {
- pos->line_item_index = i;
- pos->text_index = text_find_fitting(
- it[i]->u.text->text,
- it[i]->u.text->style,
- width,
- LINE_WIDTH
- );
- if (pos->text_index == EMPTY_INT) {
- LOG_DEBUG("text_find_fitting failed.");
- return NULL;
- }
- } else {
- pos->line_item_index = i;
- pos->text_index = -1;
- }
- return pos;
- } else {
- width += d;
- }
- }
- return pos;
-}
-
-static double
-images_find_biggest_height(struct ChoLineItem **left_items, int line_item_index, struct Obj **img_objs)
-{
- struct ChoLineItem **it;
- char *name;
- pdfio_obj_t *obj;
- int i = 0;
- double end = line_item_index;
- double biggest = 0.0;
- double height;
- if (end == -1) {
- end = 10000;
- }
- for (it = left_items; *it && i <= end; it++, i++) {
- if (!(*it)->is_text) {
- name = image_name((*it)->u.image);
- if (!name) {
- LOG_DEBUG("image_name failed.");
- return ERROR;
- }
- obj = objs_get_obj(img_objs, name);
- if (!obj) {
- LOG_DEBUG("objs_get_obj failed.");
- return ERROR;
- }
- height = image_height((*it)->u.image, obj);
- if (height > biggest) {
- biggest = height;
- }
- free(name);
- }
- }
- return biggest;
-}
-
-static int
-text_above_find_index_to_break_line(struct ChoLineItem **items, struct ChoLineItemAbove **text_above, struct CharPosition *pos)
-{
- int position = 0;
- int i, k;
- if (pos->text_index == -1) {
- for (i = 0; items[i]; i++) {
- if (pos->line_item_index == i) {
- goto FOUND;
- }
- if (items[i]->is_text) {
- for (k = 0; items[i]->u.text->text[k]; k++) {
- position++;
- }
- }
- }
- } else {
- for (i = 0; items[i]; i++) {
- if (items[i]->is_text) {
- for (k = 0; items[i]->u.text->text[k]; k++) {
- if (pos->line_item_index == i && pos->text_index == k) {
- goto FOUND;
- }
- position++;
- }
- }
- }
- }
- return -2;
- FOUND:
- for (i = 0; text_above[i]; i++) {
- if (text_above[i]->position >= position) {
- return i;
- }
- }
- return -1;
-}
-
-static void
-text_above_update_positions(struct ChoLineItemAbove **aboves, size_t consumed_lyrics)
-{
- struct ChoLineItemAbove **a = aboves;
- for (a = aboves; *a; a++) {
- (*a)->position -= consumed_lyrics + 1; // why plus one?
- }
-}
-
-static bool
-pdf_texts_add_lyrics(
- struct ChoLineItem *item,
- struct PDFContext *ctx,
- int i
-)
-{
- struct PDFText ***texts;
- struct SpaceNeeded **sp;
- double width;
- int t = 0;
- int c;
- texts = &ctx->content->pages[ctx->page]->texts;
- *texts = erealloc(*texts, (ctx->text+1) * sizeof(struct PDFText *));
- (*texts)[ctx->text] = pdf_text_new();
- if (!ctx->spaces) {
- (*texts)[ctx->text]->text = strdup(item->u.text->text);
- (*texts)[ctx->text]->style = cho_style_copy(item->u.text->style);
- (*texts)[ctx->text]->x = ctx->x;
- (*texts)[ctx->text]->y = ctx->y;
- width = text_width(item->u.text->text, item->u.text->style);
- if (width == ERROR) {
- LOG_DEBUG("text_width failed.");
- return false;
- }
- (*texts)[ctx->text]->width = width;
- if (item->u.text->style->href) {
- if (!annot_url_link_add(ctx, item->u.text->style, width)) {
- LOG_DEBUG("annot_url_link_add failed.");
- return false;
- }
- }
- ctx->x += width;
- if ((*texts)[ctx->text]->style->font->size > ctx->biggest_font_size) {
- ctx->biggest_font_size = (*texts)[ctx->text]->style->font->size;
- }
- ctx->consumed_lyrics += strlen((*texts)[ctx->text]->text);
- ctx->text++;
- return true;
- }
- for (c = 0; item->u.text->text[c]; c++) {
- (*texts)[ctx->text]->text = erealloc((*texts)[ctx->text]->text, (t+1) * sizeof(char));
- (*texts)[ctx->text]->text[t] = item->u.text->text[c];
- t++;
- for (sp = ctx->spaces; *sp; sp++) {
- if ((*sp)->line_item_index == i && (*sp)->text_index == c) {
- size_t len = grapheme_next_character_break_utf8(&item->u.text->text[c], 10);
- size_t i;
- for (i = 0; i<len-1; i++, t++) {
- c++;
- (*texts)[ctx->text]->text = erealloc((*texts)[ctx->text]->text, (t+1) * sizeof(char));
- (*texts)[ctx->text]->text[t] = item->u.text->text[c];
- }
- (*texts)[ctx->text]->text = erealloc((*texts)[ctx->text]->text, (t+1) * sizeof(char));
- (*texts)[ctx->text]->text[t] = 0;
- (*texts)[ctx->text]->style = cho_style_copy(item->u.text->style);
- (*texts)[ctx->text]->x = ctx->x;
- (*texts)[ctx->text]->y = ctx->y;
- width = text_width((*texts)[ctx->text]->text, item->u.text->style);
- if (width == ERROR) {
- LOG_DEBUG("text_width failed.");
- return false;
- }
- (*texts)[ctx->text]->width = width;
- if (item->u.text->style->href) {
- if (!annot_url_link_add(ctx, item->u.text->style, width)) {
- LOG_DEBUG("annot_url_link_add failed.");
- return false;
- }
- }
- ctx->x += width;
- ctx->x += (*sp)->amount;
- t = 0;
- ctx->consumed_lyrics += strlen((*texts)[ctx->text]->text);
- ctx->text++;
- *texts = erealloc(*texts, (ctx->text+1) * sizeof(struct PDFText *));
- (*texts)[ctx->text] = pdf_text_new();
- }
- }
- }
- (*texts)[ctx->text]->text = erealloc((*texts)[ctx->text]->text, (t+1) * sizeof(char));
- (*texts)[ctx->text]->text[t] = 0;
- (*texts)[ctx->text]->style = cho_style_copy(item->u.text->style);
- (*texts)[ctx->text]->x = ctx->x;
- (*texts)[ctx->text]->y = ctx->y;
- width = text_width((*texts)[ctx->text]->text, item->u.text->style);
- if (width == ERROR) {
- LOG_DEBUG("text_width failed.");
- return false;
- }
- (*texts)[ctx->text]->width = width;
- if (item->u.text->style->href) {
- if (!annot_url_link_add(ctx, item->u.text->style, width)) {
- LOG_DEBUG("annot_url_link_add failed.");
- return false;
- }
- }
- ctx->x += width;
- if ((*texts)[ctx->text]->style->font->size > ctx->biggest_font_size) {
- ctx->biggest_font_size = (*texts)[ctx->text]->style->font->size;
- }
- ctx->consumed_lyrics += strlen((*texts)[ctx->text]->text);
- ctx->text++;
- return true;
-}
-
-static double
-calc_x(double width, enum Alignment align)
-{
- if (align == A_CENTER) {
- return MARGIN_HORIZONTAL + (LINE_WIDTH - width) / 2;
- }
- return MARGIN_HORIZONTAL;
-}
-
-static const char *
-handle_index(int index, char a, char b, char c)
-{
- int i = 0;
- static char str[16];
- memset(&str, 0, sizeof(str));
- switch (index) {
- case 1:
- str[i++] = a;
- break;
- case 2:
- str[i++] = a;
- str[i++] = a;
- break;
- case 3:
- str[i++] = a;
- str[i++] = a;
- str[i++] = a;
- break;
- case 4:
- str[i++] = a;
- str[i++] = b;
- break;
- case 5:
- str[i++] = b;
- break;
- case 6:
- str[i++] = b;
- str[i++] = a;
- break;
- case 7:
- str[i++] = b;
- str[i++] = a;
- str[i++] = a;
- break;
- case 8:
- str[i++] = b;
- str[i++] = a;
- str[i++] = a;
- str[i++] = a;
- break;
- case 9:
- str[i++] = a;
- str[i++] = c;
- }
- str[i] = 0;
- return str;
-}
-
-static const char *
-numeral_system_western_arabic_to_roman(unsigned int n)
-{
- if (n > 999) {
- util_log(LOG_ERR, "Converting numbers higher than 999 is not supported.");
- return NULL;
- }
- const char *str;
- static char roman[64];
- int k;
- int r = 0;
- memset(&str, 0, sizeof(str));
- char i = 'I';
- char v = 'V';
- char x = 'X';
- char l = 'L';
- char c = 'C';
- char d = 'D';
- char m = 'M';
- int index_0 = n - n / 10 * 10;
- int index_1 = (n - n / 100 * 100 - index_0) / 10;
- int index_2 = (n - n / 1000 * 1000 - index_0 - index_1) / 100;
- if (index_2 > 0) {
- str = handle_index(index_2, c, d, m);
- for (k = 0; str[k]; k++, r++) {
- roman[r] = str[k];
- }
- }
- if (index_1 > 0) {
- str = handle_index(index_1, x, l, c);
- for (k = 0; str[k]; k++, r++) {
- roman[r] = str[k];
- }
- }
- if (index_0 > 0) {
- str = handle_index(index_0, i, v, x);
- for (k = 0; str[k]; k++, r++) {
- roman[r] = str[k];
- }
- }
- roman[r] = 0;
- return roman;
-}
-
-static const char *
-numeral_system_number_to_str(enum NumeralSystem system, int n)
-{
- if (system == NUS_ROMAN) {
- const char *str = numeral_system_western_arabic_to_roman((unsigned int)n);
- if (!str) {
- LOG_DEBUG("numeral_system_western_arabic_to_roman failed.");
- return NULL;
- }
- return str;
- } else {
- static char str[11+1];
- sprintf((char *)&str, "%d", n);
- return str;
- }
-}
-
-static bool
-pdf_page_add_page_no(struct PDFContext *ctx, enum NumeralSystem numeral_system)
-{
- struct PDFText ***texts;
- struct ChoStyle *style;
- const char *page_no;
- double width, x;
-
- style = cho_style_new();
- style->font->name = strdup(DEFAULT_FONT_FAMILY);
- texts = &ctx->content->pages[ctx->page]->texts;
- page_no = numeral_system_number_to_str(numeral_system, ctx->page+1);
- if (!page_no) {
- LOG_DEBUG("numeral_system_number_to_str failed.");
- return false;
- }
- width = text_width(page_no, style);
- if (width == ERROR) {
- LOG_DEBUG("text_width failed.");
- return false;
- }
- *texts = erealloc(*texts, (ctx->text+1) * sizeof(struct PDFText *));
- (*texts)[ctx->text] = pdf_text_new();
- (*texts)[ctx->text]->text = strdup(page_no);
- (*texts)[ctx->text]->style = style;
- (*texts)[ctx->text]->x = MEDIABOX_WIDTH - MARGIN_HORIZONTAL / 2 - width;
- (*texts)[ctx->text]->y = ctx->margin_bottom / 2;
- (*texts)[ctx->text]->width = width;
- switch (g_config->output->page_no->align) {
- case A_LEFT:
- x = MARGIN_HORIZONTAL / 2;
- break;
- case A_CENTER:
- x = MARGIN_HORIZONTAL + (LINE_WIDTH - width) / 2;
- break;
- case A_RIGHT:
- x = MEDIABOX_WIDTH - MARGIN_HORIZONTAL / 2 - width;
- break;
- default:
- util_log(LOG_ERR, "Invalid Alignment enum value '%d'.", g_config->output->page_no->align);
- return false;
- }
- (*texts)[ctx->text]->x = x;
- ctx->text++;
- return true;
-}
-
-static bool
-pdf_page_close_then_add(struct PDFContext *ctx, enum NumeralSystem numeral_system)
-{
- ctx->content->pages[ctx->page]->texts = erealloc(
- ctx->content->pages[ctx->page]->texts,
- (ctx->text+1) * sizeof(struct PDFText *)
- );
- ctx->content->pages[ctx->page]->texts[ctx->text] = NULL;
- ctx->content->pages[ctx->page]->images = erealloc(
- ctx->content->pages[ctx->page]->images,
- (ctx->image+1) * sizeof(struct PDFImage *)
- );
- ctx->content->pages[ctx->page]->images[ctx->image] = NULL;
- ctx->content->pages[ctx->page]->diagrams = erealloc(
- ctx->content->pages[ctx->page]->diagrams,
- (ctx->diagram+1) * sizeof(struct ChordDiagram *)
- );
- ctx->content->pages[ctx->page]->diagrams[ctx->diagram] = NULL;
- ctx->text = 0;
- ctx->image = 0;
- ctx->diagram = 0;
- ctx->page++;
- ctx->content->pages = erealloc(ctx->content->pages, (ctx->page+1) * sizeof(struct PDFPage *));
- ctx->content->pages[ctx->page] = pdf_page_new();
- ctx->y = MEDIABOX_HEIGHT - MARGIN_TOP;
- if (g_config->output->page_no->show) {
- if (!pdf_page_add_page_no(ctx, numeral_system)) {
- LOG_DEBUG("pdf_page_add_page_no failed.");
- return false;
- }
- }
- return true;
-}
-
-static bool
-pdf_texts_add_text(
- struct PDFContext *ctx,
- const char *text,
- struct ChoStyle *style,
- enum Alignment align,
- enum NumeralSystem numeral_system
-)
-{
- struct PDFText ***texts;
- char str[strlen(text)+1];
- double width;
- int index;
- strcpy((char *)&str, text);
- texts = &ctx->content->pages[ctx->page]->texts;
- width = text_width(text, style);
- if (width == ERROR) {
- LOG_DEBUG("text_width failed.");
- return false;
- }
- if (width > LINE_WIDTH) {
- char *t = (char *)&str;
- while (width > LINE_WIDTH) {
- if (ctx->y < ctx->margin_bottom) {
- if (!pdf_page_close_then_add(ctx, numeral_system)) {
- LOG_DEBUG("pdf_page_close_then_add failed.");
- return false;
- }
- texts = &ctx->content->pages[ctx->page]->texts;
- }
- index = text_find_fitting(t, style, 0.0, LINE_WIDTH);
- if (index == EMPTY_INT) {
- LOG_DEBUG("text_find_fitting failed.");
- return false;
- }
- t[index] = 0;
- width = text_width(t, style);
- if (width == ERROR) {
- LOG_DEBUG("text_width failed.");
- return false;
- }
- ctx->x = calc_x(width, align);
- *texts = erealloc(*texts, (ctx->text+1) * sizeof(struct PDFText *));
- (*texts)[ctx->text] = pdf_text_new();
- (*texts)[ctx->text]->text = strdup(t);
- (*texts)[ctx->text]->style = cho_style_copy(style);
- (*texts)[ctx->text]->x = ctx->x;
- (*texts)[ctx->text]->y = ctx->y;
- (*texts)[ctx->text]->width = width;
- if (style->href) {
- if (!annot_url_link_add(ctx, style, width)) {
- LOG_DEBUG("annot_url_link_add failed.");
- return false;
- }
- }
- ctx->text++;
- ctx->y -= 8.0 + style->font->size;
- t += index+1;
- width = text_width(t, style);
- if (width == ERROR) {
- LOG_DEBUG("text_width failed.");
- return false;
- }
- }
- width = text_width(t, style);
- if (width == ERROR) {
- LOG_DEBUG("text_width failed.");
- return false;
- }
- ctx->x = calc_x(width, align);
- *texts = erealloc(*texts, (ctx->text+1) * sizeof(struct PDFText *));
- (*texts)[ctx->text] = pdf_text_new();
- (*texts)[ctx->text]->text = strdup(t);
- (*texts)[ctx->text]->style = cho_style_copy(style);
- (*texts)[ctx->text]->x = ctx->x;
- (*texts)[ctx->text]->y = ctx->y;
- (*texts)[ctx->text]->width = width;
- if (style->href) {
- if (!annot_url_link_add(ctx, style, width)) {
- LOG_DEBUG("annot_url_link_add failed.");
- return false;
- }
- }
- ctx->text++;
- ctx->y -= 8.0 + style->font->size;
- } else {
- if (ctx->y < ctx->margin_bottom) {
- if (!pdf_page_close_then_add(ctx, numeral_system)) {
- LOG_DEBUG("pdf_page_close_then_add failed.");
- return false;
- }
- texts = &ctx->content->pages[ctx->page]->texts;
- }
- ctx->x = calc_x(width, align);
- *texts = erealloc(*texts, (ctx->text+1) * sizeof(struct PDFText *));
- (*texts)[ctx->text] = pdf_text_new();
- (*texts)[ctx->text]->text = strdup(text);
- (*texts)[ctx->text]->style = cho_style_copy(style);
- (*texts)[ctx->text]->x = ctx->x;
- (*texts)[ctx->text]->y = ctx->y;
- (*texts)[ctx->text]->width = width;
- if (style->href) {
- if (!annot_url_link_add(ctx, style, width)) {
- LOG_DEBUG("annot_url_link_add failed.");
- return false;
- }
- }
- ctx->text++;
- ctx->y -= 8.0 + style->font->size;
- }
- return true;
-}
-
-static int
-pdf_toc_page_count(
- struct TocEntry **entries,
- struct ChoStyle *style,
- double max_title_width
-)
-{
- int page = 0;
- double y = MEDIABOX_HEIGHT - MARGIN_TOP;
- double width;
- struct TocEntry **toc;
- for (toc = entries; *toc; toc++) {
- if (y < MARGIN_BOTTOM) {
- y = MEDIABOX_HEIGHT - MARGIN_TOP;
- page++;
- }
- int index;
- char tmp[strlen((*toc)->title)+1];
- strcpy((char *)&tmp, (*toc)->title);
- width = text_width((*toc)->title, style);
- if (width == ERROR) {
- LOG_DEBUG("text_width failed.");
- return -1;
- }
- width += MARGIN_HORIZONTAL;
- if (width > max_title_width) {
- char *t = (char *)&tmp;
- while (width > max_title_width) {
- index = text_find_fitting(t, style, MARGIN_HORIZONTAL, max_title_width);
- if (index == EMPTY_INT) {
- LOG_DEBUG("text_find_fitting failed.");
- return -1;
- }
- t[index] = 0;
- y -= 8.0 + style->font->size;
- t += index + 1;
- width = text_width(t, style);
- if (width == ERROR) {
- LOG_DEBUG("text_width failed.");
- return -1;
- }
- }
- y -= 8.0 + style->font->size;
- } else {
- y -= 8.0 + style->font->size;
- }
- }
- return page + 1;
-}
-
-static const char *
-toc_dots_create(double available_width, double dot_width)
-{
- available_width -= MARGIN_HORIZONTAL;
- int dot_count;
- static char dots[1024];
- memset(&dots, 0, sizeof(dots));
- dot_count = (int)floor(available_width / dot_width);
- if (dot_count > 1023) {
- return NULL;
- }
- memset(&dots, (int)'.', dot_count);
- dots[dot_count+1] = 0;
- return dots;
-}
-
-static bool
-pdf_texts_add_toc_entry(
- struct PDFContext *ctx,
- struct TocEntry *entry,
- struct ChoStyle *style,
- double max_song_title_width,
- int toc_page_count,
- double dot_width
-)
-{
- struct PDFText ***texts;
- texts = &ctx->content->pages[ctx->page]->texts;
- double width, page_no_x, end_of_title_x, width_between_title_and_page_no, available_dots_width;
- double page_no_width, dots_width;
- int index, line_count;
- char tmp[strlen(entry->title)+1];
- char page_no[11+1];
- strcpy((char *)&tmp, entry->title);
- width = text_width(entry->title, style);
- if (width == ERROR) {
- LOG_DEBUG("text_width failed.");
- return false;
- }
- if (width+MARGIN_HORIZONTAL > max_song_title_width) {
- char *t = (char *)&tmp;
- line_count = 0;
- while (width+MARGIN_HORIZONTAL > max_song_title_width) {
- if (ctx->y < MARGIN_BOTTOM) {
- if (!pdf_page_close_then_add(ctx, NUS_ROMAN)) {
- LOG_DEBUG("pdf_page_close_then_add failed.");
- return false;
- }
- texts = &ctx->content->pages[ctx->page]->texts;
- }
- index = text_find_fitting(t, style, MARGIN_HORIZONTAL, max_song_title_width);
- if (index == EMPTY_INT) {
- LOG_DEBUG("text_find_fitting failed.");
- return false;
- }
- t[index] = 0;
- *texts = erealloc(*texts, (ctx->text+1) * sizeof(struct PDFText *));
- (*texts)[ctx->text] = pdf_text_new();
- (*texts)[ctx->text]->text = strdup(t);
- (*texts)[ctx->text]->style = cho_style_copy(style);
- (*texts)[ctx->text]->x = MARGIN_HORIZONTAL;
- (*texts)[ctx->text]->y = ctx->y;
- ctx->y -= 8.0 + style->font->size;
- line_count++;
- width = text_width(t, style);
- if (width == ERROR) {
- LOG_DEBUG("text_width failed.");
- return false;
- }
- (*texts)[ctx->text]->width = width;
- t += index + 1;
- width = text_width(t, style);
- if (width == ERROR) {
- LOG_DEBUG("text_width failed.");
- return false;
- }
- ctx->text++;
- }
- if (ctx->y < MARGIN_BOTTOM) {
- if (!pdf_page_close_then_add(ctx, NUS_ROMAN)) {
- LOG_DEBUG("pdf_page_close_then_add failed.");
- return false;
- }
- texts = &ctx->content->pages[ctx->page]->texts;
- }
- end_of_title_x = width;
- *texts = erealloc(*texts, (ctx->text+1) * sizeof(struct PDFText *));
- (*texts)[ctx->text] = pdf_text_new();
- (*texts)[ctx->text]->text = strdup(t);
- (*texts)[ctx->text]->style = cho_style_copy(style);
- (*texts)[ctx->text]->x = MARGIN_HORIZONTAL;
- (*texts)[ctx->text]->y = ctx->y;
- (*texts)[ctx->text]->width = width;
- ctx->text++;
- sprintf((char *)&page_no, "%d", entry->page_index+1);
- width = text_width(page_no, style);
- if (width == ERROR) {
- LOG_DEBUG("text_width failed.");
- return false;
- }
-
- page_no_x = MEDIABOX_WIDTH - width - MARGIN_HORIZONTAL;
- width_between_title_and_page_no = page_no_x - end_of_title_x;
- available_dots_width = width_between_title_and_page_no - TOC_DOTS_GAP_WIDTH*2;
- const char *dots = toc_dots_create(available_dots_width, dot_width);
- if (!dots) {
- LOG_DEBUG("toc_dots_create failed.");
- return false;
- }
-
- *texts = erealloc(*texts, (ctx->text+1) * sizeof(struct PDFText *));
- (*texts)[ctx->text] = pdf_text_new();
- (*texts)[ctx->text]->text = strdup(dots);
- (*texts)[ctx->text]->style = cho_style_copy(style);
- (*texts)[ctx->text]->x = MARGIN_HORIZONTAL + end_of_title_x + TOC_DOTS_GAP_WIDTH;
- (*texts)[ctx->text]->y = ctx->y;
- ctx->text++;
-
- *texts = erealloc(*texts, (ctx->text+1) * sizeof(struct PDFText *));
- (*texts)[ctx->text] = pdf_text_new();
- (*texts)[ctx->text]->text = strdup(page_no);
- (*texts)[ctx->text]->style = cho_style_copy(style);
- (*texts)[ctx->text]->x = page_no_x;
- (*texts)[ctx->text]->y = ctx->y;
- (*texts)[ctx->text]->width = width;
- line_count++;
- if (!annot_page_link_add(ctx, entry, toc_page_count, line_count, style->font->size)) {
- LOG_DEBUG("annot_page_link_add");
- return false;
- }
- ctx->text++;
- ctx->y -= 8.0 + style->font->size;
- } else {
- if (ctx->y < MARGIN_BOTTOM) {
- if (!pdf_page_close_then_add(ctx, NUS_ROMAN)) {
- LOG_DEBUG("pdf_page_close_then_add failed.");
- return false;
- }
- texts = &ctx->content->pages[ctx->page]->texts;
- }
- end_of_title_x = width;
- *texts = erealloc(*texts, (ctx->text+1) * sizeof(struct PDFText *));
- (*texts)[ctx->text] = pdf_text_new();
- (*texts)[ctx->text]->text = strdup(entry->title);
- (*texts)[ctx->text]->style = cho_style_copy(style);
- (*texts)[ctx->text]->x = MARGIN_HORIZONTAL;
- (*texts)[ctx->text]->y = ctx->y;
- width = text_width(entry->title, style);
- if (width == ERROR) {
- LOG_DEBUG("text_width failed.");
- return false;
- }
- (*texts)[ctx->text]->width = width;
- ctx->text++;
- sprintf((char *)&page_no, "%d", entry->page_index+1);
- page_no_width = text_width(page_no, style);
- if (page_no_width == ERROR) {
- LOG_DEBUG("text_width failed.");
- return false;
- }
-
- page_no_x = MEDIABOX_WIDTH - page_no_width - MARGIN_HORIZONTAL;
- width_between_title_and_page_no = page_no_x - end_of_title_x;
- available_dots_width = width_between_title_and_page_no - TOC_DOTS_GAP_WIDTH*2;
- const char *dots = toc_dots_create(available_dots_width, dot_width);
- if (!dots) {
- LOG_DEBUG("toc_dots_create failed.");
- return false;
- }
- dots_width = text_width(dots, style);
- if (dots_width == ERROR) {
- LOG_DEBUG("text_width failed.");
- return false;
- }
-
- *texts = erealloc(*texts, (ctx->text+1) * sizeof(struct PDFText *));
- (*texts)[ctx->text] = pdf_text_new();
- (*texts)[ctx->text]->text = strdup(dots);
- (*texts)[ctx->text]->style = cho_style_copy(style);
- (*texts)[ctx->text]->x = MARGIN_HORIZONTAL + end_of_title_x + TOC_DOTS_GAP_WIDTH;
- (*texts)[ctx->text]->y = ctx->y;
- (*texts)[ctx->text]->width = dots_width;
- ctx->text++;
-
- *texts = erealloc(*texts, (ctx->text+1) * sizeof(struct PDFText *));
- (*texts)[ctx->text] = pdf_text_new();
- (*texts)[ctx->text]->text = strdup(page_no);
- (*texts)[ctx->text]->style = cho_style_copy(style);
- (*texts)[ctx->text]->x = page_no_x;
- (*texts)[ctx->text]->y = ctx->y;
- (*texts)[ctx->text]->width = page_no_width;
- if (!annot_page_link_add(ctx, entry, toc_page_count, 1, style->font->size)) {
- LOG_DEBUG("annot_page_link_add");
- return false;
- }
- ctx->text++;
- ctx->y -= 8.0 + style->font->size;
- }
- return true;
-}
-
-static bool
-pdf_toc_create(
- struct PDFContent **toc_content,
- struct PDFContent *pdf_content,
- struct Config *config
-)
-{
- double max_song_title_width, dot_width;
- int toc_page_count;
- struct PDFContext ctx;
- struct PDFText ***texts;
- struct ChoStyle *toc_style, *title_style;
- struct TocEntry **toc;
-
- pdf_context_init(&ctx);
- ctx.content = pdf_content_new();
- ctx.content->pages = emalloc(sizeof(struct PDFPage *));
- ctx.content->pages[ctx.page] = pdf_page_new();
- texts = &ctx.content->pages[ctx.page]->texts;
- if (config->output->page_no->show) {
- if (!pdf_page_add_page_no(&ctx, NUS_ROMAN)) {
- LOG_DEBUG("pdf_page_add_page_no failed.");
- return false;
- }
- }
- toc_style = config->output->styles[TT_TOC];
- toc = pdf_content->toc;
- max_song_title_width = LINE_WIDTH * 0.85;
- toc_page_count = pdf_toc_page_count(toc, toc_style, max_song_title_width);
- if (toc_page_count == -1) {
- LOG_DEBUG("pdf_toc_page_count failed.");
- return false;
- }
- title_style = config->output->styles[TT_TOC_TITLE];
- if (!pdf_texts_add_text(&ctx, config->output->toc->title, title_style, A_CENTER, NUS_ROMAN)) {
- LOG_DEBUG("pdf_texts_add_text failed.");
- return false;
- }
- ctx.y -= 30.0;
- dot_width = text_width(".", toc_style);
- if (dot_width == ERROR) {
- LOG_DEBUG("text_width failed.");
- return false;
- }
- for (; *toc; toc++) {
- if (!pdf_texts_add_toc_entry(&ctx, *toc, toc_style, max_song_title_width, toc_page_count, dot_width)) {
- LOG_DEBUG("pdf_texts_add_toc_entry failed.");
- return false;
- }
- }
- texts = &ctx.content->pages[ctx.page]->texts;
- *texts = erealloc(*texts, (ctx.text+1) * sizeof(struct PDFText *));
- (*texts)[ctx.text] = NULL;
- ctx.page++;
- ctx.content->pages = erealloc(ctx.content->pages, (ctx.page+1) * sizeof(struct PDFPage *));
- ctx.content->pages[ctx.page] = NULL;
- *toc_content = ctx.content;
- return true;
-}
-
-static bool
-pdf_content_create(
- struct PDFContent **out,
- struct ChoSong **songs,
- struct Config *config,
- struct Obj **img_objs
-)
-{
- struct ChoMetadata **m;
- struct ChoSection **se;
- struct ChoLine **li;
- struct PDFText ***texts;
- struct PDFImage ***imgs;
- struct PDFContext ctx;
- struct ChordDiagram ***diagrams, **dgrams, **dgrams_begin;
- bool show_diagram = config->output->diagram->show;
- bool start_song_on_new_page = config->output->start_song_on_new_page;
- double width, height;
-
- pdf_context_init(&ctx);
- if (show_diagram) {
- ctx.margin_bottom = 150.0;
- }
- ctx.content = pdf_content_new();
- ctx.content->pages = emalloc(sizeof(struct PDFPage *));
- ctx.content->pages[ctx.page] = pdf_page_new();
- texts = &ctx.content->pages[ctx.page]->texts;
- imgs = &ctx.content->pages[ctx.page]->images;
- diagrams = &ctx.content->pages[ctx.page]->diagrams;
- if (config->output->page_no->show) {
- if (!pdf_page_add_page_no(&ctx, NUS_WESTERN_ARABIC)) {
- LOG_DEBUG("pdf_page_add_page_no failed.");
- return false;
- }
- }
- int s;
- for (s = 0; songs[s]; s++) {
- if (show_diagram) {
- struct ChoChord **chords = NULL;
- if (!pdf_get_chords(songs[s], &chords)) {
- LOG_DEBUG("pdf_get_chords failed.");
- return false;
- }
- if (chords) {
- qsort(chords, cho_chord_count(chords), sizeof(struct ChoChord *), cho_chord_compare);
- dgrams = chord_diagrams_create(config, &chords, songs[s]->diagrams);
- dgrams_begin = dgrams;
- while (*dgrams) {
- // debug_chord_diagram_print(*dgrams);
- *diagrams = erealloc(*diagrams, (ctx.diagram+1) * sizeof(struct ChordDiagram *));
- (*diagrams)[ctx.diagram] = *dgrams;
- ctx.diagram++;
- dgrams++;
- }
- free(dgrams_begin);
- }
- cho_chords_free(chords);
- }
- for (m = songs[s]->metadata; *m; m++) {
- if (!strcmp((*m)->name, "title")) {
- ctx.content->toc = erealloc(ctx.content->toc, (ctx.toc_entry+1) * sizeof(struct TocEntry *));
- ctx.content->toc[ctx.toc_entry] = emalloc(sizeof(struct TocEntry));
- ctx.content->toc[ctx.toc_entry]->title = strdup((*m)->value);
- ctx.content->toc[ctx.toc_entry]->page_index = ctx.page;
- ctx.content->toc[ctx.toc_entry]->page_y = ctx.y;
- ctx.toc_entry++;
- if (!pdf_texts_add_text(&ctx, (*m)->value, (*m)->style, A_CENTER, NUS_WESTERN_ARABIC)) {
- LOG_DEBUG("pdf_texts_add_text failed.");
- return false;
- }
- texts = &ctx.content->pages[ctx.page]->texts;
- imgs = &ctx.content->pages[ctx.page]->images;
- diagrams = &ctx.content->pages[ctx.page]->diagrams;
- }
- }
- for (m = songs[s]->metadata; *m; m++) {
- if (!strcmp((*m)->name, "subtitle")) {
- /*
- INFO: (*m)->style will be ignored and the config style will be
- used because the subtitle style can only be manipulated from the
- config file
- */
- struct ChoStyle *output_style;
- output_style = config->output->styles[TT_SUBTITLE];
- if (!pdf_texts_add_text(&ctx, (*m)->value, output_style, A_CENTER, NUS_WESTERN_ARABIC)) {
- LOG_DEBUG("pdf_texts_add_text failed.");
- return false;
- }
- texts = &ctx.content->pages[ctx.page]->texts;
- imgs = &ctx.content->pages[ctx.page]->images;
- diagrams = &ctx.content->pages[ctx.page]->diagrams;
- }
- }
- ctx.y -= 30.0;
- for (se = songs[s]->sections; *se; se++) {
- if ((*se)->label) {
- if (!pdf_texts_add_text(&ctx, (*se)->label->text, (*se)->label->style, A_LEFT, NUS_WESTERN_ARABIC)) {
- LOG_DEBUG("pdf_texts_add_text failed.");
- return false;
- }
- texts = &ctx.content->pages[ctx.page]->texts;
- imgs = &ctx.content->pages[ctx.page]->images;
- diagrams = &ctx.content->pages[ctx.page]->diagrams;
- }
- for (li = (*se)->lines; *li; li++) {
- int item_index;
- int text_above_index;
- struct CharPosition *pos;
- struct ChoLineItemAbove **left_aboves = (*li)->text_above;
- struct ChoLineItem **left_items = (*li)->items;
- while (*left_aboves || *left_items) {
- ctx.consumed_lyrics = 0;
- ctx.biggest_font_size = 0.0;
- ctx.prev_added_space = 0.0;
- char *string;
- struct ChoStyle *style;
- if (!calc_space_between_text_above(left_items, left_aboves, img_objs, &ctx.spaces)) {
- LOG_DEBUG("calc_space_between_text_above failed.");
- return false;
- }
- pos = items_find_position_to_break_line(left_items, ctx.spaces, img_objs);
- if (pos->line_item_index == -1) {
- item_index = 10000;
- text_above_index = 10000;
- } else {
- item_index = pos->line_item_index;
- text_above_index = text_above_find_index_to_break_line(left_items, left_aboves, pos);
- if (text_above_index == -2) {
- LOG_DEBUG("text_above_find_index_to_break_line failed.");
- return false;
- }
- if (text_above_index == -1) {
- text_above_index = 20000;
- }
- }
- bool text_above_exist;
- int i;
- for (i = 0; left_aboves[i] && i<text_above_index; i++) {
- width = line_width_until_text_above(left_items, left_aboves[i], img_objs, NULL);
- if (width == ERROR) {
- LOG_DEBUG("line_width_until_text_aboave failed.");
- return false;
- }
- ctx.x = MARGIN_HORIZONTAL + width + ctx.prev_added_space;
- struct SpaceNeeded **sp;
- for (sp = ctx.spaces; *sp; sp++) {
- if ((*sp)->text_above_index == i) {
- ctx.x += (*sp)->amount;
- ctx.prev_added_space += (*sp)->amount;
- }
- }
- *texts = erealloc(*texts, (ctx.text+1) * sizeof(struct PDFText *));
- (*texts)[ctx.text] = pdf_text_new();
- (*texts)[ctx.text]->x = ctx.x;
- (*texts)[ctx.text]->y = ctx.y;
- if (left_aboves[i]->is_chord) {
- string = cho_chord_name_generate(left_aboves[i]->u.chord);
- style = cho_style_copy(left_aboves[i]->u.chord->style);
- } else {
- string = strdup(left_aboves[i]->u.annot->text);
- style = cho_style_copy(left_aboves[i]->u.annot->style);
- }
- (*texts)[ctx.text]->text = string;
- (*texts)[ctx.text]->style = style;
- (*texts)[ctx.text]->width = text_width(string, style);
- if ((*texts)[ctx.text]->width == ERROR) {
- LOG_DEBUG("text_width failed.");
- return false;
- }
- if (style->href) {
- if (!annot_url_link_add(&ctx, style, (*texts)[ctx.text]->width)) {
- LOG_DEBUG("annot_url_link_add failed.");
- return false;
- }
- }
- if (style->font->size > ctx.biggest_font_size) {
- ctx.biggest_font_size = style->font->size;
- }
- ctx.text++;
- }
- height = images_find_biggest_height(left_items, pos->line_item_index, img_objs);
- if (height == ERROR) {
- LOG_DEBUG("images_find_biggest_height failed.");
- return false;
- }
- text_above_exist = i > 0;
- if (text_above_exist) {
- left_aboves += i;
- if (height > 2.0 + ctx.biggest_font_size) {
- ctx.y -= height;
- } else {
- ctx.y -= 2.0 + ctx.biggest_font_size;
- }
- } else {
- if (height > 0.0) {
- ctx.y -= height;
- }
- }
- if (ctx.y < ctx.margin_bottom) {
- struct PDFText **tmp = NULL;
- int tm = 0;
- ctx.y = MEDIABOX_HEIGHT - MARGIN_TOP;
- if (text_above_exist) {
- /* INFO: chords/annotations and their corresponding lyrics won't be splitted */
- double prev_y = (*texts)[ctx.text-1]->y;
- for (int p = ctx.text-1; prev_y == (*texts)[p]->y; p--) {
- (*texts)[p]->y = ctx.y;
- tmp = erealloc(tmp, (tm+1) * sizeof(struct PDFText *));
- tmp[tm] = (*texts)[p];
- tm++;
- *texts = erealloc(*texts, (--ctx.text) * sizeof(struct PDFText *));
- }
- }
- if (!pdf_page_close_then_add(&ctx, NUS_WESTERN_ARABIC)) {
- LOG_DEBUG("pdf_page_close_then_add failed.");
- return false;
- }
- texts = &ctx.content->pages[ctx.page]->texts;
- imgs = &ctx.content->pages[ctx.page]->images;
- diagrams = &ctx.content->pages[ctx.page]->diagrams;
- if (text_above_exist) {
- for (int i=0; i<tm; i++) {
- *texts = erealloc(*texts, (ctx.text+1) * sizeof(struct PDFText *));
- (*texts)[ctx.text] = tmp[i];
- ctx.text++;
- }
- free(tmp);
- }
- if (text_above_exist) {
- if (height > 2.0 + ctx.biggest_font_size) {
- ctx.y -= height;
- } else {
- ctx.y -= 2.0 + ctx.biggest_font_size;
- }
- } else {
- ctx.y -= height;
- }
- }
- ctx.biggest_font_size = 0.0;
- ctx.x = MARGIN_HORIZONTAL;
- i = 0;
- while (*left_items && i < item_index) {
- if ((*left_items)->is_text) {
- if (!pdf_texts_add_lyrics(*left_items, &ctx, i)) {
- LOG_DEBUG("pdf_texts_add_lyrics failed.");
- return false;
- }
- texts = &ctx.content->pages[ctx.page]->texts;
- imgs = &ctx.content->pages[ctx.page]->images;
- diagrams = &ctx.content->pages[ctx.page]->diagrams;
- } else {
- *imgs = erealloc(*imgs, (ctx.image+1) * sizeof(struct PDFImage *));
- (*imgs)[ctx.image] = pdf_image_new();
- (*imgs)[ctx.image]->name = image_name((*left_items)->u.image);
- if (!(*imgs)[ctx.image]->name) {
- LOG_DEBUG("image_name failed.");
- return false;
- }
- (*imgs)[ctx.image]->obj = objs_get_obj(img_objs, (*imgs)[ctx.image]->name);
- if (!(*imgs)[ctx.image]->obj) {
- LOG_DEBUG("objs_get_obj failed.");
- return false;
- }
- (*imgs)[ctx.image]->width = image_width((*left_items)->u.image, (*imgs)[ctx.image]->obj);
- (*imgs)[ctx.image]->height = image_height((*left_items)->u.image, (*imgs)[ctx.image]->obj);
- (*imgs)[ctx.image]->x = ctx.x;
- (*imgs)[ctx.image]->y = ctx.y;
- ctx.x += (*imgs)[ctx.image]->width;
- ctx.image++;
- }
- i++;
- left_items++;
- }
- if (pos->line_item_index != -1 && pos->text_index != -1) {
- if ((*left_items)->is_text) {
- char *tmp;
- (*left_items)->u.text->text[pos->text_index] = 0;
- tmp = strdup(&(*left_items)->u.text->text[pos->text_index+1]);
- if (!pdf_texts_add_lyrics(*left_items, &ctx, i)) {
- LOG_DEBUG("pdf_texts_add_lyrics failed.");
- return false;
- }
- free((*left_items)->u.text->text);
- (*left_items)->u.text->text = tmp;
- texts = &ctx.content->pages[ctx.page]->texts;
- imgs = &ctx.content->pages[ctx.page]->images;
- diagrams = &ctx.content->pages[ctx.page]->diagrams;
- }
- } else
- if (pos->line_item_index != -1 && pos->text_index == -1) {
- if (!(*left_items)->is_text) {
- *imgs = erealloc(*imgs, (ctx.image+1) * sizeof(struct PDFImage *));
- (*imgs)[ctx.image] = pdf_image_new();
- (*imgs)[ctx.image]->name = image_name((*left_items)->u.image);
- if (!(*imgs)[ctx.image]->name) {
- LOG_DEBUG("image_name failed.");
- return false;
- }
- (*imgs)[ctx.image]->obj = objs_get_obj(img_objs, (*imgs)[ctx.image]->name);
- if (!(*imgs)[ctx.image]->obj) {
- LOG_DEBUG("objs_get_obj failed.");
- return false;
- }
- (*imgs)[ctx.image]->width = image_width((*left_items)->u.image, (*imgs)[ctx.image]->obj);
- (*imgs)[ctx.image]->height = image_height((*left_items)->u.image, (*imgs)[ctx.image]->obj);
- (*imgs)[ctx.image]->x = ctx.x;
- (*imgs)[ctx.image]->y = ctx.y;
- ctx.image++;
- }
- left_items++;
- }
- ctx.y -= 8.0 + ctx.biggest_font_size;
- if (ctx.y < ctx.margin_bottom) {
- if (!pdf_page_close_then_add(&ctx, NUS_WESTERN_ARABIC)) {
- LOG_DEBUG("pdf_page_close_then_add failed.");
- return false;
- }
- texts = &ctx.content->pages[ctx.page]->texts;
- imgs = &ctx.content->pages[ctx.page]->images;
- diagrams = &ctx.content->pages[ctx.page]->diagrams;
- }
- spaces_free(ctx.spaces);
- ctx.spaces = NULL;
- free(pos);
- pos = NULL;
- text_above_update_positions(left_aboves, ctx.consumed_lyrics);
- }
- if ((*li)->btype == BT_PAGE) {
- if (!pdf_page_close_then_add(&ctx, NUS_WESTERN_ARABIC)) {
- LOG_DEBUG("pdf_page_close_then_add failed.");
- return false;
- }
- texts = &ctx.content->pages[ctx.page]->texts;
- imgs = &ctx.content->pages[ctx.page]->images;
- diagrams = &ctx.content->pages[ctx.page]->diagrams;
- }
- }
- ctx.y -= SECTION_GAP_WIDTH;
- }
- if (start_song_on_new_page) {
- if (!pdf_page_close_then_add(&ctx, NUS_WESTERN_ARABIC)) {
- LOG_DEBUG("pdf_page_close_then_add failed.");
- return false;
- }
- texts = &ctx.content->pages[ctx.page]->texts;
- imgs = &ctx.content->pages[ctx.page]->images;
- diagrams = &ctx.content->pages[ctx.page]->diagrams;
- }
- }
- *texts = erealloc(*texts, (ctx.text+1) * sizeof(struct PDFText *));
- (*texts)[ctx.text] = NULL;
- *imgs = erealloc(*imgs, (ctx.image+1) * sizeof(struct PDFImage *));
- (*imgs)[ctx.image] = NULL;
- *diagrams = erealloc(*diagrams, (ctx.diagram+1) * sizeof(struct ChordDiagram *));
- (*diagrams)[ctx.diagram] = NULL;
- if (start_song_on_new_page) {
- pdf_page_free(ctx.content->pages[ctx.page]);
- ctx.content->pages[ctx.page] = NULL;
- } else {
- ctx.page++;
- ctx.content->pages = erealloc(ctx.content->pages, (ctx.page+1) * sizeof(struct PDFPage *));
- ctx.content->pages[ctx.page] = NULL;
- }
- ctx.content->toc = erealloc(ctx.content->toc, (ctx.toc_entry+1) * sizeof(struct TocEntry *));
- ctx.content->toc[ctx.toc_entry] = NULL;
- *out = ctx.content;
- return true;
-}
-
-static bool
-pdf_toc_render(struct PDFContent *content, pdfio_file_t *file)
-{
- struct PDFPage **pages;
- struct PDFText **texts;
- pdfio_stream_t *stream;
- pages = content->pages;
- int p;
- for (p = 0; pages[p]; p++) {
- g_current_page_index = p;
- stream = pdf_page_create(file, NULL, pages[p]->annots);
- if (!stream) {
- LOG_DEBUG("pdf_page_create failed.");
- return false;
- }
- for (texts = pages[p]->texts; *texts; texts++) {
- if (!pdf_text_show(stream, *texts)) {
- LOG_DEBUG("pdf_text_show failed.");
- return false;
- }
- }
- if (!pdfioStreamClose(stream)) {
- LOG_DEBUG("pdfioStreamClose failed.");
- return false;
- }
- }
- return true;
-}
-
-static bool
-pdf_content_render(struct PDFContent *content, pdfio_file_t *file)
-{
- int p;
- struct PDFPage **pages;
- struct PDFText **texts;
- struct PDFImage **imgs;
- pdfio_stream_t *stream;
- pages = content->pages;
- for (p = 0; pages[p]; p++) {
- g_current_page_index = p;
- stream = pdf_page_create(file, pages[p]->images, pages[p]->annots);
- if (!stream) {
- LOG_DEBUG("pdf_page_create failed.");
- return false;
- }
- for (texts = pages[p]->texts; *texts; texts++) {
- if (!pdf_text_show(stream, *texts)) {
- LOG_DEBUG("pdf_text_show failed.");
- return false;
- }
- }
- for (imgs = pages[p]->images; *imgs; imgs++) {
- if (
- !pdfioContentDrawImage(
- stream,
- (*imgs)->name,
- (*imgs)->x,
- (*imgs)->y,
- (*imgs)->width,
- (*imgs)->height
- )
- ) {
- LOG_DEBUG("pdfioContentDrawImage failed.");
- return false;
- }
- }
- if (pages[p]->diagrams) {
- double x = MARGIN_HORIZONTAL;
- double y = 40.0;
- double size = 50.0;
- double padding = 30.0;
- struct ChordDiagram **d;
- /* TODO: Handle line break when too long */
- for (d = pages[p]->diagrams; *d; d++) {
- debug_chord_diagram_print(*d);
- if ((*d)->show) {
- if (!chord_diagram_draw(stream, *d, x, y, size)) {
- LOG_DEBUG("chord_diagram_draw failed.");
- return false;
- }
- x += size + padding;
- }
- }
- }
- if (!pdfioStreamClose(stream)) {
- LOG_DEBUG("pdfioStreamClose failed.");
- return false;
- }
- }
- return true;
-}
-
-char *
-out_pdf_create(
- const char *cho_filepath,
- const char *output_folder_or_file,
- struct ChoSong **songs,
- struct Config *config
-)
-{
- struct Font **needed_fonts;
- struct Obj **img_objs = NULL;
- struct PDFContent *pdf_content = NULL;
- struct PDFContent *toc_content = NULL;
- pdfio_rect_t media_box_a4 = { 0.0, 0.0, MEDIABOX_WIDTH, MEDIABOX_HEIGHT };
- pdfio_rect_t crop_box = { 0.0, 0.0, MEDIABOX_WIDTH, MEDIABOX_HEIGHT };
- char *dirpath, *pdf_filepath;
-
- g_config = config;
-
- memset(&g_current_font_name, 0, sizeof(g_current_font_name));
- memset(&g_cho_dirpath, 0, PATH_MAX);
-
- if (cho_filepath) {
- dirpath = filepath_dirname(cho_filepath);
- } else {
- dirpath = getcwd(NULL, 0);
- }
- strcpy((char *)&g_cho_dirpath, dirpath);
- free(dirpath);
- pdf_filepath = pdf_filepath_create(songs, cho_filepath, output_folder_or_file);
- if (!pdf_filepath) {
- LOG_DEBUG("pdf_filepath_create failed.");
- return NULL;
- }
- g_pdf_file = pdfioFileCreate(pdf_filepath, "2.0", &media_box_a4, &crop_box, NULL, NULL);
- if (!g_pdf_file) {
- LOG_DEBUG("pdfioFileCreate failed.");
- return NULL;
- }
- if (!pdf_set_title(g_pdf_file, songs)) {
- LOG_DEBUG("pdf_set_title failed.");
- goto CLEAN;
- }
- needed_fonts = fonts_get_all(songs, config);
- if (!pdf_load_fonts(needed_fonts, config)) {
- LOG_DEBUG("pdf_load_fonts failed.");
- goto CLEAN;
- }
- cho_fonts_free(needed_fonts);
- if (!pdf_load_images(&img_objs, g_pdf_file, songs)) {
- LOG_DEBUG("pdf_load_images failed.");
- goto CLEAN;
- }
- if (!pdf_content_create(&pdf_content, songs, config, img_objs)) {
- LOG_DEBUG("pdf_content_create failed.");
- goto CLEAN;
- }
- if (config->output->toc->show) {
- if (!pdf_toc_create(&toc_content, pdf_content, config)) {
- LOG_DEBUG("pdf_toc_create failed.");
- goto CLEAN;
- }
- if (!pdf_toc_render(toc_content, g_pdf_file)) {
- LOG_DEBUG("pdf_toc_render failed.");
- goto CLEAN;
- }
- }
- if (!pdf_content_render(pdf_content, g_pdf_file)) {
- LOG_DEBUG("pdf_content_render failed.");
- goto CLEAN;
- }
- objs_free(img_objs);
- pdf_content_free(toc_content);
- pdf_content_free(pdf_content);
- if (!pdfioFileClose(g_pdf_file)) {
- LOG_DEBUG("pdfioFileClose failed.");
- goto CLEAN;
- }
- g_pdf_file = NULL;
- objs_free(g_fonts);
- g_fonts = NULL;
- g_current_font_size = 0.0;
- g_current_page_index = 0;
- g_config = NULL;
- return pdf_filepath;
- CLEAN:
- if (unlink(pdf_filepath)) {
- LOG_DEBUG("unlink failed.");
- }
- return NULL;
-}
diff --git a/out_pdf.h b/out_pdf.h
@@ -1,103 +0,0 @@
-#include <pdfio.h>
-#include "types.h"
-#include "chordpro.h"
-
-#define MEDIABOX_HEIGHT 841.995
-#define MEDIABOX_WIDTH 595.35
-#define MARGIN_TOP 50.0
-#define MARGIN_BOTTOM 50.0
-// #define MARGIN_BOTTOM 180.0
-#define MARGIN_HORIZONTAL 80.0
-#define LINE_WIDTH MEDIABOX_WIDTH - MARGIN_HORIZONTAL * 2
-#define MIN_CHORD_GAP_WIDTH 5.0
-#define SECTION_GAP_WIDTH 10.0
-#define TOC_DOTS_GAP_WIDTH 10.0
-
-#define PATH_MAX 4096
-
-enum LineLocation {
- LL_OVER,
- LL_STRIKETHROUGH,
- LL_UNDER
-};
-
-enum FontType {
- FT_TTF,
- FT_OTF
-};
-
-enum NumeralSystem {
- NUS_WESTERN_ARABIC,
- NUS_ROMAN
-};
-
-struct CharPosition {
- int line_item_index;
- int text_index;
-};
-
-struct Obj {
- char *name;
- pdfio_obj_t *value;
-};
-
-struct PDFText {
- char *text;
- struct ChoStyle *style;
- double x;
- double y;
- double width;
-};
-
-struct PDFImage {
- double x;
- double y;
- double width;
- double height;
- char *name;
- pdfio_obj_t *obj;
-};
-
-struct PDFPage {
- struct PDFText **texts;
- struct PDFImage **images;
- pdfio_array_t *annots;
- struct ChordDiagram **diagrams;
-};
-
-struct TocEntry {
- int page_index;
- double page_y;
- char *title;
-};
-
-struct PDFContent {
- struct PDFPage **pages;
- struct TocEntry **toc;
-};
-
-struct SpaceNeeded {
- int line_item_index;
- int text_index;
- int text_above_index;
- double amount;
-};
-
-struct PDFContext {
- struct PDFContent *content;
- double x;
- double y;
- int text;
- int image;
- int diagram;
- int page;
- int toc_entry;
- struct SpaceNeeded **spaces;
- double biggest_font_size;
- size_t consumed_lyrics;
- double prev_added_space;
- double margin_bottom;
-};
-
-char *out_pdf_create(const char *cho_filename, const char *output_folder_or_file, struct ChoSong **songs, struct Config *config);
-pdfio_obj_t *out_pdf_fnt_obj_get_by_name(const char *name);
diff --git a/types.h b/types.h
@@ -1,338 +0,0 @@
-#include <stdint.h>
-
-#ifndef _TYPES_H_
-#define _TYPES_H_
-
-enum TextType : int8_t {
- TT_CHORD,
- TT_ANNOT,
- TT_CHORUS,
- TT_FOOTER,
- TT_GRID,
- TT_TAB,
- TT_TOC,
- TT_TOC_TITLE,
- TT_TEXT,
- TT_TITLE,
- TT_SUBTITLE,
- TT_LABEL,
- TT_COMMENT,
- TT_COMMENT_ITALIC,
- TT_COMMENT_BOX,
- TT_LENGTH
-};
-
-enum Alignment : int8_t {
- A_LEFT,
- A_CENTER,
- A_RIGHT
-};
-
-enum Anchor {
- AN_PAPER,
- AN_PAGE,
- AN_COLUMN,
- AN_LINE,
- AN_FLOAT
-};
-
-enum BreakType : int8_t {
- BT_LINE,
- BT_PAGE,
- BT_COLUMN
-};
-
-enum ChordDiagramContent : int8_t {
- CDC_STRING,
- CDC_KEYBOARD
-};
-
-enum ChordQualifier {
- CQ_MIN,
- CQ_MAJ,
- CQ_AUG,
- CQ_DIM
-};
-
-enum SectionType {
- ST_NEWSONG,
- ST_CHORUS,
- ST_VERSE,
- ST_BRIDGE,
- ST_TAB,
- ST_GRID,
- ST_CUSTOM
-};
-
-enum SizeType {
- ST_POINT,
- ST_PERCENT,
- ST_EM,
- ST_EX
-};
-
-enum FontFamily : int8_t {
- FF_NORMAL,
- FF_SANS,
- FF_SERIF,
- FF_MONOSPACE
-};
-
-enum FontStyle : int8_t {
- FS_ROMAN,
- FS_OBLIQUE,
- FS_ITALIC
-};
-
-enum FontWeight : int8_t {
- FW_REGULAR,
- FW_BOLD
-};
-
-enum LineStyle : int8_t {
- LS_SINGLE,
- LS_DOUBLE,
- LS_NONE
-};
-
-enum NoteType {
- NT_NOTE,
- NT_SHARP,
- NT_FLAT
-};
-
-struct FontPresence {
- bool name;
- bool family;
- bool style;
- bool weight;
- bool size;
-};
-
-struct ChoStylePresence {
- struct FontPresence font;
- bool foreground_color;
- bool background_color;
- bool underline_style;
- bool underline_color;
- bool overline_style;
- bool overline_color;
- bool strikethrough;
- bool strikethrough_color;
- bool boxed;
- bool boxed_color;
- bool rise;
- bool href;
-};
-
-struct Font {
- char *name;
- enum FontFamily family;
- enum FontStyle style;
- enum FontWeight weight;
- double size;
-};
-
-struct RGBColor {
- uint8_t red;
- uint8_t green;
- uint8_t blue;
-};
-
-struct ChoStyle {
- struct Font *font;
- struct RGBColor *foreground_color;
- struct RGBColor *background_color;
- enum LineStyle underline_style;
- struct RGBColor *underline_color;
- enum LineStyle overline_style;
- struct RGBColor *overline_color;
- bool strikethrough;
- struct RGBColor *strikethrough_color;
- bool boxed;
- struct RGBColor *boxed_color;
- double rise;
- char *href;
-};
-
-struct ChoChord {
- struct ChoStyle *style;
- bool is_canonical;
- char *name;
- char *root;
- enum ChordQualifier qual;
- char *ext;
- char *bass;
-};
-
-struct ChoText {
- struct ChoStyle *style;
- char *text;
-};
-
-struct ChoLineItem {
- bool is_text;
- union {
- struct ChoImage *image;
- struct ChoText *text;
- } u;
-};
-
-struct ChoLineItemAbove {
- int position;
- bool is_chord;
- union {
- struct ChoChord *chord;
- struct ChoText *annot;
- } u;
-};
-
-struct ChoLine {
- struct ChoLineItemAbove **text_above;
- struct ChoLineItem **items;
- enum BreakType btype;
-};
-
-struct ChoMetadata {
- char *name;
- char *value;
- struct ChoStyle *style;
-};
-
-struct ChoSection {
- enum SectionType type;
- struct ChoText *label;
- struct ChoLine **lines;
-};
-
-struct ChoSong {
- struct ChoMetadata **metadata;
- struct ChoSection **sections;
- struct ChordDiagram **diagrams;
- bool present_text_types[TT_LENGTH];
-};
-
-struct ChoImage {
- bool is_asset;
- char *id;
- char *src;
- struct Size *width;
- struct Size *height;
- struct Size *width_scale;
- struct Size *height_scale;
- enum Alignment align;
- double border;
- struct Size *spread_space;
- char *href;
- struct Size *x;
- struct Size *y;
- enum Anchor anchor;
- struct Size *dx;
- struct Size *dy;
- struct Size *w;
- struct Size *h;
- bool bbox;
-};
-
-struct Size {
- enum SizeType type;
- double d;
-};
-
-struct StringDiagram {
- char *name;
- int8_t base_fret;
- int8_t frets[12];
- int8_t fingers[12];
-};
-
-struct KeyboardDiagram {
- char *name;
- int8_t keys[24];
-};
-
-struct ChordDiagram {
- bool show;
- struct RGBColor *color;
- bool is_string_instrument;
- union {
- struct StringDiagram *sd;
- struct KeyboardDiagram *kd;
- } u;
-};
-
-enum NotationSystem {
- NS_COMMON,
- NS_GERMAN,
- NS_SCANDINAVIAN,
- NS_LATIN,
- NS_ROMAN,
- NS_NASHVILLE,
- NS_CUSTOM
-};
-
-enum ParseMode {
- PM_STRICT,
- PM_RELAXED
-};
-
-enum Instrument : int8_t {
- INS_GUITAR,
- INS_KEYBOARD,
- INS_MANDOLIN,
- INS_UKULELE
-};
-
-struct Note {
- char *note;
- char *sharp;
- char *flat;
-};
-
-struct ConfigChords {
- enum NotationSystem notation_system;
- enum ParseMode mode;
-};
-
-struct ConfigChorus {
- char *label;
- bool quote;
-};
-
-struct ConfigParser {
- struct ConfigChords *chords;
- struct Note **notes;
-};
-
-struct ConfigChordDiagram {
- bool show;
- enum Instrument instrument;
-};
-
-struct ConfigToc {
- bool show;
- char *title;
-};
-
-struct ConfigPageNo {
- bool show;
- enum Alignment align;
-};
-
-struct ConfigOutput {
- struct ConfigChorus *chorus;
- struct ConfigToc *toc;
- struct ConfigChordDiagram *diagram;
- struct ConfigPageNo *page_no;
- struct ChoStyle **styles; // TODO: Make array of size 7
- struct Note **notes;
- enum NotationSystem notation_system;
- bool start_song_on_new_page;
-};
-
-struct Config {
- struct ConfigOutput *output;
- struct ConfigParser *parser;
-};
-
-#endif /* _TYPES_H_ */
diff --git a/util.c b/util.c
@@ -1,502 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdbool.h>
-#include <stdarg.h>
-#include <ctype.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <errno.h>
-#include <assert.h>
-#include <limits.h>
-#include "types.h"
-#include "util.h"
-
-static bool g_show_info_logs = false;
-
-void
-util_log_enable_info_logs(void)
-{
- g_show_info_logs = true;
-}
-
-void *
-emalloc(size_t size)
-{
- void *ptr = malloc(size);
- if (!ptr) {
- perror("malloc failed");
- exit(1);
- }
- return ptr;
-}
-
-void *
-erealloc(void *ptr, size_t size)
-{
- void *tmp = realloc(ptr, size);
- if (!tmp) {
- perror("realloc failed");
- exit(1);
- }
- return tmp;
-}
-
-void
-util_log(enum LogLevel level, const char *msg, ...)
-{
- if (level == LOG_INFO && !g_show_info_logs) {
- return;
- }
-#if COLOR == 1
- const char *log_level = "";
- const char *color = "";
- switch (level) {
- case LOG_INFO:
- log_level = "INFO";
- color = "37";
- break;
- case LOG_WARN:
- log_level = "WARN";
- color = "33";
- break;
- case LOG_ERR:
- log_level = " ERR";
- color = "31";
- break;
- case LOG_TODO:
- log_level = "TODO";
- color = "34";
- break;
- }
- fprintf(stderr, "\033[1;%sm%s\033[0m: ", color, log_level);
- va_list va;
- va_start(va, msg);
- vfprintf(stderr, msg, va);
- fprintf(stderr, "\n");
-#else
- const char *log_level = "";
- switch (level) {
- case LOG_INFO:
- log_level = "INFO";
- break;
- case LOG_WARN:
- log_level = "WARN";
- break;
- case LOG_ERR:
- log_level = " ERR";
- break;
- case LOG_TODO:
- log_level = "TODO";
- break;
- }
- fprintf(stderr, "%s: ", log_level);
- va_list va;
- va_start(va, msg);
- vfprintf(stderr, msg, va);
- fprintf(stderr, "\n");
-#endif
-}
-
-bool
-str_starts_with(const char *str, const char *part)
-{
- unsigned int i;
- size_t part_len = strlen(part);
- if (part_len > strlen(str))
- return false;
- for (i=0; i<part_len; i++) {
- if (str[i] != part[i])
- return false;
- }
- return true;
-}
-
-char *
-str_normalize(const char *str)
-{
- char *normalized = NULL;
- char c;
- int n = 0;
- int i;
- for (i = 0; str[i]; i++) {
- if (str[i] == ' ' || str[i] == '/' || str[i] == '.') {
- normalized = erealloc(normalized, (n+1) * sizeof(char));
- normalized[n] = '-';
- n++;
- continue;
- }
- if (str[i] == '\'' || str[i] == ',')
- continue;
- c = (char)tolower(str[i]);
- normalized = erealloc(normalized, (n+1) * sizeof(char));
- normalized[n] = c;
- n++;
- }
- normalized = erealloc(normalized, (n+1) * sizeof(char));
- normalized[n] = 0;
- return normalized;
-}
-
-char *
-str_trim(const char *str)
-{
- char *trimmed = NULL;
- int begin = 0;
- int end = 0;
- int len = (int)strlen(str);
- for (int i=0; i<len; i++) {
- if (
- str[i] == ' ' ||
- str[i] == '\n' ||
- str[i] == '\t' ||
- str[i] == '\r'
- )
- begin++;
- else
- break;
- }
- for (int i=len-1; i>=0; i--) {
- if (
- str[i] == ' '||
- str[i] == '\n' ||
- str[i] == '\t' ||
- str[i] == '\r'
- )
- end++;
- else
- break;
- }
- int k = 0;
- for (int i=0; i<len; i++) {
- if (i >= begin && i < len - end) {
- trimmed = erealloc(trimmed, (k+1) * sizeof(char));
- trimmed[k] = str[i];
- k++;
- }
- }
- trimmed = erealloc(trimmed, (k+1) * sizeof(char));
- trimmed[k] = 0;
- return trimmed;
-}
-
-char *
-str_remove_leading_whitespace(const char *str)
-{
- int i = 0;
- while (str[i] == ' ' || str[i] == '\t') {
- i++;
- }
- return strdup(&str[i]);
-}
-
-int
-str_compare(const char *a, const char *b)
-{
- if (a && b) {
- return strcmp(a, b);
- } else
- if (!a && !b) {
- return 0;
- } else
- if (a && !b) {
- return 1;
- } else
- if (!a && b) {
- return -1;
- }
- assert(false);
-}
-
-bool
-strs_has(char **strs, const char *str)
-{
- if (!strs) {
- return false;
- }
- char **s;
- for (s = strs; *s; s++) {
- if (!strcmp(*s, str)) {
- return true;
- }
- }
- return false;
-}
-
-void
-strs_add(char ***strs, const char *str)
-{
- int i = 0;
- if (*strs) {
- char **s;
- for (s = *strs; *s; s++, i++);
- }
- *strs = erealloc(*strs, (i+2) * sizeof(char *));
- (*strs)[i] = strdup(str);
- (*strs)[i+1] = NULL;
-}
-
-void
-strs_free(char **strs)
-{
- if (!strs) {
- return;
- }
- char **s;
- for (s = strs; *s; s++) {
- free(*s);
- }
- free(strs);
-}
-
-long
-str_to_number(const char *str)
-{
- long n;
- char *endptr;
- n = strtol(str, &endptr, 10);
- if (str == endptr) {
- return -1;
- }
- if ((n == LONG_MIN || n == LONG_MAX) && errno == ERANGE) {
- return -1;
- }
- return n;
-}
-
-enum FileType
-file_type(const char *path)
-{
- struct stat s;
- if (stat(path, &s) != 0) {
- return F_ERROR;
- }
- if (S_ISDIR(s.st_mode)) {
- return F_FOLDER;
- }
- if (S_ISREG(s.st_mode)) {
- return F_REG_FILE;
- }
- return F_OTHER;
-}
-
-char *
-file_read(const char *filepath)
-{
- char *str = NULL;
- char buf;
- size_t read;
- int i = 0;
- FILE *fp = fopen(filepath, "r");
- if (!fp) {
- LOG_DEBUG("fopen failed.");
- return NULL;
- }
- while (1) {
- read = fread(&buf, 1, 1, fp);
- if (read == 1) {
- str = erealloc(str, (i+1) * sizeof(char));
- str[i] = buf;
- i++;
- } else {
- str = erealloc(str, (i+1) * sizeof(char));
- str[i] = 0;
- break;
- }
- }
- fclose(fp);
- return str;
-}
-
-char *
-file_extension_replace_or_add(const char *filepath, const char *extension)
-{
- size_t extension_len = strlen(extension);
- char *new = NULL;
- int mark = -1;
- int i, k;
- int path_len;
- for (i = 0; filepath[i]; i++) {
- if (filepath[i] == '.') {
- mark = i;
- }
- }
- if (mark == -1) {
- path_len = (int)strlen(filepath);
- new = emalloc((path_len+2+extension_len) * sizeof(char));
- for (i = 0; i < path_len; i++) {
- new[i] = filepath[i];
- }
- new[i] = '.';
- i++;
- for (k = 0; extension[k]; k++, i++) {
- new[i] = extension[k];
- }
- new[i] = 0;
- } else {
- new = emalloc((mark+2+extension_len) * sizeof(char));
- for (i = 0; i <= mark; i++) {
- new[i] = filepath[i];
- }
- for (k = 0; extension[k]; k++, i++) {
- new[i] = extension[k];
- }
- new[i] = 0;
- }
- return new;
-}
-
-bool
-file_extension_equals(const char *filepath, const char *extension)
-{
- int mark = -1;
- int i;
- for (i = strlen(filepath)-1; i >= 0; i--) {
- if (filepath[i] == '.') {
- mark = i;
- break;
- }
- }
- if (!strcmp(&filepath[mark+1], extension)) {
- return true;
- }
- return false;
-}
-
-char *
-filepath_add_ending_slash_if_missing(const char *path)
-{
- size_t len = strlen(path);
- if (path[len-1] == '/') {
- return strdup(path);
- } else {
- char *path_with_slash = emalloc((len+2) * sizeof(char));
- strcpy(path_with_slash, path);
- path_with_slash[len] = '/';
- path_with_slash[len+1] = 0;
- return path_with_slash;
- }
-}
-
-char *
-filepath_basename(const char *path)
-{
- int begin = 0;
- int i;
- for (i = 0; path[i]; i++) {
- if (path[i] == '/') {
- begin = i+1;
- }
- }
- return strdup(&path[begin]);
-}
-
-char *
-filepath_dirname(const char *path)
-{
- char *dirname;
- int i, end = 0;
- for (i = 0; path[i]; i++) {
- if (path[i] == '/') {
- end = i;
- }
- }
- if (end == 0) {
- dirname = emalloc(2 * sizeof(char));
- dirname[0] = '.';
- dirname[1] = 0;
- return dirname;
- }
- dirname = emalloc((end+1)* sizeof(char));
- for (i = 0; i < end; i++) {
- dirname[i] = path[i];
- }
- dirname[i] = 0;
- return dirname;
-}
-
-char *
-filepath_resolve_tilde(const char *path)
-{
- char *home;
- char *str = NULL;
- if (*path == '~') {
- home = getenv("HOME");
- if (!home) {
- LOG_DEBUG("getenv failed.");
- return NULL;
- }
- str = erealloc(str, (strlen(home)+strlen(path)) * sizeof(char));
- strcpy(str, home);
- strcat(str, &path[1]);
- return str;
- } else {
- return strdup(path);
- }
-}
-
-static const char *
-size_type_to_string(enum SizeType type)
-{
- switch (type) {
- case ST_PERCENT:
- return "%";
- case ST_EM:
- return "em";
- case ST_EX:
- return "ex";
- default:
- return "";
- }
-}
-
-struct Size *
-size_create(const char *str)
-{
- size_t len = strlen(str);
- struct Size *size = emalloc(sizeof(struct Size));
- char *endptr;
- double d;
- d = strtod(str, &endptr);
- if (str == endptr || errno == ERANGE) {
- LOG_DEBUG("strtod failed.");
- return NULL;
- }
- size->d = d;
- size->type = ST_POINT;
- if (len > 1 && str[len-1] == '%') {
- if (size->d < 1.0 || size->d > 100.0) {
- util_log(LOG_ERR, "invalid percentage.");
- return NULL;
- }
- size->d = d / 100.0;
- size->type = ST_PERCENT;
- } else
- if (len > 2 && str[len-2] == 'e' && str[len-1] == 'm') {
- size->type = ST_EM;
- } else
- if (len > 2 && str[len-2] == 'e' && str[len-1] == 'x') {
- size->type = ST_EX;
- }
- return size;
-}
-
-struct Size *
-size_copy(struct Size *size)
-{
- struct Size *copy = emalloc(sizeof(struct Size));
- copy->type = size->type;
- copy->d = size->d;
- return copy;
-}
-
-const char *
-size_to_string(struct Size *size)
-{
- static char str[10+1];
- if (size->d > 999999) {
- sprintf((char *)&str, ">999.999");
- } else {
- sprintf((char *)&str, "%.1f%s", size->d, size_type_to_string(size->type));
- }
- return str;
-}
diff --git a/util.h b/util.h
@@ -1,59 +0,0 @@
-#include "types.h"
-
-#ifdef DEBUG
-#define LOG_DEBUG(msg) fprintf(stderr, msg"\n")
-#else
-#define LOG_DEBUG(msg)
-#endif
-
-#define LENGTH(x) (sizeof x / sizeof x[0])
-
-#define COLOR_BOLD_RED "\033[1;31m"
-#define COLOR_BOLD_ORANGE "\033[1;33m"
-#define COLOR_BOLD_WHITE "\033[1;37m"
-#define COLOR_BOLD_BLUE "\033[1;34m"
-#define COLOR_RESET "\033[0m"
-
-enum LogLevel {
- LOG_INFO,
- LOG_WARN,
- LOG_ERR,
- LOG_TODO
-};
-
-enum FileType {
- F_ERROR,
- F_FOLDER,
- F_REG_FILE,
- F_OTHER
-};
-
-void util_log_enable_info_logs(void);
-
-void *emalloc(size_t size);
-void *erealloc(void *ptr, size_t size);
-void util_log(enum LogLevel level, const char *msg, ...);
-
-bool str_starts_with(const char *str, const char *part);
-char *str_normalize(const char *str);
-char *str_trim(const char *str);
-char *str_remove_leading_whitespace(const char *str);
-void strs_free(char **strs);
-bool strs_has(char **strs, const char *str);
-void strs_add(char ***strs, const char *str);
-int str_compare(const char *a, const char *b);
-long str_to_number(const char *str);
-
-enum FileType file_type(const char *path);
-char *file_read(const char *filepath);
-char *file_extension_replace_or_add(const char *filepath, const char *extension);
-bool file_extension_equals(const char *filepath, const char *extension);
-
-char *filepath_add_ending_slash_if_missing(const char *path);
-char *filepath_basename(const char *path);
-char *filepath_dirname(const char *path);
-char *filepath_resolve_tilde(const char *path);
-
-struct Size *size_create(const char *str);
-struct Size *size_copy(struct Size *size);
-const char *size_to_string(struct Size *size);