From 7c2e488ed4c76db3a8ea1207f70537904138a5ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20Techet?= Date: Tue, 5 Mar 2024 23:09:04 +0100 Subject: [PATCH 1/2] geanyctags: fix some warnings --- geanyctags/src/geanyctags.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/geanyctags/src/geanyctags.c b/geanyctags/src/geanyctags.c index 2cea22463..00a5c71ab 100644 --- a/geanyctags/src/geanyctags.c +++ b/geanyctags/src/geanyctags.c @@ -545,7 +545,7 @@ static void create_dialog_find_file(void) size_group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); label = gtk_label_new_with_mnemonic(_("_Search for:")); - gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); + gtk_label_set_xalign(GTK_LABEL(label), 0.0); gtk_size_group_add_widget(size_group, label); s_ft_dialog.combo = gtk_combo_box_text_new_with_entry(); @@ -557,13 +557,13 @@ static void create_dialog_find_file(void) ui_entry_add_clear_icon(GTK_ENTRY(entry)); gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE); - ebox = gtk_hbox_new(FALSE, 6); + ebox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6); gtk_box_pack_start(GTK_BOX(ebox), label, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(ebox), s_ft_dialog.combo, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(vbox), ebox, TRUE, FALSE, 0); label = gtk_label_new_with_mnemonic(_("_Match type:")); - gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); + gtk_label_set_xalign(GTK_LABEL(label), 0.0); gtk_size_group_add_widget(size_group, label); s_ft_dialog.combo_match = gtk_combo_box_text_new(); @@ -573,16 +573,16 @@ static void create_dialog_find_file(void) gtk_combo_box_set_active(GTK_COMBO_BOX(s_ft_dialog.combo_match), 1); gtk_label_set_mnemonic_widget(GTK_LABEL(label), s_ft_dialog.combo_match); - ebox = gtk_hbox_new(FALSE, 6); + ebox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6); gtk_box_pack_start(GTK_BOX(ebox), label, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(ebox), s_ft_dialog.combo_match, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(vbox), ebox, TRUE, FALSE, 0); s_ft_dialog.case_sensitive = gtk_check_button_new_with_mnemonic(_("C_ase sensitive")); - gtk_button_set_focus_on_click(GTK_BUTTON(s_ft_dialog.case_sensitive), FALSE); + gtk_widget_set_focus_on_click(s_ft_dialog.case_sensitive, FALSE); s_ft_dialog.declaration = gtk_check_button_new_with_mnemonic(_("_Declaration")); - gtk_button_set_focus_on_click(GTK_BUTTON(s_ft_dialog.declaration), FALSE); + gtk_widget_set_focus_on_click(s_ft_dialog.declaration, FALSE); g_object_unref(G_OBJECT(size_group)); /* auto destroy the size group */ From f89952d514b2e7a7e8451fddd27ac033c1b140cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20Techet?= Date: Tue, 5 Mar 2024 23:13:42 +0100 Subject: [PATCH 2/2] geanyctags: update the readtags library --- geanyctags/src/readtags.c | 367 ++++++++++++++++++++++++++------------ geanyctags/src/readtags.h | 20 ++- 2 files changed, 275 insertions(+), 112 deletions(-) diff --git a/geanyctags/src/readtags.c b/geanyctags/src/readtags.c index 23f90ee10..45488c36a 100644 --- a/geanyctags/src/readtags.c +++ b/geanyctags/src/readtags.c @@ -32,20 +32,31 @@ typedef struct { char *buffer; } vstring; +/* Define readtags' own off_t. */ +#ifdef _WIN32 +typedef long long rt_off_t; +#else +typedef off_t rt_off_t; +#endif + /* Information about current tag file */ struct sTagFile { /* has the file been opened and this structure initialized? */ - short initialized; + unsigned char initialized; /* format of tag file */ - short format; + unsigned char format; + /* 1 "u-ctags" is set to !_TAG_OUTPUT_MODE pseudo tag + * and "slash" is set to !_TAG_OUTPUT_FILESEP + * pseudo tag in the tags file. */ + unsigned char inputUCtagsMode; /* how is the tag file sorted? */ tagSortType sortMethod; /* pointer to file structure */ FILE* fp; /* file position of first character of `line' */ - off_t pos; + rt_off_t pos; /* size of tag file in seekable positions */ - off_t size; + rt_off_t size; /* last line read */ vstring line; /* name of tag in last line read */ @@ -53,7 +64,7 @@ struct sTagFile { /* defines tag search state */ struct { /* file position of last match for tag */ - off_t pos; + rt_off_t pos; /* name of tag last searched for */ char *name; /* length of name for partial matches */ @@ -97,8 +108,34 @@ static const size_t PseudoTagPrefixLength = 2; * FUNCTION DEFINITIONS */ +static rt_off_t readtags_ftell(FILE *fp) +{ + rt_off_t pos; + +#ifdef _WIN32 + pos = _ftelli64(fp); +#else + pos = ftell(fp); +#endif + + return pos; +} + +static int readtags_fseek(FILE *fp, rt_off_t pos, int whence) +{ + int ret; + +#ifdef _WIN32 + ret = _fseeki64(fp, pos, whence); +#else + ret = fseek(fp, pos, whence); +#endif + + return ret; +} + /* Converts a hexadecimal digit to its value */ -static int xdigitValue (char digit) +static int xdigitValue (unsigned char digit) { if (digit >= '0' && digit <= '9') return digit - '0'; @@ -114,32 +151,33 @@ static int xdigitValue (char digit) * Reads the first character from the string, possibly un-escaping it, and * advances *s to the start of the next character. */ -static int readTagCharacter (const char **s) +static int readTagCharacter (const char **const s) { - int c = **(const unsigned char **)s; + const unsigned char *p = (const unsigned char *) *s; + int c = *p; - (*s)++; + p++; if (c == '\\') { - switch (**s) + switch (*p) { - case 't': c = '\t'; (*s)++; break; - case 'r': c = '\r'; (*s)++; break; - case 'n': c = '\n'; (*s)++; break; - case '\\': c = '\\'; (*s)++; break; + case 't': c = '\t'; p++; break; + case 'r': c = '\r'; p++; break; + case 'n': c = '\n'; p++; break; + case '\\': c = '\\'; p++; break; /* Universal-CTags extensions */ - case 'a': c = '\a'; (*s)++; break; - case 'b': c = '\b'; (*s)++; break; - case 'v': c = '\v'; (*s)++; break; - case 'f': c = '\f'; (*s)++; break; + case 'a': c = '\a'; p++; break; + case 'b': c = '\b'; p++; break; + case 'v': c = '\v'; p++; break; + case 'f': c = '\f'; p++; break; case 'x': - if (isxdigit ((*s)[1]) && isxdigit ((*s)[2])) + if (isxdigit (p[1]) && isxdigit (p[2])) { - int val = (xdigitValue ((*s)[1]) << 4) | xdigitValue ((*s)[2]); + int val = (xdigitValue (p[1]) << 4) | xdigitValue (p[2]); if (val < 0x80) { - (*s) += 3; + p += 3; c = val; } } @@ -147,6 +185,8 @@ static int readTagCharacter (const char **s) } } + *s = (const char *) p; + return c; } @@ -285,7 +325,7 @@ static int readTagLineRaw (tagFile *const file, int *err) char *const pLastChar = file->line.buffer + file->line.size - 2; char *line; - file->pos = ftell (file->fp); + file->pos = readtags_ftell (file->fp); if (file->pos < 0) { *err = errno; @@ -312,7 +352,8 @@ static int readTagLineRaw (tagFile *const file, int *err) *err = ENOMEM; result = 0; } - if (fseek (file->fp, file->pos, SEEK_SET) < 0) + + if (readtags_fseek (file->fp, file->pos, SEEK_SET) < 0) { *err = errno; result = 0; @@ -485,26 +526,15 @@ static unsigned int countContinuousBackslashesBackward(const char *from, return counter; } -static tagResult parseTagLine (tagFile *file, tagEntry *const entry, int *err) +/* When unescaping, the input string becomes shorter. + * e.g. \t occupies two bytes on the tag file. + * It is converted to 0x9 and occupies one byte. + * memmove called here for shortening the line + * buffer. */ +static char *unescapeInPlace (char *q, char **tab, size_t *p_len) { - int i; - char *p = file->line.buffer; - size_t p_len = strlen (p); - char *tab = strchr (p, TAB); - - memset(entry, 0, sizeof(*entry)); - - entry->name = p; - if (tab != NULL) - { - *tab = '\0'; - } + char *p = q; - /* When unescaping, the input string becomes shorter. - * e.g. \t occupies two bytes on the tag file. - * It is converted to 0x9 and occupies one byte. - * memmove called here for shortening the line - * buffer. */ while (*p != '\0') { const char *next = p; @@ -513,21 +543,50 @@ static tagResult parseTagLine (tagFile *file, tagEntry *const entry, int *err) *p = (char) ch; p++; - p_len -= skip; + *p_len -= skip; if (skip > 1) { /* + 1 is for moving the area including the last '\0'. */ - memmove (p, next, p_len + 1); - if (tab) - tab -= skip - 1; + memmove (p, next, *p_len + 1); + if (*tab) + *tab -= skip - 1; } } + return p; +} + +static tagResult parseTagLine (tagFile *file, tagEntry *const entry, int *err) +{ + int i; + char *p = file->line.buffer; + size_t p_len = strlen (p); + char *tab = strchr (p, TAB); + + memset(entry, 0, sizeof(*entry)); + + entry->name = p; + if (tab != NULL) + { + *tab = '\0'; + } + + p = unescapeInPlace (p, &tab, &p_len); + if (tab != NULL) { p = tab + 1; entry->file = p; tab = strchr (p, TAB); + if (file->inputUCtagsMode) + { + if (tab != NULL) + { + *tab = '\0'; + } + p = unescapeInPlace (p, &tab, &p_len); + } + if (tab != NULL) { int fieldsPresent; @@ -554,12 +613,12 @@ static tagResult parseTagLine (tagFile *file, tagEntry *const entry, int *err) else ++p; } - else if (isdigit ((int) *(unsigned char*) p)) + else if (isdigit (*(unsigned char*) p)) { /* parse line number */ entry->address.pattern = p; entry->address.lineNumber = atol (p); - while (isdigit ((int) *(unsigned char*) p)) + while (isdigit (*(unsigned char*) p)) ++p; if (p) { @@ -636,6 +695,8 @@ static tagResult readPseudoTags (tagFile *const file, tagFileInfo *const info) int err = 0; tagResult result = TagSuccess; const size_t prefixLength = strlen (PseudoTagPrefix); + int tag_output_mode_u_ctags = 0; + int tag_output_filesep_slash = 0; info->file.format = 1; info->file.sort = TAG_UNSORTED; @@ -683,7 +744,7 @@ static tagResult readPseudoTags (tagFile *const file, tagFileInfo *const info) err = TagErrnoUnexpectedFormat; break; } - file->format = (short) m; + file->format = (unsigned char) m; } else if (strcmp (key, "TAG_PROGRAM_AUTHOR") == 0) { @@ -721,6 +782,16 @@ static tagResult readPseudoTags (tagFile *const file, tagFileInfo *const info) break; } } + else if (strcmp (key, "TAG_OUTPUT_MODE") == 0) + { + if (strcmp (value, "u-ctags") == 0) + tag_output_mode_u_ctags = 1; + } + else if (strcmp (key, "TAG_OUTPUT_FILESEP") == 0) + { + if (strcmp (value, "slash") == 0) + tag_output_filesep_slash = 1; + } info->file.format = file->format; info->file.sort = file->sortMethod; @@ -730,6 +801,10 @@ static tagResult readPseudoTags (tagFile *const file, tagFileInfo *const info) info->program.version = file->program.version; } } + + if (tag_output_mode_u_ctags && tag_output_filesep_slash) + file->inputUCtagsMode = 1; + if (fsetpos (file->fp, &startOfLine) < 0) err = errno; @@ -748,7 +823,7 @@ static tagResult gotoFirstLogicalTag (tagFile *const file) { fpos_t startOfLine; - if (fseek(file->fp, 0L, SEEK_SET) == -1) + if (readtags_fseek(file->fp, 0, SEEK_SET) == -1) { file->err = errno; return TagFailure; @@ -798,37 +873,55 @@ static tagFile *initialize (const char *const filePath, tagFileInfo *const info) result->fields.max, sizeof (tagExtensionField)); if (result->fields.list == NULL) goto mem_error; - result->fp = fopen (filePath, "rb"); + +#if defined(__GLIBC__) && (__GLIBC__ >= 2) \ + && defined(__GLIBC_MINOR__) && (__GLIBC_MINOR__ >= 3) + result->fp = fopen (filePath, "rbm"); +#endif + if (result->fp == NULL) + { + errno = 0; + result->fp = fopen (filePath, "rb"); + } if (result->fp == NULL) { info->status.error_number = errno; goto file_error; } - else - { - if (fseek (result->fp, 0, SEEK_END) == -1) - { - info->status.error_number = errno; - goto file_error; - } - result->size = ftell (result->fp); - if (result->size == -1) - { - info->status.error_number = errno; - goto file_error; - } - if (fseek(result->fp, 0L, SEEK_SET) == -1) - { - info->status.error_number = errno; - goto file_error; - } - if (readPseudoTags (result, info) == TagFailure) - goto file_error; + /* Record the size of the tags file to `size` field of result. */ + if (readtags_fseek (result->fp, 0, SEEK_END) == -1) + { + info->status.error_number = errno; + goto file_error; + } + result->size = readtags_ftell (result->fp); + if (result->size == -1) + { + /* fseek() retruns an int value. + * We observed following behavior on Windows; + * if sizeof(int) of the platform is too small for + * representing the size of the tags file, fseek() + * returns -1 and it doesn't set errno. + */ + info->status.error_number = errno; + if (info->status.error_number == 0) + info->status.error_number = TagErrnoFileMaybeTooBig; - info->status.opened = 1; - result->initialized = 1; + goto file_error; + } + if (readtags_fseek(result->fp, 0, SEEK_SET) == -1) + { + info->status.error_number = errno; + goto file_error; } + + if (readPseudoTags (result, info) == TagFailure) + goto file_error; + + info->status.opened = 1; + result->initialized = 1; + return result; mem_error: info->status.error_number = ENOMEM; @@ -870,19 +963,23 @@ static void terminate (tagFile *const file) static tagResult readNext (tagFile *const file, tagEntry *const entry) { tagResult result; - if (file == NULL || ! file->initialized) + + if (file == NULL) + return TagFailure; + + if (! file->initialized) { file->err = TagErrnoInvalidArgument; - result = TagFailure; - } - else if (! readTagLine (file, &file->err)) - result = TagFailure; - else - { - result = (entry != NULL) - ? parseTagLine (file, entry, &file->err) - : TagSuccess; + return TagFailure; } + + if (! readTagLine (file, &file->err)) + return TagFailure; + + result = (entry != NULL) + ? parseTagLine (file, entry, &file->err) + : TagSuccess; + return result; } @@ -901,9 +998,9 @@ static const char *readFieldValue ( return result; } -static int readTagLineSeek (tagFile *const file, const off_t pos) +static int readTagLineSeek (tagFile *const file, const rt_off_t pos) { - if (fseek (file->fp, pos, SEEK_SET) < 0) + if (readtags_fseek (file->fp, pos, SEEK_SET) < 0) { file->err = errno; return 0; @@ -947,11 +1044,11 @@ static tagResult findFirstNonMatchBefore (tagFile *const file) #define JUMP_BACK 512 int more_lines; int comp; - off_t start = file->pos; - off_t pos = start; + rt_off_t start = file->pos; + rt_off_t pos = start; do { - if (pos < (off_t) JUMP_BACK) + if (pos < (rt_off_t) JUMP_BACK) pos = 0; else pos = pos - JUMP_BACK; @@ -967,7 +1064,7 @@ static tagResult findFirstMatchBefore (tagFile *const file) { tagResult result = TagFailure; int more_lines; - off_t start = file->pos; + rt_off_t start = file->pos; if (findFirstNonMatchBefore (file) != TagSuccess) return TagFailure; do @@ -984,10 +1081,10 @@ static tagResult findFirstMatchBefore (tagFile *const file) static tagResult findBinary (tagFile *const file) { tagResult result = TagFailure; - off_t lower_limit = 0; - off_t upper_limit = file->size; - off_t last_pos = 0; - off_t pos = upper_limit / 2; + rt_off_t lower_limit = 0; + rt_off_t upper_limit = file->size; + rt_off_t last_pos = 0; + rt_off_t pos = upper_limit / 2; while (result != TagSuccess) { if (! readTagLineSeek (file, pos)) @@ -1034,7 +1131,10 @@ static tagResult findSequentialFull (tagFile *const file, int (* isAcceptable) (tagFile *const, void *), void *data) { - if (file == NULL || !file->initialized || file->err) + if (file == NULL) + return TagFailure; + + if (!file->initialized || file->err) { file->err = TagErrnoInvalidArgument; return TagFailure; @@ -1076,18 +1176,18 @@ static tagResult find (tagFile *const file, tagEntry *const entry, file->search.nameLength = strlen (name); file->search.partial = (options & TAG_PARTIALMATCH) != 0; file->search.ignorecase = (options & TAG_IGNORECASE) != 0; - if (fseek (file->fp, 0, SEEK_END) < 0) + if (readtags_fseek (file->fp, 0, SEEK_END) < 0) { file->err = errno; return TagFailure; } - file->size = ftell (file->fp); + file->size = readtags_ftell (file->fp); if (file->size == -1) { file->err = errno; return TagFailure; } - if (fseek(file->fp, 0L, SEEK_SET) == -1) + if (readtags_fseek(file->fp, 0, SEEK_SET) == -1) { file->err = errno; return TagFailure; @@ -1095,18 +1195,12 @@ static tagResult find (tagFile *const file, tagEntry *const entry, if ((file->sortMethod == TAG_SORTED && !file->search.ignorecase) || (file->sortMethod == TAG_FOLDSORTED && file->search.ignorecase)) { -#ifdef DEBUG - fputs ("\n", stderr); -#endif result = findBinary (file); if (result == TagFailure && file->err) return TagFailure; } else { -#ifdef DEBUG - fputs ("\n", stderr); -#endif result = findSequential (file); if (result == TagFailure && file->err) return TagFailure; @@ -1155,15 +1249,18 @@ static tagResult findNext (tagFile *const file, tagEntry *const entry) static tagResult findPseudoTag (tagFile *const file, int rewindBeforeFinding, tagEntry *const entry) { - if (file == NULL || (!file->initialized) || file->err) + if (file == NULL) + return TagFailure; + + if (!file->initialized || file->err) { - file->err= TagErrnoInvalidArgument;; + file->err = TagErrnoInvalidArgument; return TagFailure; } if (rewindBeforeFinding) { - if (fseek(file->fp, 0L, SEEK_SET) == -1) + if (readtags_fseek(file->fp, 0, SEEK_SET) == -1) { file->err = errno; return TagFailure; @@ -1188,7 +1285,10 @@ extern tagFile *tagsOpen (const char *const filePath, tagFileInfo *const info) extern tagResult tagsSetSortType (tagFile *const file, const tagSortType type) { - if (file == NULL || (!file->initialized) || file->err) + if (file == NULL) + return TagFailure; + + if (!file->initialized || file->err) { file->err = TagErrnoInvalidArgument; return TagFailure; @@ -1209,7 +1309,10 @@ extern tagResult tagsSetSortType (tagFile *const file, const tagSortType type) extern tagResult tagsFirst (tagFile *const file, tagEntry *const entry) { - if (file == NULL || (!file->initialized) || file->err) + if (file == NULL) + return TagFailure; + + if (!file->initialized || file->err) { file->err = TagErrnoInvalidArgument; return TagFailure; @@ -1222,7 +1325,10 @@ extern tagResult tagsFirst (tagFile *const file, tagEntry *const entry) extern tagResult tagsNext (tagFile *const file, tagEntry *const entry) { - if (file == NULL || (!file->initialized) || file->err) + if (file == NULL) + return TagFailure; + + if (!file->initialized || file->err) { file->err = TagErrnoInvalidArgument; return TagFailure; @@ -1242,21 +1348,29 @@ extern const char *tagsField (const tagEntry *const entry, const char *const key extern tagResult tagsFind (tagFile *const file, tagEntry *const entry, const char *const name, const int options) { - if (file == NULL || !file->initialized || file->err) + if (file == NULL) + return TagFailure; + + if (!file->initialized || file->err) { file->err = TagErrnoInvalidArgument; return TagFailure; } + return find (file, entry, name, options); } extern tagResult tagsFindNext (tagFile *const file, tagEntry *const entry) { - if (file == NULL || !file->initialized || file->err) + if (file == NULL) + return TagFailure; + + if (!file->initialized || file->err) { file->err = TagErrnoInvalidArgument; return TagFailure; } + return findNext (file, entry); } @@ -1270,6 +1384,39 @@ extern tagResult tagsNextPseudoTag (tagFile *const file, tagEntry *const entry) return findPseudoTag (file, 0, entry); } +extern tagResult tagsFindPseudoTag (tagFile *const file, tagEntry *const entry, + const char *const name, const int match) +{ + size_t len; + tagEntry entry0; + tagEntry *entryp = entry? entry: &entry0; + + tagResult r = tagsFirstPseudoTag (file, entryp); + if (r != TagSuccess) + return r; + + if (match & TAG_PARTIALMATCH) + len = strlen (name); + + do + { + if (match & TAG_PARTIALMATCH) + { + if (strncmp (entryp->name, name, len) == 0) + return TagSuccess; + } + else + { + if (strcmp (entryp->name, name) == 0) + return TagSuccess; + } + r = tagsNextPseudoTag (file, entryp); + } + while (r == TagSuccess); + + return r; +} + extern tagResult tagsClose (tagFile *const file) { tagResult result = TagFailure; diff --git a/geanyctags/src/readtags.h b/geanyctags/src/readtags.h index 866f4b049..b936fcfcc 100644 --- a/geanyctags/src/readtags.h +++ b/geanyctags/src/readtags.h @@ -39,7 +39,7 @@ typedef enum { #define sortType tagSortType #endif -/* Options for tagsFind() */ +/* Options for tagsFind() and tagsFindPseudoTag() */ #define TAG_FULLMATCH 0x0 #define TAG_PARTIALMATCH 0x1 @@ -59,6 +59,7 @@ typedef enum { * (Zero or a positive integer is expected.) */ TagErrnoInvalidArgument = -4, /* Unexpected argument passed to the API * function */ + TagErrnoFileMaybeTooBig = -5, /* Maybe the tags file is too big */ } tagErrno; struct sTagFile; @@ -258,7 +259,7 @@ extern tagResult tagsFindNext (tagFile *const file, tagEntry *const entry); /* * Does the same as tagsFirst(), but is specialized to pseudo tags. -* If tagFileInfo doesn't contain pseudo tags you are interested, read +* If tagFileInfo doesn't contain pseudo tags you are interested in, read * them sequentially with this function and tagsNextPseudoTag(). */ extern tagResult tagsFirstPseudoTag (tagFile *const file, tagEntry *const entry); @@ -269,6 +270,21 @@ extern tagResult tagsFirstPseudoTag (tagFile *const file, tagEntry *const entry) */ extern tagResult tagsNextPseudoTag (tagFile *const file, tagEntry *const entry); +/* +* Does the same as tagsFind(), but is specialized to pseudo tags. +* The available values for `match' are: +* +* TAG_PARTIALMATCH +* Tags whose leading characters match `name' will qualify. +* +* TAG_FULLMATCH +* Only tags whose full lengths match `name' will qualify. +* +* NOTE: unlike tagsFind(), this function uses liner-searching even if +* the tags file is sorted. +*/ +extern tagResult tagsFindPseudoTag (tagFile *const file, tagEntry *const entry, const char *const name, const int match); + /* * Call tagsClose() at completion of reading the tag file, which will * close the file and free any internal memory allocated. The function will