aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Czigler <37268479+mcpcpc@users.noreply.github.com>2021-03-25 13:14:35 -0400
committerGitHub <noreply@github.com>2021-03-25 13:14:35 -0400
commit61e68a22f58c3e04784bef86e9e19044113a9eb9 (patch)
tree67a6e62726f4c945ec0c86c8e2c4189f10baf34e
parentreleased at 0.2.5 (diff)
downloadkirc-61e68a22f58c3e04784bef86e9e19044113a9eb9.tar.gz
kirc-61e68a22f58c3e04784bef86e9e19044113a9eb9.tar.bz2
kirc-61e68a22f58c3e04784bef86e9e19044113a9eb9.tar.xz
kirc-61e68a22f58c3e04784bef86e9e19044113a9eb9.tar.zst
kirc-61e68a22f58c3e04784bef86e9e19044113a9eb9.zip
released at 0.2.6
Diffstat (limited to '')
-rw-r--r--.github/CODE_OF_CONDUCT73
-rw-r--r--.github/workflows/codeql-analysis.yml62
-rw-r--r--README4
-rw-r--r--kirc.c308
4 files changed, 229 insertions, 218 deletions
diff --git a/.github/CODE_OF_CONDUCT b/.github/CODE_OF_CONDUCT
deleted file mode 100644
index 21e5ef9..0000000
--- a/.github/CODE_OF_CONDUCT
+++ /dev/null
@@ -1,73 +0,0 @@
-# Contributor Covenant Code of Conduct
-
-## Our Pledge
-
-In the interest of fostering an open and welcoming environment, we as
-contributors and maintainers pledge to making participation in our project and
-our community a harassment-free experience for everyone, regardless of age, body
-size, disability, ethnicity, gender identity and expression, level of experience,
-education, socio-economic status, nationality, personal appearance, race,
-religion, or sexual identity and orientation.
-
-## Our Standards
-
-Examples of behavior that contributes to creating a positive environment
-include:
-
-* Using welcoming and inclusive language
-* Being respectful of differing viewpoints and experiences
-* Gracefully accepting constructive criticism
-* Focusing on what is best for the community
-* Showing empathy towards other community members
-
-Examples of unacceptable behavior by participants include:
-
-* The use of sexualized language or imagery and unwelcome sexual attention or
- advances
-* Trolling, insulting/derogatory comments, and personal or political attacks
-* Public or private harassment
-* Publishing others' private information, such as a physical or electronic
- address, without explicit permission
-* Other conduct which could reasonably be considered inappropriate in a
- professional setting
-
-## Our Responsibilities
-
-Project maintainers are responsible for clarifying the standards of acceptable
-behavior and are expected to take appropriate and fair corrective action in
-response to any instances of unacceptable behavior.
-
-Project maintainers have the right and responsibility to remove, edit, or
-reject comments, commits, code, wiki edits, issues, and other contributions
-that are not aligned to this Code of Conduct, or to ban temporarily or
-permanently any contributor for other behaviors that they deem inappropriate,
-threatening, offensive, or harmful.
-
-## Scope
-
-This Code of Conduct applies both within project spaces and in public spaces
-when an individual is representing the project or its community. Examples of
-representing a project or community include using an official project e-mail
-address, posting via an official social media account, or acting as an appointed
-representative at an online or offline event. Representation of a project may be
-further defined and clarified by project maintainers.
-
-## Enforcement
-
-Instances of abusive, harassing, or otherwise unacceptable behavior may be
-reported by contacting the project team at {{ email }}. All
-complaints will be reviewed and investigated and will result in a response that
-is deemed necessary and appropriate to the circumstances. The project team is
-obligated to maintain confidentiality with regard to the reporter of an incident.
-Further details of specific enforcement policies may be posted separately.
-
-Project maintainers who do not follow or enforce the Code of Conduct in good
-faith may face temporary or permanent repercussions as determined by other
-members of the project's leadership.
-
-## Attribution
-
-This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
-available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
-
-[homepage]: https://www.contributor-covenant.org
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
deleted file mode 100644
index 8670f66..0000000
--- a/.github/workflows/codeql-analysis.yml
+++ /dev/null
@@ -1,62 +0,0 @@
-name: "CodeQL"
-
-on:
- push:
- branches: [master]
- pull_request:
- # The branches below must be a subset of the branches above
- branches: [master]
- schedule:
- - cron: '0 20 * * 0'
-
-jobs:
- analyze:
- name: Analyze
- runs-on: ubuntu-latest
-
- strategy:
- fail-fast: false
- matrix:
- # Override automatic language detection by changing the below list
- # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python']
- language: ['cpp']
- # Learn more...
- # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection
-
- steps:
- - name: Checkout repository
- uses: actions/checkout@v2
- with:
- # We must fetch at least the immediate parents so that if this is
- # a pull request then we can checkout the head.
- fetch-depth: 2
-
- # If this run was triggered by a pull request event, then checkout
- # the head of the pull request instead of the merge commit.
-# - run: git checkout HEAD^2
-# if: ${{ github.event_name == 'pull_request' }}
-
- # Initializes the CodeQL tools for scanning.
- - name: Initialize CodeQL
- uses: github/codeql-action/init@v1
- with:
- languages: ${{ matrix.language }}
-
- # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
- # If this step fails, then you should remove it and run the build manually (see below)
- - name: Autobuild
- uses: github/codeql-action/autobuild@v1
-
- # â„šī¸ Command-line programs to run using the OS shell.
- # 📚 https://git.io/JvXDl
-
- # âœī¸ If the Autobuild fails above, remove it and uncomment the following three lines
- # and modify them (or add more) to build your code if your project
- # uses a compiled language
-
- #- run: |
- # make bootstrap
- # make release
-
- - name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@v1
diff --git a/README b/README
index be6a73f..6a9cbc4 100644
--- a/README
+++ b/README
@@ -53,11 +53,11 @@ Support Documentation
Please refer to the official for examples, troubleshooting and use cases.
- https://mcpcpc.github.io/kirc/documentation.html
+ http://kirc.io/docs.html
Contact
-------
For any further questions or concerns, feel free to email me at:
- michaelczigler [at] mcpcpc [dot] com
+ michaelczigler[at]mcpcpc[dot]com
diff --git a/kirc.c b/kirc.c
index ffc514d..80812c3 100644
--- a/kirc.c
+++ b/kirc.c
@@ -14,7 +14,7 @@
#include <sys/ioctl.h>
#define CTCP_CMDS "ACTION VERSION TIME CLIENTINFO PING"
-#define VERSION "0.2.5"
+#define VERSION "0.2.6"
#define MSG_MAX 512
#define CHA_MAX 200
#define NIC_MAX 26
@@ -24,6 +24,7 @@ static char cdef[MSG_MAX] = "?"; /* default PRIVMSG channel */
static int conn; /* connection socket */
static int verb = 0; /* verbose output */
static int sasl = 0; /* SASL method */
+static int isu8 = 0; /* UTF-8 flag */
static char *host = "irc.freenode.net"; /* host address */
static char *port = "6667"; /* port */
static char *chan = NULL; /* channel(s) */
@@ -59,10 +60,14 @@ struct State {
char *prompt; /* Prompt to display. */
char *buf; /* Edited line buffer. */
size_t buflen; /* Edited line buffer size. */
- size_t plen; /* Prompt length. */
- size_t pos; /* Current cursor position. */
- size_t oldpos; /* Previous refresh cursor position. */
- size_t len; /* Current edited line length. */
+ size_t plenb; /* Prompt length. */
+ size_t plenu8; /* Prompt length. */
+ size_t posb; /* Current cursor position. */
+ size_t posu8; /* Current cursor position. */
+ size_t oldposb; /* Previous refresh cursor position. */
+ size_t oldposu8; /* Previous refresh cursor position. */
+ size_t lenb; /* Current edited line length. */
+ size_t lenu8; /* Current edited line length. */
size_t cols; /* Number of columns in terminal. */
int history_index; /* Current line in the edit history */
};
@@ -168,6 +173,98 @@ static int getColumns(int ifd, int ofd) {
}
}
+static void bufPosMove(struct State *l, ssize_t dest, ssize_t src, size_t size) {
+ memmove(l->buf + l->posb + dest, l->buf + l->posb + src, size);
+}
+
+static void bufPosMoveEnd(struct State *l, ssize_t dest, ssize_t src) {
+ bufPosMove(l, dest, src, l->lenb - (l->posb + src) + 1);
+}
+
+static int u8CharStart(char c) {
+ int ret = 1;
+ if (isu8 != 0) {
+ ret = (c & 0x80) == 0x00 || (c & 0xC0) == 0xC0;
+ }
+ return ret;
+}
+
+static int u8CharSize(char c) {
+ int ret = 1;
+ if(isu8 != 0) {
+ int size = 0;
+ while (c & (0x80 >> size)) {
+ size++;
+ }
+ ret = (size != 0) ? size : 1;
+ }
+ return ret;
+}
+
+static size_t u8Len(const char *s) {
+ size_t lenu8 = 0;
+ while (*s != '\0') {
+ lenu8 += u8CharStart(*(s++));
+ }
+ return lenu8;
+}
+
+static size_t u8Prev(const char *s, size_t posb) {
+ if (posb != 0) {
+ do {
+ posb--;
+ } while ((posb > 0) && !u8CharStart(s[posb]));
+ }
+ return posb;
+}
+
+static size_t u8Next(const char *s, size_t posb) {
+ if (s[posb] != '\0') {
+ do {
+ posb++;
+ } while((s[posb] != '\0') && !u8CharStart(s[posb]));
+ }
+ return posb;
+}
+
+static int setIsu8_C(int ifd, int ofd) {
+ if (isu8) {
+ return 0;
+ }
+ if (write(ofd, "\r", 1) != 1) {
+ return -1;
+ }
+ if (getCursorPosition(ifd, ofd) != 1) {
+ return -1;
+ }
+ const char* testChars[] = {
+ "\xe1\xbb\xa4",
+ NULL
+ };
+ for (const char** it = testChars; *it; it++){
+ if (write(ofd, *it, strlen(*it)) != (ssize_t) strlen(*it)) {
+ return -1;
+ }
+ int pos = getCursorPosition(ifd, ofd);
+ if (write(ofd, "\r", 1) != 1) {
+ return -1;
+ }
+ for (int i = 1; i < pos; i++) {
+ if (write(ofd, " ", 1) != 1) {
+ return -1;
+ }
+ }
+ if (write(ofd, "\r", 1) != 1) {
+ return -1;
+ }
+ if (pos != 2) {
+ return 0;
+ }
+ }
+ isu8 = 1;
+ return 0;
+ }
+
static void abInit(struct abuf *ab) {
ab->b = NULL;
ab->len = 0;
@@ -189,57 +286,66 @@ static void abFree(struct abuf *ab) {
static void refreshLine(struct State *l) {
char seq[64];
- size_t plen = strlen(l->prompt) + 2;
+ size_t plenu8 = l->plenu8 + 2;
int fd = STDOUT_FILENO;
char *buf = l->buf;
- size_t len = l->len;
- size_t pos = l->pos;
+ size_t lenb = l->lenb;
+ size_t lenu8 = l->lenu8;
+ size_t posu8 = l->posu8;
struct abuf ab;
l->cols = getColumns(STDIN_FILENO, STDOUT_FILENO);
- while ((plen + pos) >= l->cols) {
- buf++;
- len--;
- pos--;
+ while ((plenu8 + posu8) >= l->cols) {
+ size_t movedBy = u8Next(buf, 0);
+ buf += movedBy;
+ lenb += movedBy;
+ lenu8--;
+ posu8--;
}
- while ((plen + len) > l->cols) {
- len--;
+ while ((plenu8 + lenu8) > l->cols) {
+ lenu8--;
+ lenb = u8Prev(buf, lenb);
}
-
abInit(&ab);
snprintf(seq, sizeof(seq), "\r");
abAppend(&ab, seq, strnlen(seq, MSG_MAX));
- abAppend(&ab,l->prompt, strnlen(l->prompt, MSG_MAX));
+ abAppend(&ab,l->prompt, l->plenb);
abAppend(&ab, "> ", 2);
- abAppend(&ab, buf, len);
+ abAppend(&ab, buf, lenb);
snprintf(seq, sizeof(seq), "\x1b[0K");
abAppend(&ab, seq, strnlen(seq, MSG_MAX));
- snprintf(seq, sizeof(seq), "\r\x1b[%dC", (int)(pos + plen));
+ if (posu8 + plenu8) {
+ snprintf(seq, sizeof(seq), "\r\x1b[%dC", (int)(posu8 + plenu8));
+ } else {
+ snprintf(seq, sizeof(seq), "\r");
+ }
abAppend(&ab, seq, strlen(seq));
if (write(fd, ab.b, ab.len) == -1) {}
abFree(&ab);
}
-static int editInsert(struct State *l, char c) {
- if (l->len < l->buflen) {
- if (l->len == l->pos) {
- l->buf[l->pos] = c;
- l->pos++;
- l->len++;
- l->buf[l->len] = '\0';
- if ((l->plen + l->len) < l->cols) {
- char d = c;
- if (write(STDOUT_FILENO, &d, 1) == -1) {
+static int editInsert(struct State *l, char *c) {
+ size_t clenb = strlen(c);
+ if ((l->lenb + clenb) < l->buflen) {
+ if (l->lenu8 == l->posu8) {
+ strcpy(l->buf + l->posb, c);
+ l->posu8++;
+ l->lenu8++;
+ l->posb += clenb;
+ l->lenb += clenb;
+ if ((l->plenu8 + l->lenu8) < l->cols) {
+ if (write(STDOUT_FILENO, c, clenb) == -1) {
return -1;
}
} else {
refreshLine(l);
}
} else {
- memmove(l->buf + l->pos + 1,l->buf + l->pos,l->len - l->pos);
- l->buf[l->pos] = c;
- l->len++;
- l->pos++;
- l->buf[l->len] = '\0';
+ bufPosMoveEnd(l, clenb, 0);
+ memmove(l->buf + l->posb, c, clenb);
+ l->posu8++;
+ l->lenu8++;
+ l->posb += clenb;
+ l->lenb += clenb;
refreshLine(l);
}
}
@@ -247,85 +353,104 @@ static int editInsert(struct State *l, char c) {
}
static void editMoveLeft(struct State *l) {
- if (l->pos > 0) {
- l->pos--;
+ if (l->posb > 0) {
+ l->posb = u8Prev(l->buf, l->posb);
+ l->posu8--;
refreshLine(l);
}
}
static void editMoveRight(struct State *l) {
- if (l->pos != l->len) {
- l->pos++;
+ if (l->posu8 != l->lenu8) {
+ l->posb = u8Next(l->buf, l->posb);
+ l->posu8++;
refreshLine(l);
}
}
static void editMoveHome(struct State *l) {
- if (l->pos != 0) {
- l->pos = 0;
+ if (l->posb != 0) {
+ l->posb = 0;
+ l->posu8 = 0;
refreshLine(l);
}
}
static void editMoveEnd(struct State *l) {
- if (l->pos != l->len) {
- l->pos = l->len;
+ if (l->posu8 != l->lenu8) {
+ l->posb = l->lenb;
+ l->posu8 = l->lenu8;
refreshLine(l);
}
}
static void editDelete(struct State *l) {
- if ((l->len > 0) && (l->pos < l->len)) {
- memmove(l->buf + l->pos, l->buf + l->pos + 1, l->len - l->pos - 1);
- l->len--;
- l->buf[l->len] = '\0';
+ if ((l->lenu8 > 0) && (l->posu8 < l->lenu8)) {
+ size_t this_size = u8Next(l->buf, l->posb) - l->posb;
+ bufPosMoveEnd(l, 0, this_size);
+ l->lenb -= this_size;
+ l->lenu8--;
refreshLine(l);
}
}
static void editBackspace(struct State *l) {
- if ((l->pos > 0) && (l->len > 0)) {
- memmove(l->buf + l->pos - 1, l->buf + l->pos, l->len - l->pos);
- l->pos--;
- l->len--;
- l->buf[l->len] = '\0';
+ if ((l->posu8 > 0) && (l->lenu8 > 0)) {
+ size_t prev_size = l->posb - u8Prev(l->buf, l->posb);
+ bufPosMoveEnd(l, (ssize_t)-prev_size, 0);
+ l->posb -= prev_size;
+ l->lenb -= prev_size;
+ l->posu8--;
+ l->lenu8--;
refreshLine(l);
}
}
static void editDeletePrevWord(struct State *l) {
- size_t old_pos = l->pos;
- while ((l->pos > 0) && (l->buf[l->pos - 1] == ' ')) {
- l->pos--;
- }
- while ((l->pos > 0) && (l->buf[l->pos - 1] != ' ')) {
- l->pos--;
+ size_t old_posb = l->posb;
+ size_t old_posu8 = l->posu8;
+ while ((l->posb > 0) && (l->buf[l->posb - 1] == ' ')) {
+ l->posb--;
+ l->posu8--;
+ }
+ while ((l->posb > 0) && (l->buf[l->posb - 1] != ' ')) {
+ if (u8CharStart(l->buf[l->posb - 1])) {
+ l->posu8--;
+ }
+ l->posb--;
}
- size_t diff = old_pos - l->pos;
- memmove(l->buf + l->pos, l->buf + old_pos, l->len - old_pos + 1);
- l->len -= diff;
+ size_t diffb = old_posb - l->posb;
+ size_t diffu8 = old_posu8 - l->posu8;
+ bufPosMoveEnd(l, 0, diffb);
+ l->lenb -= diffb;
+ l->lenu8 -= diffu8;
refreshLine(l);
}
static void editDeleteWholeLine(struct State *l) {
l->buf[0] = '\0';
- l->pos = l->len = 0;
+ l->posb = l->lenb = l->posu8 = l->lenu8 = 0;
refreshLine(l);
}
static void editDeleteLineToEnd(struct State *l) {
- l->buf[l->pos] = '\0';
- l->len = l->pos;
+ l->buf[l->posb] = '\0';
+ l->lenb = l->posb;
+ l->lenu8 = l->posu8;
refreshLine(l);
}
static void editSwapCharWithPrev(struct State *l) {
- if (l->pos > 0 && l->pos < l->len) {
- int aux = l->buf[l->pos - 1];
- l->buf[l->pos - 1] = l->buf[l->pos];
- l->buf[l->pos] = aux;
- if (l->pos != (l->len - 1)) {
- l->pos++;
+ if (l->posu8 > 0 && l->posu8 < l->lenu8) {
+ char aux[8];
+ ssize_t prev_size = l->posb - u8Prev(l->buf, l->posb);
+ ssize_t this_size = u8Next(l->buf, l->posb) - l->posb;
+ memmove(aux, l->buf + l->posb, this_size);
+ bufPosMove(l, -prev_size + this_size, -prev_size, prev_size);
+ memmove(l->buf + l->posb - prev_size, aux, this_size);
+ if (l->posu8 != l->lenu8-1){
+ l->posu8++;
+ l->posb += this_size;
}
refreshLine(l);
}
@@ -345,7 +470,8 @@ static void editHistory(struct State *l, int dir) {
}
strncpy(l->buf, history[history_len - (1 + l->history_index)], l->buflen);
l->buf[l->buflen - 1] = '\0';
- l->len = l->pos = strlen(l->buf);
+ l->lenb = l->posb = strnlen(l->buf, MSG_MAX);
+ l->lenu8 = l->posu8 = u8Len(l->buf);
refreshLine(l);
}
}
@@ -416,11 +542,12 @@ static void editEscSequence(struct State *l, char seq[3]) {
static int edit(struct State *l) {
char c, seq[3];
+ int ret = 0;
ssize_t nread = read(STDIN_FILENO, &c, 1);
if (nread <= 0) {
- return 1;
- }
- switch(c) {
+ ret = 1;
+ } else {
+ switch(c) {
case 13: editEnter(); return 1; /* enter */
case 3: errno = EAGAIN; return -1; /* ctrl-c */
case 127: /* backspace */
@@ -435,26 +562,42 @@ static int edit(struct State *l) {
case 14: editHistory(l, 0); break; /* Ctrl+n */
case 16: editHistory(l, 1); break; /* Ctrl+p */
case 20: editSwapCharWithPrev(l); break; /* ctrl-t */
+ case 27: editEscSequence(l, seq); break; /* escape sequence */
case 4: /* ctrl-d */
- if (l->len > 0) {
+ if (l->lenu8 > 0) {
editDelete(l);
} else {
history_len--;
free(history[history_len]);
- return -1;
+ ret = -1;
}
break;
- case 27: editEscSequence(l, seq); break; /* escape sequence */
- default: if (editInsert(l, c)) return -1; break;
+ default:
+ if (u8CharStart(c)) {
+ char aux[8];
+ aux[0] = c;
+ int size = u8CharSize(c);
+ for (int i = 1; i < size; i++) {
+ nread = read(STDIN_FILENO, aux + i, 1);
+ if ((aux[i] & 0xC0) != 0x80) {
+ break;
+ }
+ }
+ aux[size] = '\0';
+ if (editInsert(l, aux)) {
+ ret = -1;
+ }
+ }
+ break;
+ }
}
- return 0;
+ return ret;
}
static void stateReset(struct State *l) {
- l->plen = strlen(l->prompt);
- l->oldpos = 0;
- l->pos = 0;
- l->len = 0;
+ l->plenb = strnlen(l->prompt, MSG_MAX);
+ l->plenu8 = u8Len(l->prompt);
+ l->oldposb = l->posb = l->oldposu8 = l->posu8 = l->lenb = l->lenu8 = 0;
l->history_index = 0;
l->buf[0] = '\0';
l->buflen--;
@@ -832,6 +975,9 @@ int main(int argc, char **argv) {
if (enableRawMode(STDIN_FILENO) == -1) {
return 1;
}
+ if (setIsu8_C(STDIN_FILENO, STDOUT_FILENO) == -1) {
+ return 1;
+ }
for (;;) {
if (poll(fds, 2, -1) != -1) {
if (fds[0].revents & POLLIN) {