globales.pas 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. {
  2. Unidad con declaraciones globales del proyecto
  3. Creado por Tito Hinostroza - 01/08/2014
  4. }
  5. unit Globales; {$mode objfpc}{$H+}
  6. interface
  7. uses Classes, SysUtils, Forms, SynEdit, SynEditKeyCmds, MisUtils,
  8. SynEditTypes, StrUtils, lclType, FileUtil,
  9. types, LazLogger, LazUTF8, Menus, ComCtrls ;
  10. const
  11. NOM_PROG ='Tito''s Terminal'; //nombre de programa
  12. {$I ../version.txt} //versión del programa
  13. type
  14. //Tipos de conexiones
  15. TTipCon = (
  16. TCON_TELNET, //Conexión telnet común
  17. TCON_SSH, //Conexión ssh
  18. TCON_SERIAL, //Serial
  19. TCON_OTHER //Otro proceso
  20. );
  21. var
  22. //Variables globales
  23. MsjError : String; // Bandera - Mensaje de error.
  24. patApp : string; // Ruta de la aplicación.
  25. patMacros : string; // Ruta de la carpeta de macros.
  26. patTemp : string; // Ruta de la carpeta temporal
  27. patSyntax : string; // Ruta para guardar las sintaxis.
  28. patSessions : string; // Ruta para guardar las sesiones.
  29. inputFile : string; // Archivo de entrada.
  30. showError : Boolean; // Bandera para mostrar mensajesde error.
  31. //Funciones para control del editor
  32. function IdFromTTreeNode(node: TTreeNode): string;
  33. function TTreeNodeFromId(Id: string; tree: TTreeView): TTreeNode;
  34. procedure SubirCursorBloque(ed: TSynEdit; Shift: TShiftState);
  35. procedure BajarCursorBloque(ed: TSynEdit; Shift: TShiftState);
  36. procedure InsertaColumnasBloque(ed: TsynEdit; var key: TUTF8Char);
  37. function LeerParametros: boolean;
  38. function NombDifArc(nomBase: String): String;
  39. procedure LeeArchEnMenu(arc: string; mn: TMenuItem; accion: TNotifyEvent);
  40. procedure CopiarMemu(menOrig, menDest: TMenuItem);
  41. procedure Init;
  42. implementation
  43. function IdFromTTreeNode(node: TTreeNode): string;
  44. //Returns an ID with indication of the position of a TTreeNode'.
  45. //It has the form: 1, 1.1, 1.2. Only works for two levels.
  46. var
  47. nivel: Integer;
  48. begin
  49. nivel := node.Level;
  50. if nivel = 1 then //de dos niveles
  51. Result := IntToStr(node.Parent.Index+1) + '.' +
  52. IntToStr(node.Index+1)
  53. else //de un nivel
  54. Result := IntToStr(node.Index+1);
  55. end;
  56. function TTreeNodeFromId(Id: string; tree: TTreeView): TTreeNode;
  57. //Returns a TreeNode, given the ID position. If not found, returns NIL.
  58. //Only works for two levels.
  59. var
  60. list: TStringList;
  61. it: TTreeNode;
  62. Padre: TTreeNode;
  63. i: Integer;
  64. begin
  65. Result := nil; //por defecto
  66. if Id='' then exit;
  67. list := TStringList.Create;
  68. list.Delimiter:='.';
  69. list.DelimitedText:=Id;
  70. if list.Count = 1 then begin //de un solo nivel
  71. //ubica el nodo
  72. for it in Tree.Items do if it.Level=0 then begin
  73. if IntToStr(it.Index+1) = list[0] then Result := it;
  74. end;
  75. end else begin //de dos o más niveles
  76. //ubica al nodo padre
  77. Padre := nil;
  78. for it in Tree.Items do begin
  79. if it.Level=0 then begin
  80. if IntToStr(it.Index+1) = list[0] then Padre := it;
  81. end;
  82. end;
  83. if Padre = nil then begin
  84. list.Destroy;
  85. exit; //no lo ubica
  86. end;
  87. //ubica al nodo hijo
  88. for i := 0 to Padre.Count-1 do begin
  89. it := Padre.Items[i];
  90. if it.Level=1 then begin
  91. if IntToStr(it.Index+1) = list[1] then Result := it;
  92. end;
  93. end;
  94. end;
  95. list.Destroy;
  96. end;
  97. //Funciones para control del editor
  98. procedure EdSubirCursor(ed: TSynEdit; Shift: TShiftState);
  99. //Sube el cursor del SynEdit, una psoición, considerando el estado de <Shift>
  100. { TODO : Es muy lento para varias líneas (>100) }
  101. begin
  102. if ed.SelectionMode = smColumn then //en modo columna
  103. ed.ExecuteCommand(ecColSelUp, #0, nil) //solo se puede mover con selección
  104. else //en modo normal
  105. if ssShift in Shift then
  106. ed.ExecuteCommand(ecSelUp, #0, nil) //sube
  107. else
  108. ed.ExecuteCommand(ecUp, #0, nil); //sube
  109. end;
  110. procedure EdBajarCursor(ed: TSynEdit; Shift: TShiftState);
  111. //Baja el cursor del SynEdit, una psoición, considerando el estado de <Shift>
  112. begin
  113. if ed.SelectionMode = smColumn then //en modo columna
  114. ed.ExecuteCommand(ecColSelDown, #0, nil) //solo se puede mover con selección
  115. else //en modo normal
  116. if ssShift in Shift then
  117. ed.ExecuteCommand(ecSelDown, #0, nil) //sube
  118. else
  119. ed.ExecuteCommand(ecDown, #0, nil); //sube
  120. end;
  121. procedure SubirCursorBloque(ed: TSynEdit; Shift: TShiftState);
  122. //Sube el cursor hasta encontrar una línea en blanco (si estaba en una diferente de blanco)
  123. //o hasta encontrar una línea diferente de blanco (si estaba en una línea en blanco)
  124. var
  125. curY : longint;
  126. begin
  127. CurY := ed.CaretY; //Lee posición de cursor
  128. if CurY = 1 then exit; //no se puede subir más
  129. if CurY = 2 then begin
  130. EdSubirCursor(ed, Shift); //solo puede subir una posición.
  131. exit;
  132. end;
  133. if trim(ed.lines[CurY-2]) = '' then begin
  134. //busca línea diferente de blanco
  135. while CurY > 1 do begin
  136. if trim(ed.lines[Cury-2]) <> '' then Exit; //pone y sale
  137. Dec(CurY);
  138. EdSubirCursor(ed, Shift);
  139. end;
  140. end else begin
  141. //busca línea en blanco hacia abajo
  142. while CurY > 1 do begin
  143. if trim(ed.lines[CurY-2]) = '' then Exit; //pone y sale
  144. Dec(CurY);
  145. EdSubirCursor(ed, Shift);
  146. end;
  147. end;
  148. end;
  149. procedure BajarCursorBloque(ed: TSynEdit; Shift: TShiftState);
  150. //Baja el cursor hasta encontrar una línea en blanco (si estaba en una diferente de blanco)
  151. //o hasta encontrar una línea diferente de blanco (si estaba en una línea en blanco)
  152. var
  153. curY : longint;
  154. begin
  155. CurY := ed.CaretY; //Lee posición de cursor
  156. if CurY = ed.Lines.Count then exit; //no se puede bajar más
  157. if CurY = ed.Lines.Count - 1 then begin
  158. EdBajarCursor(ed, Shift); //solo puede bajar una posición.
  159. exit;
  160. end;
  161. if trim(ed.lines[CurY-1]) = '' then begin
  162. //busca línea diferente de blanco
  163. while CurY < ed.Lines.Count do begin
  164. if trim(ed.lines[CurY-1]) <> '' then Exit; //pone y sale
  165. Inc(CurY);
  166. EdBajarCursor(ed, Shift);
  167. end;
  168. end else begin
  169. //busca línea en blanco hacia abajo
  170. while CurY < ed.Lines.Count do begin
  171. if trim(ed.lines[CurY-1]) = '' then Exit; //pone y sale
  172. Inc(CurY);
  173. EdBajarCursor(ed, Shift);
  174. end;
  175. end;
  176. end;
  177. procedure InsertaColumnasBloque(ed: TsynEdit; var key: TUTF8Char);
  178. //Inserta un caracter en un bloque de selección en modo columna.
  179. //El editor debe estar en modo columna con un bloque de selección activo.
  180. //El texto se insertará en todas las filas de la selección.
  181. { TODO : Verificar funcionamiento en líneas con tabulaciones.}
  182. var
  183. curX,curY : longint;
  184. p1,p2:TPoint;
  185. tmp: pchar;
  186. begin
  187. (*Verifica el caso particular en que se tiene solo una fila de selección en modo columna*)
  188. if ed.BlockBegin.y = ed.BlockEnd.y then begin
  189. //no hay mucho que procesar en modo columna
  190. ed.ExecuteCommand(ecChar,key,nil);
  191. //cancela procesamiento, para que no procese de nuevo el caracter
  192. key := #0;
  193. Exit;
  194. end;
  195. (*Verifica ancho de selección. Debe dejarse en ancho nulo, antes de pegar el caracter en
  196. la selección *)
  197. if ed.SelAvail then begin //se podría haber usado "if BlockBegin.x <> BlockEnd.x", pero se
  198. //se tendría problemas porque las posiciones físicas pueden
  199. //coincidir aún cuando las posiciones lógcas, no.
  200. p2 := ed.BlockEnd; //Lee final de selección
  201. //hay selección de por lo menos un caracter de ancho
  202. ed.ExecuteCommand(ecDeleteChar, #0, nil); //limpia selección
  203. //Ahora el bloque de selección tiene ancho cero, alto 1 y el cursor está dentro.
  204. //Ahora se debe restaurar la altura del bloque, modificando BlockEnd.
  205. //Se usa la posición horizontal del cursor, que coincide con el bloque
  206. //Se usa transformación, porque BlockEnd, trabaja en coordenada lógica
  207. p2.x:=ed.PhysicalToLogicalCol(ed.Lines[p2.y-1],p2.y-1,ed.CaretX);
  208. ed.BlockEnd:=p2; //restaura también, la altura original del bloque
  209. ed.SelectionMode := smColumn; //restaura el modo columna
  210. end;
  211. //El bloque de selección tiene ahora ancho cero y alto original.
  212. (* la idea aquí es poner en el portapapeles, una estructura con varias filas (tantas cono haya
  213. seleccionada) del caracter que se quiera insertar. *)
  214. //Guarda cursor
  215. curX := ed.CaretX;
  216. curY := ed.CaretY;
  217. //Lee coordenadas del bloque nulo
  218. p1 := ed.BlockBegin;
  219. p2 := ed.BlockEnd;
  220. tmp := PChar(DupeString(key+#13#10,p2.y-p1.y)+key); //construye texto
  221. ed.DoCopyToClipboard(tmp,''); //pone en portapapeles
  222. (*Aquí ya se tiene en el portapapeles, la estructura repetida del caracter a insertar*)
  223. //pega la selección modificada
  224. ed.CaretY := p1.y; //pone cursor arriba para pegar
  225. // ed.SelectionMode := smNormal; //debería poder trabajar en Normal
  226. //Si la estructura en el portapapeles, es correcta, se copiará correctamente en columnas.
  227. ed.ExecuteCommand(ecPaste,#0,nil);
  228. //desplaza Cursor y bloque, para escribir siguiente caracter a la derecha
  229. curX += 1;
  230. // p1.x += 1;
  231. // p2.x += 1;
  232. p1.x := ed.PhysicalToLogicalCol(ed.Lines[p1.y-1],p1.y-1,curX);
  233. p2.x := ed.PhysicalToLogicalCol(ed.Lines[p2.y-1],p2.y-1,curX);
  234. //calcula nuevamente la posición física del cursor, para evitar que el cursor
  235. //pueda caer en medio de una tabulación.
  236. CurX := ed.LogicalToPhysicalCol(ed.Lines[p1.y-1],p1.y-1,p1.x);
  237. //restaura posición de cursor
  238. ed.CaretX := curX;
  239. ed.CaretY := curY;
  240. //restaura bloque de selección, debe hacerse después de posicionar el cursor
  241. ed.BlockBegin := p1;
  242. ed.BlockEnd := p2;
  243. ed.SelectionMode := smColumn; //mantiene modo de columna
  244. key := #0; //cancela procesamiento de teclado
  245. end;
  246. function LeerParametros: boolean;
  247. {lee la linea de comandos
  248. Si hay error devuelve TRUE}
  249. var
  250. par : String;
  251. i : Integer;
  252. begin
  253. Result := false; //valor por defecto
  254. //valores por defecto
  255. inputFile := '';
  256. showError := True;
  257. //Lee parámetros de entrada
  258. par := ParamStr(1);
  259. if par = '' then begin
  260. MsgErr('Nombre de archivo vacío.');
  261. Result := true;
  262. exit; //sale con error
  263. end;
  264. if par[1] = '/' then begin //es parámetro
  265. i := 1; //para que explore desde el principio
  266. end else begin //es archivo
  267. inputFile := par; //el primer elemento es el archivo de entrada
  268. i := 2; //explora siguientes
  269. end;
  270. while i <= ParamCount do begin
  271. par := ParamStr(i);
  272. If par[1] = '/' Then begin
  273. Case UpCase(par) of
  274. '/NOERROR': showError := False;
  275. '/ERROR': showError := True;
  276. Else begin
  277. MsgErr('Error. Parámetro desconocido: ' + par);
  278. Result := true;
  279. exit; //sale con error
  280. End
  281. End
  282. end Else begin
  283. // archivoSal := par;
  284. End;
  285. inc(i); //pasa al siguiente
  286. end;
  287. End;
  288. function NombDifArc(nomBase: String): String;
  289. {Genera un nombre diferente de archivo, tomando el nombre dado como raiz.}
  290. const MAX_ARCH = 10;
  291. var i : Integer; //Número de intentos con el nombre de archivo de salida
  292. cadBase : String; //Cadena base del nombre base
  293. extArc: string; //extensión
  294. function NombArchivo(i: integer): string;
  295. begin
  296. Result := cadBase + '-' + IntToStr(i) + extArc;
  297. end;
  298. begin
  299. Result := nomBase; //nombre por defecto
  300. extArc := ExtractFileExt(nomBase);
  301. if ExtractFilePath(nomBase) = '' then exit; //protección
  302. //quita ruta y cambia extensión
  303. cadBase := ChangeFileExt(nomBase,'');
  304. //busca archivo libre
  305. for i := 0 to MAX_ARCH-1 do begin
  306. If not FileExists(NombArchivo(i)) then begin
  307. //Se encontró nombre libre
  308. Exit(NombArchivo(i)); //Sale con nombre
  309. end;
  310. end;
  311. //todos los nombres estaban ocupados. Sale con el mismo nombre
  312. End;
  313. procedure LeeArchEnMenu(arc: string; mn: TMenuItem; accion: TNotifyEvent);
  314. {Lee la carpeta de macros y actualiza un menú con el nombre de los archivos
  315. Devuelve la cantidad de ítems leidos. }
  316. var
  317. Hay: Boolean;
  318. SR: TSearchRec;
  319. item: TMenuItem;
  320. n : integer;
  321. begin
  322. // mn.Clear;
  323. // Crear la lista de ficheos en el dir. StartDir (no directorios!)
  324. n := 0; //contador
  325. Hay := FindFirst(arc,faAnyFile - faDirectory, SR) = 0;
  326. while Hay do begin
  327. //encontró. Crea entrada
  328. item := TMenuItem.Create(nil);
  329. item.Caption:= SysToUTF8(SR.Name); //nombre
  330. item.OnClick:=accion;
  331. mn.Add(item);
  332. //busca siguiente
  333. Hay := FindNext(SR) = 0;
  334. inc(n);
  335. end;
  336. if n = 0 then begin //no encontró
  337. //encontró. Crea entrada
  338. item := TMenuItem.Create(nil);
  339. item.Caption:= 'vacío'; //nombre
  340. item.Enabled := false;
  341. mn.Add(item);
  342. end;
  343. // Result := n;
  344. end;
  345. procedure CopiarMemu(menOrig, menDest: TMenuItem);
  346. //Copìa los ítems de un menú a otro
  347. var
  348. it: TMenuItem;
  349. i: Integer;
  350. begin
  351. menDest.Caption:=menOrig.Caption;
  352. menDest.Clear;
  353. for i := 0 To menOrig.Count - 1 do begin
  354. it := TMenuItem.Create(nil);
  355. it.Caption:= menOrig[i].Caption;
  356. it.OnClick:=menOrig[i].OnClick;
  357. it.Checked:=menOrig[i].Checked;
  358. menDest.Add(it);
  359. end;
  360. end;
  361. procedure Init;
  362. {Inicializa variables de la aplicación. Inicialmente, se teníe este código en la sección
  363. INITIALIZATION, pero como se generan mensajes GUI, en algunos casos se producían errores.
  364. }
  365. begin
  366. //Inicia directorios de la aplicación
  367. patApp := ExtractFilePath(Application.ExeName); //incluye el '\' final
  368. patSyntax := patApp + 'languages';
  369. patMacros := patApp + 'macros';
  370. patTemp := patApp + 'temp';
  371. patSessions:= patApp + 'sessions';
  372. inputFile := ''; //Archivo de entrada
  373. //Verifica existencia de carpetas de trabajo
  374. try
  375. if not DirectoryExists(patTemp) then begin
  376. msgexc('Folder /temp doesn''t exist. It will be created.');
  377. CreateDir(patTemp);
  378. end;
  379. if not DirectoryExists(patMacros) then begin
  380. msgexc('Folder /macros doesn''t exist. It will be created.');
  381. CreateDir(patMacros);
  382. end;
  383. if not DirectoryExists(patSyntax) then begin
  384. msgexc('Folder /lenguages doesn''t exist. It will be created.');
  385. CreateDir(patSyntax);
  386. end;
  387. if not DirectoryExists(patSessions) then begin
  388. msgexc('Folder /sessions doesn''t exist. It will be created.');
  389. CreateDir(patSessions);
  390. end;
  391. if not FileExists(patApp+'plink.exe') then begin
  392. msgErr('No se encuentra archivo plink.exe');
  393. end;
  394. except
  395. msgErr('Error. No se puede leer o crear directorios.');
  396. end;
  397. end;
  398. initialization
  399. finalization
  400. // {Por algún motivo, la unidad HeapTrc indica que hay gotera de memoria si no se liberan
  401. // estas cadenas: }
  402. // patApp := '';
  403. // patMacros := '';
  404. // patTemp := '';
  405. // patSyntax := '';
  406. // patSessions := '';
  407. end.