Read from template files with placeholder replacement
This commit is contained in:
parent
329dedc33b
commit
5b6f8e5083
7 changed files with 287 additions and 109 deletions
137
.clang-format
Normal file
137
.clang-format
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
---
|
||||||
|
Language: Cpp
|
||||||
|
# BasedOnStyle: Mozilla
|
||||||
|
AccessModifierOffset: -2
|
||||||
|
AlignAfterOpenBracket: Align
|
||||||
|
AlignConsecutiveMacros: false
|
||||||
|
AlignConsecutiveAssignments: false
|
||||||
|
AlignConsecutiveDeclarations: false
|
||||||
|
AlignEscapedNewlines: Right
|
||||||
|
AlignOperands: true
|
||||||
|
AlignTrailingComments: true
|
||||||
|
AllowAllArgumentsOnNextLine: true
|
||||||
|
AllowAllConstructorInitializersOnNextLine: true
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: false
|
||||||
|
AllowShortBlocksOnASingleLine: Never
|
||||||
|
AllowShortCaseLabelsOnASingleLine: false
|
||||||
|
AllowShortFunctionsOnASingleLine: Inline
|
||||||
|
AllowShortLambdasOnASingleLine: All
|
||||||
|
AllowShortIfStatementsOnASingleLine: Never
|
||||||
|
AllowShortLoopsOnASingleLine: false
|
||||||
|
AlwaysBreakAfterDefinitionReturnType: TopLevel
|
||||||
|
AlwaysBreakAfterReturnType: TopLevel
|
||||||
|
AlwaysBreakBeforeMultilineStrings: false
|
||||||
|
AlwaysBreakTemplateDeclarations: Yes
|
||||||
|
BinPackArguments: false
|
||||||
|
BinPackParameters: false
|
||||||
|
BraceWrapping:
|
||||||
|
AfterCaseLabel: false
|
||||||
|
AfterClass: true
|
||||||
|
AfterControlStatement: false
|
||||||
|
AfterEnum: true
|
||||||
|
AfterFunction: true
|
||||||
|
AfterNamespace: false
|
||||||
|
AfterObjCDeclaration: false
|
||||||
|
AfterStruct: true
|
||||||
|
AfterUnion: true
|
||||||
|
AfterExternBlock: true
|
||||||
|
BeforeCatch: false
|
||||||
|
BeforeElse: false
|
||||||
|
IndentBraces: false
|
||||||
|
SplitEmptyFunction: true
|
||||||
|
SplitEmptyRecord: false
|
||||||
|
SplitEmptyNamespace: true
|
||||||
|
BreakBeforeBinaryOperators: None
|
||||||
|
BreakBeforeBraces: Mozilla
|
||||||
|
BreakBeforeInheritanceComma: false
|
||||||
|
BreakInheritanceList: BeforeComma
|
||||||
|
BreakBeforeTernaryOperators: true
|
||||||
|
BreakConstructorInitializersBeforeComma: false
|
||||||
|
BreakConstructorInitializers: BeforeComma
|
||||||
|
BreakAfterJavaFieldAnnotations: false
|
||||||
|
BreakStringLiterals: true
|
||||||
|
ColumnLimit: 80
|
||||||
|
CommentPragmas: '^ IWYU pragma:'
|
||||||
|
CompactNamespaces: false
|
||||||
|
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||||
|
ConstructorInitializerIndentWidth: 2
|
||||||
|
ContinuationIndentWidth: 2
|
||||||
|
Cpp11BracedListStyle: false
|
||||||
|
DeriveLineEnding: true
|
||||||
|
DerivePointerAlignment: false
|
||||||
|
DisableFormat: false
|
||||||
|
ExperimentalAutoDetectBinPacking: false
|
||||||
|
FixNamespaceComments: false
|
||||||
|
ForEachMacros:
|
||||||
|
- foreach
|
||||||
|
- Q_FOREACH
|
||||||
|
- BOOST_FOREACH
|
||||||
|
IncludeBlocks: Preserve
|
||||||
|
IncludeCategories:
|
||||||
|
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
|
||||||
|
Priority: 2
|
||||||
|
SortPriority: 0
|
||||||
|
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
|
||||||
|
Priority: 3
|
||||||
|
SortPriority: 0
|
||||||
|
- Regex: '.*'
|
||||||
|
Priority: 1
|
||||||
|
SortPriority: 0
|
||||||
|
IncludeIsMainRegex: '(Test)?$'
|
||||||
|
IncludeIsMainSourceRegex: ''
|
||||||
|
IndentCaseLabels: true
|
||||||
|
IndentGotoLabels: true
|
||||||
|
IndentPPDirectives: None
|
||||||
|
IndentWidth: 2
|
||||||
|
IndentWrappedFunctionNames: false
|
||||||
|
JavaScriptQuotes: Leave
|
||||||
|
JavaScriptWrapImports: true
|
||||||
|
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||||
|
MacroBlockBegin: ''
|
||||||
|
MacroBlockEnd: ''
|
||||||
|
MaxEmptyLinesToKeep: 1
|
||||||
|
NamespaceIndentation: None
|
||||||
|
ObjCBinPackProtocolList: Auto
|
||||||
|
ObjCBlockIndentWidth: 2
|
||||||
|
ObjCSpaceAfterProperty: true
|
||||||
|
ObjCSpaceBeforeProtocolList: false
|
||||||
|
PenaltyBreakAssignment: 2
|
||||||
|
PenaltyBreakBeforeFirstCallParameter: 19
|
||||||
|
PenaltyBreakComment: 300
|
||||||
|
PenaltyBreakFirstLessLess: 120
|
||||||
|
PenaltyBreakString: 1000
|
||||||
|
PenaltyBreakTemplateDeclaration: 10
|
||||||
|
PenaltyExcessCharacter: 1000000
|
||||||
|
PenaltyReturnTypeOnItsOwnLine: 200
|
||||||
|
PointerAlignment: Left
|
||||||
|
ReflowComments: true
|
||||||
|
SortIncludes: true
|
||||||
|
SortUsingDeclarations: true
|
||||||
|
SpaceAfterCStyleCast: false
|
||||||
|
SpaceAfterLogicalNot: false
|
||||||
|
SpaceAfterTemplateKeyword: false
|
||||||
|
SpaceBeforeAssignmentOperators: true
|
||||||
|
SpaceBeforeCpp11BracedList: false
|
||||||
|
SpaceBeforeCtorInitializerColon: true
|
||||||
|
SpaceBeforeInheritanceColon: true
|
||||||
|
SpaceBeforeParens: ControlStatements
|
||||||
|
SpaceBeforeRangeBasedForLoopColon: true
|
||||||
|
SpaceInEmptyBlock: false
|
||||||
|
SpaceInEmptyParentheses: false
|
||||||
|
SpacesBeforeTrailingComments: 1
|
||||||
|
SpacesInAngles: false
|
||||||
|
SpacesInConditionalStatement: false
|
||||||
|
SpacesInContainerLiterals: true
|
||||||
|
SpacesInCStyleCastParentheses: false
|
||||||
|
SpacesInParentheses: false
|
||||||
|
SpacesInSquareBrackets: false
|
||||||
|
SpaceBeforeSquareBrackets: false
|
||||||
|
Standard: Latest
|
||||||
|
StatementMacros:
|
||||||
|
- Q_UNUSED
|
||||||
|
- QT_REQUIRE_VERSION
|
||||||
|
TabWidth: 8
|
||||||
|
UseCRLF: false
|
||||||
|
UseTab: Never
|
||||||
|
...
|
||||||
|
|
|
@ -12,7 +12,7 @@ steps:
|
||||||
image: debian
|
image: debian
|
||||||
commands:
|
commands:
|
||||||
- cp quark /usr/local/bin
|
- cp quark /usr/local/bin
|
||||||
- useradd web && su web && cd
|
- useradd web
|
||||||
- mkdir -p web && cd web && echo "hello from quark" > index.html
|
- mkdir -p web && cd web && echo "hello from quark" > index.html
|
||||||
- quark -p 9130 -h run -l -u web -g web
|
- quark -p 9130 -h run -l -u web -g web
|
||||||
detach: true
|
detach: true
|
||||||
|
|
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
*.o
|
||||||
|
.gdb_history
|
||||||
|
config.h
|
||||||
|
quark
|
|
@ -1,9 +1,5 @@
|
||||||
#define HEADER_MAX 4096
|
#define HEADER_MAX 4096
|
||||||
#define FIELD_MAX 200
|
#define FIELD_MAX 200
|
||||||
#define DIRL_HEADER "header.qhtml"
|
|
||||||
#define DIRL_ENTRY "entry.qhtml"
|
|
||||||
#define DIRL_FOOTER "footer.qhtml"
|
|
||||||
#define DIRL_STYLE "dirlist.css"
|
|
||||||
|
|
||||||
/* mime-types */
|
/* mime-types */
|
||||||
static const struct {
|
static const struct {
|
||||||
|
|
215
dirl.c
215
dirl.c
|
@ -8,12 +8,14 @@
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
#include "dirl.h"
|
#include "dirl.h"
|
||||||
#include "http.h"
|
#include "http.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
static char *suffix(int t) {
|
static char*
|
||||||
|
suffix(int t)
|
||||||
|
{
|
||||||
switch (t) {
|
switch (t) {
|
||||||
case DT_FIFO:
|
case DT_FIFO:
|
||||||
return "|";
|
return "|";
|
||||||
|
@ -28,17 +30,84 @@ static char *suffix(int t) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
enum status
|
static char*
|
||||||
dirl_header_default(int fd, const struct response *res) {
|
dirl_read_template(char* tpl)
|
||||||
|
{
|
||||||
|
/* Try find template in root (note that we are chroot'ed) */
|
||||||
|
FILE* tpl_fp;
|
||||||
|
char* tpl_abs;
|
||||||
|
|
||||||
|
tpl_abs = calloc(strlen(tpl)+2, sizeof(char));
|
||||||
|
if(tpl_abs == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
tpl_abs[0] = '/';
|
||||||
|
strcat(tpl_abs, tpl);
|
||||||
|
|
||||||
|
if (!(tpl_fp = fopen(tpl_abs, "r"))) {
|
||||||
|
free(tpl_abs);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(tpl_abs);
|
||||||
|
|
||||||
|
/* Get size of template */
|
||||||
|
if (fseek(tpl_fp, 0L, SEEK_END) < 0) {
|
||||||
|
fclose(tpl_fp);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
long tpl_size;
|
||||||
|
if ((tpl_size = ftell(tpl_fp)) < 0) {
|
||||||
|
fclose(tpl_fp);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
rewind(tpl_fp);
|
||||||
|
|
||||||
|
/* Read template into tpl_buf */
|
||||||
|
char* tpl_buf = (char*)malloc(sizeof(char) * tpl_size);
|
||||||
|
|
||||||
|
if (tpl_buf == NULL) {
|
||||||
|
fclose(tpl_fp);
|
||||||
|
free(tpl_buf);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fread(tpl_buf, 1, tpl_size, tpl_fp) < tpl_size) {
|
||||||
|
if (feof(tpl_fp)) {
|
||||||
|
warn("Reached end of template %s prematurely", tpl);
|
||||||
|
} else if (ferror(tpl_fp)) {
|
||||||
|
warn("Error while reading template %s", tpl);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(tpl_fp);
|
||||||
|
free(tpl_buf);
|
||||||
|
clearerr(tpl_fp);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return tpl_buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum status
|
||||||
|
dirl_header_default(int fd, const struct response* res)
|
||||||
|
{
|
||||||
char esc[PATH_MAX];
|
char esc[PATH_MAX];
|
||||||
html_escape(res->uri, esc, sizeof(esc));
|
html_escape(res->uri, esc, sizeof(esc));
|
||||||
if (dprintf(fd,
|
if (dprintf(fd,
|
||||||
"<!DOCTYPE html>\n<html>\n\t<head>"
|
"<!DOCTYPE html>\n"
|
||||||
"<title>Index of %s</title></head>\n"
|
"<html>\n"
|
||||||
"\t<body>\n"
|
" <head>\n"
|
||||||
"\t\t<h1>Index of %s</h1>\n"
|
" <link rel=\"stylesheet\" href=\"/"DIRL_STYLE"\">\n"
|
||||||
"\t\t\t<a href=\"..\">..</a>",
|
" <title>Index of %s</title>\n"
|
||||||
esc, esc) < 0) {
|
" </head>\n"
|
||||||
|
" <body>\n"
|
||||||
|
" <h1>Index of %s</h1>\n"
|
||||||
|
" <a href=\"..\">..</a>",
|
||||||
|
esc,
|
||||||
|
esc) < 0) {
|
||||||
return S_REQUEST_TIMEOUT;
|
return S_REQUEST_TIMEOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,43 +117,19 @@ dirl_header_default(int fd, const struct response *res) {
|
||||||
enum status
|
enum status
|
||||||
dirl_header(int fd, const struct response* res)
|
dirl_header(int fd, const struct response* res)
|
||||||
{
|
{
|
||||||
|
char* tpl = dirl_read_template(DIRL_HEADER);
|
||||||
|
|
||||||
/* No header file defined, default */
|
if(tpl == NULL) {
|
||||||
#ifndef DIRL_HEADER
|
|
||||||
return dirl_header_default(fd, res);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Try find header in root (note that we are chroot'ed) */
|
|
||||||
int header_fd;
|
|
||||||
if ( (header_fd = open(("/" DIRL_HEADER), O_RDONLY)) < 0 ) {
|
|
||||||
return dirl_header_default(fd, res);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get size of header */
|
|
||||||
struct stat header_stat;
|
|
||||||
if (fstat(header_fd, &header_stat) < 0) {
|
|
||||||
return dirl_header_default(fd, res);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Allocate space for file */
|
|
||||||
char *header = (char *) malloc(sizeof(char) * header_stat.st_size);
|
|
||||||
if (header == NULL) {
|
|
||||||
return dirl_header_default(fd, res);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read header into string for template replacement */
|
|
||||||
if ( (read(header_fd, header, header_stat.st_size)) < 0) {
|
|
||||||
free(header);
|
|
||||||
return dirl_header_default(fd, res);
|
return dirl_header_default(fd, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Replace placeholder */
|
/* Replace placeholder */
|
||||||
char *nhead = replace(header, "{idx}", "something");
|
char* nhead = replace(tpl, "{idx}", "something");
|
||||||
|
|
||||||
/* Write header */
|
/* Write header */
|
||||||
write(fd, nhead, strlen(nhead));
|
write(fd, nhead, strlen(nhead));
|
||||||
|
|
||||||
free(header);
|
free(tpl);
|
||||||
free(nhead);
|
free(nhead);
|
||||||
|
|
||||||
/* listing header */
|
/* listing header */
|
||||||
|
@ -92,12 +137,16 @@ dirl_header(int fd, const struct response *res)
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum status
|
static enum status
|
||||||
dirl_entry_default(int fd, const struct dirent* entry) {
|
dirl_entry_default(int fd, const struct dirent* entry)
|
||||||
|
{
|
||||||
char esc[PATH_MAX];
|
char esc[PATH_MAX];
|
||||||
|
|
||||||
html_escape(entry->d_name, esc, sizeof(esc));
|
html_escape(entry->d_name, esc, sizeof(esc));
|
||||||
if (dprintf(fd, "<br />\n\t\t<a href=\"%s%s\">%s%s</a>", esc,
|
if (dprintf(fd,
|
||||||
(entry->d_type == DT_DIR) ? "/" : "", esc,
|
"<br />\n\t\t<a href=\"%s%s\">%s%s</a>",
|
||||||
|
esc,
|
||||||
|
(entry->d_type == DT_DIR) ? "/" : "",
|
||||||
|
esc,
|
||||||
suffix(entry->d_type)) < 0) {
|
suffix(entry->d_type)) < 0) {
|
||||||
return S_REQUEST_TIMEOUT;
|
return S_REQUEST_TIMEOUT;
|
||||||
}
|
}
|
||||||
|
@ -106,30 +155,33 @@ dirl_entry_default(int fd, const struct dirent* entry) {
|
||||||
}
|
}
|
||||||
|
|
||||||
enum status
|
enum status
|
||||||
dirl_entry(int fd, const struct dirent* entry) {
|
dirl_entry(int fd, const struct dirent* entry)
|
||||||
/* Try find entry in root (note that we are chroot'ed) */
|
{
|
||||||
int entry_fd;
|
char* tpl = dirl_read_template(DIRL_ENTRY);
|
||||||
if ((entry_fd = open(("/" DIRL_ENTRY), O_RDONLY)) < 0) {
|
|
||||||
|
if (tpl == NULL) {
|
||||||
return dirl_entry_default(fd, entry);
|
return dirl_entry_default(fd, entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get size of entry*/
|
/* Replace placeholder */
|
||||||
struct stat entry_stat;
|
char* nentry = replace(tpl, "{entry}", entry->d_name);
|
||||||
if (fstat(entry_fd, &entry_stat) < 0) {
|
|
||||||
return dirl_entry_default(fd, entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Write entry */
|
/* Write entry */
|
||||||
if (sendfile(fd, entry_fd, NULL, entry_stat.st_size) < 0) {
|
write(fd, nentry, strlen(nentry));
|
||||||
return dirl_entry_default(fd, entry);
|
|
||||||
}
|
free(tpl);
|
||||||
|
free(nentry);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum status
|
static enum status
|
||||||
dirl_footer_default(int fd) {
|
dirl_footer_default(int fd)
|
||||||
if (dprintf(fd, "\n\t</body>\n</html>\n") < 0) {
|
{
|
||||||
|
if (dprintf(fd,
|
||||||
|
"\n"
|
||||||
|
" </body>\n"
|
||||||
|
"</html>") < 0) {
|
||||||
return S_REQUEST_TIMEOUT;
|
return S_REQUEST_TIMEOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,49 +189,32 @@ dirl_footer_default(int fd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
enum status
|
enum status
|
||||||
dirl_footer(int fd) {
|
dirl_footer(int fd)
|
||||||
/* Try find footer in root (note that we are chroot'ed) */
|
{
|
||||||
int footer_fd;
|
char* tpl = dirl_read_template(DIRL_FOOTER);
|
||||||
if ((footer_fd = open(("/" DIRL_FOOTER), O_RDONLY)) < 0) {
|
|
||||||
|
if(tpl == NULL) {
|
||||||
return dirl_footer_default(fd);
|
return dirl_footer_default(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get size of footer */
|
/* Replace placeholder */
|
||||||
struct stat footer_stat;
|
char* nfoot = replace(tpl, "{idx}", "something");
|
||||||
if (fstat(footer_fd, &footer_stat) < 0) {
|
|
||||||
return dirl_footer_default(fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Write footer */
|
/* Write footer */
|
||||||
if (sendfile(fd, footer_fd, NULL, footer_stat.st_size) < 0) {
|
write(fd, nfoot, strlen(nfoot));
|
||||||
return dirl_footer_default(fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
free(tpl);
|
||||||
|
free(nfoot);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int dirl_skip(const char *name) {
|
int
|
||||||
(void) name;
|
dirl_skip(const char* name)
|
||||||
#ifdef DIRL_HEADER
|
{
|
||||||
if(!strcmp(name, DIRL_HEADER)) {
|
(void)name; // noop; avoid unused warning
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#ifdef DIRL_ENTRY
|
|
||||||
if (!strcmp(name, DIRL_ENTRY)) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#ifdef DIRL_FOOTER
|
|
||||||
if (!strcmp(name, DIRL_FOOTER)) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#ifdef DIRL_STYLE
|
|
||||||
if (!strcmp(name, DIRL_STYLE)) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return 0;
|
return !strcmp(name, DIRL_HEADER) //
|
||||||
|
|| !strcmp(name, DIRL_ENTRY) //
|
||||||
|
|| !strcmp(name, DIRL_FOOTER) //
|
||||||
|
|| !strcmp(name, DIRL_STYLE);
|
||||||
}
|
}
|
||||||
|
|
6
dirl.h
6
dirl.h
|
@ -8,6 +8,11 @@
|
||||||
|
|
||||||
#include "http.h"
|
#include "http.h"
|
||||||
|
|
||||||
|
#define DIRL_HEADER ".header.tpl"
|
||||||
|
#define DIRL_ENTRY ".entry.tpl"
|
||||||
|
#define DIRL_FOOTER ".footer.tpl"
|
||||||
|
#define DIRL_STYLE "style.css"
|
||||||
|
|
||||||
struct dirl_env_entry {
|
struct dirl_env_entry {
|
||||||
char *name;
|
char *name;
|
||||||
char *value;
|
char *value;
|
||||||
|
@ -22,6 +27,7 @@ struct dirl_env {
|
||||||
* meaning. Skips header-, entry-, footer templates and dirlist style css.
|
* meaning. Skips header-, entry-, footer templates and dirlist style css.
|
||||||
*/
|
*/
|
||||||
int dirl_skip(const char*);
|
int dirl_skip(const char*);
|
||||||
|
|
||||||
enum status dirl_header(int, const struct response*);
|
enum status dirl_header(int, const struct response*);
|
||||||
enum status dirl_entry(int, const struct dirent*);
|
enum status dirl_entry(int, const struct dirent*);
|
||||||
enum status dirl_footer(int);
|
enum status dirl_footer(int);
|
||||||
|
|
2
util.c
2
util.c
|
@ -199,7 +199,7 @@ replace(const char *src, const char *old, const char* new) {
|
||||||
srcidx = srcidx_old+old_len;
|
srcidx = srcidx_old+old_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
strcpy(bufidx, srcidx); // copy tail
|
strncpy(bufidx, srcidx, strlen(srcidx)); // copy tail
|
||||||
|
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue