getline.c

来自「ReactOS是一些高手根据Windows XP的内核编写出的类XP。内核实现机」· C语言 代码 · 共 2,474 行 · 第 1/4 页

C
2,474
字号
	matchpfx = (char *) malloc(mlen + 1);
	memcpy(matchpfx, cp, mlen);
	matchpfx[mlen] = '\0';

#define GL_COMPLETE_VECTOR_BLOCK_SIZE 64

	nused = 0;
	ntoalloc = GL_COMPLETE_VECTOR_BLOCK_SIZE;
	newgl_matchlist = (char **) malloc((size_t) (sizeof(char *) * (ntoalloc + 1)));
	if (newgl_matchlist == NULL) {
		free(matchpfx);
		gl_beep();
		return 0;
	}
	gl_matchlist = newgl_matchlist;
	nalloced = ntoalloc;
	for (i=nused; i<=nalloced; i++)
		gl_matchlist[i] = NULL;

	gl_completion_exact_match_extra_char = ' ';
	for (nprocused = 0;; nprocused++) {
		if (nused == nalloced) {
			ntoalloc += GL_COMPLETE_VECTOR_BLOCK_SIZE;
			newgl_matchlist = (char **) realloc((char *) gl_matchlist, (size_t) (sizeof(char *) * (ntoalloc + 1)));
			if (newgl_matchlist == NULL) {
				/* not enough memory to expand list -- abort */
				for (i=0; i<nused; i++)
					free(gl_matchlist[i]);
				free(gl_matchlist);
				gl_matchlist = NULL;
				gl_beep();
				free(matchpfx);
				return 0;
			}
			gl_matchlist = newgl_matchlist;
			nalloced = ntoalloc;
			for (i=nused; i<=nalloced; i++)
				gl_matchlist[i] = NULL;
		}
	        cp = gl_completion_proc(matchpfx, nprocused);
		if (cp == NULL)
			break;
		if ((cp[0] == '.') && ((cp[1] == '\0') || ((cp[1] == '.') && (cp[2] == '\0'))))
			continue;	/* Skip . and .. */
		gl_matchlist[nused++] = cp;
	}

	if (gl_ellipses_during_completion != 0) {
		gl_fixup(gl_prompt, gl_pos, gl_pos);
		gl_puts("    ");
	}

	/* We now have an array strings, whose last element is NULL. */
	strtoadd = NULL;
	strtoadd1 = NULL;
	amt = 0;

	addquotes = (gl_filename_quoting_desired > 0) || ((gl_filename_quoting_desired < 0) && (gl_completion_proc == gl_local_filename_completion_proc));

	if (nused == 1) {
		/* Exactly one match. */
		strtoadd = gl_matchlist[0];
	} else if (tabtab != 0) {
		/* TAB-TAB: print all matches */
		gl_display_matches(nused);
	} else if ((nused > 1) && (mlen > 0)) {
		/* Find the greatest amount that matches. */
		for (glen = strlen(matchpfx); ; glen++) {
			allmatch = 1;
			for (i=1; i<nused; i++) {
				if (gl_matchlist[0][glen] != gl_matchlist[i][glen]) {
					allmatch = 0;
					break;
				}
			}
			if (allmatch == 0)
				break;
		}
		strtoadd1 = (char *) malloc(glen + 1);
		if (strtoadd1 != NULL) {
			memcpy(strtoadd1, gl_matchlist[0], glen);
			strtoadd1[glen] = '\0';
			strtoadd = strtoadd1;
		}
	}

	if (strtoadd != NULL) {
		if ((qmode == 0) && (addquotes != 0)) {
			if (strpbrk(strtoadd, gl_filename_quote_characters) != NULL) {
				qmode = (strchr(strtoadd, '"') == NULL) ? '"' : '\'';
				memmove(curposp + 1, curposp, lenaftercursor + 1 /* NUL */);
				curposp++;
				*startp++ = (char) qmode;
			}
		}
		startoff = (size_t) (startp - buf);
		amt = strlen(strtoadd);
		if ((amt + startoff + lenaftercursor) >= bufsize)
			amt = bufsize - (amt + startoff + lenaftercursor);
		memmove(curposp + amt - mlen, curposp, lenaftercursor + 1 /* NUL */);
		curposp += amt - mlen;
		memcpy(startp, strtoadd, amt);
		if (nused == 1) {
			/* Exact match. */
			if (qmode != 0) {
				/* Finish the quoting. */
				memmove(curposp + 1, curposp, lenaftercursor + 1 /* NUL */);
				curposp++;
				buf[amt + startoff] = (char) qmode;
				amt++;
			}
			memmove(curposp + 1, curposp, lenaftercursor + 1 /* NUL */);
			curposp++;
			buf[amt + startoff] = (char) gl_completion_exact_match_extra_char;
			amt++;
		} else if ((!wasateol) && (!isspace(*curposp))) {
			/* Not a full match, but insert a
			 * space for better readability.
			 */
			memmove(curposp + 1, curposp, lenaftercursor + 1 /* NUL */);
			curposp++;
			buf[amt + startoff] = ' ';
		}
		*loc = (int) (startoff + amt);

		if (strtoadd1 != NULL)
			free(strtoadd1);
	}

	/* Don't need this any more. */
	for (i=0; i<nused; i++)
		free(gl_matchlist[i]);
	free(gl_matchlist);
	gl_matchlist = NULL;
	free(matchpfx);

	return 0;
}	/* gl_do_tab_completion */




