X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Futil.c;h=57bfa89bb77051a53a5964ee4c3f7520079391ff;hb=fb90a556c88027b2ba639037bacb55770414a4e2;hp=2f8225c0f493707625bfca9f85eef446206fe654;hpb=818e02ef3545b000e104b79cf52610ac0f1765cd;p=i3%2Fi3 diff --git a/src/util.c b/src/util.c index 2f8225c0..57bfa89b 100644 --- a/src/util.c +++ b/src/util.c @@ -1,49 +1,48 @@ /* - * vim:ts=8:expandtab + * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager + * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) * - * © 2009 Michael Stapelberg and contributors - * - * See file LICENSE for license information. - * - * util.c: Utility functions, which can be useful everywhere. + * util.c: Utility functions, which can be useful everywhere within i3 (see + * also libi3). * */ -#include -#include -#include -#include +#include "all.h" + #include #include -#include -#include #if defined(__OpenBSD__) #include #endif +#include +#include +#include +#include -#include - -#include "i3.h" -#include "data.h" -#include "table.h" -#include "layout.h" -#include "util.h" -#include "xcb.h" -#include "client.h" -#include "log.h" -#include "ewmh.h" - -static iconv_t conversion_descriptor = 0; -struct keyvalue_table_head by_parent = TAILQ_HEAD_INITIALIZER(by_parent); -struct keyvalue_table_head by_child = TAILQ_HEAD_INITIALIZER(by_child); +#define SN_API_NOT_YET_FROZEN 1 +#include int min(int a, int b) { - return (a < b ? a : b); + return (a < b ? a : b); } int max(int a, int b) { - return (a > b ? a : b); + return (a > b ? a : b); +} + +bool rect_contains(Rect rect, uint32_t x, uint32_t y) { + return (x >= rect.x && + x <= (rect.x + rect.width) && + y >= rect.y && + y <= (rect.y + rect.height)); +} + +Rect rect_add(Rect a, Rect b) { + return (Rect){a.x + b.x, + a.y + b.y, + a.width + b.width, + a.height + b.height}; } /* @@ -52,100 +51,56 @@ int max(int a, int b) { * */ bool update_if_necessary(uint32_t *destination, const uint32_t new_value) { - uint32_t old_value = *destination; + uint32_t old_value = *destination; - return ((*destination = new_value) != old_value); + return ((*destination = new_value) != old_value); } /* - * The s* functions (safe) are wrappers around malloc, strdup, …, which exits if one of - * the called functions returns NULL, meaning that there is no more memory available + * exec()s an i3 utility, for example the config file migration script or + * i3-nagbar. This function first searches $PATH for the given utility named, + * then falls back to the dirname() of the i3 executable path and then falls + * back to the dirname() of the target of /proc/self/exe (on linux). * - */ -void *smalloc(size_t size) { - void *result = malloc(size); - exit_if_null(result, "Error: out of memory (malloc(%zd))\n", size); - return result; -} - -void *scalloc(size_t size) { - void *result = calloc(size, 1); - exit_if_null(result, "Error: out of memory (calloc(%zd))\n", size); - return result; -} - -char *sstrdup(const char *str) { - char *result = strdup(str); - exit_if_null(result, "Error: out of memory (strdup())\n"); - return result; -} - -/* - * The table_* functions emulate the behaviour of libxcb-wm, which in libxcb 0.3.4 suddenly - * vanished. Great. + * This function should be called after fork()ing. * - */ -bool table_put(struct keyvalue_table_head *head, uint32_t key, void *value) { - struct keyvalue_element *element = scalloc(sizeof(struct keyvalue_element)); - element->key = key; - element->value = value; - - TAILQ_INSERT_TAIL(head, element, elements); - return true; -} - -void *table_remove(struct keyvalue_table_head *head, uint32_t key) { - struct keyvalue_element *element; - - TAILQ_FOREACH(element, head, elements) - if (element->key == key) { - void *value = element->value; - TAILQ_REMOVE(head, element, elements); - free(element); - return value; - } - - return NULL; -} - -void *table_get(struct keyvalue_table_head *head, uint32_t key) { - struct keyvalue_element *element; - - TAILQ_FOREACH(element, head, elements) - if (element->key == key) - return element->value; - - return NULL; -} - -/* - * Starts the given application by passing it through a shell. We use double fork - * to avoid zombie processes. As the started application’s parent exits (immediately), - * the application is reparented to init (process-id 1), which correctly handles - * childs, so we don’t have to do it :-). + * The first argument of the given argv vector will be overwritten with the + * executable name, so pass NULL. * - * The shell is determined by looking for the SHELL environment variable. If it - * does not exist, /bin/sh is used. + * If the utility cannot be found in any of these locations, it exits with + * return code 2. * */ -void start_application(const char *command) { - if (fork() == 0) { - /* Child process */ - if (fork() == 0) { - /* Stores the path of the shell */ - static const char *shell = NULL; - - if (shell == NULL) - if ((shell = getenv("SHELL")) == NULL) - shell = "/bin/sh"; - - /* This is the child */ - execl(shell, shell, "-c", command, (void*)NULL); - /* not reached */ - } - exit(0); - } - wait(0); +void exec_i3_utility(char *name, char *argv[]) { + /* start the migration script, search PATH first */ + char *migratepath = name; + argv[0] = migratepath; + execvp(migratepath, argv); + + /* if the script is not in path, maybe the user installed to a strange + * location and runs the i3 binary with an absolute path. We use + * argv[0]’s dirname */ + char *pathbuf = strdup(start_argv[0]); + char *dir = dirname(pathbuf); + sasprintf(&migratepath, "%s/%s", dir, name); + argv[0] = migratepath; + execvp(migratepath, argv); + +#if defined(__linux__) + /* on linux, we have one more fall-back: dirname(/proc/self/exe) */ + char buffer[BUFSIZ]; + if (readlink("/proc/self/exe", buffer, BUFSIZ) == -1) { + warn("could not read /proc/self/exe"); + exit(1); + } + dir = dirname(buffer); + sasprintf(&migratepath, "%s/%s", dir, name); + argv[0] = migratepath; + execvp(migratepath, argv); +#endif + + warn("Could not start %s", name); + exit(2); } /* @@ -154,365 +109,231 @@ void start_application(const char *command) { * */ void check_error(xcb_connection_t *conn, xcb_void_cookie_t cookie, char *err_message) { - xcb_generic_error_t *error = xcb_request_check(conn, cookie); - if (error != NULL) { - fprintf(stderr, "ERROR: %s (X error %d)\n", err_message , error->error_code); - xcb_disconnect(conn); - exit(-1); - } + xcb_generic_error_t *error = xcb_request_check(conn, cookie); + if (error != NULL) { + fprintf(stderr, "ERROR: %s (X error %d)\n", err_message , error->error_code); + xcb_disconnect(conn); + exit(-1); + } } /* - * Converts the given string to UCS-2 big endian for use with - * xcb_image_text_16(). The amount of real glyphs is stored in real_strlen, - * a buffer containing the UCS-2 encoded string (16 bit per glyph) is - * returned. It has to be freed when done. + * This function resolves ~ in pathnames. + * It may resolve wildcards in the first part of the path, but if no match + * or multiple matches are found, it just returns a copy of path as given. * */ -char *convert_utf8_to_ucs2(char *input, int *real_strlen) { - size_t input_size = strlen(input) + 1; - /* UCS-2 consumes exactly two bytes for each glyph */ - int buffer_size = input_size * 2; - - char *buffer = smalloc(buffer_size); - size_t output_size = buffer_size; - /* We need to use an additional pointer, because iconv() modifies it */ - char *output = buffer; - - /* We convert the input into UCS-2 big endian */ - if (conversion_descriptor == 0) { - conversion_descriptor = iconv_open("UCS-2BE", "UTF-8"); - if (conversion_descriptor == 0) { - fprintf(stderr, "error opening the conversion context\n"); - exit(1); - } - } - - /* Get the conversion descriptor back to original state */ - iconv(conversion_descriptor, NULL, NULL, NULL, NULL); - - /* Convert our text */ - int rc = iconv(conversion_descriptor, (void*)&input, &input_size, &output, &output_size); - if (rc == (size_t)-1) { - perror("Converting to UCS-2 failed"); - if (real_strlen != NULL) - *real_strlen = 0; - return NULL; +char *resolve_tilde(const char *path) { + static glob_t globbuf; + char *head, *tail, *result; + + tail = strchr(path, '/'); + head = strndup(path, tail ? tail - path : strlen(path)); + + int res = glob(head, GLOB_TILDE, NULL, &globbuf); + free(head); + /* no match, or many wildcard matches are bad */ + if (res == GLOB_NOMATCH || globbuf.gl_pathc != 1) + result = sstrdup(path); + else if (res != 0) { + die("glob() failed"); + } else { + head = globbuf.gl_pathv[0]; + result = scalloc(strlen(head) + (tail ? strlen(tail) : 0) + 1); + strncpy(result, head, strlen(head)); + if (tail) + strncat(result, tail, strlen(tail)); } + globfree(&globbuf); - if (real_strlen != NULL) - *real_strlen = ((buffer_size - output_size) / 2) - 1; - - return buffer; + return result; } /* - * Returns the client which comes next in focus stack (= was selected before) for - * the given container, optionally excluding the given client. + * Checks if the given path exists by calling stat(). * */ -Client *get_last_focused_client(xcb_connection_t *conn, Container *container, Client *exclude) { - Client *current; - SLIST_FOREACH(current, &(container->workspace->focus_stack), focus_clients) - if ((current->container == container) && ((exclude == NULL) || (current != exclude))) - return current; - return NULL; +bool path_exists(const char *path) { + struct stat buf; + return (stat(path, &buf) == 0); } - /* - * Sets the given client as focused by updating the data structures correctly, - * updating the X input focus and finally re-decorating both windows (to signalize - * the user the new focus situation) - * - */ -void set_focus(xcb_connection_t *conn, Client *client, bool set_anyways) { - /* The dock window cannot be focused, but enter notifies are still handled correctly */ - if (client->dock) - return; - - /* Store the old client */ - Client *old_client = SLIST_FIRST(&(c_ws->focus_stack)); - - /* Check if the focus needs to be changed at all */ - if (!set_anyways && (old_client == client)) - return; - - /* Store current_row/current_col */ - c_ws->current_row = current_row; - c_ws->current_col = current_col; - c_ws = client->workspace; - ewmh_update_current_desktop(); - /* Load current_col/current_row if we switch to a client without a container */ - current_col = c_ws->current_col; - current_row = c_ws->current_row; - - /* Update container */ - if (client->container != NULL) { - client->container->currently_focused = client; - - current_col = client->container->col; - current_row = client->container->row; - } - - CLIENT_LOG(client); - /* Set focus to the entered window, and flush xcb buffer immediately */ - xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT, client->child, XCB_CURRENT_TIME); - ewmh_update_active_window(client->child); - //xcb_warp_pointer(conn, XCB_NONE, client->child, 0, 0, 0, 0, 10, 10); - - if (client->container != NULL) { - /* Get the client which was last focused in this particular container, it may be a different - one than old_client */ - Client *last_focused = get_last_focused_client(conn, client->container, NULL); - - /* In stacking containers, raise the client in respect to the one which was focused before */ - if ((client->container->mode == MODE_STACK || client->container->mode == MODE_TABBED) && - client->container->workspace->fullscreen_client == NULL) { - /* We need to get the client again, this time excluding the current client, because - * we might have just gone into stacking mode and need to raise */ - Client *last_focused = get_last_focused_client(conn, client->container, client); - - if (last_focused != NULL) { - DLOG("raising above frame %p / child %p\n", last_focused->frame, last_focused->child); - uint32_t values[] = { last_focused->frame, XCB_STACK_MODE_ABOVE }; - xcb_configure_window(conn, client->frame, XCB_CONFIG_WINDOW_SIBLING | XCB_CONFIG_WINDOW_STACK_MODE, values); - } - } - - /* If it is the same one as old_client, we save us the unnecessary redecorate */ - if ((last_focused != NULL) && (last_focused != old_client)) - redecorate_window(conn, last_focused); - } - - /* If the last client was a floating client, we need to go to the next - * tiling client in stack and re-decorate it. */ - if (old_client != NULL && client_is_floating(old_client)) { - DLOG("Coming from floating client, searching next tiling...\n"); - Client *current; - SLIST_FOREACH(current, &(client->workspace->focus_stack), focus_clients) { - if (client_is_floating(current)) - continue; - - DLOG("Found window: %p / child %p\n", current->frame, current->child); - redecorate_window(conn, current); - break; - } - - } - - SLIST_REMOVE(&(client->workspace->focus_stack), client, Client, focus_clients); - SLIST_INSERT_HEAD(&(client->workspace->focus_stack), client, focus_clients); - - /* If we’re in stacking mode, this renders the container to update changes in the title - bars and to raise the focused client */ - if ((old_client != NULL) && (old_client != client) && !old_client->dock) - redecorate_window(conn, old_client); - - /* redecorate_window flushes, so we don’t need to */ - redecorate_window(conn, client); -} - -/* - * Called when the user switches to another mode or when the container is - * destroyed and thus needs to be cleaned up. + * Goes through the list of arguments (for exec()) and checks if the given argument + * is present. If not, it copies the arguments (because we cannot realloc it) and + * appends the given argument. * */ -void leave_stack_mode(xcb_connection_t *conn, Container *container) { - /* When going out of stacking mode, we need to close the window */ - struct Stack_Window *stack_win = &(container->stack_win); - - SLIST_REMOVE(&stack_wins, stack_win, Stack_Window, stack_windows); - - xcb_free_gc(conn, stack_win->pixmap.gc); - xcb_free_pixmap(conn, stack_win->pixmap.id); - xcb_destroy_window(conn, stack_win->window); - - stack_win->rect.width = -1; - stack_win->rect.height = -1; +static char **append_argument(char **original, char *argument) { + int num_args; + for (num_args = 0; original[num_args] != NULL; num_args++) { + DLOG("original argument: \"%s\"\n", original[num_args]); + /* If the argument is already present we return the original pointer */ + if (strcmp(original[num_args], argument) == 0) + return original; + } + /* Copy the original array */ + char **result = smalloc((num_args+2) * sizeof(char*)); + memcpy(result, original, num_args * sizeof(char*)); + result[num_args] = argument; + result[num_args+1] = NULL; + + return result; } /* - * Switches the layout of the given container taking care of the necessary house-keeping + * Returns the name of a temporary file with the specified prefix. * */ -void switch_layout_mode(xcb_connection_t *conn, Container *container, int mode) { - if (mode == MODE_STACK || mode == MODE_TABBED) { - /* When we’re already in stacking mode, nothing has to be done */ - if ((mode == MODE_STACK && container->mode == MODE_STACK) || - (mode == MODE_TABBED && container->mode == MODE_TABBED)) - return; - - if (container->mode == MODE_STACK || container->mode == MODE_TABBED) - goto after_stackwin; - - /* When entering stacking mode, we need to open a window on - * which we can draw the title bars of the clients, it has - * height 1 because we don’t bother here with calculating the - * correct height - it will be adjusted when rendering anyways. - * Also, we need to use max(width, 1) because windows cannot - * be created with either width == 0 or height == 0. */ - Rect rect = {container->x, container->y, max(container->width, 1), 1}; - - uint32_t mask = 0; - uint32_t values[2]; - - /* Don’t generate events for our new window, it should *not* be managed */ - mask |= XCB_CW_OVERRIDE_REDIRECT; - values[0] = 1; - - /* We want to know when… */ - mask |= XCB_CW_EVENT_MASK; - values[1] = XCB_EVENT_MASK_ENTER_WINDOW | /* …mouse is moved into our window */ - XCB_EVENT_MASK_BUTTON_PRESS | /* …mouse is pressed */ - XCB_EVENT_MASK_EXPOSURE; /* …our window needs to be redrawn */ - - struct Stack_Window *stack_win = &(container->stack_win); - stack_win->window = create_window(conn, rect, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_CURSOR_LEFT_PTR, false, mask, values); - - stack_win->rect.height = 0; - - /* Initialize the entry for our cached pixmap. It will be - * created as soon as it’s needed (see cached_pixmap_prepare). */ - memset(&(stack_win->pixmap), 0, sizeof(struct Cached_Pixmap)); - stack_win->pixmap.referred_rect = &stack_win->rect; - stack_win->pixmap.referred_drawable = stack_win->window; - - stack_win->container = container; - - SLIST_INSERT_HEAD(&stack_wins, stack_win, stack_windows); - } else { - if (container->mode == MODE_STACK || container->mode == MODE_TABBED) - leave_stack_mode(conn, container); +char *get_process_filename(const char *prefix) { + char *dir = getenv("XDG_RUNTIME_DIR"); + if (dir == NULL) { + struct passwd *pw = getpwuid(getuid()); + const char *username = pw ? pw->pw_name : "unknown"; + sasprintf(&dir, "/tmp/i3-%s", username); + } else { + char *tmp; + sasprintf(&tmp, "%s/i3", dir); + dir = tmp; + } + if (!path_exists(dir)) { + if (mkdir(dir, 0700) == -1) { + perror("mkdir()"); + return NULL; } -after_stackwin: - container->mode = mode; - - /* Force reconfiguration of each client */ - Client *client; + } + char *filename; + sasprintf(&filename, "%s/%s.%d", dir, prefix, getpid()); + free(dir); + return filename; +} - CIRCLEQ_FOREACH(client, &(container->clients), clients) - client->force_reconfigure = true; +#define y(x, ...) yajl_gen_ ## x (gen, ##__VA_ARGS__) +#define ystr(str) yajl_gen_string(gen, (unsigned char*)str, strlen(str)) - render_layout(conn); +char *store_restart_layout() { + setlocale(LC_NUMERIC, "C"); +#if YAJL_MAJOR >= 2 + yajl_gen gen = yajl_gen_alloc(NULL); +#else + yajl_gen gen = yajl_gen_alloc(NULL, NULL); +#endif - if (container->currently_focused != NULL) { - /* We need to make sure that this client is above *each* of the - * other clients in this container */ - Client *last_focused = get_last_focused_client(conn, container, container->currently_focused); + dump_node(gen, croot, true); - CIRCLEQ_FOREACH(client, &(container->clients), clients) { - if (client == container->currently_focused || client == last_focused) - continue; + setlocale(LC_NUMERIC, ""); - DLOG("setting %08x below %08x / %08x\n", client->frame, container->currently_focused->frame); - uint32_t values[] = { container->currently_focused->frame, XCB_STACK_MODE_BELOW }; - xcb_configure_window(conn, client->frame, - XCB_CONFIG_WINDOW_SIBLING | XCB_CONFIG_WINDOW_STACK_MODE, values); - } + const unsigned char *payload; +#if YAJL_MAJOR >= 2 + size_t length; +#else + unsigned int length; +#endif + y(get_buf, &payload, &length); + + /* create a temporary file if one hasn't been specified, or just + * resolve the tildes in the specified path */ + char *filename; + if (config.restart_state_path == NULL) { + filename = get_process_filename("restart-state"); + if (!filename) + return NULL; + } else { + filename = resolve_tilde(config.restart_state_path); + } + + int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); + if (fd == -1) { + perror("open()"); + free(filename); + return NULL; + } + + int written = 0; + while (written < length) { + int n = write(fd, payload + written, length - written); + /* TODO: correct error-handling */ + if (n == -1) { + perror("write()"); + free(filename); + close(fd); + return NULL; + } + if (n == 0) { + printf("write == 0?\n"); + free(filename); + close(fd); + return NULL; + } + written += n; +#if YAJL_MAJOR >= 2 + printf("written: %d of %zd\n", written, length); +#else + printf("written: %d of %d\n", written, length); +#endif + } + close(fd); - if (last_focused != NULL) { - DLOG("Putting last_focused directly underneath the currently focused\n"); - uint32_t values[] = { container->currently_focused->frame, XCB_STACK_MODE_BELOW }; - xcb_configure_window(conn, last_focused->frame, - XCB_CONFIG_WINDOW_SIBLING | XCB_CONFIG_WINDOW_STACK_MODE, values); - } + if (length > 0) { + printf("layout: %.*s\n", (int)length, payload); + } + y(free); - set_focus(conn, container->currently_focused, true); - } + return filename; } /* - * Gets the first matching client for the given window class/window title. - * If the paramater specific is set to a specific client, only this one - * will be checked. + * Restart i3 in-place + * appends -a to argument list to disable autostart * */ -Client *get_matching_client(xcb_connection_t *conn, const char *window_classtitle, - Client *specific) { - char *to_class, *to_title, *to_title_ucs = NULL; - int to_title_ucs_len = 0; - Client *matching = NULL; - - to_class = sstrdup(window_classtitle); - - /* If a title was specified, split both strings at the slash */ - if ((to_title = strstr(to_class, "/")) != NULL) { - *(to_title++) = '\0'; - /* Convert to UCS-2 */ - to_title_ucs = convert_utf8_to_ucs2(to_title, &to_title_ucs_len); - } +void i3_restart(bool forget_layout) { + char *restart_filename = forget_layout ? NULL : store_restart_layout(); - /* If we were given a specific client we only check if that one matches */ - if (specific != NULL) { - if (client_matches_class_name(specific, to_class, to_title, to_title_ucs, to_title_ucs_len)) - matching = specific; - goto done; - } + kill_configerror_nagbar(true); - DLOG("Getting clients for class \"%s\" / title \"%s\"\n", to_class, to_title); - Workspace *ws; - TAILQ_FOREACH(ws, workspaces, workspaces) { - if (ws->output == NULL) - continue; - - Client *client; - SLIST_FOREACH(client, &(ws->focus_stack), focus_clients) { - DLOG("Checking client with class=%s / %s, name=%s\n", client->window_class_instance, - client->window_class_class, client->name); - if (!client_matches_class_name(client, to_class, to_title, to_title_ucs, to_title_ucs_len)) - continue; - - matching = client; - goto done; - } - } + restore_geometry(); -done: - free(to_class); - FREE(to_title_ucs); - return matching; -} + ipc_shutdown(); -/* - * Goes through the list of arguments (for exec()) and checks if the given argument - * is present. If not, it copies the arguments (because we cannot realloc it) and - * appends the given argument. - * - */ -static char **append_argument(char **original, char *argument) { + LOG("restarting \"%s\"...\n", start_argv[0]); + /* make sure -a is in the argument list or append it */ + start_argv = append_argument(start_argv, "-a"); + + /* replace -r so that the layout is restored */ + if (restart_filename != NULL) { + /* create the new argv */ int num_args; - for (num_args = 0; original[num_args] != NULL; num_args++) { - DLOG("original argument: \"%s\"\n", original[num_args]); - /* If the argument is already present we return the original pointer */ - if (strcmp(original[num_args], argument) == 0) - return original; + for (num_args = 0; start_argv[num_args] != NULL; num_args++); + char **new_argv = scalloc((num_args + 3) * sizeof(char*)); + + /* copy the arguments, but skip the ones we'll replace */ + int write_index = 0; + bool skip_next = false; + for (int i = 0; i < num_args; ++i) { + if (skip_next) + skip_next = false; + else if (!strcmp(start_argv[i], "-r") || + !strcmp(start_argv[i], "--restart")) + skip_next = true; + else + new_argv[write_index++] = start_argv[i]; } - /* Copy the original array */ - char **result = smalloc((num_args+2) * sizeof(char*)); - memcpy(result, original, num_args * sizeof(char*)); - result[num_args] = argument; - result[num_args+1] = NULL; - return result; -} + /* add the arguments we'll replace */ + new_argv[write_index++] = "--restart"; + new_argv[write_index] = restart_filename; -/* - * Restart i3 in-place - * appends -a to argument list to disable autostart - * - */ -void i3_restart() { - LOG("restarting \"%s\"...\n", start_argv[0]); - /* make sure -a is in the argument list or append it */ - start_argv = append_argument(start_argv, "-a"); + /* swap the argvs */ + start_argv = new_argv; + } - execvp(start_argv[0], start_argv); - /* not reached */ + execvp(start_argv[0], start_argv); + /* not reached */ } -#if defined(__OpenBSD__) +#if defined(__OpenBSD__) || defined(__APPLE__) /* * Taken from FreeBSD @@ -520,31 +341,30 @@ void i3_restart() { * */ void *memmem(const void *l, size_t l_len, const void *s, size_t s_len) { - register char *cur, *last; - const char *cl = (const char *)l; - const char *cs = (const char *)s; + register char *cur, *last; + const char *cl = (const char *)l; + const char *cs = (const char *)s; - /* we need something to compare */ - if (l_len == 0 || s_len == 0) - return NULL; + /* we need something to compare */ + if (l_len == 0 || s_len == 0) + return NULL; - /* "s" must be smaller or equal to "l" */ - if (l_len < s_len) - return NULL; + /* "s" must be smaller or equal to "l" */ + if (l_len < s_len) + return NULL; - /* special case where s_len == 1 */ - if (s_len == 1) - return memchr(l, (int)*cs, l_len); + /* special case where s_len == 1 */ + if (s_len == 1) + return memchr(l, (int)*cs, l_len); - /* the last position where its possible to find "s" in "l" */ - last = (char *)cl + l_len - s_len; + /* the last position where its possible to find "s" in "l" */ + last = (char *)cl + l_len - s_len; - for (cur = (char *)cl; cur <= last; cur++) - if (cur[0] == cs[0] && memcmp(cur, cs, s_len) == 0) - return cur; + for (cur = (char *)cl; cur <= last; cur++) + if (cur[0] == cs[0] && memcmp(cur, cs, s_len) == 0) + return cur; - return NULL; + return NULL; } #endif -