note.c (scrot-1.7.tar.bz2) | : | note.c (scrot-1.8) | ||
---|---|---|---|---|
/* note.c | /* note.c | |||
Copyright 2019-2021 Daniel T. Borelli <danieltborelli@gmail.com> | Copyright 2019-2022 Daniel T. Borelli <danieltborelli@gmail.com> | |||
Copyright 2021 Guilherme Janczak <guilherme.janczak@yandex.com> | Copyright 2021-2023 Guilherme Janczak <guilherme.janczak@yandex.com> | |||
Copyright 2021 IFo Hancroft <contact@ifohancroft.com> | Copyright 2021 IFo Hancroft <contact@ifohancroft.com> | |||
Copyright 2021 Peter Wu <peterwu@hotmail.com> | Copyright 2021 Peter Wu <peterwu@hotmail.com> | |||
Permission is hereby granted, free of charge, to any person obtaining a copy | Permission is hereby granted, free of charge, to any person obtaining a copy | |||
of this software and associated documentation files (the "Software"), to | of this software and associated documentation files (the "Software"), to | |||
deal in the Software without restriction, including without limitation the | deal in the Software without restriction, including without limitation the | |||
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or | rights to use, copy, modify, merge, publish, distribute, sublicense, and/or | |||
sell copies of the Software, and to permit persons to whom the Software is | sell copies of the Software, and to permit persons to whom the Software is | |||
furnished to do so, subject to the following conditions: | furnished to do so, subject to the following conditions: | |||
skipping to change at line 29 | skipping to change at line 29 | |||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |||
THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER | THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER | |||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |||
*/ | */ | |||
/* This file is part of the scrot project. */ | ||||
#include <assert.h> | #include <assert.h> | |||
#include <stdint.h> | #include <err.h> | |||
#include <limits.h> | ||||
#include <stdio.h> | ||||
#include <stdlib.h> | ||||
#include <string.h> | ||||
#include <Imlib2.h> | ||||
#include "scrot.h" | #include "note.h" | |||
#include "options.h" | ||||
enum { // default color | enum { // default color | |||
DEF_COLOR_RED = 0, | DEF_COLOR_RED = 0, | |||
DEF_COLOR_GREEN = 0, | DEF_COLOR_GREEN = 0, | |||
DEF_COLOR_BLUE = 0, | DEF_COLOR_BLUE = 0, | |||
DEF_COLOR_ALPHA = 255 | DEF_COLOR_ALPHA = 255 | |||
}; | }; | |||
ScrotNote note; | /* | |||
* Format: -f 'NAME/SIZE' -x NUM -y NUM -t 'TEXT' -c NUM,NUM,NUM,NUM | ||||
static Imlib_Font imFont = NULL; | * | |||
* -f fontname/size - absolute path | ||||
* -x screen position x | ||||
* -y screen position y | ||||
* -t text note | ||||
* -c color(red,green,blue,alpha) range 0..255 | ||||
* | ||||
* */ | ||||
struct ScrotNote { | ||||
char *font; /* font name */ | ||||
char *text; /* text of the note */ | ||||
Imlib_Font imFont; /* private */ | ||||
int x; /* position screen (optional) */ | ||||
int y; /* position screen (optional) */ | ||||
double angle; /* angle text (optional) */ | ||||
struct Color { /* (optional) */ | ||||
int r, /* red */ | ||||
g, /* green */ | ||||
b, /* blue */ | ||||
a; /* alpha */ | ||||
} color; | ||||
}; | ||||
static struct ScrotNote *note; | ||||
static void loadFont(void); | static void loadFont(void); | |||
static char *parseText(char **, char const *const); | ||||
static char* parseText(char**, char* const); | static void pfree(char **ptr) | |||
static inline void pfree(char** ptr) | ||||
{ | { | |||
free(*ptr); | free(*ptr); | |||
*ptr = NULL; | *ptr = NULL; | |||
} | } | |||
static inline void nextSpace(char** token) | static void nextSpace(char **token) | |||
{ | { | |||
while (*++*token == ' ' && **token != '\0') { } | while (*++*token == ' ' && **token != '\0') { } | |||
} | } | |||
static inline void nextNotSpace(char** token) | static void nextNotSpace(char **token) | |||
{ | { | |||
while (*++*token != ' ' && **token != '\0') { } | while (*++*token != ' ' && **token != '\0') { } | |||
} | } | |||
void scrotNoteNew(char* format) | void scrotNoteNew(char const *const format) | |||
{ | { | |||
scrotNoteFree(); | char const *const end = format + strlen(format); | |||
char *token = strpbrk(format, "-"); | ||||
note = (ScrotNote) { | if (!token || (strlen(token) == 1)) | |||
NULL, NULL, 0, 0, 0.0, | errx(EXIT_FAILURE, "Error --note option : Malformed syntax."); | |||
{ DEF_COLOR_RED, DEF_COLOR_GREEN, | ||||
DEF_COLOR_BLUE, DEF_COLOR_ALPHA } | ||||
}; | ||||
char* const end = format + strlen(format); | scrotNoteFree(); | |||
char* token = strpbrk(format, "-"); | note = calloc(1, sizeof(*note)); | |||
if (!token || (strlen(token) == 1)) { | assert(note); | |||
malformed: | ||||
pfree(&format); | note->color.r = DEF_COLOR_RED; | |||
errx(EXIT_FAILURE, "Error --note option : Malformed syntax."); | note->color.g = DEF_COLOR_GREEN; | |||
} | note->color.b = DEF_COLOR_BLUE; | |||
note->color.a = DEF_COLOR_ALPHA; | ||||
while (token) { | while (token) { | |||
const char type = *++token; | const char type = *++token; | |||
char* savePtr = NULL; | char *savePtr = NULL; | |||
char* c; | char *c; | |||
const char *errmsg; | ||||
nextSpace(&token); | nextSpace(&token); | |||
switch (type) { | switch (type) { | |||
case 'f': | case 'f': | |||
note.font = parseText(&token, end); | note->font = parseText(&token, end); | |||
if (!note.font) | if (!note->font) | |||
errx(EXIT_FAILURE, "Error --note option : Malformed syntax for - f"); | errx(EXIT_FAILURE, "Error --note option : Malformed syntax for - f"); | |||
char* number = strrchr(note.font, '/'); | char *number = strrchr(note->font, '/'); | |||
if (!number) | if (!number) | |||
errx(EXIT_FAILURE, "Error --note option : Malformed syntax for - f, required number."); | errx(EXIT_FAILURE, "Error --note option : Malformed syntax for - f, required number."); | |||
int fontSize = optionsParseRequiredNumber(++number); | const int fontSize = optionsParseNum(++number, 1, INT_MAX, | |||
&errmsg); | ||||
if (errmsg) { | ||||
errx(EXIT_FAILURE, "option --note: font size '%s' is %s", | ||||
number, errmsg); | ||||
} | ||||
if (fontSize < 6) | if (fontSize < 6) | |||
warnx("Warning: --note option: font size < 6"); | warnx("Warning: --note option: font size < 6"); | |||
break; | break; | |||
case 'x': | case 'x': | |||
if ((1 != sscanf(token, "%d", ¬e.x) || (note.x < 0))) | if ((1 != sscanf(token, "%d", ¬e->x) || (note->x < 0))) | |||
errx(EXIT_FAILURE, "Error --note option : Malformed syntax for - x"); | errx(EXIT_FAILURE, "Error --note option : Malformed syntax for - x"); | |||
nextNotSpace(&token); | nextNotSpace(&token); | |||
break; | break; | |||
case 'y': | case 'y': | |||
if ((1 != sscanf(token, "%d", ¬e.y)) || (note.y < 0)) | if ((1 != sscanf(token, "%d", ¬e->y)) || (note->y < 0)) | |||
errx(EXIT_FAILURE, "Error --note option : Malformed syntax for - y"); | errx(EXIT_FAILURE, "Error --note option : Malformed syntax for - y"); | |||
nextNotSpace(&token); | nextNotSpace(&token); | |||
break; | break; | |||
case 'a': | case 'a': | |||
if ((1 != sscanf(token, "%lf", ¬e.angle))) | if ((1 != sscanf(token, "%lf", ¬e->angle))) | |||
errx(EXIT_FAILURE, "Error --note option : Malformed syntax for - a"); | errx(EXIT_FAILURE, "Error --note option : Malformed syntax for - a"); | |||
nextNotSpace(&token); | nextNotSpace(&token); | |||
break; | break; | |||
case 't': | case 't': | |||
note.text = parseText(&token, end); | note->text = parseText(&token, end); | |||
if (!note.text) | if (!note->text) | |||
errx(EXIT_FAILURE, "Error --note option : Malformed syntax for - t"); | errx(EXIT_FAILURE, "Error --note option : Malformed syntax for - t"); | |||
break; | break; | |||
case 'c': | case 'c': | |||
c = strtok_r(token, ",", &savePtr); | c = strtok_r(token, ",", &savePtr); | |||
int numberColors = 0; | int numberColors = 0; | |||
while (c) { | while (c) { | |||
token = c; | token = c; | |||
char *const space = strchr(c, ' '); | ||||
int const color = optionsParseRequireRange( | if (space) | |||
optionsParseRequiredNumber(c), 0 ,255); | *space = '\0'; | |||
const int color = optionsParseNum(c, 0, 255, &errmsg); | ||||
if (errmsg) { | ||||
errx(EXIT_FAILURE, "option --note: color '%s' is %s", c, | ||||
errmsg); | ||||
} | ||||
if (space) | ||||
*space = ' '; | ||||
switch (++numberColors) { | switch (++numberColors) { | |||
case 1: | case 1: | |||
note.color.r = color; | note->color.r = color; | |||
break; | break; | |||
case 2: | case 2: | |||
note.color.g = color; | note->color.g = color; | |||
break; | break; | |||
case 3: | case 3: | |||
note.color.b = color; | note->color.b = color; | |||
break; | break; | |||
case 4: | case 4: | |||
note.color.a = color; | note->color.a = color; | |||
break; | break; | |||
} | } | |||
c = strtok_r(NULL, ",", &savePtr); | c = strtok_r(NULL, ",", &savePtr); | |||
} | } | |||
if (numberColors > 4) | if (numberColors > 4) | |||
warnx("Warning --note option : Malformed syntax for -c"); | warnx("Warning --note option : Malformed syntax for -c"); | |||
break; | break; | |||
default: | default: | |||
errx(EXIT_FAILURE, "Error --note option : unknown option: '-%c'", ty pe); | errx(EXIT_FAILURE, "Error --note option : unknown option: '-%c'", ty pe); | |||
} | } | |||
token = strpbrk(token, "-"); | token = strpbrk(token, "-"); | |||
} | } | |||
if (!note.font || !note.text) | if (!note->font || !note->text) | |||
goto malformed; | errx(EXIT_FAILURE, "Error --note option : Malformed syntax."); | |||
loadFont(); | loadFont(); | |||
} | } | |||
void scrotNoteFree(void) | void scrotNoteFree(void) | |||
{ | { | |||
if (note.text) | if(!note) | |||
pfree(¬e.text); | return; | |||
if (note->text) | ||||
pfree(¬e->text); | ||||
if (note.font) | if (note->font) | |||
pfree(¬e.font); | pfree(¬e->font); | |||
if (imFont) { | if (note->imFont) { | |||
imlib_context_set_font(imFont); | imlib_context_set_font(note->imFont); | |||
imlib_free_font(); | imlib_free_font(); | |||
} | } | |||
free(note); | ||||
note = NULL; | ||||
} | } | |||
void scrotNoteDraw(Imlib_Image im) | void scrotNoteDraw(Imlib_Image im) | |||
{ | { | |||
if (!im) | if (!im) | |||
return; | return; | |||
assert(note); | ||||
assert(note->imFont); | ||||
imlib_context_set_image(im); | imlib_context_set_image(im); | |||
imlib_context_set_font(imFont); | imlib_context_set_font(note->imFont); | |||
imlib_context_set_direction(IMLIB_TEXT_TO_ANGLE); | imlib_context_set_direction(IMLIB_TEXT_TO_ANGLE); | |||
imlib_context_set_angle(note.angle); | imlib_context_set_angle(note->angle); | |||
imlib_context_set_color(note.color.r, | imlib_context_set_color(note->color.r, | |||
note.color.g, | note->color.g, | |||
note.color.b, | note->color.b, | |||
note.color.a); | note->color.a); | |||
imlib_text_draw(note.x, note.y, note.text); | imlib_text_draw(note->x, note->y, note->text); | |||
} | } | |||
void loadFont(void) | static void loadFont(void) | |||
{ | { | |||
imFont = imlib_load_font(note.font); | assert(note); | |||
if (!imFont) { | note->imFont = imlib_load_font(note->font); | |||
warnx("Error --note option : Failed to load fontname: %s", note.font); | ||||
scrotNoteFree(); | if (!note->imFont) | |||
exit(EXIT_FAILURE); | errx(EXIT_FAILURE, "Error --note option : Failed to load fontname: %s", | |||
} | note->font); | |||
} | } | |||
char* parseText(char** token, char* const end) | static char *parseText(char **token, char const *const end) | |||
{ | { | |||
assert(NULL != *token); | assert(NULL != *token); | |||
assert(NULL != end); | assert(NULL != end); | |||
if (**token != '\'') | if (**token != '\'') | |||
return NULL; | return NULL; | |||
(*token)++; | (*token)++; | |||
char* begin = *token; | char *begin = *token; | |||
while ((*token != end) && **token != '\'') | while ((*token != end) && **token != '\'') | |||
(*token)++; | (*token)++; | |||
ptrdiff_t length = (*token - begin); | ptrdiff_t length = (*token - begin); | |||
if (length == 0) | if (length == 0) | |||
return NULL; | return NULL; | |||
return strndup(begin, length); | return strndup(begin, length); | |||
End of changes. 47 change blocks. | ||||
69 lines changed or deleted | 118 lines changed or added |