void
gl_tab_completion(gl_tab_completion_proc proc)
{
	if (proc == NULL)
		proc = gl_local_filename_completion_proc;	/* default proc */
	gl_completion_proc = proc;
}	/* gl_tab_completion */




#ifndef _StrFindLocalPathDelim
static char *
_StrRFindLocalPathDelim(const char *src)	/* TODO: optimize */
{
	const char *last;
	int c;

	last = NULL;
	for (;;) {
		c = *src++;
		if (c == '\0')
			break;
		if (IsLocalPathDelim(c))
			last = src - 1;
	}

	return ((char *) last);
}	/* StrRFindLocalPathDelim */
#endif	/* Windows */




void
gl_set_home_dir(const char *homedir)
{
	size_t len;
#ifdef __windows__
	const char *homedrive, *homepath;
	char wdir[64];
#else
	struct passwd *pw;
	char *cp;
#endif

	if (gl_home_dir != NULL) {
		free(gl_home_dir);
		gl_home_dir = NULL;
	}

	if (homedir == NULL) {
#ifdef __windows__
		homedrive = getenv("HOMEDRIVE");
		homepath = getenv("HOMEPATH");
		if ((homedrive != NULL) && (homepath != NULL)) {
			len = strlen(homedrive) + strlen(homepath) + 1;
			gl_home_dir = (char *) malloc(len);
			if (gl_home_dir != NULL) {
				strcpy(gl_home_dir, homedrive);
				strcat(gl_home_dir, homepath);
				return;
			}
		}

		wdir[0] = '\0';
		if (GetWindowsDirectory(wdir, sizeof(wdir) - 1) < 1)
			(void) strncpy(wdir, ".", sizeof(wdir));
		else if (wdir[1] == ':') {
			wdir[2] = '\\';
			wdir[3] = '\0';
		}
		homedir = wdir;
#else
		cp = (char *) getlogin();
		if (cp == NULL) {
			cp = (char *) getenv("LOGNAME");
			if (cp == NULL)
				cp = (char *) getenv("USER");
		}
		pw = NULL;
		if (cp != NULL)
			pw = getpwnam(cp);
		if (pw == NULL)
			pw = getpwuid(getuid());
		if (pw == NULL)
			return;	/* hell with it */
		homedir = pw->pw_dir;
#endif
	}

	len = strlen(homedir) + /* NUL */ 1;
	gl_home_dir = (char *) malloc(len);
	if (gl_home_dir != NULL) {
		memcpy(gl_home_dir, homedir, len);
	}
}	/* gl_set_home_dir */




char *gl_getpass(const char *const prompt, char *const pass, int dsize)
{
#ifdef __unix__
	char *cp;
	int c;

	memset(pass, 0, (size_t) sizeof(dsize));
	dsize--;
	gl_init();

	/* Display the prompt first. */
	if ((prompt != NULL) && (prompt[0] != '\0'))
		gl_puts(prompt);

	cp = pass;
	while ((c = gl_getc()) != (-1)) {
		if ((c == '\r') || (c == '\n'))
			break;
		if ((c == '\010') || (c == '\177'))	{
			/* ^H and DEL */
			if (cp > pass) {
				*--cp = '\0';
				gl_putc('\010');
				gl_putc(' ');
				gl_putc('\010');
			}
		} else if (cp < (pass + dsize)) {
			gl_putc('*');
			*cp++ = c;
		}
	}
	*cp = '\0';
	gl_putc('\n');
	gl_cleanup();
	return (pass);
#else
#ifdef __windows__
	char *cp;
	int c;

	FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE));
	ZeroMemory(pass, (DWORD) sizeof(dsize));
	dsize--;

	if ((prompt != NULL) && (prompt[0] != '\0'))
		_cputs(prompt);

	for (cp = pass;;) {
		c = (int) _getch();
		if ((c == '\r') || (c == '\n'))
			break;
		if ((c == '\010') || (c == '\177'))	{
			/* ^H and DEL */
			if (cp > pass) {
				*--cp = '\0';
				_putch('\010');
				_putch(' ');
				_putch('\010');
			}
		} else if (cp < (pass + dsize)) {
			_putch('*');
			*cp++ = c;
		}
	}
	_putch('\r');
	_putch('\n');
	Sleep(40);
	FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE));

	*cp = '\0';
	return (pass);
