Skip to content

Commit f6b999e

Browse files
Copilotkovidgoyal
andauthored
Implement parse_uri_list() in dnd.c per RFC 2483
Agent-Logs-Url: https://github.com/kovidgoyal/kitty/sessions/06c06ea3-b5d0-4f78-b319-380af08bb139 Co-authored-by: kovidgoyal <1308621+kovidgoyal@users.noreply.github.com>
1 parent aa57cef commit f6b999e

1 file changed

Lines changed: 89 additions & 10 deletions

File tree

kitty/dnd.c

Lines changed: 89 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1476,15 +1476,94 @@ drag_process_item_data(Window *w, size_t idx, int has_more, const uint8_t *paylo
14761476
}
14771477

14781478
static const char**
1479-
parse_uri_list(int fd) {
1480-
(void)fd;
1481-
// TODO: Implement this, it should read the uri list from fd, parse
1482-
// it ignoring comments, see get_nth_file_url() for an example of
1483-
// parsing a uri list. If an error occurs it should call abrt() with
1484-
// appropriate error code and return NULL. The returned value should
1485-
// be a list of strings alloced by malloc with each string also
1486-
// alloced by malloc.
1487-
return NULL;
1479+
parse_uri_list(Window *w, int fd, size_t *num_uris_out) {
1480+
*num_uris_out = 0;
1481+
// Determine file size and read all data
1482+
off_t file_size = lseek(fd, 0, SEEK_END);
1483+
if (file_size < 0) { cancel_drag(w, EIO); return NULL; }
1484+
if (lseek(fd, 0, SEEK_SET) < 0) { cancel_drag(w, EIO); return NULL; }
1485+
char *buf = malloc((size_t)file_size + 1);
1486+
if (!buf) { cancel_drag(w, ENOMEM); return NULL; }
1487+
size_t total = 0;
1488+
while (total < (size_t)file_size) {
1489+
ssize_t n = read(fd, buf + total, (size_t)file_size - total);
1490+
if (n < 0) {
1491+
if (errno == EINTR) continue;
1492+
free(buf); cancel_drag(w, EIO); return NULL;
1493+
}
1494+
if (n == 0) break;
1495+
total += (size_t)n;
1496+
}
1497+
buf[total] = '\0';
1498+
1499+
// First pass: count non-comment, non-empty lines
1500+
size_t count = 0;
1501+
char *p = buf;
1502+
while (*p) {
1503+
char *eol = p + strcspn(p, "\r\n");
1504+
char saved = *eol; *eol = '\0';
1505+
char *end = eol;
1506+
while (end > p && (end[-1] == ' ' || end[-1] == '\t')) end--;
1507+
char saved_end = *end; *end = '\0';
1508+
if (*p && *p != '#') count++;
1509+
*end = saved_end;
1510+
*eol = saved;
1511+
if (saved == '\0') break;
1512+
p = eol + 1;
1513+
while (*p == '\r' || *p == '\n') p++;
1514+
}
1515+
1516+
const char **result = malloc((count + 1) * sizeof(const char*));
1517+
if (!result) { free(buf); cancel_drag(w, ENOMEM); return NULL; }
1518+
1519+
// Second pass: fill in decoded URI strings
1520+
size_t idx = 0;
1521+
p = buf;
1522+
while (*p && idx < count) {
1523+
char *eol = p + strcspn(p, "\r\n");
1524+
char saved = *eol; *eol = '\0';
1525+
char *end = eol;
1526+
while (end > p && (end[-1] == ' ' || end[-1] == '\t')) end--;
1527+
*end = '\0';
1528+
if (*p && *p != '#') {
1529+
char *decoded = NULL;
1530+
if (strncmp(p, "file://", 7) == 0) {
1531+
const char *rest = p + 7;
1532+
const char *slash = strchr(rest, '/');
1533+
if (slash) {
1534+
size_t host_len = (size_t)(slash - rest);
1535+
if (host_len == 0 || (host_len == 9 && strncasecmp(rest, "localhost", 9) == 0)) {
1536+
decoded = strdup(slash);
1537+
if (decoded) {
1538+
char *qf = decoded + strcspn(decoded, "?#");
1539+
*qf = '\0';
1540+
url_decode_inplace(decoded);
1541+
}
1542+
} else {
1543+
decoded = strdup(p);
1544+
}
1545+
} else {
1546+
decoded = strdup(p);
1547+
}
1548+
} else {
1549+
decoded = strdup(p);
1550+
}
1551+
if (!decoded) {
1552+
for (size_t k = 0; k < idx; k++) free((char*)result[k]);
1553+
free(result); free(buf);
1554+
cancel_drag(w, ENOMEM); return NULL;
1555+
}
1556+
result[idx++] = decoded;
1557+
}
1558+
*eol = saved;
1559+
if (saved == '\0') break;
1560+
p = eol + 1;
1561+
while (*p == '\r' || *p == '\n') p++;
1562+
}
1563+
result[idx] = NULL;
1564+
free(buf);
1565+
*num_uris_out = idx;
1566+
return result;
14881567
}
14891568

14901569

@@ -1500,7 +1579,7 @@ drag_remote_file_data(
15001579
}
15011580
if (item_idx == ds.num_mimes || ds.items[item_idx].fd_plus_one == 0) abrt(EINVAL);
15021581
if (ds.items[item_idx].uri_list == NULL) {
1503-
ds.items[item_idx].uri_list = parse_uri_list(ds.items[item_idx].fd_plus_one-1);
1582+
ds.items[item_idx].uri_list = parse_uri_list(w, ds.items[item_idx].fd_plus_one-1, &ds.items[item_idx].num_uris);
15041583
if (!ds.items[item_idx].uri_list) return;
15051584
}
15061585
(void)x; (void)y; (void)X; (void)Y; (void)has_more; (void)payload; (void)payload_sz;

0 commit comments

Comments
 (0)