+
+/* get_line_from_file() - This function reads an entire line from a text file
+ * up to a newline. It returns a malloc'ed char * which must be stored and
+ * free'ed by the caller. */
+extern char *get_line_from_file(FILE *file)
+{
+ static const int GROWBY = 80; /* how large we will grow strings by */
+
+ int ch;
+ int idx = 0;
+ char *linebuf = NULL;
+ int linebufsz = 0;
+
+ while (1) {
+ ch = fgetc(file);
+ if (ch == EOF)
+ break;
+ /* grow the line buffer as necessary */
+ while (idx > linebufsz-2)
+ linebuf = xrealloc(linebuf, linebufsz += GROWBY);
+ linebuf[idx++] = (char)ch;
+ if ((char)ch == '\n')
+ break;
+ }
+
+ if (idx == 0)
+ return NULL;
+
+ linebuf[idx] = 0;
+ return linebuf;
+}
+
+#if defined BB_CAT
+extern void print_file(FILE *file)
+{
+ int c;
+
+ while ((c = getc(file)) != EOF)
+ putc(c, stdout);
+ fclose(file);
+ fflush(stdout);
+}
+
+extern int print_file_by_name(char *filename)
+{
+ FILE *file;
+ if ((file = wfopen(filename, "r")) == NULL)
+ return FALSE;
+ print_file(file);
+ return TRUE;
+}
+#endif /* BB_CAT */
+
+#if defined BB_ECHO || defined BB_SH || defined BB_TR
+char process_escape_sequence(char **ptr)
+{
+ char c;
+
+ switch (c = *(*ptr)++) {
+ case 'a':
+ c = '\a';
+ break;
+ case 'b':
+ c = '\b';
+ break;
+ case 'f':
+ c = '\f';
+ break;
+ case 'n':
+ c = '\n';
+ break;
+ case 'r':
+ c = '\r';
+ break;
+ case 't':
+ c = '\t';
+ break;
+ case 'v':
+ c = '\v';
+ break;
+ case '\\':
+ c = '\\';
+ break;
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ c -= '0';
+ if ('0' <= **ptr && **ptr <= '7') {
+ c = c * 8 + (*(*ptr)++ - '0');
+ if ('0' <= **ptr && **ptr <= '7')
+ c = c * 8 + (*(*ptr)++ - '0');
+ }
+ break;
+ default:
+ (*ptr)--;
+ c = '\\';
+ break;
+ }
+ return c;
+}
+#endif
+
+#if defined BB_BASENAME || defined BB_LN || defined BB_SH || defined BB_INIT || defined BB_FEATURE_USE_PROCFS
+char *get_last_path_component(char *path)
+{
+ char *s=path+strlen(path)-1;
+
+ /* strip trailing slashes */
+ while (s && *s == '/') {
+ *s-- = '\0';
+ }
+
+ /* find last component */
+ s = strrchr(path, '/');
+ if (s==NULL) return path;
+ else return s+1;
+}
+#endif
+
+#if defined BB_GREP || defined BB_SED
+void xregcomp(regex_t *preg, const char *regex, int cflags)
+{
+ int ret;
+ if ((ret = regcomp(preg, regex, cflags)) != 0) {
+ int errmsgsz = regerror(ret, preg, NULL, 0);
+ char *errmsg = xmalloc(errmsgsz);
+ regerror(ret, preg, errmsg, errmsgsz);
+ error_msg_and_die("xregcomp: %s\n", errmsg);
+ }
+}
+#endif
+
+#if defined BB_CAT || defined BB_HEAD || defined BB_WC
+FILE *wfopen(const char *path, const char *mode)
+{
+ FILE *fp;
+ if ((fp = fopen(path, mode)) == NULL) {
+ error_msg("%s: %s\n", path, strerror(errno));
+ errno = 0;
+ }
+ return fp;
+}
+#endif
+
+#if defined BB_HOSTNAME || defined BB_LOADACM || defined BB_MORE \
+ || defined BB_SED || defined BB_SH || defined BB_UNIQ \
+ || defined BB_WC || defined BB_CMP
+FILE *xfopen(const char *path, const char *mode)
+{
+ FILE *fp;
+ if ((fp = fopen(path, mode)) == NULL)
+ error_msg_and_die("%s: %s\n", path, strerror(errno));
+ return fp;
+}
+#endif
+
+int applet_name_compare(const void *x, const void *y)
+{
+ const struct BB_applet *applet1 = x;
+ const struct BB_applet *applet2 = y;
+
+ return strcmp(applet1->name, applet2->name);
+}
+