#endif	/* __windows__ */
#endif	/* ! __unix__ */
}	/* gl_getpass */




#ifdef __unix__

char *
gl_local_filename_completion_proc(const char *start, int idx)
{
	static DIR *dir = NULL;
	static int filepfxoffset;
	static size_t filepfxlen;

	const char *filepfx;
	struct dirent *dent;
	char *cp;
	const char *dirtoopen, *name;
	char *dirtoopen1;
	size_t len, len2;
	struct stat st;

	if (idx == 0) {
		if (dir != NULL) {
			/* shouldn't get here! */
			closedir(dir);
			dir = NULL;
		}
	}

	if (dir == NULL) {
		dirtoopen1 = NULL;
		cp = _StrRFindLocalPathDelim(start);
		if (cp == start) {
			dirtoopen = LOCAL_PATH_DELIM_STR;	/* root dir */
			filepfxoffset = 1;
		} else if (cp == NULL) {
			dirtoopen = ".";
			filepfxoffset = 0;
		} else {
			len = strlen(start) + 1;
			dirtoopen1 = (char *) malloc(len);
			if (dirtoopen1 == NULL)
				return NULL;
			memcpy(dirtoopen1, start, len);
			len = (cp - start);
			dirtoopen1[len] = '\0';
			dirtoopen = dirtoopen1;
			filepfxoffset = (int) ((cp + 1) - start);
		}

		if (strcmp(dirtoopen, "~") == 0) {
			if (gl_home_dir == NULL)
				gl_set_home_dir(NULL);
			if (gl_home_dir == NULL)
				return (NULL);
			dirtoopen = gl_home_dir;
		}

		dir = opendir(dirtoopen);
		if (dirtoopen1 != NULL)
			free(dirtoopen1);

		filepfx = start + filepfxoffset;
		filepfxlen = strlen(filepfx);
	}

	if (dir != NULL) {
		/* assumes "start" is same for each iteration. */
		filepfx = start + filepfxoffset;

		for (;;) {
			dent = readdir(dir);
			if (dent == NULL) {
				/* no more items */
				closedir(dir);
				dir = NULL;

				if (idx == 1) {
					/* There was exactly one match.
					 * In this special case, we
					 * want to append a / instead
					 * of a space.
					 */
					cp = gl_matchlist[0];
					if ((cp[0] == '~') && ((cp[1] == '\0') || (IsLocalPathDelim(cp[1])))) {
						len = strlen(cp + 1) + /* NUL */ 1;
						len2 = strlen(gl_home_dir);
						if (IsLocalPathDelim(gl_home_dir[len2 - 1]))
							len2--;
						cp = (char *) realloc(gl_matchlist[0], len + len2);
						if (cp == NULL) {
							cp = gl_matchlist[0];
						} else {
							memmove(cp + len2, cp + 1, len);
							memcpy(cp, gl_home_dir, len2);
							gl_matchlist[0] = cp;
						}
					}
					if ((lstat(cp, &st) == 0) && (S_ISDIR(st.st_mode)))
						gl_completion_exact_match_extra_char = LOCAL_PATH_DELIM;
				}
				return NULL;
			}

			name = dent->d_name;
			if ((name[0] == '.') && ((name[1] == '\0') || ((name[1] == '.') && (name[2] == '\0'))))
				continue;	/* Skip . and .. */

			if ((filepfxlen == 0) || (strncmp(name, filepfx, filepfxlen) == 0)) {
				/* match */
				len = strlen(name);
				cp = (char *) malloc(filepfxoffset + len + 1 /* spare */ + 1 /* NUL */);
				*cp = '\0';
				if (filepfxoffset > 0)
					memcpy(cp, start, (size_t) filepfxoffset);
				memcpy(cp + filepfxoffset, name, len + 1);
				return (cp);
			}
		}
	}

	return NULL;
}	/* gl_local_filename_completion_proc */

#endif	/* __unix__ */





#ifdef __windows__

char *
gl_local_filename_completion_proc(const char *start, int idx)
{
	static HANDLE searchHandle = NULL;
	static int filepfxoffset;
	static size_t filepfxlen;

	WIN32_FIND_DATA ffd;
	DWORD dwErr;
	char *cp, *c2, ch;
	const char *filepfx;
	const char *dirtoopen, *name;
	char *dirtoopen1, *dirtoopen2;
	size_t len, len2;

	if (idx == 0) {
		if (searchHandle != NULL) {
			/* shouldn't get here! */
			FindClose(searchHandle);
			searchHandle = NULL;
		}
	}


	if (searchHandle == NULL) {
		dirtoopen1 = NULL;
		dirtoopen2 = NULL;
		cp = _StrRFindLocalPathDelim(start);
		if (cp == start) {
			dirtoopen = LOCAL_PATH_DELIM_STR;	/* root dir */
			filepfxoffset = 1;
		} else if (cp == NULL) {
			dirtoopen = ".";
			filepfxoffset = 0;
		} else {
			len = strlen(start) + 1;
			dirtoopen1 = (char *) malloc(len);
			if (dirtoopen1 == NULL)
				return NULL;
			memcpy(dirtoopen1, start, len);
			len = (cp - start);
			dirtoopen1[len] = '\0';
			dirtoopen = dirtoopen1;
			filepfxoffset = (int) ((cp + 1) - start);
		}

		if (strcmp(dirtoopen, "~") == 0) {
			if (gl_home_dir == NULL)
				gl_set_home_dir(NULL);
			if (gl_home_dir == NULL)
				return (NULL);
			dirtoopen = gl_home_dir;
		}

		len = strlen(dirtoopen);
		dirtoopen2 = (char *) malloc(len + 8);
		if (dirtoopen2 == NULL) {
			if (dirtoopen1 != NULL)
				free(dirtoopen1);
			return NULL;
		}

		memcpy(dirtoopen2, dirtoopen, len + 1);
		if (dirtoopen2[len - 1] == LOCAL_PATH_DELIM)
			memcpy(dirtoopen2 + len, "*.*", (size_t) 4);
		else
			memcpy(dirtoopen2 + len, "\\*.*", (size_t) 5);

		/* "Open" the directory. */
		memset(&ffd, 0, sizeof(ffd));
		searchHandle = FindFirstFile(dirtoopen2, &ffd);

		free(dirtoopen2);
		if (dirtoopen1 != NULL)
			free(dirtoopen1);

		if (searchHandle == INVALID_HANDLE_VALUE) {
			return NULL;
		}

		filepfx = start + filepfxoffset;
		filepfxlen = strlen(filepfx);
	} else {
		/* assumes "start" is same for each iteration. */
		filepfx = start + filepfxoffset;
		goto next;
	}

	for (;;) {

		name = ffd.cFileName;
		if ((name[0] == '.') && ((name[1] == '\0') || ((name[1] == '.') && (name[2] == '\0'))))
			goto next;	/* Skip . and .. */

		if ((filepfxlen == 0) || (strnicmp(name, filepfx, filepfxlen) == 0)) {
			/* match */
			len = strlen(name);
			cp = (char *) malloc(filepfxoffset + len + 4 /* spare */ + 1 /* NUL */);
			*cp = '\0';
			if (filepfxoffset > 0)
				memcpy(cp, start, filepfxoffset);
			memcpy(cp + filepfxoffset, name, len + 1);
			if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
				/* Embed file type with name. */
				c2 = cp + filepfxoffset + len + 1;
				*c2++ = '\0';
				*c2++ = 'd';
				*c2 = '\0';
			} else {
				c2 = cp + filepfxoffset + len + 1;
				*c2++ = '\0';
				*c2++ = '-';
				*c2 = '\0';
			}
			return (cp);
		}

next:
		if (!FindNextFile(searchHandle, &ffd)) {
			dwErr = GetLastError();
			if (dwErr != ERROR_NO_MORE_FILES) {
				FindClose(searchHandle);
				searchHandle = NULL;
				return NULL;
			}

			/* no more items */
			FindClose(searchHandle);
			searchHandle = NULL;

			if (idx == 1) {
				/* There was exactly one match.
				 * In this special case, we
				 * want to append a \ instead
				 * of a space.
				 */
				cp = gl_matchlist[0];
				ch = (char) cp[strlen(cp) + 2];
				if (ch == (char) 'd')
					gl_completion_exact_match_extra_char = LOCAL_PATH_DELIM;

				if ((cp[0] == '~') && ((cp[1] == '\0') || (IsLocalPathDelim(cp[1])))) {
					len = strlen(cp + 1) + /* NUL */ 1;
					len2 = strlen(gl_home_dir);
					if (IsLocalPathDelim(gl_home_dir[len2 - 1]))
						len2--;
					cp = (char *) realloc(gl_matchlist[0], len + len2 + 4);
					if (cp == NULL) {
						cp = gl_matchlist[0];
					} else {
						memmove(cp + len2, cp + 1, len);
						memcpy(cp, gl_home_dir, len2);
						c2 = cp + len + len2;
						*c2++ = '\0';
						*c2++ = ch;
						*c2 = '\0';
						gl_matchlist[0] = cp;
					}
				}
			}
			break;
		}
	}
	return (NULL);
}	/* gl_local_filename_completion_proc */

#endif	/* __windows__ */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?